ネガティブマージン(margin に負の値)や position: absolute; を指定した要素が、親要素からはみ出した場合に、横スクロールが奇妙な現われ方をしたので調べてみた。
まずは簡略化したコードを用意。
<div id="wrap">
<div class="left">左ブロック</div>
<div class="right">右ブロック</div>
</div>
#wrap {
margin: 0 auto;
width: 300px;
}
#wrap .left {
margin-left: -100px;
}
#wrap .right {
margin-right: -100px;
}
#wrapの横幅は300pxなので、ブラウザのウインドウ幅が300px未満になったときに横スクロールが発生する。ところで、#wrapには子要素のブロック要素が二つあり、それぞれ左右に100pxだけ、親要素からはみ出ている状態にある。
この場合、ウインドウ幅を小さくしていくと、どのように表示されるだろうか。
##はみ出した部分はスクロール幅に含まれるのか
結論からいうと、右側だけ含まれる。
文章だけでは分かりにくいので画像をどうぞ。
###ウインドウ幅が広いとき
###ウインドウ幅を狭くしたとき
画面下部に横スクロールが出ている。
スクロールバーは左端に達しているので、赤いブロックの左にはみ出た部分は見えなくなっている。
一方で、右には若干スクロールさせる余地が残っており、青いブロックの右にはみ出した部分は表示される。
横幅の小さい端末で閲覧した時に、左右アンバランス(左側に寄っているよう)に配置されて見えてしまう。
このとき、window, document, 親要素の幅を取ってみた。
console.log( $(window).width(), $(document).width(), $("#wrap").width());
// 400, 450, 300
###ウインドウ幅を親要素の幅と同じにしたとき
右側にはみ出た青い部分は全部見えるが、左側にはみ出た赤い部分は全く見えなくなる。
同じく、window, document, 親要素の幅を取ってみた。
console.log( $(window).width(), $(document).width(), $("#wrap").width());
// 300, 400, 300
なぜか右側にはみ出た長さ分だけ、documentは親要素より大きくなっていて、
左側にはみ出た分は無視され(documentの幅に含まれない)るため、横スクロールで右側だけ見える。
#対処策
親要素のさらに外側をブロック要素で囲み、左右にはみ出た分も含めた幅をwidthに指定する。
<div id="outer">
<div id="wrap">
<div class="left">左ブロック</div>
<div class="right">右ブロック</div>
</div>
</div>
#outer {
margin: 0 auto;
width: 500px;
}
はみ出る長さを後で変えるかもしれない、というときは、
この要素の幅も変更しなければいけないので、やや気持ち悪い。
#仕様か
以下のブラウザで同じ挙動を確認。(いずれもOS X)
- Google Chrome
- Safari
- Firefox
一見奇妙な挙動なので戸惑うが、主要ブラウザで同じところを見ると仕様なのだろうと思われる。
推測に過ぎないが、テキストが長くて親要素を突き出してしまうケースを想定して、
右側にはみ出た分だけはdocumentの幅に含めるようにしたのではないだろうか。
(右から左へ記述する言語を無視していることになるが)
W3Cの文書までは確認できていない。