子要素を親要素(インナー幅)からはみ出させて、画面いっぱいに表示したり、
片側だけ画面いっぱいに表示する方法を学びました。
実装方法は色々あると思いますが、今回はcalc関数を使って実装する方法と注意点を書いていきます。
今回のポイント
先に今回のポイントを書きます。
width:100vw
と左右どちらかもしくは両方のmarginにcacl(50% - 50vw)
指定- vwはスクロールバーの幅も含むため、横スクロールに注意
以下より詳しく書いていきます↓
完成サンプルとコード
今回実装するサンプルとコードを書いていきます。
コードに関して、画面幅いっぱいにするためや注意点を記述している行には、ハイライト表示させています。
完成サンプル
CodeSandBoxを使って、サンプルを作成しました↓
HTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>【CSS】子要素を親要素からはみ出して画面いっぱいにする方法</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="l-main">
<div class="l-spacer" data-space="xxs:large">
<h1 class="p-pageTitle">【CSS】子要素を親要素からはみ出して画面いっぱいにする方法</h1>
<div class="l-container">
<section class="p-content">
<div class="p-content__inner" data-direction="column">
<div class="p-content__header">
<h2 class="p-content__title">画面幅いっぱい</h3>
</div>
<!-- /.p-content__header -->
<div class="p-content__body " data-overDirection="full">
<p class="p-content__text">画面幅いっぱいに表示</p>
</div>
<!-- /.p-content__body -->
</div>
<!-- /.p-content__inner -->
</section>
<!-- /.p-content -->
<section class="p-content">
<div class="p-content__inner" data-direction="row">
<div class="p-content__header">
<h2 class="p-content__title">左側いっぱい</h3>
</div>
<!-- /.p-content__header -->
<div class="p-content__body" data-overDirection="left">
<p class="p-content__text">左側いっぱいに表示</p>
</div>
<!-- /.p-content__body -->
</div>
<!-- /.p-content__inner -->
</section>
<!-- /.p-content -->
<section class="p-content">
<div class="p-content__inner" data-direction="row">
<div class="p-content__header" >
<h2 class="p-content__title">右側いっぱい</h3>
</div>
<!-- .p-content__header -->
<div class="p-content__body" data-overDirection="right">
<p class="p-content__text">右側いっぱいに表示</p>
</div>
<!-- /.p-content__body -->
</div>
<!-- /.p-content__inner -->
</section>
<!-- /.p-content -->
</div>
<!-- /.l-container -->
</div>
<!-- /.l-spacer -->
</main>
</body>
</html>
CSS
/* ====================================================
リセットCSS
======================================================*/
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* ==========================================================
横スクロール対策
=============================================================*/
.l-main{
overflow-x: hidden;
/* -webkit-overflow-scrolling: touch; Safari 13以降は不要*/
}
/* ===============================================================
インナー幅:1000px
=================================================================*/
.l-container {
max-width: 1000px;
width:95%;
margin: 6rem auto;
border: 2px solid #333;
padding: 3rem;
}
/* =====================================================
子要素を画面幅いっぱいにするためのCSS
=======================================================*/
/* 画面幅いっぱいに表示 */
.p-content__body[data-overDirection~="full"] {
width: 100vw;
margin: 0 calc(50% - 50vw);
}
/* 左側いっぱいに表示 */
.p-content__body[data-overDirection~="left"] {
width: 100vw;
margin-left: calc(50% - 50vw);
}
/* 右側いっぱいに表示 */
.p-content__body[data-overDirection~="right"] {
width: 100vw;
margin-right: calc(50% - 50vw);
}
/* ===============================================================
以下、装飾・レイアウト用
=================================================================*/
.l-spacer[data-space~="xxs:large"] {
padding: 5rem 0;
}
/* ===============================================================
以下、長いので省略(続きのコードはCodeSandBoxを確認)
=================================================================*/
画面幅いっぱいにする方法の解説
画面幅いっぱいにする方法を解説していきます。
結論
画面いっぱいに表示させたい子要素に
width:100vwと、左右どちらかもしくは両方のmarginにcalc(50% – 50vw)
で実装できます!
以下の条件を前提として、なぜこれで実装できるのか解説していきます。
- 画面幅:1000px
- インナー幅:500px
width:100vw
の指定
width:100vw
は横幅を画面幅(ウィンドウサイズ)いっぱいにするための指定です。
単位は%ではなく、vwなので注意してください。
今回の場合、画面幅が1000pxなので、子要素の幅も1000pxです!
width:100vw
のみ指定した場合、以下のようになります↓

margin: 0 calc(50% - 50vw)
の指定
「margin:0 calc(50% - 50vw)
って、何してんねん!」と初めて見た時思いましたが、
これは、親要素の半分の幅だけずらしてから画面幅の半分の幅だけ戻すということをしています。
ちょっとイメージしづらいので、
margin-left:50%;
とmargin-left:-50vw
に分けて書いていきます。
margin-left:50%;
の指定
margin-left:50%
の指定で、親要素の半分の幅を左にずらしています。
解説の条件でインナー幅:500pxと設定したので、
インナー幅の半分250pxを左にずらしています。
margin-left:50%
を指定した場合、以下のようになります↓

margin-left:-50vw;
の指定
margin-left:-50vw
の指定で、画面幅の半分の幅だけ右に戻しています。
解説の条件で画面幅を1000pxと設定したので、
画面幅の半分500pxを右に戻しています。
margin-left:-50vw
を指定した場合、以下のようになります↓

以上がmargin: 0 calc(50% - 50vw)
の解説になります。
これを利用して画面いっぱいに表示したり、右 or 左側だけ画面いっぱいに表示することができます!
なんでこんな方法思い付くんでしょうか?
考えた人すごい!!!
注意点
注意点をまとめました↓
横スクロールの対策
注意点として、vwはスクロールバーの領域も含めた幅になります。
スクロールバーが表示されている状態で閲覧している場合、横スクロールが起きて表示が崩れます。
そのため、インナー幅を指定した要素より親または祖先の要素にoverflow-x:hidden;
を指定する必要があります。
ただ、body
要素とhtml
要素にはoverflow-x:hidden;
が効かないらしいので、body
要素の直下にdiv
要素で全体を包んで指定したり、インナー幅を指定した要素を何かしらの要素で包んで指定する必要があります。
今回は、main
要素に指定しました。
詳しくはこちら→【CSS】bodyタグにoverflow-x:hiddenが効かない原因と対処法
※2022/03/29追記
また、overflow:hidden;
を設定している要素内では、position:sticky;
が機能しないため注意が必要です。overflow-x:hidden;
のみ指定しても機能しません。overflow:hidden;
を設定している要素内でコンテンツを固定して縦スクロールさせたい場合は、position:fixed
とJavaScriptを使う必要があります。
ちなみに、overflow-y:hidden;
を指定した要素内でposition:sticky;
とleft:0;
の固定横スクロールは機能します
※2023/03/04追記
html要素とbody要素両方にoverflow-x:hidden;
をつけるとちゃんと機能するらしいです。参考→html, body { overflow-x: hidden; } 両方に設定するのはなぜ?
またoverflow:clip;
を使えば、position:sticky;
が機能するみたいです。
しかし、Safari16以降でしか対応していないので注意が必要です。
overflow:clip;の対応状況→“overflow:clip” | Can I use… Support tables for HTML5, CSS3, etc
スクロールバーが表示されている状態
スクロールバーが表示されている状態とは、Windowsで閲覧している場合や、Macの設定で「システム環境設定 > 一般」の「スクロールバーの表示」のところを「常に表示」にチェックを入れている場合です。
スクロールをなめらかにする
最後に、main
要素に-webkit-overflow-scrolling: touch;
と指定している部分について解説します。
iOS環境で、ページ全体をスクロールする時は問題ないですが、要素内でスクロールする時にカクカクしていたらしく、スクロールをなめらかにするための指定です。
ただ、現在はデフォルトでなめらかなスクロールになるようになっているので不要です。
詳しくはこちら→【CSS】overflow-scrolling: touchが不要になりました
まとめ
画面いっぱいにはみ出すレイアウトがあれば、今回の記事を参考に実装していきたいと思います。
最後まで読んでいただきありがとうございました!!
※コリスさんの記事で、borde-imageを使ったやり方が紹介されています↓
CSSでこんなことができるの知ってた? 要素・コンテナのサイズに関係なく、ボーダーや背景をはみ出して配置するテクニック
参考サイト
参考にさせていただいたサイト一覧↓
・【CSS】bodyタグにoverflow-x:hiddenが効かない原因と対処法
・【CSS】overflow-scrolling: touchが不要になりました
・-webkit-overflow-scrolling 要らなくなってる
・子要素を親要素(インナー幅)からはみ出して画面いっぱいにするCSS
・コンテナからの解放