「width: 100%が効かない…」
この問題が起きた時、見る箇所は決まっています。
それは、親の幅、またはその親。
なぜなら、width: 100%は親の幅の影響を受けるから。
そこで今回はwidth: 100%
が効かない例をあげ、原因特定までの道すじを解説します。
htmlの親子関係【前提】
例を見ていく前に、htmlの親子関係をサラッと解説。
さっそくですが、以下は親が<div>・子が<p>です。
<div>
<p>
</p>
</div>
親:<div>
子:<p>
<div>は、<p>を含んでいます。
このように、親の中に子が入っているのを「入れ子」と言います。
【参考記事】css指定で見るべき、htmlの親子関係
ちなみにこれは、親子関係になってません。
<div>
<div>
<p>
</p>
この場合、<div>と<p>は兄弟関係になります。
入れ子
こちらはどうでしょう。
<main>
<section>
<div>
<p>
</p>
</div>
<section>
</main>
親が<div>、子が<p>。
ただし、<div>は<section>に囲われており、ここでも入れ子が成立。
親:<section>
子:<div>
さらに、<main>は<section>を入れ子にしてます。
親:<main>
子:<section>
それぞれの関係性↓
<main> | ↔︎ | <section> | ↔︎ | <div> | ↔︎ | <p> |
親 | ↔︎ | 子/親 | ↔︎ | 子/親 | ↔︎ | 子 |
注目すべきは…
<p>は<div>だけでなく<section>などにも含まれ、入れ子が何層にもなっている点。
それでは、この入れ子構造を踏まえて次をご覧ください。
祖先要素・子孫要素
「祖先要素」
ある要素から見た、その上の要素(親を含める)。
「子孫要素」
ある要素から見た、その下の要素(子を含める)。
上の例で言うと、
<main>
<section>
<div>
<p>
</p>
</div>
<section>
</main>
<p>の祖先要素
<div> <section> <main>
<main>の子孫要素
<section> <div> <p>
となります。
- 親要素の中に子要素が入っている状態が入れ子。
- 入れ子構造は何層にもなる。
width: 100%が効かない原因を探る
冒頭のとおり、これから見ていく例がこちら。
「img画像を、レスポンシブさせるためwidth: 100%に指定。しかし、画面幅を変化させても画像幅は600pxのまま」
width: 100%
とすれば、レスポンシブできるはず…
しかし、画像幅は600pxと固定された数値のまま。
つまりパソコン用では横幅いっぱいに広がらず、スマホでは縮小されないというケース。
もと画像がこちら↓
width: 100%
が効いておらず、レスポンシブでも画像幅600pxのまま↓
書いてあるhtmlレイアウトとcss指定は、以下となります。
少しコード量が多いですが…
<main>
<section>
<div>
<p>
<img src="airport.jpg" alt="空港">
夕暮れの空港
</p>
</div>
</section>
</main>
main {
background-color: #fffae5; /* クリーム色 */
}
section {
width: 600px;
margin: 0 auto;
}
div {
margin-bottom: 30px;
}
p {
font-size: 24px;
background-color: #ffffff;
}
img {
width: 100%;
}
親子関係はこちら。
<main> | ↔︎ | <section> | ↔︎ | <div> | ↔︎ | <p> | ↔︎ | <img> |
親 | ↔︎ | 子/親 | ↔︎ | 子/親 | ↔︎ | 子/親 | ↔︎ | 子 |
それでは解説します。
親のwidthを見る
もう1度、どのように効かないのかを確認。
「img画像を、レスポンシブ対応させるためwidth: 100%に指定。しかし、画面幅を変化させても画像幅は600pxのまま」
「imgにwidth: 100%
と指定したけど、画像幅は600pxのまま」とあります。
なので、まずwidth: 100%
とはなにかを考えます。
width: 100%は、親の幅に対する子の割合ですね。
で、<img>の親はなにかというと<p>。
<main>
<section>
<div>
<p>
<img src="airport.jpg" alt="空港">
夕暮れの空港
</p>
</div>
</section>
</main>
width: 100%
なので、親と同じ幅になります。
<p>の幅 = <img>の幅
これは大丈夫ですね。
それじゃあ、<p>の幅はいくつなのか。
<p>を見るとwidth
は指定していません。
p {
font-size: 32px;
background-color: #ffffff;
}
幅に対する指定がないので、widthの値はauto(初期値)になります。
※初期値 = 指定を行っていない時、はじめから与えられている値。
【参考記事】初期値の使い所を理解する
そして、<p>はブロック要素なのでautoだと、親と同じ幅をとります。
ですので、<p>の親を見ましょう。
【補足】width: autoとwidth: 100%の違い
auto
と100%
の違いはこちら。
width | 幅の計算方法 |
auto | 幅 = 左右padding + 左右border + 要素の幅 |
100% | 幅 = 要素の幅 |
auto
では幅を計算する時、左右のパディングやボーダーを含みます。
一方、100%で幅を計算する時は、左右のパディングやボーダーを含みません。
もしwidth:100%
で、かつ左右にパディングやボーダーを指定したら、親からはみ出てしまいます。
なので、この場合はbox-sizing: border-box
という指定を行いましょう。
すると、親と同じ幅をとれます。
理由は、box-sizing: border-box
を指定することで、パディングやボーダーを含んで幅の計算をしてくれるから。
つまりauto
と同じあつかいになるんです。
くわしくは、box-sizingとは?をご覧ください。
なぜ、<p>はautoで<img>は100%?
<p> <img>ともにwidth
を指定しないと初期値autoになります。
この時、<p>はブロック要素なので親と同じ幅に。
一方、<img>はインライン要素のため、画像本来の大きさで表示されます。
ですので、<img>を親と同じ幅にするなら、width: 100%
とする必要があるのです。
このような理由で、ブロック要素にはauto
をインライン要素には100%を指定するのが一般的です。
【参考記事】ブロック要素とインライン要素の違い
補足が長すぎですね、すみません。
一応さきほどは、
「<p>はブロック要素なので、width
の指定がない場合、親要素と同じ幅となります。
なので、<p>の親を見ましょう。」
と述べてました。
というわけで、次へ。
親の親のwidthを見る
<p>の親は、なにかというと<div>です。
<img>からみると、<div>は「親の親」になります。
<main>
<section>
<div>
<p>
<img src="airport.jpg" alt="空港">
夕暮れの空港
</p>
</div>
</section>
</main>
先ほど、<p>は親と同じ幅をとっていると分かりました。
なので、
<div>の幅 = <p>の幅
となります。
というわけで、<div>の指定を見ると幅の指定は…ありません。
div {
margin-bottom: 30px;
}
そうすると、width
は初期値auto
となるため、<div>も親と同じ幅をとります。
次に見るのは、やっぱり<div>の親ですね。
と、ここまでは大丈夫でしょうか?
一旦、レイアウトを見返しましょう↓
<main>
<section>
<div>
<p>
<img src="airport.jpg" alt="空港">
夕暮れの空港
</p>
</div>
</section>
</main>
親の親の親のwidthを見て、入れ子を理解する
<div>の親は、<section>です。
そして、<img>から見ると<section>は「親の親の親」になります。
<main>
<section>
<div>
<p>
<img src="airport.jpg" alt="空港">
夕暮れの空港
</p>
</div>
</section>
</main>
<div>は親と同じ幅をとるので、
<section>の幅 = <div>の幅
となります。
で、<section>の幅はどうなっているかというと。
width: 600px
の指定がありました。
section {
width: 600px;
margin: 0 auto;
}
ということは、各要素の幅は以下のようになります。
<section> | = | <div> | = | <p> | = | <img> |
結果、
<section>のwidth: 600px | = | <img>のwidth: 100% |
となるわけです。
だから画面幅が変化しても、<img>の幅は600pxのままだったんですね。
これは<section>の幅が、<img>の幅にまで影響を及ぼしていたということになります。
<img>から遠く離れた<section>のwidth: 600px
がちゃんと影響していたわけです。
例えると、おじいちゃんの遺伝子がひ孫くらいまで引き継がれた感じかと。
場合によってはもっと離れたケースもあります。
ですので、その時はさらに上へとたどりましょう。
親を見る → 親の親を見る → 親の親の親を見る → 親の親の親の親を見る
さいごに、つけ足しみたいで恐縮ですが、サラッと解決策をお伝えします。
<section>をwidth: auto
としましょう。
またはwidth
の指定を削除してください。
すると、<section>の幅は初期値auto
を取ることになるので。
<section>のwidth
がauto
だと、画像の幅も画面幅の拡大・縮小によって大きさが変化します。
参考サイト
この記事は、HTML Living StandardとCSS3をもとに書きました。
HTML Living Standardはhtmlの、CSS3はcssのルールブックみたいなものです。
両方とも、その最新版です。
- <percentage>|MDN Web Docs
- 5.5. パーセンテージ: <percentage>タイプ「CSS 値と単位モジュール レベル 4」|W3C
- 1.10 HTML の簡単な紹介|HTML Living Standard
いずれも翻訳ありです。
やや専門的に書かれてるので、お時間ある方だけどうぞ。
まとめ
今回は、width: 100%が効かない場合の原因を突き止めました。
ポイントは、こちら。
width: 100%が効かない時は、親やその親の幅を確認する。
参考してみてください。
次は、コメントアウトの使い方をマスターしてみませんか?
コメントをうまく使えば、複雑な入れ子も見やすくできます。
また、レイアウト構造を理解する助けにもなるので、ご覧ください。