CSS 最近のWebページやアプリのレイアウトに適した、ラッパーの実装テクニックを徹底解説
Post on:2020年7月9日
最近のWebページやアプリに適した、ラッパーの実装テクニックを紹介します。
ラッパーとはコンテンツを読みやすい幅に包むもので、CSSでのラッパーの実装、マージンやパディングの追加、中央揃え、ラッパーのバリエーション、FlexboxやCSS Gridとの組み合わせ方など、レイアウトの実装テクニックが満載です。
Styling Layout Wrappers In CSS
by Ahmad Shadeed
- はじめに
- ラッパーとは
- ページにラッパーが必要な理由
- CSSでのラッパーの実装
- ラッパーのdisplayのタイプ
- ラッパー間のマージンの追加
- 全画面セクション内のラッパー
- ヒーローセクションにラッパーが必要ですか?
- ラッパーを中央揃えにするか、左揃えにするか
- ラッパーのバリエーションに対するCSS変数の使用
- display: contents;を使用する
- 流動的な背景に固定コンテンツを配置
- 終わりに
はじめに
Webページのコンテンツは、読みやすい幅に包まれている必要があります。これを実現するためには、ラッパーやコンテナと呼ばれるものを使用します。CSSでラッパーを使用することは、それに伴いいくつかの課題が生じる可能性があります。
この記事では、CSSで実装するレイアウトのラッパー、その仕組み、使い方、さらに使用しない場合の注意点を解説します。ここでは、ラッパーとコンテナという言葉を使用していますが、どちらも同じ意味です。
準備は整いました、さぁ始めましょう!
ラッパーとは
ラッパー、またはコンテナとは、要素のグループが別の要素の内側にラップ、または包まれていることを意味します。
例えば下記のように、追加の要素を使用せずに、<body>要素にラッパーを追加することができます。
1 2 3 4 5 6 7 |
body { max-width: 1170px; margin-left: auto; margin-right: auto; padding-left: 16px; padding-right: 16px; } |
ただし、<body>要素にラッパーを追加することは、今日の実装では実用的ではない場合があります。ラッパー要素は、子アイテムがその境界の外に出てしまうのを防ぐために使用するからです。下記のモックアップで見てみましょう。
ラッパーで境界の外に出てしまうのを防ぐ
aside要素とmain要素があり、それらを包む.wrapper要素があります。もちろん、.wrapper要素には、幅が定義されています。
1 2 3 4 |
<div class="wrapper"> <aside>...</aside> <main>...</main> </div> |
ラッパーがない場合を考えてみましょう。aside要素とmain要素はスクリーンの端にくっつき、特に大きなスクリーンではユーザーにとって非常に煩わしくなります。
ラッパーがない場合の表示
ラッパーがなく、要素を包んでいる要素がない場合は、上記のように要素が伸びて表示されます。この動作はユーザーが経験するべきものではありません。その理由を説明します。
ページにラッパーが必要な理由
ページにラッパーを使用することで、デザイナーまたはデベロッパーとして認識しておく必要がある利点がたくさんあります。
- コンテンツをより読みやすくします。
ラッパーがない場合、テキストや画像などのコンテンツはスクリーンの幅いっぱいに伸びてしまうことがあります。小さなスクリーンでは問題ないように思うかもしれませんが、大きいスクリーンでは非常に迷惑です。 - デザイン要素はグループ化した方がスペースを与えるのに適しています。
- デザイン要素を列に分割するのは、ラッパーがないと簡単にはできません。
CSSでのラッパーの実装
ラッパーの基本と利点を理解したところで、CSSでラッパーを実装する方法を見てみましょう。
幅を定義する
最初にラッパーの幅を決めておく
CSSでラッパーを実装する際に最初に決めることは、ラッパーの幅です。
ラッパーの幅をいくつにしますか? 幅の値はデザインに依存します。一般的に、ラッパーの幅は1000px~1300pxの間に定義されていることが多いです。
例えば、Bootstrapでは1170pxの幅が使用されています。
1 2 3 |
.wrapper { width: 1170px; } |
このCSSの記述では、スクリーンサイズが1170px以下だと横スクロールが表示されてしまうため、widthプロパティだけを使用するのではなく、max-widthプロパティを追加することをお勧めします。
1 2 3 4 |
.wrapper { width: 1170px; max-width: 100%; } |
もちろんこの記述で機能しますが、widthを削除して、max-widthのみにして使用することもできます。
1 2 3 |
.wrapper { max-width: 1170px; } |
これで、ラッパーに幅を定義しました。次はセンタリングに進みましょう。
ラッパーのセンタリング
ラッパーを中央に配置
ラッパーを中央に配置するには、左右にautoのマージンを追加します。
1 2 3 4 |
.wrapper { max-width: 1170px; margin: 0 auto; } |
CSSの仕様によると、autoのマージンは次のように機能します。
margin-leftとmargin-rightの両方がautoの場合、使用される値は等しくなります。これは、要素を含むブロックの端を基準にして要素を水平方向に中央揃えします。
autoのマージンについて詳しく知りたい場合は、CSSのプロパティ値「auto」を使ったテクニックのまとめ、マージンやサイズや配置やFlexboxなどをご覧ください。
上記のmargin: 0 auto;は、上・下のマージンを0に、左・右をautoに定義したものです。この記述を使用するといくつかの影響がありますが、それについてはこの記事の後半で解説します。
今のところは、ロングハンド版でmarginを定義することをお勧めします。
1 2 3 4 5 |
.wrapper { max-width: 1170px; margin-left: auto; margin-right: auto; } |
左右にスペースを与える
ラッパーの左右にスペースを与える
センタリングした後に考慮すべきことは、左右にスペースを与えることです。ビューポートのサイズがラッパーの最大幅より小さい場合、ラッパーの端がビューポートにくっついてしまいます。
1 2 3 4 5 6 7 |
.wrapper { max-width: 1170px; margin-left: auto; margin-right: auto; padding-left: 16px; padding-right: 16px; } |
スペースはpaddingを追加することで、ビューポートのサイズが最大幅以下であっても、左右から16pxのオフセットを確保することができます。paddingはスペースが十分ではない時にラッパーがビューポートの端にくっついてしまうのを避ける方法として機能します。
追記: ラッパーの幅にパーセントを使用する
padding-leftやpadding-rightを使用せずに、max-width: 90%;を使用するツイートがありました。
ラッパーの幅にパーセントを使用、この実装でも左右に余白ができる
これは機能しますが、大きいスクリーンでビューポートの幅が90%だと大きすぎるので、メディアクエリで上書きするとよいでしょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
.wrapper { max-width: 90%; margin-left: auto; margin-right: auto; } /* 大きいスクリーン用 */ @media (min-width: 1170px) { .wrapper { max-width: 1170px; } } |
幅にパーセントを使用することで、ステップが1つ追加されました。固定幅を使用することで、このステップは簡単に回避できます。ツイートで提案されたもう一つの方法は、width: 90%;とmax-width: 1170px;を組み合わせることです。
1 2 3 4 5 6 |
.wrapper { width: 90%; max-width: 1170px; margin-left: auto; margin-right: auto; } |
これは興味深い提案ですが、私はスペースをパーセントの幅に依存するのではなく、paddingで与えたいと思います。
ラッパーのdisplayのタイプ
ラッパーは<div>なので、デフォルトではブロックレベルの要素です。問題は、ラッパー内のコンテンツをグリッドに配置したい場合に、displayのタイプをgridに変更したい場合はどうすればよいかということです。
この問題は「関係の分離」というコンセプトに反するので、あまりお勧めしません。ラッパーは他のコンテンツを包むためのものであり、それ以上でも以下でもありません。もしグリッドのラッパーが必要な場合は、ラッパーの中に別の<div>を追加して、display: grid;を定義する方が簡単で分かりやすく、将来的にメンテナンスもしやすくなります。
1 2 3 |
<div class="wrapper"> <!-- コンテンツ --> </div> |
1つの<div>に複数の役割を与えるのはお勧めできません。
ラッパー要素が別のページで使用される可能性もあり、意図せずにレイアウトが崩れてしまう可能性もあります。
1 2 3 4 5 |
.wrapper { display: grid; grid-template-columns: 2fr 1fr; grid-gap: 16px; } |
より良い解決策は次のようになります。
1 2 3 4 5 |
div class="wrapper"> <div class="featured-news"> <!-- グリッドに配置する必要がある要素 --> </div> </div> |
1 2 3 4 5 |
.featured-news { display: grid; grid-template-columns: 2fr 1fr; grid-gap: 16px; } |
コンテンツをラップするための<div>要素をどこに追加したかに注目してください。グリッドをラップする場所に追加します。
また、class名はサイト内の異なるページで再利用できる命名規則を使用するのは、さらに良い解決策です。この記事では命名規則については本題から逸れるので触れません。
ラッパー間のマージンの追加
ラッパー要素を中央に配置するために、ショートハンド版を使用することを推奨しなかったことを覚えていますか?
下記がショートハンド版のCSSです。
1 2 3 |
.wrapper { margin: 0 auto; } |
このCSSはもちろん動作しますが、ページ上に複数のラッパーがあり、それらのラッパー間にスペースを与える必要がある場合、混乱する可能性があります。.wrapperに別のバリエーションclassを追加した場合、marginを定義しても機能しない可能性があります。
1 2 3 4 5 6 7 8 9 10 11 |
.wrapper-variation { margin-top: 50px; } .wrapper { max-width: 1170px; margin-left: auto; margin-right: auto; padding-left: 16px; padding-right: 16px; } |
.wrapper-variation要素で定義したマージンは、margin: 0 auto;で上書きされるため機能しません。ショートハンドで定義されたプロパティは、ロングハンドで定義されたプロパティを上書きします。
このような混乱を避けるために、ロングハンドで定義することをお勧めします。
それでは、マージンを追加してみましょう。
プロジェクトごとにマージンとパディングのユーティリティクラスを用意し、必要に応じて使用します。
ラッパー間にマージンを追加
1 2 3 4 5 |
<div class="wrapper mb-5"></div> <section> <div class="wrapper"></div> </section> <div class="wrapper"></div> |
1 2 3 |
.mb-5 { margin-bottom: 3rem !important; } |
このようにして、ラッパーのCSSはそのままで、スペースをユーティリティクラスで与えることができます。あなたは疑問に思うかもしれません。1つのページに1つのラッパーを追加できるのに、なぜ複数のラッパーを追加する必要があるのですか?
上記のHTMLでは、2つのラッパー間に<section>要素があります。
ユーティリティクラスのポイントはそのスタイルを強制することなので、!importantを使用するのは適切です。!importantがあることで、それを確実に実現することができます。
全画面セクション内のラッパー
幅が100%のセクションがあり、その中にラッパーがある場合があります。前述した例と少し似ています。
HTMLの構造は次のようになります
1 2 3 4 5 6 |
<section> <div class="wrapper"></div> </section> <section> <div class="wrapper"></div> </section> |
<section>の幅はビューポートの100%で、背景や画像を追加することができます。その中にはラッパーがあり、コンテンツが幅いっぱいになるのを防ぎます。
セクションは幅いっぱいで、コンテンツはラッパーで内包
上記には、セクションに背景画像があり、ビューポートの幅いっぱいを占めています。内包されたコンテンツはラッパーの幅によって制限されています。
ヒーローセクションにラッパーが必要ですか?
答えは、場合によって異なります。
よく見かけるデザインで見てましょう。
1つ目は、コンテンツが中央に配置され、特定の幅に制限されています。
1つ目のデザイン
2つ目は、コンテンツがメインラッパーの幅に広がっています。
2つ目のデザイン
これらの2つのデザインをよりよく理解するために、それぞれの実装方法を見てましょう。
コンテンツを中央に配置
ヒーローコンテンツを配置し、ラッパーを考慮せずにすべてを中央に配置したいと思うかもしれません。
1 2 3 4 5 |
<section class="hero"> <h2>How to make bread at home</h2> <p>....</p> <p><a href="/sign-up">Sign up</a></p> </section> |
このHTMLは、text-alignでコンテンツを中央揃えにすることができます。
1 |
.hero { text-align: center; } |
ブラウザのサイズを変更するまでは、これで良さそうです。気になる問題点を解説します。
コンテンツが端にくっつく
左右にパディングがないため、コンテンツは適切なスペースを空けずに端にくっつきます。これはコンテンツを見たり読むのを困難にするため、ユーザーにとって好ましくありません。
スクリーンサイズが小さいと、端にくっつく
大きいスクリーンにおける行の長さ
逆に、スクリーンサイズが大きいと、行が長すぎてしまいます。これではテキストが非常に読みにくくなります。webtypography.netによると、1行の最適な文字数は45~75文字で、この範囲を超えると読みにくくなります。
スクリーンサイズが大きいと、行が長い
これらの問題を回避するためには、スマホの時にスペースを与えたり、ラッパーを使用して行が長くならないようにします。
1 2 3 4 5 6 7 |
<section class="hero"> <div class="hero__wrapper"> <h2>How to make bread at home</h2> <p>...</p> <p><a href="/sign-up">Sign up</a></p> </div> </section> |
.hero__wrapperでラッパーを加え、これらの問題に対応します。
1 2 3 4 5 6 7 |
.hero__wrapper { max-width: 720px; margin-left: auto; margin-right: auto; padding-left: 16px; padding-right: 16px; } |
コンテンツの中央揃えは、用途に応じてお好みのテクニックを使用できます。この例では、text-align: center;だけでコンテンツを中央揃えにできます。
ラッパーを中央揃えにするか、左揃えにするか
どちらが正しいというのはありませんが、ラップトップで表示するとラッパーが中央に、デスクトップで表示すると左寄せにしているサイトを見たことがあります。
Techcrunchのサイトで、スクリーンサイズが大きいと左寄せに表示されます。
左: ラップトップ、右: デスクトップ
個人的には、左右にスペースがあり中央配置されたサイトが好きです。しかし、これには私が知らない理由があるかもしれません。何かアイデアがあれば、Twitterで教えてください!
ラッパーのバリエーションに対するCSS変数の使用
ラッパーのサイズが1つだけ必要になることは、ほとんどありません。コンテンツやデザインに応じて、ラッパーの幅は小さいものや大きいものが必要になります。
CSS変数を使用することでモダンに実装でき、柔軟性が大幅に向上します。
1 |
<div class="wrapper"></div> |
1 2 3 4 5 6 7 |
.wrapper { max-width: var(--wrapper-width, 1170px); margin-left: auto; margin-right: auto; padding-left: 16px; padding-right: 16px; } |
varに2つの値があることに注目してください。1つ目の値は変数--wrapper-widthで、2つ目の値は1170pxです。この2つ目の値は変数のフォールバックで、つまり--wrapper-widthが設定されていない場合は1170pxが使用されます。
これは何を意味しているのでしょうか?
下記のように--wrapper-widthを上書きすることで、ラッパーのバリエーションを作成できることを意味しています。
1 |
<div class="wrapper" style="--wrapper-width: 720px"></div> |
このようにして、カスタムラッパーを作成します。
- 新しいclassを追加
- スタイルのコピーと複製
- 将来性が高く、DevToolsから簡単に調整可能
CSS変数を上書きするためにインラインのスタイルを使用するというのが気に入らない場合は、代わりに新しいclassを追加することができます。
1 |
<div class="wrapper wrapper--small"></div> |
1 2 3 4 |
.wrapper--small { --wrapper-width: 720px; /* これにより、デフォルトのラッパー幅が上書きされる。 */ } |
display: contents;を使用する
まず、この値について簡単に説明します。CSSの各要素はボックスであり、そのボックスにはcontent, padding, margin, borderが含まれています。display: contents;を定義することで、そのボックスはフローから削除されます。周辺の開始タグと終了タグを削除するようなイメージです。
1 2 3 4 5 |
<header class="site-header"> <div class="wrapper site-header__wrapper"> <!-- ヘッダのコンテンツ --> </div> </header> |
1 2 3 4 5 |
.site-header__wrapper { display: flex; flex-wrap: wrap; justify-content: space-between; } |
ヘッダをラッパーの幅に制限
上記の例では、ヘッダをラッパーの幅によって制限させるのではなく、ページの全幅に拡張させたい時があるかもしれません。
1 2 3 4 5 6 7 8 9 |
.site-header__wrapper { display: contents; } .site-header { display: flex; flex-wrap: wrap; justify-content: space-between; } |
display: contents;を使用することで、.wrapper要素は非表示になります。あとは、.site-header要素にdisplay: flex;を定義すると、.wrapperの子孫アイテムは.site-headerの子アイテムになります。
ヘッダをページの全幅に制限
流動的な背景に固定コンテンツを配置
Lea Verouは自身の本「CSS Secrets(Amazonで見る)」で、ラッパーが内部にある(ビューポートの全幅を占める)流動的な背景があるセクションに使える興味深いテクニックを紹介しています。
1 2 3 |
<section> <div class="wrapper"></div> </section> |
1 2 3 4 5 6 7 8 9 10 11 |
section { background-color: #ccc; } .wrapper { max-width: 1170px; margin-left: auto; margin-right: auto; padding-left: 16px; padding-right: 16px; } |
margin-left: auto;とmargin-right: auto;は、ビューポートの幅の半分からコンテンツの幅を引いて計算する方法で機能します。これと同じことは、paddingでもできます。
流動的な背景に固定コンテンツを配置
1 2 3 |
section { padding: 1rem calc(50% - 585px); } |
また、終わりではありません。
スマホではコンテンツは端にくっついてしまいます。それを回避するには、下記のようにpaddingを加えます。
1 2 3 4 5 6 7 8 9 |
section { padding: 1rem; } @media (min-width: 1170px) { section { padding: 1rem calc(50% - 585px); } } |
別の回避策としては、CSSのmax()関数を使用することです。簡単に説明すると、paddingの最小値に1remを定義し、50% - 585pxの計算値を定義します。
1 2 3 |
section { padding: 1rem max(1rem, (50% - 585px)); } |
min(), max(), clamp()について詳しく知りたい場合は、下記をご覧ください。
終わりに
参考記事
コメントや提案があれば、@shadeed9までお願いします。
sponsors