CSSの便利なプロパティmin-widthとmax-width、min-heightとmax-heightの効果的な使い方のまとめ
Post on:2020年1月23日
Webページやスマホアプリのレイアウトをはじめ、画像、ボタン、ナビゲーションなどを親要素に応じてそれらの幅や高さを適したサイズにしたい時がありませんか? そんな時には、min-widthとmax-width、min-heightとmax-heightを効果的に使用すると、非常に便利です。
widthとheightプロパティにおけるminとmaxの効果的な使い方を紹介します。
Min and Max Width/Height in CSS
by Ahmad Shadeed
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
はじめに
要素の幅をその親に対して相対的にすると同時に、要素を動的にする必要があることがあります。つまり、利用可能なスペースに基づいてその要素のサイズを拡張できるように、ベースの幅や高さを定義する場合です。
例えば、ボタンを最小幅にする必要があるけれど、それ以下のサイズにはならないようにしたい時には、min-widthプロパティが非常に役立ちます。
この記事ではwidthとheightのmaxとminについて解説し、それぞれの便利な使い方とヒントを含めて詳細に説明します。
widthプロパティにおけるminとmax
最初は、widthに関するプロパティです。
min-widthとmax-widthがあり、どちらも重要で、それぞれ用途が異なります。
min-widthの基礎知識
min-widthの値を定義する場合、widthプロパティに使用される値がmin-widthに指定した値より小さくならないという利点があります。min-widthのデフォルト値はautoで、これは0に相当することを注意してください。
min-widthの基本的な使い方を見てましょう。
ボタンにmin-width: 100px;を定義
上記の画像には、さまざまなテキストを含むボタンがあります。テキストは1ワードから長いワードまでの3種類です。1ワードの場合でも最小幅を保証するには、min-widthを使用する必要があります。幅の最小値は100pxなので、「Done」のように短い文字でもボタンの幅は十分に目立つように表示されます。
これは多言語のWebサイトを扱う場合に非常に重要です。例えば、アラビア語の例を見てましょう。
多言語サイトの例
ボタンにある「تم」は完了を意味します。
左のボタンは幅が小さすぎるので、右のボタンのようにmin-widthの値を増やすとボタンがクリック・タップしやすくなります。
min-widthとpadding
min-widthは、コンテンツが長い場合に幅を広げることができますが、適切な外観を実現するには、水平方向にpaddingを加えるとよいでしょう。
コンテンツが長い場合にも対応するように、paddingを加える
max-widthの基礎知識
max-widthの値を定義する場合、widthプロパティに使用される値がmax-widthに指定した値より大きくならないという利点があります。max-widthのデフォルト値はnoneです。
max-widthの一般的な使用例は、画像でよく見かけます。
画像にmax-width: 100%;を定義
左は画像が親要素よりも大きくなってしまい、枠からはみ出しています。右のようにmax-width: 100%を使用すると、画像の幅は親の幅を超えません。そして、画像が親よりも小さい場合は、影響を与えません。
min-widthとmax-width
では、その要素にmin-widthとmax-widthの両方を定義した場合は、どうなるでしょうか? どちらかが上書きしますか? 言い換えると、どちらがより高い優先度を持っていると思いますか?
min-widthの値がmax-widthの値よりも大きい場合、min-widthの値が要素の幅と見なされます。次のコードを見て考えてみましょう。
1 2 3 |
<div class="wrapper"> <div class="sub"></div> </div> |
1 2 3 4 5 |
.sub { width: 100px; min-width: 50%; max-width: 100%; } |
上記のコードは、下記のように表示されます。
min-widthとmax-widthの両方を定義した場合
widthの値は100pxで、さらにmin-widthとmax-widthが定義されています。その結果、要素の幅はその要素を含むブロック(親要素)の50%を超えません。
実際の表示は、デモページでご覧ください。
See the Pen
Min Width - Example 2 by Ahmad Shadeed (@shadeed)
on CodePen.
heightプロパティにおけるminとmax
heightプロパティにもminとmaxがあります。
min-heightの基礎知識
min-heightの値を定義する場合、heightプロパティに使用される値がmin-heightに指定した値より小さくならないという利点があります。min-heightのデフォルト値はautoで、これは0に相当することを注意してください。
では、min-heightの基本的な使い方を見てましょう。
テキストを含むセクションがあり、期待しているのはテキストが短くても長くても適切に表示できるようにセクションの高さを最小にすることです。
セクションにmin-height: 100px;を定義
スタイルシートは、下記の通りです。
1 2 3 4 5 6 7 8 9 |
.sub { display: flex; align-items: center; justify-content: center; padding: 1rem; min-height: 100px; color: #fff; background: #3c78dB; } |
min-height: 100px;と定義したので、高さの最小値は100pxです。Flexboxを使用すると、テキストはセクションの中央に配置できます。
テキストが長くなると、どうなるでしょうか?
テキストが長い場合
想像通りの結果だと思います。セクションの高さは拡張され、長いテキストが含まれて表示されます。これで、コンテンツに反応する流動的なコンポーネントを構築できます。
See the Pen
Min Height - Example 1 by Ahmad Shadeed (@shadeed)
on CodePen.
max-heightの基礎知識
max-heightの値を定義する場合、heightプロパティに使用される値がmax-heightに指定した値より大きくならないという利点があります。max-heightのデフォルト値はnoneです。
下記の例では、コンテンツにmax-height: 150px;を定義しています。しかし、テキストがスペースよりも大きいため、オーバーフローが発生しています。そのため、テキストは親要素からはみ出していしまいました。
コンテンツにmax-height: 150px;を定義
minとmaxプロパティの効果的な使い方
min-width、min-height、max-width、max-heightの効果的な使い方について説明します。
タグのリスト
タグのリストを実装する場合は、タグが短い場合に外観に影響を与えないように最小幅を定義することをお勧めします。
幅は100px以下にならないように定義
実装に柔軟性を持たせることで、テキストがどんなに短くても見栄えがよくなります。逆に、長い場合、最大文字数が設定されていない場合はどうでしょうか?
max-widthも使用できます。
1 2 3 4 5 6 7 8 9 |
.c-tag { display: inline-block; min-width: 100px; max-width: 250px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; /*Other styles*/ } |
max-widthを使用すると、タグの幅は特定値に制限されます。しかし、それだけでは十分ではありません。制限を超える文字は省略表示にしましょう。
See the Pen
Min Width - Use case 1 by Ahmad Shadeed (@shadeed)
on CodePen.
ボタン
ボタンのコンポーネントには複数のバリエーションがあるため、ボタンの最小値と最大値にはさまざまな使用例があります。基本的な使い方を見てましょう。
ボタンでの使用例
「Get」ボタンの幅が小さいことに注目してください。最小幅を定義しないと、このようにテキストが短い場合に外観を損なうことがあります。この場合は、min-widthを定義することが重要です。
Flexboxで最小幅をゼロに定義する
min-widthのデフォルト値はautoで、0として扱われます。しかし、要素がFlexアイテムの場合、min-widthの値は0として計算されません。Flexアイテムの最小サイズは、そのコンテナのサイズと同じになります。
デフォルトでは、Flexアイテムは最小コンテンツサイズ(最も長い単語や固定サイズの要素の長さ)を下回ることはありません。これを変更するには、min-widthまたはmin-heightを定義します。
w3.org
どういうことなのか、見てましょう。
Flexboxの使用例
アイコンの横のテキストは長いため、オーバーフローしています。横スクロールも表示されるかもしれません。CSSで長いテキストを省略してみます。
1 2 3 4 5 |
.c-person__name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } |
テキストはFlexアイテムなので、解決するには最小幅をリセットし、強制的にゼロにすることです。
1 2 3 4 |
.c-person__name { /*Other styles*/ min-width: 0; } |
min-width: 0;を定義することで、解決します。
Flexアイテムにmin-width: 0;を定義
メイン軸にオーバーフローが表示されているFlexアイテムで、Flexアイテムのメイン軸のmin-sizeプロパティで指定すると、自動的に最小サイズが指定されます。
w3.org
つまり、overflowプロパティにvisible以外の値に定義すると、min-widthが0として計算され、min-width: 0;を定義しなくても問題が解決されます。
See the Pen
Min Width and Flexbox Issue by Ahmad Shadeed (@shadeed)
on CodePen.
Flexboxで最小高さをゼロに定義する
前述のmin-widthと比べてあまり一般的なものではありませんが、起きる可能性があります。確認ですが、これはコンテンツより短くできないFlexアイテムに関連した問題です。その結果、min-height値はコンテンツの長さと同じ長さに設定されます。
どういうことなのか、見てましょう。
Flexboxの使用例
レッドで表示されているテキストは、親にクリップされているので、表示されません。パネルの本体はFlexアイテムなので、最小高さはコンテンツと同じです。これを防ぐためには、高さの最小値をリセットする必要があります。HTMLとCSSを見てましょう。
1 2 3 4 5 6 |
<div class="c-panel"> <h2 class="c-panel__title"><!-- Title --></h2> <div class="c-panel__body"> <div class="c-panel__content"><!-- Content --></div> </div> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.c-panel { display: flex; flex-direction: column; height: 180px; } .c-panel__body { min-height: 0; } .c-panel__content { overflow-y: scroll; height: 100%; } |
パネルの本体(.c-panel__body)にmin-height: 0;を定義することでプロパティがリセットされ、期待通りに動作するようになります。
min-widthとmax-widthのミックス
場合によっては、最小幅の要素があり、同時に最大幅ではないことがあります。これは実装者が意図せずにコンポーネントの幅が広すぎる可能性があります。例えば、下記のような例です。
min-widthとmax-widthのミックス
幅はpx単位で定義されているので、スマホのビューポートで動作する保証はありません。これを解決するには、最小と最大プロパティにpxの代わりに%を使用します。
コンテンツを実際に入れてみましょう。
画像に次のCSSを定義します。
1 2 3 4 |
img { min-width: 35%; max-width: 70%; } |
これで期待通りに動作するようになりました。
min-widthとmax-widthのミックス
See the Pen
Mixing Min Width and Max Width by Ahmad Shadeed (@shadeed)
on CodePen.
ページのラッパーとコンテナ
max-widthの最も有用な使い方の1つは、ページのラッパーまたはコンテナです。ページに最大幅を加えることでコンテンツが読みやすくなり、ユーザーが簡単にスキャンしやすくなります。
ページのラッパーにmax-widthを定義
ページのラッパーにmax-widthを定義し、中央にコンテンツを配置するために左右にpaddingを与えました。
1 2 3 4 5 6 7 |
.wrapper { max-width: 1170px; padding-left: 16px; padding-right: 16px; margin-left: auto; margin-right: auto; } |
max-widthとchユニット
文字数に応じて幅を定義
ch単位は要素のフォントの0(ゼロ)文字幅と等しくなります。この単位をmax-widthと組み合わせることによって、文字数に応じて幅を定義できます。
コンテンツが文字中心の場合、ch単位を使用すると便利です。
1 2 3 4 |
.wrapper { max-width: 70ch; /* Other styles */ } |
高さが不明な要素をアニメーション化する
場合によっては、アコーディオンや高さが不明なメニューをアニメーション化させたいことがあるかもしれません。その場合、max-heightが適切な解決策になることがあります。
拡張するメニュー
ハンバーガーアイコンをクリックすると、メニューが上から下にスライドします。これは高さを固定しない(非推奨)と、JavaScriptを使用しない限り実装できません。
しかし、max-heightを使用すればJavaScriptなしで実装できます。例えば、max-height: 20rem; のように高さに大きめの値を定義すると、max-height: 0;からmax-height: 20rem;までアニメーションさせることができます。
1 2 3 4 5 6 7 8 9 |
.c-nav { max-height: 0; overflow: hidden; transition: 0.3s linear; } .c-nav.is-active { max-height: 22rem; } |
実際の動作はデモでもご覧ください。
See the Pen
Max Height Animation by Ahmad Shadeed (@shadeed)
on CodePen.
ヒーロー要素のためのmin-height
通常、要素に固定の高さを定義するのは好ましいことではありません。流動的なコンポーネントを構築するのとは、反対のことになるからです。しかし、ヒーロー要素に最小の高さを定義することは、その中に長いコンテンツを追加する場合に便利です(けっこうあることです)。
下記の例を見てましょう。固定の高さを定義されたヒーロー要素があります。
固定の高さを定義されたヒーロー要素
コンテンツが長くなると、オーバーフローしてヒーロー要素からはみだします。これは良くありません。
コンテンツを長くすると、はみだす
この問題に対応するには、heightの代わりにmin-heightを加えることです。これによりページが変に見えることはありません。しかし、そもそもCMSではそのような問題が起こらないようにすべきです。
min-heightを加える
オーバーフローの問題は、コンテンツの量がヒーロー要素より多い場合だけではありません。テキストの折り返しが原因でスクリーンのサイズが変更された場合にも発生することがあります。
スマホだと、テキストの折り返しでオーバーフローする
代わりにmin-heightを使用した場合、この問題は発生しません。
モーダルコンポーネント
モーダルコンポーネントの場合、スマホからデスクトップまでのスクリーンで動作できるように、最小と最大の幅が必要です。CSS Tricksに興味深い記事があります。
コンセプト1
1 2 3 4 |
.c-modal__body { width: 600px; max-width: 100%; } |
コンセプト2
1 2 3 4 |
.c-modal__body { width: 100%; max-width: 600px; } |
個人的にはmax-width: 600pxを定義するだけでよいので、コンセプト2を好みます。モーダルをdivで実装すると、ブロック要素なので幅は100%になります。
モーダルを実装する場合は、さまざまなビューポートで確認してください。使用可能なビューポートのスペースが十分でない場合、幅が親の100%に変化することに注意してください。
See the Pen
Max Width Modal by Ahmad Shadeed (@shadeed)
on CodePen.
min-heightとスティッキーフッタ
ページのコンテンツが短い場合、フッタが下部に配置されていないことがあります。
コンテンツが短いので、フッタが最下部にならない
フッタが最下部に配置されていないことに注目してください。これはコンテンツの長さがブラウザの高さほど長くないのが原因です。期待する表示は、次のようになります。
フッタを常に最下部に配置
body要素をFlexコンテナとして作成し、次にその最小高さをビューポートの高さの100%に設定します。
1 2 3 4 5 6 7 8 9 |
body { display: flex; flex-direction: column; min-height: 100vh; } footer { margin-top: auto; } |
実際の動作は下記のデモでご覧ください。
デモページ
最大幅・高さとビューポート単位の流体比率
ビューポートのサイズに応じて比率を維持するコンテナを実装するには、padding hackが便利です。このテクニックを使用すると、ビューポート単位と最大幅・高さを組み合わせることで、実装できます。
Miriam Suzanneの記事を参考に、その仕組みを説明したいと思います。
ビューポートのサイズに応じて比率を維持するコンテナ
サイズが644*1000pxの画像があります。これを流動的にするには、以下が必要です
- アスペクト比: 高さと幅
- コンテナの幅: 固定値または動的(100%)にすることが可能
- ビューポートの幅の100%にアスペクト比を掛けたheightを設定
- コンテナの幅にアスペクト比を掛けたmax-heightを設定
- コンテナの幅に等しくなるようにmax-widthを設定
1 2 3 4 5 6 7 8 9 |
img { --ratio: 664 / 1000; --container-width: 30em; display: block; height: calc(100vw * var(--ratio)); max-height: calc(var(--container-width) * var(--ratio)); width: 100%; max-width: var(--container-width); } |
See the Pen
Fluid Ratio with Max Height/Width by Ahmad Shadeed (@shadeed)
on CodePen.
高さが100%のhtmlとbody
body要素にビューポートの高さを100%にしたい場合は、どうすればよいでしょうか? これはStackOverflowにあるように、よくある質問です。
まず、html要素にheight: 100%;を定義する必要があります。これにより、ルート要素の高さが100%になります。次に、body要素にmin-heightを加えます。min-heightにする理由は、コンテンツの長さに関係なくbodyの高さが動的になるからです。
1 2 3 4 5 6 7 |
html { height: 100%; } body { min-height: 100%; } |
実際の動作は下記のデモでご覧ください。
デモページ
メモ
min-widthとブロック要素
場合によっては、min-widthを適用しようとしている要素がブロック要素であることを忘れるかもしれません。その結果、混乱する可能性がありますが、要素には影響しません。要素がブロックレベルではないことを確認してください。
CSSの比較関数
StackOverflowにこんな質問がありました。
次のようなことを行うことは可能ですか?
max-width: calc(max(500px, 100% - 80px))
max-width: max(500px, calc(100% - 80px)))
期待する動作は要素の幅を500pxに保つことで、超えないようにすることです。ビューポートの幅が要素を含めるのに十分でない場合、その幅は100% - 80pxになります。
私は2番目を試してみました。この記事を書いている現在最新版はChrome(v79)とSafari(v13.0.3)で動作します。これはこの記事の範囲外ですが、近いうちに詳細を記事にするかもしれないでの、メモしておきます。
1 2 3 4 5 6 7 8 9 10 |
.yourselector { max-width: calc(100% - 80px); } /* Update: I changed the max-width from 500px to 580px. Thanks @fvsch */ @media screen and (max-width: 580px) { .yourselector { max-width: 500px; } } |
リソース
- Flex items and min-width:0 by Dominic McPhee
- CSS: Flex and "min-width" by Dominik Schöler
- Flexbugs by Philip Walton
コメントや提案があれば、@shadeed9にください。
sponsors