CSSのプロパティの値に「auto」を使ったテクニックのまとめ、マージンやサイズや配置やFlexboxなど
Post on:2020年4月14日
CSSの「auto」は非常に便利な値で、マージンやサイズ(width, height)や配置などのプロパティに使用することができます。「auto」がどのように機能するのか、「auto」を活用したテクニックを紹介します。
自動マージン、autoを使った要素のサイズ指定、中央配置に使用するautoの仕組み、FlexboxやGridで知っておくと便利なautoの使い方、overflowにおけるautoなど、実用的なテクニックが満載です。
Everything About Auto in CSS
by Ahmad Shadeed
- はじめに
- widthプロパティにおけるauto
- width:auto; の使いどころ
- heightプロパティにおけるauto
- marginプロパティにおけるauto
- 絶対配置された要素におけるmarginのauto
- Flexboxにおけるauto
- Flexboxのプロパティにおけるauto
- Gridにおけるauto
- overflowプロパティにおけるauto
- 配置プロパティにおけるauto
- autoを使った使用例
- リソース
はじめに
autoの使い方はCSSのプロパティによって異なります。
この記事ではそれぞれのプロパティのコンテキストで値を解説します。
widthプロパティにおけるauto
<div>や<p>などのブロックレベルの要素のwidthの初期値はautoです。そのため、要素を含むブロックは水平方向のスペース全体を占めます。
CSSの仕様によると、下記の通りです。
margin-left + border-left-width + padding-left + width + padding-right + border-right-width + margin-right = 包含ブロックの幅
要素のwidthの値にautoを定義した場合、親要素よりも大きくなることなく、margin, padding, borderを持つことができます。つまり、width: auto;を適用したコンテンツボックスの幅は、margin, padding, borderを差し引いたコンテンツそのものになります。
width: auto;とwidth: 100%;の違い
コードで見てましょう。
1 2 3 |
<div class="wrapper"> <div class="item"></div> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
* { box-sizing: border-box; } .wrapper { max-width: 600px; margin: 2rem auto 0; padding: 1rem; } .item { padding: 1rem; margin: 0 50px; border: 15px solid #1f2e17; } |
.itemにwidthを定義していませんが、問題ありません。div要素のwidthの初期値はautoなので、.itemは親の中に収まっています。
div要素のwidthの初期値はauto
.itemのwidthを初期値のautoではなく、100%に変更するとどうなるでしょうか? 親の100%に加えて、左右にmarginを加えた値になります。
1 2 3 4 5 6 |
.item { width: 100%; padding: 1rem; margin: 0 50px; border: 15px solid #1f2e17; } |
.itemのwidthを100%にした場合
.itemの幅は568pxで、計算式は下記のようになります。
border-left-width + padding-left + width + padding-right + border-right-width = アイテムの幅
15 + 16 + 506 + 16 + 15 = 568px
方向がltrの場合は、margin-rightは完全に無視されます。ただし、レイアウトがrtlの場合はmargin-leftが無視されます。
レイアウトがrtlの場合
width:auto; の使いどころ
基本的なことを説明しただけではコンセプトを理解するのに十分ではないので、width: auto;の具体的な使用例を紹介します。
スマホとデスクトップで異なる幅のボタン
スマホとデスクトップでボタンの幅を変える
2つのボタンがあり、スマホでは横並び(親の50%)に、デスクトップでは親の幅いっぱいに配置するためにはどうすればよいでしょうか?
1 2 3 4 5 6 7 8 |
<div class="group"> <div class="group__item"> <button class="c-button">Sign In</button> </div> <div class="group__item"> <button class="c-button c-button--ghost">Register</button> </div> </div> |
まずは、スマホ用のCSSはFlexboxを仕様して、ボタンを横並びに配置します。
1 2 3 4 5 6 7 |
.group { display: flex; } .group__item { width: 50%; } |
デスクトップでは幅をいっぱいにする必要があります。width: 100%;を定義したくなるかもしれませんが、もっとよい解決策があります。
1 2 3 4 5 6 7 8 9 10 |
@media (min-width: 800px) { /* ラッパーをflexからブロック要素に戻す */ .group { display: block; } .group__item { width: auto; } } |
これで、.group__itemはブロック要素になるため、width: auto;を定義すると、親の使用可能なスペースを適切に占めます。
heightプロパティにおけるauto
heightプロパティにおけるautoは、widthは少々異なります。要素の高さは初期値はautoであるコンテンツと同じです。
実際の例を見てましょう。
1 2 3 |
<div class="wrapper"> <div class="item">What's my height?</div> </div> |
.itemをコンテナの高さいっぱいにする方法は、2つあります。
- .wrapperに固定値の高さを与え、.item要素にheight: 100%;を定義する。
- .wrapperにFlexboxを定義すると、Flexアイテムの.itemは伸縮する。
1 2 3 4 5 6 7 |
.wrapper { height: 200px; } .item { height: 100%; } |
子要素を親の高さいっぱいにする
marginプロパティにおけるauto
marginの場合、幅が分かっている要素を水平方向の中央に配置するために使用するのが一般的な使用例です。
実際の例を見てましょう。
子要素を水平方向の中央に配置したい
ブルーの矩形を水平方向の中央に配置するためには、下記のように記述します。
1 2 3 4 |
.element { margin-left: auto; margin-right: auto; } |
CSSの仕様によると
margin-leftとmargin-rightの両方がautoの場合、適用される値は等しくなります。そのため、要素を含むブロックの端を基準にして要素を水平方向の中央に配置します。
両方をautoにすると、適用される値は等しくなる
絶対配置された要素におけるmarginのauto
子要素を中央に配置
絶対配置された要素を中央に配置するためのもう一つの使用例は、marign: auto;です。親要素に対して水平・垂直方向の中央に配置したい要素がある場合は、translateXやtranslateYを使用したくなるかもしれません。
これが機能するためには、次の2つが必要です。
- widthとheightが固定値であること。
- 子要素がposition: absolute;になっていること。
1 2 3 |
<div class="wrapper"> <div class="item">I am centered.</div> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.wrapper { position: relative; } .item { width: 200px; height: 100px; position: absolute; left: 0; top: 0; right: 0; bottom: 0; margin: auto; } |
Flexboxにおけるauto
Flexboxで自動マージン(marign: auto;)を使用すると、いくつかのケースで非常に便利です。子アイテムに自動マージンを与えると、その子アイテムは反対側にプッシュされます。例えば、Flexアイテムにmargin-left: auto;を与えると、右寄せになります。
実際の例を見てましょう。
親がFlexコンテナで、子のFlexアイテムが2つあります。
子のFlexアイテムが2つある
2の子要素(.item-2)を右寄せにしたい場合、margin-left: auto;を使用します。
1 2 3 4 5 6 7 |
.wrapper { display: flex; } .item-2 { margin-left: auto; } |
2の子要素を右寄せに配置
プッシュする方向は水平だけでなく、垂直方向にも機能します。
今後は、margin-top: auto;を与えてみます。
1 2 3 |
.item-2 { margin-top: auto; } |
margin-top: auto;は下寄せに配置される
子要素が1つしかない場合であれば、margin: auto;だけで水平と垂直方向の中央に配置できます。
1 2 3 |
.item-1 { margin: auto; } |
水平と垂直方向の中央に配置
Flexboxのプロパティにおけるauto
Flexboxでは子アイテムにflex: auto;を使用できます。これはどういう意味でしょうか?
子アイテムにflex: auto;を定義した場合、flex: 1 1 autoと同等で、つまり下記と同じになります。
1 2 3 4 5 |
.item { flex-grow: 1; flex-shrink: 1; flex-basis: auto; } |
MDNによると、
アイテムはwidthとheightプロパティに応じてサイズが調整されますが、Flexコンテナ内の余分な空きスペースを吸収するために大きくなり、コンテナに合うように最小サイズに縮小されます。flex: 1 1 auto;を定義するのと同等です。
flex: auto;のアイテムは、幅と高さに基づいてサイズが調整されますが、使用可能なスペースに応じて拡大または縮小されます。
1 2 3 4 5 |
<div class="wrapper"> <div class="item item-1">Item</div> <div class="item">Item</div> <div class="item">Item</div> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.wrapper { display: flex; flex-wrap: wrap; } .item { width: 120px; height: 500px; } .item-1 { flex: auto; } |
2と3は幅120pxで、1は使用可能スペースを占める
Gridにおけるauto
Gridのカラムにautoを定義
Gridのカラムにautoを定義
CSS Gridではカラムの幅をautoにすると、コンテンツの量に応じた幅になります。
1 2 3 4 |
.wrapper { display: grid; grid-template-columns: auto 1fr 1fr; } |
Gridと自動マージン
CSS Gridを使用した場合、自動マージン(margin: auto;)を使用することでFlexboxと同様の結果を得ることができます。例えば、Gridで実装したコンポーネントがあり、Gridアイテムにmargin-left: auto;を与えると、右にプッシュされ、その幅はコンテンツの長さに基づきます。
Gridで実装したコンポーネント
Item1の幅はグリッドの領域ではなく、コンテンツにも基づいた幅にしたい場合は、margin-left: auto; を与えることで実現できます。
1 2 3 |
.item-1 { margin-left: auto; } |
Item1は右寄せに配置される
右から左へのレイアウト
margin-left: auto;やmargin-right: auto;の使用は、日本語や英語のように左から右へのレイアウトに最適です。ただし、多言語サイトの場合はこれらの値を反対するように注意してください。さらに、FlexboxやGridのプロパティも使用することをお勧めします。そうでない場合は、自動マージンを最後の手段として使用し、その代わりにCSSの論理プロパティを使用してください。
参考: 知っておくと便利な論理プロパティ、ボックスモデルにおける古い方法とこれからの方法
overflowプロパティにおけるauto
要素を実装する場合、その中のコンテンツ量の最小と最大を考える必要があります。コンテンツ量が最大になった場合は、スクロールバーが必要になるかもしれません。
その場合、下記のCSSを使用したくなるかもしれません。
1 2 3 |
.element { overflow-y: scroll; } |
しかし、このCSSではコンテンツ量が最小の場合でもブラウザによってスクロールバーが表示されてしまいます。
要素にoverflow-y: scroll;を定義
WindowsのChromeでは、スクロールバーは常に表示されます。これは期待されない、紛らわしい挙動です。
その代わりに、autoを使用することで、コンテンツの高さがコンテナよりも大きくない限り、スクロールバーが表示されないようにすることができます。
ユーザーエージェントに依存します。コンテンツがpaddingボックス内に収まる場合、それは可視されているように見えますが、新しいブロックフォーマットのコンテキストは確率されています。コンテンツがオーバーフローした場合、デスクトップブラウザはスクロールバーを提供します。
参考: MDN
1 2 3 |
.element { overflow-y: auto; } |
配置プロパティにおけるauto
CSSの配置プロパティ、top, right, bottom, leftでは、値にキーワードのautoを使用できます。
padding付きの親要素に、絶対配置された子要素
padding付きの親要素があり、その中に子アイテムがあります。子アイテムは絶対配置されていますが、配置場所を定義するプロパティはありません。
1 2 3 4 5 6 7 8 9 10 |
.wrapper { position: relative; padding: 16px; } .item { position: absolute; width: 100px; height: 100px; } |
CSSでは各プロパティに初期値があります。子アイテムをデベロッパーツールで調べた場合、leftプロパティの値は何になると思いますか?
子アイテムをデベロッパーツールで調査
leftの値は16pxになっていました! 定義していないのになぜそうなってしまったのでしょうか? 理由は絶対配置された要素は、position: relative;で最も近い親に対して相対的になるからです。親にはpadding: 16px;が定義されているので、子要素は上左から16pxに配置されます。面白いですよね。
何のメリットがあるのか疑問に思うかもしれません。話を進めましょう。
ビューポートが小さなサイズのスマホで、子アイテムを左から100pxに配置する必要があるとします。デスクトップではデフォルトの位置に配置されます。
1 2 3 4 5 6 7 8 9 10 |
.wrapper { position: relative; } .item { position: absolute; left: 100px; width: 100px; height: 100px; } |
ビューポートが大きなサイズのデスクトップでleftをリセットするにはどうすればよいでしょうか? left: 0;は子が左端にくっつくため、使用できません。
left: 0;だと、左端にくっつくからダメ
子アイテムをリセットするための正しい方法は、left: auto;を使用することです。MDNによると、
静的な要素の場合、要素は水平方向に配置されるべき場所に配置される。
つまり、この場合はpaddingが尊重され、子アイテムを親アイテムの端にくっつけないということです。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.item { position: absolute; left: 100px; width: 100px; height: 100px; } @media (min-width: 800px) { .item { /* This is equivalent to left: 16px */ left: auto; } } |
topプロパティについても同じことが当てはまります。rightとbottomプロパティについては、デフォルトの計算値は要素の幅と高さにそれぞれ等しくなります。
autoを使った使用例
autoを使った使用例をいくつか紹介します。お役に立てれば幸いです。
ツールチップの矢印
ツールチップには、ユーザーに分かりやすくするために矢印が必要です。デザインシステムの場合は、複数の状態を考慮する必要があります。
例えば、ツールチップに左と右向きの2種類の矢印が必要になる場合があります。
左と右向きの矢印があるツールチップ
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.tooltip:before { /* Arrow code */ position: absolute; left: -15px; } /* This is a version where the arrow is pointing to the right */ .tooltip.to-right:before { /* Arrow code */ position: absolute; left: auto; right: -15px; } |
left: -15px;をleft: auto;で上書きしていることに注目です。間違いではありませんが、代わりに下記のようにすることをお勧めします。
1 2 3 4 5 6 7 8 9 10 11 |
.tooltip:before { position: absolute; right: 100%; } .tooltip.to-right:before { /* Arrow code */ position: absolute; right: auto; left: 100%; } |
100%にすることで、矢印のサイズを変更すると失敗する可能性のあるハードコードされた値(矢印の幅)の使用を回避しました。これはより多くの可能性に対応できる解決策です。
カードのコンポーネント
カードがあり、左上にアイコンがある場合、そのアイコンが装飾目的またはアクションのどちらでもよいですが、逆方向にも配置される場合があるとします。
アイコンが配置されたカード
left: auto;でベースとなる実装をリセットし、right: 15px;で右に配置します。
1 2 3 4 5 6 7 8 9 10 |
.card .icon { position: absolute; left: 15px; top: 15px; } .card.is-right .icon { left: auto; right: 15px; } |
Flexboxと自動マージン
Flexboxに関しては、可能性は無限大です。自動マージンと組み合わせることで、パワフルなレイアウトを構築することができます。
Flexboxと自動マージンで右寄せに配置
タイトル、テキスト、アクションボタンを含む行があります。アクションボタンを右寄せに配置したい場合は、自動マージンで簡単に実装できます。
1 2 3 4 5 6 |
<div class="item"> <div class="item-group"> <!-- Title and description --> </div> <button class="item__action">Confirm</button> </div> |
1 2 3 4 5 6 7 8 9 |
.item { display: flex; flex-wrap: wrap; justify-content: space-between; } .item__action { margin-left: auto; } |
これで完成です!
margin-left: auto;を使用することで、アクションボタンが自動マージンで右端に押し出されます。また、多言語サイト(左右ではなく、右左のレイアウト)の場合でも、CSSの論理プロパティで対応できます。
1 2 3 |
.item__action { margin-inline-start: auto; } |
CSS Gridと自動マージン
Gridアイテムにマージンを追加する場合は、固定値・%・autoのいずれかになります。この記事では、autoに注目してみます。
CSS Gridと自動マージン
1 2 3 4 |
<p class="input-group"> <label for="">Full Name</label> <input type="email" name="" id=""> </p> |
1 2 3 4 5 6 7 8 9 |
.input-group { display: grid; grid-template-columns: 1fr; grid-gap: 1rem; @media (min-width: 700px) { grid-template-columns: 0.7fr 2fr; } } |
ラベルを右揃え(入力欄の左端)に合わせたい場合は、下記のように記述します。
1 2 3 |
.input-group label { margin-left: auto; } |
自動マージンで、ラベルを右揃えに
モーダルと自動マージン
コンテンツ量が多いモーダル
モーダルウインドウを実装する時には、コンテンツ量が多い場合にどうなるかを考慮しておくことが重要です。
1 2 3 |
.modal-body { overflow-y: auto; } |
これだけで、コンテンツの高さがスクリーンサイズより大きい場合にのみスクロールバーが表示されます。
リソース
- The difference between width:auto and width:100%
- The peculiar magic of flexbox and auto margins
- How Auto Margins Work in Flexbox
これで終わりです。
コメントや提案があれば、@shadeed9までお願いします。
sponsors