CSSの100vwに垂直スクロールバーの幅が含まれる問題を解決する

CSSで使用できる単位の vw (Viewport Width) をうまく使えてますか?

親要素の横幅を基準にする % と異なり、vw はブラウザの表示領域を基準にするため、祖先要素の横幅に依存しない相対的な幅を設定することができます。

この vw にはブラウザの表示領域に表示されるスクロールバーの幅も含まれます。

スクロールバーの幅は、ブラウザによって異なるだけでなく、コンテンツの量や閲覧環境 (PC・タブレット・スマートフォン) によって、表示されたり表示されなかったりするので、vw は使いづらい印象があります。

今回は、スクロールバーの幅や表示・非表示の影響を受けずに 100vw を活用するためのテクニックを紹介します。

まず、前提として、一定の横幅で表示させたいコンテンツと、画面いっぱいに表示させたいコンテンツの2種類が混在し、それぞれをdiv要素などでラップするようなことはしたくない、そういったケースで有効な方法になります。

1. vw で余白の幅を設定

今回のテクニックのキモになる部分です。

コンテンツの表示領域にwidthプロパティを設定して、margin: 0 auto; などでセンタリングさせるのは割とポピュラーだと思います。しかし、この方法は vw との相性がよくありません。

なぜなら、幅を伴うスクロールバーが表示される閲覧環境では、width: 100%; の中央と、width: 100vw; の中央にズレが生じるためです。

そのため、センタリングさせた要素内で、次のようなスタイルが適用された要素は、左右にスクロールバーの半分の幅だけ、はみ出てしまいます。

.alignfull {
  margin-right: calc( 50% - 50vw );
  margin-left: calc( 50% - 50vw );
}

そこで、コンテンツの表示領域に横幅を設定するのではなく、その左右の余白の幅を vw (paddingプロパティとcalc関数値とvw) で設定します。

<!DOCTYPE html>
<html …>
  <head>
    …
    <style>
    body {
      margin: 0;
    }
    @media ( min-width: 481px ) {
      ._content {
        padding-right: calc( 50vw - 240px );
        padding-left: calc( 50vw - 240px );
      }
    }
    </style>
  </head>
  <body>
    <div class="_content">
      <p>Lorem ipsum …</p>
      <p class="alignfull">Lorem ipsum …</p>
      <p>Lorem ipsum …</p>
    </div>
  </body>
</html>

上記のCSSコードで左右の余白は、ブラウザの表示領域の半分から240pxを引いた数値になります。

コンテンツの表示領域は、幅を伴うスクロールバーが表示される閲覧環境では480pxからスクロールバーの幅を引いた数値、そうでない場合は480pxぴったりになります。

ちなみに、paddingプロパティはマイナスの値が無効なので、calc( 50vw - 240px ) の計算結果が0未満なっても問題ないのですが、IE11にはcalc関数値でマイナスの値になったpaddingプロパティが有効になってしまうというバグが存在するため、メディアクエリ (@media ( min-width: 481px ) { … }) を使用して、paddingプロパティの値が0以上になる場合に限定しています。

2. コンテンツを画面いっぱいに表示させる設定

左右の余白の幅は分かっているので、その幅分、要素の横幅を vw (marginプロパティとcalc関数値とvw) で拡張します。

<!DOCTYPE html>
<html …>
  <head>
    …
    <style>
    body {
      margin: 0;
    }
    @media ( min-width: 481px ) {
      ._content {
        padding-right: calc( 50vw - 240px );
        padding-left: calc( 50vw - 240px );
      }
      ._content .alignfull {
        margin-right: calc( 240px - 50vw );
        margin-left: calc( 240px - 50vw );
      }
    }
    </style>
  </head>
  <body>
    <div class="_content">
      <p>Lorem ipsum …</p>
      <p class="alignfull">Lorem ipsum …</p>
      <p>Lorem ipsum …</p>
    </div>
  </body>
</html>

上記のCSSコードでは、240pxから左右の余白は表示領域の半分を引いた数値になります。

この設定は、コンテンツの表示領域よりブラウザの表示領域が広くなったときだけ適用させたいので、メディアクエリで設定する必要があります。

「CodePen」による実際の表示

See the Pen alignfull by nov (@numerofive) on CodePen.

WordPressのブロックエディタで、画面いっぱいにコンテンツを表示させる「alignfull」と、通常よりも少し大きめコンテンツを表示させる「alignwide」が使われるようになりました。

その対応策として、今回の 100vw でコンテンツを表示させる方法を思いつきました。

幅を伴うスクロールバーの有無で、コンテンツの表示領域の幅が変わるのは、ちょっと気持ち悪いですが、ブラウザの表示領域ぴったりにコンテンツを表示させる方を優先させるのであれば、仕方ないのかなと思ってます。

関連記事