Edited at

スクロールバーの幅に依存しないスタイル指定

More than 3 years have passed since last update.


問題

CSSで overflow: scroll; を指定した要素はスクロールバーが表示されます。

...と、思っていた時期がぼくにもありました。

Yosemite 以降の Mac(OS X 10.10~) では、OS のデフォルト設定でスクロールバーを非表示にしている為、overflow: scroll;を指定してもスクロールバーは表示されません。

その為、スクロールバーが表示される前提でスタイル指定していると表示が崩れてしまいます。


「え?同じブラウザを使っているのに表示崩れが起きるだと!?」

「OSも影響するよー」「▂▅▇█▓▒░(’ω’)░▒▓█▇▅▂」


そもそもスクロールバーの幅はOSやブラウザによって異なるはずで、本来はこれに依存しないスタイル指定をするのが良いはずです。

とはいっても、面倒であったり難しかったりで一般的なスクロールバーの幅(15pxぐらい)を width の計算などに含める方は少なからずいるのではないでしょうか?

しかし前述のとおりスクロールバーは必ずしも表示されません。この手法では表示崩れが起きる原因となってしまう為、何らかの対策が必要です。

かといってJavaScriptで計算するのは、やり過ぎ感が否めません・・・。


具体例

スクロールバーの幅を差し引きたい場面を想定してみました。

下記の例では、.exampleにはスクロールバーが表示されず、.bad.goodにはスクロールバーが表示される前提です。

それぞれは縦に並んでいて、.rightに指定したborderの位置を揃えたいとします。

<div class="example">

<ul>
<li class="left">可変幅</li>
<li class="right">固定幅</li>
</ul>
</div>
<div class="bad">
<ul>
<li class="left">可変幅</li>
<li class="right">固定幅</li>
</ul>
</div>
<div class="good">
<ul>
<li class="left">可変幅</li>
<li class="right">固定幅</li>
</ul>
</div>

ul li {

float: left;
}
.right {
border-left: 1px solid #000;
}
.example {
overflow-y: auto;
}
.bad, .good {
overflow-y: scroll;
}
.example.left {
width: calc(100% - 100px);
}
.example.right {
width: 100px;
}

/*
* 悪い例
* スクロールバーの横幅を15pxと仮定して差し引いている
*/

.bad.left {
width: calc(100% - 85px);
}
.bad.right {
width: calc(100px - 15px);
}

/*
* 良い例
* スクロールバーに依存せず 100vw から固定幅を差し引いている
*/

.good.left {
width: calc(100vw - 100px);
}
.good.right {
width: 100px;
}


解説

まず注目したいのは.example.leftで指定している100%と、.bad.leftでしている100%は異なる値という点です。

.example.left100%はブラウザの左端からブラウザの右端までの値です。

.bad.left100%はブラウザの左端からスクロールバーの左端までの値です。

すなわちスクロールバーの有無によってずれてしまうのは、スクロールバーの影響を受けた値を計算に利用しているためと言えます。

今回の具体例で利用した解決案では、全体の横幅の計算に100%ではなく100vwという値を利用しています。

vwviewport widthという値で、1vwは viewport で指定された幅の 1/100 です。

(※ viewport についてはググれば沢山記事があるので、ここでは割愛します。)

viewportを指定していない場合はブラウザの横幅が100vwとなるはずですが、特に理由がなければ指定するのが良いかと思います。

vwはスクロールバーの横幅に影響を受けず、常にviewport(≒ブラウザの横幅)を基準にするため、スクロールバーの横幅に依存しない指定ができます。

vwはIE9以降であれば利用可能なため、機会があれば是非使ってみてください。