PR

widthの正体を暴く

HTML/CSSを学ぶ

みなさんこんにちは。今回は「CSSといえばまずはwidth」というくらい皆さんも目にしている、widthプロパティについて改めて解説していきます。

近年はwidthを工夫するだけで相当なバリエーションのレスポンシブデザインを実装することができます。ぜひ覚えてみましょう。

前提編:要素の横幅はどう決まるのか

widthの前に、HTML/CSSにおいて要素の横幅がどのような計算式で決まるかを確認します。

実はbox-sizingというサイズの計算方法を決めるプロパティの値によって2通りあり、ややこしいのでここで整理します。

結論としては次の表のようになります。

box-sizingの値計算式
content-box(初期値)要素の横幅 = width + 左右のpadding + 左右のborder
border-box要素の横幅 = width

それぞれの挙動を例を見ながら確認しましょう。以下のプロパティを指定した場合、それぞれのbox-sizingの値でどう変わるでしょうか。

border: 3px solid #000000;
width: 200px;
padding-left: 20px;
padding-right: 20px;
background-color: skyblue;

box-sizing: content-box; の時

横幅は246px

横幅は200px + 20px * 2 + 3px * 2 = 246pxになります。

box-sizing: border-box; の時

横幅は200px

横幅は200px になります。padding、borderは要素の内側に作られるイメージです。

基本はborder-boxで使う

上記の例を見るとbox-sizing: border-box;の方が直感的で分かりやすいですね。また、content-boxの場合width: 100%でpaddingをつけたりすると親要素をはみ出してしまうという扱いにくさがあります(下図)。

横幅は100% + 20px * 2

よって実際の案件では基本的に全要素をborder-boxにして使います。最近のリセットCSSでは多くの場合この指定が含まれています。

本記事では以後border-box前提で解説をしていきます。

基本編

ではwidthの基本的な使い方を確認しましょう。値にはいくつかの書き方がありますが、よく使う単位の挙動を見ていきます。

ぜひブラウザの画面幅を変えながら変化を確認してみてください。

px

数値による絶対指定です。画面幅をいくら変えても常に指定した値で固定されます。

width: 250px;

サンプル


多くの要素は画面幅に関わらず横幅が変わらないということはあまりないので意外と使う頻度は少ないです。ボタンのように「画面幅は小さくても要素が小さすぎるとタップしにくい」という場合には固定pxで作ることがあります。

逆に下手にpxを使うと画面幅や親要素を突き抜けてしまうことがあるので注意して使う必要があります。

例えば親要素(ピンク)はwidht: 50%、子要素は固定px(水色)で指定すると子要素がはみ出します。(下図)。

%

親要素の横幅に対して何%か、で横幅が決まります。ほとんどの要素はこの%で指定することになるでしょう。pxのように親要素をはみ出すことがないですし、画面幅の変化にも強い要素になります。

また、親要素に対してぴったりにしたい場合が多いのでwidth: 100%;を指定しておくのが良いです。

width: 50%;

サンプル


※厳密には120%のように100より大きい数値を指定できるため親要素をはみ出すような指定もできます。

vw

画面幅に対して何%か、で横幅が決まります。vwの場合は親要素が何pxかは関係ありません。

width: 30vw;

サンプル


%で指定するのと似ており多くの場合は%で指定する方が良いのですが、

  • 親要素をあえてはみ出させたい
  • ただし画面幅に対して変化させたい

という場面で活躍します。例えば特定の要素だけコンテンツ幅をはみ出させたいようなデザインです(下画像)。

https://toyota.jp/cwalks/

テキストコンテンツ部分は同じ幅に収まっていますが、画像だけ画面幅ぴったりのサイズですね。これをセクションを分けずに実現できます。

詳しい実装方法はこちらをご覧ください。

auto

widthに何も指定しなかった場合、初期値として設定されているautoが適用されます。box-sizing: border-box; の場合、概ねwidth: 100%; と同じ挙動をします。ただしinline-blockの要素の場合挙動が変わるので注意しましょう(下図)。

width: auto;
width: 100%;

このように、

  • width: auto; はコンテンツ分の幅になる
  • width: 100%; は親要素と同じ幅になる

という違いが生まれます。横幅いっぱいではなくコンテンツ分だけ横幅が欲しい場面はあり、そういう時に使い分けできそうです。

とはいえ今となっては後述のfit-contentというキーワードでいつでもそれができるようになったのであまり覚えなくても良いでしょう。

応用編

fit-content

コンテンツの量に合うように自動でサイズが調整されます。

width: fit-content;

サンプル

ダミーテキスト
ダミーテキストダミーテキストダミーテキストダミーテキスト
ダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキスト

横幅いっぱいではなくテキスト部分だけに装飾を付けたい場合に非常に便利です。ぜひ覚えておきましょう。

calc()

計算式をそのまま指定することができます。異なる単位の計算ができるのが特徴です。

width: calc(20% + 150px);

サンプル


主に用途としては、

  • 異なる単位の計算じゃないとぴったりにならない時
  • 計算式をコード上に残した方が管理・保守の面で有効な時

が挙げられるかなと思います。具体的な例を挙げるのが難しいので言葉の説明だけになってしまいますが、たまに使いたい場面はあります。

また次に説明するclampはcalc以上の使い方ができるものですので合わせてご覧ください。

clamp

通常の値に加えて最大値/最小値を合わせて指定ができる関数です。

width: clamp(最小値, 値, 最大値);

という使い方をします。真ん中の値は推奨値とも呼ばれ、最大/最小に達さない限りその値で横幅が決まります。

具体的には次のように書きます。

width: clamp(300px, 50%, 400px);

サンプル

最大値に達したら黄色、最小値に達したらピンク、それ以外は水色に色が変わります。


サンプルのように、最大値と最小値を合わせて定義しています。max-width/min-widthと併用しても良いですが、個人的にはこの書き方が好みなのでよく使います。

また推奨値には計算式も定義可能です。

width: (20px, 240 / 375 * 100vw , 300px)

clampにおいてはcalcを使わず直接計算式を指定できます。

このclampはレスポンシブにおいて痒い所に手が届くもので、デザインカンプの中でどうしてもうまく再現できない要素があったらぜひclampを検討してみてください。より具体的な使い方は過去に記事を書いているのでそちらをご覧ください。

使い方編

基本的なフォームの場合

具体的な例を出してwidthの基本的な使い方を考えてみましょう。以下のフォームがあったとします。

コードは以下の通りです(クリックで開きます)。

index.html
<form action="#" class="Form">
  <label class="Form-Item">
    <span class="Form-Item-Label">お名前</span>
    <input type="text" name="name" class="Form-Item-Input" />
  </label>
  <label class="Form-Item">
    <span class="Form-Item-Label">メールアドレス</span>
    <input type="email" name="email" class="Form-Item-Input" />
  </label>
  <label class="Form-Item">
    <span class="Form-Item-Label">電話番号</span>
    <input type="tel" name="tel" class="Form-Item-Input" />
  </label>
  <label class="Form-Item">
    <span class="Form-Item-Label">お問い合わせ内容</span>
    <textarea name="content" class="Form-Item-Textarea"></textarea>
  </label>
  <button type="button" class="Form-Button">送信</button> <!-- 今回はダミーなので押しても動作しないようにtype="button" にしている -->
</form>
style.css
.Form {
  margin: auto;
  border: 1px solid #ddd;
  width: 100%;
  max-width: 500px;
  padding: 20px;
}

.Form-Item {
  display: block;
  margin-bottom: 20px;
  width: 100%;
}

.Form-Item-Label {
  font-weight: bold;
}

.Form-Item-Input {
  margin-top: 10px;
  padding: 10px;
  border: 1px solid #ddd;
}

.Form-Item-Textarea {
  margin-top: 10px;
  padding: 10px;
  border: 1px solid #ddd;
  resize: none;
}

.Form-Button {
  margin: auto;
  border: 1px solid #ddd;
  width: 200px;
  padding: 10px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #fff;
  cursor: pointer;
}

この時、

  • フォーム全体
  • 各項目の入力欄(lebelタグ部分)
    • 見出し
    • input部分
  • 送信ボタン

のそれぞれのwidthはどのように考えて値を指定しているでしょうか。

結局のところはデザインカンプでどうなっているかで決まるのでそれの通りにコーディングしましょう、ということにはなります。

このフォームの場合、僕は以下のように考えています。

  • フォーム全体は画面幅に対して横幅が変化することが望ましいので、%で指定する。
  • SPサイズは画面いっぱいで良いが、PCサイズにおいては画面幅ぴったりだと大きすぎるのでwidth: 100%; の上でmax-widthで制限をかける。
  • 各項目の入力欄(labelタグ部分)は親要素の幅に合わせて変化するので%で指定する。
  • 「お名前」「メールアドレス」などの見出し部分は特に横幅を決める必要がないのでwidth: auto; のまま。
  • input部分は横幅いっぱいが望ましいのでwidth: 100%;
  • 送信ボタンは画面幅によって変化するというよりも常に押しやすいサイズであるのが望ましいので固定pxで指定する。
    • ただしサイズが大きい分にはその問題がないので、デザイン的に許容されるならwidth: 100%; でも良い。

基本的にこのように考えています。フォーム全体の横幅制限は、実際のデザインではさらに親要素でコンテンツ幅が800px前後に制限されている場合が多いです。

こうやって見ると、やはりWebサイトにおける基本的なセクションにおいてwidthを固定pxで指定することは少なそうですね。

使い回すパーツの場合

前述のフォームにもありますが、「ボタン」というものはいろんな箇所で使われるケースが多いですね。同じデザインが使い回される場合でも、中の文字は異なります。固定pxでは文字の長さによっては2行になってしまい見栄えが良くないですね。

そんな時はfit-contentを使ってみましょう。以下のように中の文字の長さに合わせてボタンのサイズがうまく変化します。

コードは以下の通り。

<button class="Button">送信</button>
<button class="Button">〇〇したい方はこちら</button>
<button class="Button">もっと見る</button>
.Button {
  border: 1px solid #ddd;
  width: fit-content;
  padding: 10px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #fff;
  cursor: pointer;
}

文字数が少ない時にサイズが小さいなと思ったらmin-widthを追加します。

.Button {
  border: 1px solid #ddd;
  width: fit-content;
  min-width: 100px; /* 追加 */
  padding: 10px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #fff;
  cursor: pointer;
}

このように、コンテンツの長さが変わることが想定されるならそれによって崩れないように工夫してみましょう。

まとめ

というわけでwidthについて細かく解説してみました。

もちろんこれでwidthの全てを解説しているわけではありません。しかしまずは今回の記事で解説した内容を理解し、しっかり使いこなせるようになりましょう。

display: flex; やdisplay: grid; が絡んだ場合の記事はこちら。

参考

width - CSS: カスケーディングスタイルシート | MDN
width は CSS のプロパティで、要素の幅を設定します。既定では、このプロパティはコンテンツ領域の幅を設定しますが、 box-sizing を border-box に設定すると、境界領域の幅を設定します。
fit-content() - CSS: カスケーディングスタイルシート | MDN
fit-content() は CSS の関数で、指定された寸法を min(max-content, max(min-content, 引数)) の式に従って有効な範囲の寸法に収めます。
fit-content - CSS: カスケーディングスタイルシート | MDN
fit-content は fit-content(stretch) として動作します。実際には、ボックスは利用可能な空間を使用しますが、 max-content 以上にはならないことを意味します。

コメント

タイトルとURLをコピーしました