前面两章讲到了CSS的一些基础用法,这一章主要聚集于CSS的框结构和布局等。
基本框
CSS认为每一个元素都会生成一个或多个矩形框,这些被称为元素框。实际上,框不一定要是矩形的,不过就现在来讲,框都是矩形的。将框想像为矩形,也更加方便大家对框结构进行理解。
每一个元素框都具有外边距、框和内边距。元素内容的背景会应用到内边距,但是不会应用到外边距。外边距一般是透明的,透过外边距可以看到父元素的背景。内边距不能为负值,外边距可以。
如果元素未设置边框颜色,则边框颜色默认取元素的前景颜色。如果边框样式有某种缝隙,那么透过这些缝隙应该是可以看到元素的背景的。
块级元素
一般的,一个元素的width
被定义为从左内边界到右内边界的距离,height
则是从上内边距到下内边界的距离。在大多情况下,文档的高度和宽度都是由浏览器自动确定的。
水平格式化
width影响的是元素内容区的宽度,而非整个可见的元素框。如元素,其
width
为200px
,但是在默认的盒模型下,该元素的实际宽度为200px + 1px * 2 + 5px * 2 + 5px * 2 = 222px
。在CSS3中,引入了box-sizing
属性来控制盒模型。为了尽量简化理解,我们这里都默认使用的box-sizing
为content-box
,或者假装暂时不知道box-sizing
属性。
水平属性
水平属性的七大基本属性是:margin-left
、border-left
、padding-left
、width
、padding-right
、border-right
和margin-right
。这七个属性中,只有margin-left
、width
和margin-right
可以设置为auto
,其余属性必须要设定为特定的值。
大家要记住一点,元素框的宽度(之和)应该等为父元素的width
。因此,如果以上三个可以设置为auto
的属性中有一个被设置为auto
时,该属性的值由其余两个被指定的属性以及父元素的width
来决定。那么,如果用户“强迫症”式地为三个属性都指定了值,但是其指定值不能满足子元素框与父元素width
之间的关系(过度受限),会发生什么呢?这种情况下,在从左往右的阅读模式中,margin-right
会被自动设置为auto
;从右往左阅读模式时情况则正好相反。
在不止一个auto
的情况下,需要进行分类讨论:
-
如果两个边距都设置为
auto
,则它们会被设置为相等的值,而最终达到的效果则是元素会相对于父元素进行水平居中显示。大家要注意这与text-align
的区别:text-align
是对元素内部的内容进行居中,而自动左右外边距则是会将元素进行居中。
如果
width
和外边距之一被设置为auto
, 余下的另一个外边距被设置为指定值,则设置为auto
的外边距会被自动设置为0
。如果三个属性都被设置为
auto
,则左右外边距都会被设置为0
,width
保持为auto
,最终会使元素的内容区尽可能得宽。这种情况是默认情况,即用户不显式地设置这三个值时,浏览器会默认进行这样的处理。
负外边距
如果我们为元素设置了负外边距,那么会是怎样的显示效果呢?
举个例子:
div {width: 400px; border: 3px solid black}
p.wide {margin-left: 10px; width: auto; margin-right: -50px; background: #eee}
这样会得到什么效果?
你会看到子元素的内容超出了父元素的内容区,视觉上会觉得子元素比父元素宽。那么,这样的情况有违反之前说的“元素框的宽度(之和)应该等为父元素的
width
”这样的规则吗?
答案是:没有。
为什么呢?因为此时元素的width
的值为440px
,大家可以计算一下,上述原则在这样的情况下是否成立。
正是由于这种情况,具有负边距的元素有时会与父元素之外的元素发生重叠。
在元素发生过度受限的情况时,大家记住,受伤的永远都是右边距(从左向右阅读模式)。即当元素过度受限,导致父子元素宽度关系得不到满足时,右边距会被强制设置为使等式成立的值,而不会管此时右边距的值为正还是负。
内边距、边框和内容的宽度(和高度)是绝对不能为负的,唯一可以被设置为负值的只有外边距。
如果以百分数来设置这些属性,其表现方式与以具体单位设置时是一样的。只是要记住一点,百分数的基数是包含元素的width
。同时需要注意的是:边框的宽度不能是百分数,而只能是长度。所以,想通过百分数来完全指定一个元素的尺寸,是不可能的。
对于替换元素,我们在非替换元素介绍的所有规则都适合。只有一点不同,当设置替换元素的width
为auto
时,该元素的宽度是其实际内容的宽度。如果一个替换元素的width
被设置为一个不等于其原始宽度的值,则其height
值会等比例缩放,除非用户显式地指定了一个height
值。
顺便补充一点,在使用jQuery时,可以用不同的方法获得元素的不同宽度。
垂直格式化
一个元素的默认高度由其内容决定。同时,与width
一样,height
定义的是元素内容区的高度(默认盒模型的情况下),而非元素框的总高度。
与宽度属性不一样,如果正常流中的一个块元素的margin-top
和margin-bottom
被设置为auto
,它会自动被设置为0
,这也说明我们不能通过将margin-top
和margin-bottom
设置为auto
来达到垂直居中的效果。
如果一个块级正常流元素的height
被设置为一个百分数,这个值则是其包含块height
值的一个而百分数。如果没有显式地声明包含块的height
,百分数高度会被重置为auto
。
如果块级正常流元素的高度设置为auto
,而且只有块级子元素,那么它的默认高度将是从最高块级子元素的外边框边界到最低块级子元素的外边框边界之间的距离。所以,子元素的外边距会超出包含该元素的父元素的边框。不过,如果块级元素有上内边距或下内边距,或者有上边框或下边框,则其高度值是从其最高子元素的上外边距到其最低子元素的下外边距之间的距离。这是为什么呢?
合并垂直外边距
垂直格式化的另一个重要特性就是垂直相邻外边距会发生合并,且这种合并只会发生在外边距。如果元素有内边距和边框,则它们不会发生合并。这也就解释了为什么在不设置包含元素的边框和内边距的情况下,子元素的外边距会超出包含该元素的父元素的边框。
负外边距会影响垂直格式化,而且会影响到外边距如何合并。如果垂直外边距都设置为负值,那么浏览器会取两个外边距绝对值的最大值的相反数;如果一个正外边距和一个负外边距合并,会从正外边距减去这个负外边距的绝对值。
由于负边距的存在,可能会造成元素之间的重叠。发生重叠的元素要怎么显示呢?由于浏览器总会按从前到后的顺序显示元素,所以文档中后出现的正常流元素可能会覆盖较早出现的元素。
列表项
大家在使用列表时需要注意,与一个列表元素关联的标志可能在列表项内容之外,也可能处理为内容开始处的一个内联标志,这取决于属性list-style-position
的值。
行内元素
在开始进一步的介绍之前,我们先回顾一些基本概念。
em框
em
框在字体中定义,也称为字符框。实际的字形有可能比em
框更高或更矮。
内容区
内容区可以是元素中各字符的em框串在一起构成的框,也可以是由元素中字符字形描述的框。
行间距
行间距是font-size
和line-height
之差。
行内框
行内框等于内容框加行间距所构成的框。对于非替换元素,元素行内框的高度刚好等于line-height
的值。对于替换元素,元素行内框的高度则恰好等于内容区的高度,因为行间距不能应用于替换元素。
行框
包含一行中出现的行内框的最高点和最低点的最小框。各行行框的顶端紧挨着上一行行框的底端。
下面我们再了解一组有用的行为和概念:
内容区类似于一个块级元素的内容框。
行内元素的背景应用于内容区及所有的内边距。
行内元素的边框要包围内容区及所有的内边距和边框。
非替换元素的内边距、边框和外边距对行内元素或其生成的框没有垂直效果。即,它们不会影响元素行内框的高度。
替换元素的外边距和边框会影响该元素行内框的高度,相应地,也可以影响包含该行内框的行框的高度。
行内框在行中根据其vertical-align
属性垂直对齐。
行内格式化
line-height
实际只影响行内元素和其他行内内容,而不会影响块级元素,至少不会直接地影响到块级元素。也可以为一个块级元素设置line-height
,但是这个值只是应用于块级元素的内联内容时才会影响到视觉效果。
可以为一个块级元素设置line-height
,并将这个值应用于块中的所有内容,而不论内容是否包含在行内元素中。实际上,我们可以认为块级元素中包含的各文本行本身都是行内元素,而不论是否真正用行内元素的标记包围起来。也就是说,在块级元素上设置line-height
,实际会应用于其包含的行内元素。
垂直对齐
对于行内元素的垂直对齐,我们使用vertical-align
样式来控制。vertical-align
的各关键字的含义如下:
top
将元素行内框的顶端与包含该行内框的元素的行框的顶端对齐
bottom
将元素行内框的底商与包含该行内框的元素的行框的底端对齐
text-top
将元素行内框的顶端与父元素内容区的顶端对齐
text-bottom
将元素行内框的底端与父元素内容区的底端对齐
middle
将元素行内框的垂直中点与父元素基线上0.5ex
处的一点对齐
super
将元素的内容区和行内框上移。上移的距离因浏览器的不同而各不相同。
sub
将元素的内容区和行内框下移。下移的距离因浏览器的不同而各不相同。
vertical-align
的百分数计算值是相对于元素的line-height
来计算的。
管理行高
首先,大家需要记住一点:line-height
相对于元素本身的font-size
设置,而不是相对于父元素设置。在使用百分比或em
等进行line-height
的设置时,需要牢记这一点。
不知大家是否还记得,之前已经提过,非替换元素的内边距、边框和外边距对行内元素或其生成的框不会影响行框的高度,也就是说,如果为行内元素设置了边框,且边框较宽,则容易导致不同行之间产生元素的覆盖。这时就需要使用line-height来解决这个问题。
在设置line-height
,并且想让子元素继承line-height
的设置时,最好是设置一个原始数据。如line-height:1.5
。这样,在子元素继承此值之后,也会基于此值来计算出相对于子元素的字体大小的正确行高。
上例中我们只是将span
的字体大小设置为28px
,如果使用更大的值(如50px
),你会发现在父元素的line-height
设置为1.5em
时,各行之间发生了重叠。而当line-height
设置为1.5
时,无论字体如何设置,由于子元素继承的是缩放因子,而非计算值,所以总是能得到正确的行高。
行内替换元素
一般认为行内替换元素有固有的高度和宽度,有固有高度的替换元素可能导致行框比正常要高。这不会改变行中任何元素的line-height
值,包括替换元素本身。它只是会让行框的高度恰如能包含替换元素及其所有框属性。换句话说,会用替换元素整体(内容、外边距、边框和内边距)来定义元素的行内框。
需要注意的是,不同于非替换元素,替换元素的边距和边框会影响行框的高度,因为它们要作为行内替换元素的行内框的一部分。
默认地,行内替换元素位于基线上,在对行内替换元素进行垂直布局的时候需要注意这一点。
改变元素显示
我们可以使用display
样式来改变元素的角色。如将行内元素显示为块元素。但是需要注意的是,我们使用display
改变的只是元素的显示角色,但是并不改变其本质。也就是说,即便是使用display
将行内元素显示为块级元素,但是此行内元素本质上还是行内元素,因上并不会改变一些约定人俗成的东西。如“行内元素可能是一个块元素的后代,但是反过来却不行”。
这里,我们将inline-block
单独拿出来讲一下。什么叫“inline-block”?即行内块元素。对于该元素的理解,可以将其理解为嵌在行中的替换元素。它的底端默认位于文本行的基线上。如果行内块元素的width
未定义,或者显式声明为auto
,则元素框会收缩以适应内容。