マージンと幅と高さの関係
これについて話す前に、包含ボックスとは何か、および包含ボックスの概念と幅と高さの関係について知っておく必要があります。以前の記事 CSS :要素の高さと幅の議論に関する一連の記事 (パート 3) を参照してください。
HTML
<div class="wrap"> <div class="item1"></div> <div class="item2"></div></div>
CSS
.wrap { float: left; border: 2px solid #000; } .item1 { width: 100px; height: 100px; background: #fdf; margin-left: 10px; margin-top: 10px; margin-right: 20px; margin-bottom: 30px; }.item2 { width: 50px; height: 50px; background: #adf; }
原則 2 を満たすことができる条件は 1 つだけです。要素には幅がなく、はドキュメント フロー内にあります。このとき、親要素のラップによって生成される包含ボックスの幅と高さは、子要素のボーダー ボックスの幅と高さにマージンの幅と高さを加えたものと等しくなります。言い換えれば、子要素のマージン値もその包含ボックスの一部です。マージンの基準線は 2 種類あります。 1 つ目は margin-top と margin-left の基準線です。 2 つ目は margin-bottom と margin-right の基準線です。 marginの基準となるのはcontaining-boxの端線です。 上記の例のように、要素.item1のmargin-topとmargin-leftの値を調整すると、要素 .item1 が配置されているボックスのサイズも変化するため、そのエッジ ラインも常に変化し、これにより .item1 要素自体の位置も変化します。 .item1 自体が移動したように見えます。 2 番目のタイプのマージンの基準線は、要素自体のエッジ ラインに基づいています (マージンの外側がエッジ ラインです)。同様に、上の例では margin-bottom の値、 の margin-bottom を調整します。 item1 も常に変化しており、それ自体のエッジ ラインが常に移動しており、それが .item2 の移動にもつながります。上記の議論に基づいて、マージンの調整は、基準線の位置をそれ自体に対して相対的に移動すると同時に、基準線に対して移動する要素を移動させることと同等であると結論付けることができます。要素自体は、包含ボックスのエッジ線に対して相対的に移動し、要素自体の兄弟である要素は、要素自体のエッジ線に対して相対的に移動します。基準線の模式図は図のようになります。基準線の矢印方向の変化のマージン値はすべて正の値になります。 要約すると、マージンを使用して要素自体を移動することも、隣接する要素を移動することもできます。移動するときに知っておく必要があるのは、その要素が含まれるボックスのサイズも変化するということです。 要約すると、要素の幅と高さがコンテンツの幅と高さに等しい場合、その要素を含むボックスのサイズは、コンテンツのマージン値を調整することで調整できます。ボックスを使用すると、要素自体も移動します。つまり、両方の要素を移動することも、要素間の間隔を調整することもできます。
2. 要素のボーダーボックスの幅 + マージンは、その要素を含むボックスの幅に等しい (原則 2)
<div class="wrap"> <div class="wrap-inner"></div></div>.wrap { width: 100px; border: 2px solid #000; margin: 0 auto;}.wrap-inner { height: 50px; background: #fdf;}
質問1
body { margin: 0;}.container { margin: 0 auto; width: 980px;}.inner-wrap { margin-left: -10px;}.inner { float: left; margin-left: 10px; width: 320px; height: 200px; background: #2df;}
此布局便利用了原理2,利用负margin增加了inner-wrap的宽度,但不改变整体的宽的情况下,实现效果。如下
上面的例子仅仅只是实现了三列固定宽度的布局,这样的布局当屏幕宽度发生变化的时候便会出现问题。因此我们便会有如下需求。
左右列固定,中间列自适应栗子
html
<div class="main"> <div class="main-content"></div></div><div class="left"></div><div class="right"></div>
css
.main { float: left; width: 100%;}.main-content { height: 200px; background: #2da; margin: 0 200px;}.left,.right { float: left; width: 200px; height: 200px; background: #ccc;}.left { margin-left: -100%;}.right { margin-left: -200px;}
效果如下,当你缩小屏幕时,中间部分会随着屏幕的缩小而缩小,另外两部分宽度不变,同样也满足了主要内容优先加载的需求,可谓一举两得
可以看出上面的布局利用了原理2,但是这里仍然会有几个为什么要问。
首先,为什么main里面一定要嵌套main-content,为什么不能直接使用单个main(假设1)?
其次,为什么main上一定要设置float:left,可以设置其他值吗,如position:absolute(假设2)?
分析上面的布局之前,我们也要了解到上面的布局满足了我们的什么需求,这里有两点1.主要内容优先加载。2.主要内容自适应。这里我们可以分析一下,我们是怎样达到上述两个目的的。首先,要达到目的1,我们就的把div.main放在前面来写,因为浏览器是从下到下渲染页面的,放在前面的也就会先渲染。且由于div.main为文档流中的块级元素,因此会独占一行,因此我们需要使其脱离文档流,这样才能使下面的元素能有机会上的来(这里之所以不考虑display:inline-block是因为div.main的长度会独占一行,就算设置display:inline-block也没有任何作用,下面的元素仍然上不来)。而要达到目的2,需要用到原理2。同时在上面提出的两个问题中,有两个假设。
假设1,如果使用单个main可不可以满足上述两个需求?我们可以试试。
html
<div class="main"></div><div class="left"></div><div class="right"></div>
css
body { margin:0;}/*这里注意需要改掉main的流方式,下面的元素才上的来*/.main { float:left margin: 0 210px; height: 200px; background:#2da;}.left,.right { float: left; width: 200px; height: 200px; background: #ccc;}.left { margin-left: -100%;}.right { margin-left: -200px;}
从中线分开的黄色两部分为各自为main的左右外边距
从结果中,我们可以看出使用单个main是不行的,因为在不设宽度且元素不在文档流中时,元素的宽度为0,不能满足我们的需求,正因为我们同时要满足1.main元素不在文档流中2.元素不设宽度且在文档流中。这两个条件当然是不能同时在一个main元素下能达到的,因此我们需要再嵌套一个main-content让它来满足条件2。这也就解释了为什么一定要嵌套一个main-content。
解决了问题1,现在我们来说问题2。
假设2,main上的float值可以换为position:absolute吗?
同样的,我们试试
html
<div class="main"> <div class="main-content"></div></div><div class="left"></div><div class="right"></div>
css
body { margin: 0;}.main { position:absolute; width:100%;}.main-content { margin: 0 210px; height: 200px; background: #2da;}.left,.right { width: 200px; height: 200px; background:#ccc;}.left { float: left;}.right { float: right;}
答案是可以的,只是我们需要改掉一些值,而当main为float之所以要给div.left与div.right要设置margin-left值是因为浮动元素浮动时,当它的外边缘碰到包含框或者另一个浮动框的边框为止。而为浮动元素的div.main占据了整整一行,因此下面的浮动元素div.left与div.right便被挤了下来,而设置它们的margin-left值便可以把它们移上去,这里便运用了原理1。而当我们把div.main的float值改为position:absolute时,便不会存在被挤下来的问题,可直接设置div.left与div.right的float的值。效果如下。
如若只需要达到宽度自适应的要求,那么,这时候便可以将div.main放在最后面且不用嵌套div.main-content,具体如何实现,大家可以自己试试。
两列布局的道理也是差不多的,这里我就不写了,大家可以看这篇文章
margin系列之布局篇
如下所示设计稿,在我们进行布局的过程中,可能会出现border重合的情况,因为一方面我们需要对整个整体加上border,而另一方面我们又需要利用border隔开那三个小块。那么如果我们对每个小块都加上右边框,可以想象,最右边就会出现边框的堆叠而这不是我们希望看到的,所以,要如何解决这个问题,可以看如下例子给出的答案。
栗子
html
<ul> <li>1</li> <li>2</li> <li>3</li></ul>
css
ul { position:absolute; margin: 0; padding:0; list-style:none; border: 4px solid #c5c5c5;}li { float:left; width: 200px; height: 50px; line-height: 50px; text-align: center; border-right: 4px solid #c5c5c5;}
没在li上加margin-right:-4px;前,效果如图,发生了堆叠。
加了margin-right: -4px后,达到预期效果。因为加上了ul的右边框发生了移动与第三个li的右边框进行了重叠。因此效果上来看便符合了预期,如图
此布局便利用了原理1,通过元素对相邻元素位置的控制来达到预期的效果。
而利用原理1也可以实现元素居中的布局,先让元素上左各移50%,然后再让设置元素的上左margin值设置为元素自身宽度的一半长度,以对元素本身进行移动。便可达到元素居中放置的目的。