幅制限のある親要素を左右突き抜けてブラウザ全幅表示するcss
現象
スマホではコンテンツが両サイド(表示可能領域の全幅)に接していると、その先にコンテンツが存在する(見切れている)のではないかと混乱を招くことが想定されるので、両サイドにスペースを設けるために全体をラッピングする親要素を設けることがあります。
しかし、画像要素など見切れている(可能性がある)ことが問題にならない要素は全幅表示したいことがあります。
左右に余白を設けたレイアウト
あいうえお
1 2 3 4 |
<div class="wrapSpace"> <p class="border">あいうえお</p> <img src="/image/sunset-1600.png"> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.wrapSpace{ width: 80%; padding: 100px 20px; border: 1px solid #ccc; margin-left: auto; margin-right: auto; } p.border{ border: 1px solid #f00; } img{ width: 100%; } |
対策
このようなケースでは親要素の幅制限を突き抜ける制御で解決できます。
基本的な考え方としては、ブラウザ可視範囲の半分から対象要素の半分を差し引いた範囲、要するに左右の余白部分を、マイナスマージンに割り当てることで、強制的に拡張してしまうというけっこう乱暴な制御です。
方法
拡張したい要素の親要素に、強制拡張用の制御「.spFull」を割り当てます。
あいうえお
【HTML】
1 2 3 4 |
<div class="wrapSpace"> <p class="spFull border">あいうえお</p> <div class="spFull"><img src="/image/sunset-1600.png"></div> </div> |
【css】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
.wrapSpace{ width: 80%; padding: 100px 20px; border: 1px solid #ccc; margin-left: auto; margin-right: auto; } p.border{ border: 1px solid #f00; } img{ width: 100%; } .spFull { margin: 0 calc(50% - 50vw); width: 100vw; } |
問題点
(※ ここで指摘している現象はPCブラウザでのものです。スマホにはあてはまりません。)
拡張した要素の左端(あいうえおの「あ」)が見切れているのがわかります。
原因はブラウザ幅を示す「vw」には縦スクロールバーの幅が含まれるからです。
左右端が見切れても問題ない場合(例えば文字列中央寄せ)は、ブラウザ可視範囲と同等の親要素(最上位はbody)に「overflow-x: hidden;」を割り当ててください(このページでは解りやすいように敢えて横スクロールバーを表示させています)。
きっちり見切れないようにしたい場合は、以下のようにしてください。
あいうえお
【HTML】
1 2 3 4 |
<div class="wrapSpace"> <p class="spFullJust border">あいうえお</p> <div class="spFullJust"><img src="/image/sunset-1600.png"></div> </div> |
【css】
1 2 3 4 |
.spFullJust { margin: 0 calc(50% - 50vw + 8.5px); width: calc(100vw - 17px); } |
「17px」は縦スクロールバーの幅です。幅はブラウザ可視領域幅から17pxを差し引き、左右のマージンはその半分ずつの8.5pxを加算(マイナスマージンですので物理的には差し引く)する制御を追加しました。
17pxはブラウザによって微妙に異なるようです。PC版Chrome(Edge)、Firefoxでは正常動作を確認済みです。
スマホのブラウザを含め縦スクロールバーの幅に対する微妙な制御は、cssだけでは無理なようですので、jQueryとの併用で制御してください。
結果
スマホのための両サイドスペース要素があっても、両サイドぴったりデザインをhtml構造を変更することなく手軽に対応可能となります。
2023.7.20 追記
最新のブラウザによっては縦スクロールバーの幅がコンテンツの有効幅に影響を与えないもの、要するに17pxを演算に含めなくても良いものがあるようです。
Firefoxでは .spFullJust を適用すると両端に隙間が空いてしまうことが判りました。Chrome、Edgeでは依然として縦スクロールバーの幅17pxを演算に含めることが必要なようです。
対策としてはブラウザの種別に応じてcssを切り替えることが考えられます。
ブラウザ種別の判定は下記ページをご参照ください。
アクセスされたブラウザ名をPHPで判別する方法
厳密性を追求しなくても良い場合は既述のように .spFull を適用して body に「overflow-x: hidden;」を割り当てることで十分だと思います。
【HTML】
1 2 3 4 |
<div class="wrapSpace"> <p class="spFull border">あいうえお</p> <div class="spFull"><img src="/image/sunset-1600.png"></div> </div> |
【css】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
body{ overflow-x: hidden; } .wrapSpace{ width: 80%; padding: 100px 20px; border: 1px solid #ccc; margin-left: auto; margin-right: auto; } p.border{ border: 1px solid #f00; } img{ width: 100%; } .spFull { margin: 0 calc(50% - 50vw); width: 100vw; } |
2023.7.28 追記
左右 margin で水平位置を制御するのではなく、transform で制御する方法です。
あいうえお
【HTML】
1 2 3 4 |
<div class="wrapSpace"> <p class="spFullTransform border">あいうえお</p> <div class="spFullTransform"><img src="/image/sunset-1600.png"></div> </div> |
【css】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
.wrapSpace{ width: 80%; padding: 100px 20px; border: 1px solid #ccc; margin-left: auto; margin-right: auto; } p.border{ border: 1px solid #f00; } img{ width: 100%; } .spFullTransform { /* 幅をブラウザ幅に一致させる */ max-width: 100vw; width: 100vw; /* 位置をブラウザの水平中央に移動 左端位置を中央→要素の半分だけ左にtranslate*/ -webkit-transform: translateX(-50%); -ms-transform: translateX(-50%); transform: translateX(-50%); left: 50%; position: relative; } |
chromeなどではやはりスクロールバーの分の調整が必要なようです。17pxを調整するか body の overflow:hidden で対策してください。
(※ 当ページは社内技術資料としての位置付けですので読みにくいこともあるかもしれませんが、一般の方の課題解決に役立てれば幸いです。)