[css] セットしたmarginが親要素に影響を及ぼす話

2021年9月2日

テクノロジー

eyecatch 人の失敗に敏感な、ユゲタです。 とある、WEBサイトで使えるツールを開発していた時に、何故だかわからないが、ページ内の上部の方で、なんだかズレが生じていることに気が付きました。 どうやら、とあるエレメントのmargin(margin-top) の値分ズレているという事まで分かったんですが、 これってcssのmarginのバグというか、失敗というか、仕様とは言い切れないmarginの特性のようなものらしく、 上位階層(設定していあるエレメント以外)への影響について調査してみることにしました。

調査事始め

とりあえず、サンプルとして次のようなHTML構成を作ってみました。 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <div class="a"> <p>TEST</p> </div> </body> </html> <style> body{ background-color:#eee; } .a{ background-color:rgb(255,128,128); } p{ border : 1px solid black; margin : 50px; } </style> これをブラウザで表宇すると・・・ こんな風に表示されますが、少し解説すると、div.aの中に表示されているpなんですが、pにmargin:50px;がセットされているので、 本来であれば、このように表示されてほしいんですが、縦軸のmarginが、親要素に吸い取られているように見えます。

marginの妙

これは、marginがついたオブジェクトを縦並びに並べても同じ原因で、想定通りにならないということ同じ現象で、 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <p>aaa</p> <p>bbb</p> <p>ccc</p> </body> </html> <style> body{ background-color:#eee; } p{ border : 1px solid black; margin : 50px; } </style> このサンプルソースを表示すると、 こーなります。 この事象を知っている人は、回避法なども心得ていると思いますが、初心者はまあまあハマりんぐな、事象であることは間違いないでしょう。 簡単に説明すると、
margin-topとmargin-bottomは、その前後にくるエレメントで相殺する
というcssの不思議な特性が影響しているようです。 でも、本来はこういった動きにはなってはいけないんですが、どのブラウザでも、同じ挙動になります。 もはや、ブラウザの仕様としてあきらめるとして、どうやったら、これを回避できるのかと言うと、それを次にまとめてみました。

回避法

1. 親要素にborderをセットする

親要素にborder(border-width)が0以外の値でセットされていると、きちんと、innerにmarginがセットされます。 .a{ border:1px solid transparent; background-color:rgb(255,128,128); } 色をtransparentにすると、透明色でわからないようにセットできます。

2. 親要素にpaddingをセットする

borderでなくて、paddingでもイケるようです。 .a{ padding:0.1px; background-color:rgb(255,128,128); } それも、0.1pxのような、目で見てわからない値にセットすることで、誤差として値を埋め込むことでも、marginが正常に表示されます。

3. position:absolute または、fixedをセットする

position:absolute;内においては、marginは相殺されずに正常に表示されます。 .a{ position:absolute; background-color:rgb(255,128,128); } どちらも、独立エレメントとして、確率されるからでしょうね。 でも、サイズ指定などをしないといけないので、少し不便かも

4. overflow:hiddenをセットする。

多くのサイトで書かれている対応方法がコレで、親要素に、overflow:hidden;をセットするだけなのだそうです。 .a{ overflow:hidden; background-color:rgb(255,128,128); } overflow:visibleでは、相殺モードになってしまうので、hiddenにするのがポイントのようですが、bodyなどにはセットしてしまうと、スクロールができなくなったりもするので、 使用場所によって、上記のどれかを選択して行う必要があるようです。

ベストプラクティス

とりあえず、ボクの行き着いた結論として、こうしたmarginを周辺に影響させないようにするには、marginを受け止めてくれる親要素を1階層増やしておいて、 overflow:hiddenをセットしておくのが、難も考えずに不具合が起きにくいのではないかと考えた。 とにかくHTMLのネストが深くなってしまうのは、いただいかたが無いのかもしれない・・・

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ