CSSのレイアウトで、ラッパーが異なるコンテンツのツラをcalc()関数のパディングで揃える
Post on:2022年3月24日
sponsorsr
メインのヘッダは固定幅、記事のヘッダは流動幅、ラッパーが異なるコンテンツのツラを揃えるCSSのテクニックを紹介します。
下記のようにヘッダのロゴと記事のタイトルを揃えたい時はありませんか?
CSSのcalc()関数を使用した動的なパディングを使用すると、簡単に実装できます。デスクトップの大きいスクリーン、スマホなどの小さいスクリーン、記事が長くてスクロールバーが表示される場合などにも対応しています。

Aligning Content In Different Wrappers
by Ahmad Shadeed
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
固定幅と流動幅でツラを揃える
Webページのレイアウトに取り組んでいたら、興味深い問題にぶつかりました。

ロゴと記事のヘッダを揃えたい
このレイアウトは、下記の通りです。
- メインのヘッダ: ロゴとナビゲーション
- 記事のヘッダ: 見出しとテキスト
- ボディコンテンツ
メインのヘッダは、水平方向に中央配置された固定幅でラップされています。
| 1 2 3 4 5 | <header class="site-header">     <div class="wrapper">         <!-- Header content -->     </div> </heade | 
| 1 2 3 4 5 6 7 | .wrapper {     max-width: 1100px;     margin-left: auto;     margin-right: auto;     padding-left: 1rem;     padding-right: 1rem; } | 
記事のヘッダはラップされておらず、独立した流動幅で機能しています。
| 1 2 3 4 5 6 7 8 9 | <header class="site-header">     <div class="wrapper">         <!-- Header content -->     </div> </header> <div class="article-header">     <h1><!-- Title --></h1>     <p>!-- Description --></p> </div> | 
ここで問題になるのは、ロゴと記事タイトルのツラ揃えです。
上記の図を見ると分かるように、ロゴの開始位置とツラを揃えるために記事のヘッダの左側にパディングがあります。最初は実装可能なように思いましたが、スクリーンサイズを変更すると、その考えが変わるでしょう。
下記はスクリーンサイズを大きくしたものです。記事のヘッダがロゴと揃っていないことに注目してください。

スクリーンサイズを大きくすると、揃わない
逆に、スクリーンサイズが小さい場合も同様の現象が発生します。

スクリーンサイズを小さくすると、揃わない
ここで解決しようとしている問題は、スクリーンの左端からコンテンツのラッパーの開始点までのスペースに基づいて動的に変化するpadding-left値を設定することです。
下記の図をご覧ください。
メインのヘッダとボディコンテンツは両方とも固定幅の要素にラップされていますが、記事のヘッダは流動幅でラップされていません。実現したいのは、記事のヘッダのための動的なパディングの値です。

記事のヘッダに動的なパディングを設定する
動的なパディングを設定するには、数学が必要になります。数式を言葉で表すと、こんな感じです。
動的なパディング = (ビューポートの幅 - ラッパーの幅) / 2
値に置き換えてみます。

記事のヘッダに動的なパディングを設定する
ビューポートが1300pxで、ラッパーが1100pxだと、こうなります。
動的なパディング = (1300 - 1100) / 2 = 100
なぜ2で割るのか、不思議に思われるかもしれません。答えは、左右に動的なエリアが2つあるので、片側だけの値が必要となるからです。

記事のヘッダに動的なパディングを設定する
動的なパディングを実装するテクニック
CSSで動的なパディングを実装するために、下記の4つを使用します。
- ビューポート単位
 参考: ビューポート単位「vw, vh, vmin, vmax」を使ったCSSのテクニックのまとめ
- calc()関数
 参考: CSSのcalc()関数を使うとスゴイ便利!ページのレイアウト、要素やフォントのサイズ指定など実装テクニックのまとめ
- max()比較関数
 参考: CSSの比較関数が便利すぎる!min(), max(), clamp()の使い方を詳しく解説
- CSS変数(カスタムプロパティ)
 参考: CSS変数の優れた使い方、コンポーネントのバリエーションを実装するのに役立つ
まずは、ビューポートの全幅を取得するために、100vw値を使用します。
| 1 2 3 | .article-header {     padding-left: calc(100vw - calc(1100px / 2)); } | 
これでpadding-leftの値は動的になり、記事のヘッダがロゴやナビゲーションと揃うようになります。
しかし、まだ終わりではありません。
.wrapperの水平方向のパディングを考慮する必要があります。
| 1 2 3 | .article-header {     padding-left: calc(100vw - calc(1100px / 2) - 32px); } | 
32pxは、左右のパディングの合計値です。
スマホでのパディングの処理
ラッパーからパディング値を引いたので、スマホでは記事ヘッダのパディングはゼロになります。

スマホで表示すると、パディングがゼロになる
このパディングを元に戻すには、CSSのmax()比較関数の助けを借りる必要があります。目的は、パディングの最小値を設定することです。
| 1 2 3 | .article-header {     padding-left: max(1rem, calc(100vw - calc(1100px / 2) - 32px)); } | 
これで、水平方向のパディングは少なくとも1remになり、ビューポートのサイズが大きくなったときに動的になります。
max()比較関数について、便利な使い方は下記をご覧ください。
このCSSをどこにでも使用できるようにする
上記のすべてを1つのCSS変数内に追加すると、さまざまな場所で使用できるようになります。
| 1 2 3 4 5 6 7 8 9 10 11 12 | :root {   --wrapper-width: 1100px;   --wrapper-padding: 16px;   --space: max(     1rem,     calc((100vw - calc(var(--wrapper-width) - var(--wrapper-padding) * 2)) / 2)   ); } .article-header {     padding-left: var(--space); } | 
スクロールバーで位置がずれる問題を解決する方法
macOSでは、ユーザーがシステム環境設定で選択しない限り、デフォルトでスクロールバーは表示されません。デフォルトでスクロールバーが表示されている場合、100vwはビューポート幅の100%からスクロールバー幅を引いた値になります。
これは、位置がずれる原因となります。

macOSで100vwがずれる問題
この要素はラッパーの中に存在しないため、100vwの代わりに100%に置き換えれば、期待通りに機能します。
| 1 2 3 4 5 6 7 8 9 10 11 12 | :root {   --wrapper-width: 1100px;   --wrapper-padding: 16px;   --space: max(     1rem,     calc((100% - calc(var(--wrapper-width) - var(--wrapper-padding) * 2)) / 2)   ); } .article-header {     padding-left: var(--space); } | 
Dannie Vintherは、max()がcalc()関数を使用せずに計算できることを私に思い出させました。いいですね。
| 1 2 3 4 5 6 | :root {     --space: max(         1rem,         100% - (var(—wrapper) - ((var(—wrapper-padding) * 2) / 2))     ); } | 
実際の動作は、下記をご覧ください。
  See the Pen 
  Align content in different wrappers by Ahmad Shadeed (@shadeed)
  on CodePen.
今回のCSSの小技は以上です。
あなたが何か新しいことを学んだことを願っています!
終わりに
この記事があなたのお役に立てれば幸いです。
コメントや提案があれば、@shadeed9までお願いします。
sponsors















