要用到的基本术语和概念:
- 替换元素:用作为其他内容占位符的一个元素,或说替换元素内容的部分并非由文档内容直接表示。比如img元素它由文档本身之外的一个图像来替换,比如input元素要由一个单选按钮,复选框,文本输入框等替换。替换元素多为行级元素,行级替换元素可以像块级元素一样设置width/height/padding/margin。
- 非替换元素:元素的内容本身包含在文档中,或说其内容由User Agent在元素本身生成的框中显示。比如一个段落p元素里的文本本身就放在该元素内。
- 块级非替换元素:比如div,p,blockquote 等。
- 行级非替换元素:比如span,i 等,注意行级非替换元素设置不了width,height,marginTop和marginBottom(原因后面解释)。
- em框:我们常用的font-size属性与你看到的实际字体大小之间的关系由字体的设计者来确定,这种关系设置为字体本身中的一个em框,如下的蓝色方框。所以font-size的作用是为给定字体的em框提供一个大小(但并不能保证实际显示的字符就是这种大小,实际的字符可能比em框更高或更矮)
- 内容区:
- 在非替换元素中,内容区是元素中各字符的em框串在一起构成的框。
- 在替换元素中,内容区是元素固有高度+可能有的内边距+边框+外边距,比如下图img如果说它有padding,border,margin的话。
- 行间距:是font-size值和line-height值之差。这个差值其实要分为两半分别应用到内容区的顶部和底部,称为半行间距。行间距只能用于非替换元素。没错顶线和底线构成了内容区em框。
- 行内框:这个框通过向内容区增加行间距来描述。
- 非替换元素行内框的高度刚好等于line-height就是上图的行高。
- 替换元素行内框的高度就是其内容区的高度,因为替换元素没有行间距。
- 行框:一行中每个字符都有自己的行内框,行框就是包含该行中出现的行内框的最高点的最低点的最小框,也就是说行框的上边界位于最高行内框的上边界,行框的底边要放在最低行内框的下边界。
需要知道的画外音:
- 内容区类似于一个块级元素的盒子模型中的内容框content。
- 行内元素的背景应用于内容区及所有内边距,边框。
- 行内元素的边框要包围内容区及其所有内外边距。
- 替换元素的内外边距和边框确实会影响该元素的行内框高度,相应地也会影响行框高度。可以拿img元素想想是不是这样。
- 非替换元素的内外边距和边框对行内元素或其生成的元素没有垂直效果(即有名的margin重叠问题)。
这样才会进入正题:
part 1:为什么行级非替换元素比如span设置margin-top和margin-bottom并没有什么卵用?
你也许会说因为span不是块级元素所以设置margin-top和margin-bottom才会没用,那我反问你为何span设置了margin-left和margin-right就起作用呢,他们都是margin一族的啊?不知道了吧,所以真正原因不是那么简单。我是从行高方面分析的,也许不完全正确,但谁又知道css的渲染机制到底内部是怎样或是w3c为什么要这样规定呢...
首先你需要知道行框(说通俗点也就是行高line-height)是怎么来的,由行内框确定的是不是,而span这个行级非替换元素的行内框就是它的内容区(也就是它的em框,说通俗点就是font-size)+上下行间距。上面说过内容区类似于一个块级元素的盒子模型中的内容框content,任你怎么设置margin-top和margin-bottom,就算你设置border-top,boder-bottom,padding-top,padding-bottom都对行高没什么卵用。对于span来说行高只和em框,上下行间距有关。如果说盒子模型不是反映元素在文档流中占据位置的必要条件,毕竟行高还反映着元素在文档流中占据的高度。如果说span元素的内容区像img替换元素这样内容区本身就包含着边框,内外间距,那确实会影响该元素的行高。
part 2:利用line-height为什么会使文本或子元素的文本垂直居中?
1 <p style="height:50px;background-color:red"> 2 <span style="background-color:yellow"> 3 我是子元素的文本 4 </span> 5 </p>
由于没有给span元素设置padding和border,此时黄色部分就是span元素的内容区啦,span元素此时继承来的font-size为16px(chrome下默认html的font-size为16px),增加内容区上下的行间距使span元素的行高撑满父元素,文本不就居中了。父元素的content内容高度为50px,所以直接给span元素设置line-height为50px就大功告成。很多人误认为这样是把span元素居中了,其实不是的,span元素并没移动,而是它的行高增加了。
参考:部分概念内容参考自《css权威指南》,大部分为自己理解,如理解有误还望各位菊苣指出好让我迷途知返及时改正