Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting

这一章主要讲解下CSS在渲染的时候的理论原理。没人或书籍能够覆盖到css的所有细节,所以在我们日常使用中遇到css的问题的时候,了解CSS的渲染逻辑将有效帮助大家排查问题。


基本的盒模型

CSS的基本思想就是假定每个元素都是由1个或多个盒子组成的,称为element boxes。在每个box的中间有一块内容区域(content area),而包围内容区域的就是像padding, border, outline和margin的各种可选边框,之所以说是可选的因为所有这些边框的默认宽度都是0,如下图所示:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第1张图片
7-1.png

像padding,border和margin都有各自的设置选项,但outline就没有了。另外内容的背景也只应用与padding内部,margins都设置为透明的,这样可以让所有父元素的背景都看的见。padding是不准有负数的,但margin却可以,在后面咱们会详细讨论。

我们先从border开始,border类型包括solid和inset(inset就是内嵌的意思,看起来效果像凹槽)。border的颜色通过border-color设置,如果没有被设置的话,那就默认采用前景色(foreground color,不清楚么,如果说元素内容的颜色是不是清楚了),最后要记住border的宽度是不准设置负值的。

快览

首先我们来解释下后面要用到的几个重要的概念:

  1. Normal flow:正常的流
    这个指的是文本默认的渲染顺序,一般语言都是一样的:从左到右,从上到下。而在某些特殊的语言中会有所不同,而咱们HTML语言其实也是遵循这一规则的,既然前面说过每个元素都是box,所以正常的流的意思就是,元素的box默认以这种顺序排列。那怎么样才能跳出这种normal flow呢?方法也有很多,可以设置为float, position, 或是flexible box 和grid layout。

  2. Nonreplaced element: 无法替代的元素
    这主要指那种内容放在document的元素,举个例子,

    就是一个无法替代的元素,因为其文本内容就在元素自己当中。

  3. Replaced element: 可替代元素
    和上面相反,这里的元素是可以替换的,例如img元素,他其实就是指向一张图片;同样,大部分的表单元素也都是可替换的。

  4. Root element: 根元素
    这个我们很熟悉了,就是document文档树的根节点,像咱们常用HTML文档,其根节点就是html;而在XML文档中,根节点可以任意指定,例如RSS文件的根节点就是rss。

  5. Block box
    block的盒子它就像积木一样是纵向堆叠的,常用的有段落p,标题h1~6,和最常用的div。想要生成block盒子的元素可以通过声明display:block来实现。

  6. Inline box
    跟block相对的就是inline box, 常见的inline类型有strong和span等。如果想要变成inline box 只要声明display:inline就好。

  7. Inline-block box
    这个box在内部表现的像block,而在外部表现的像inline。就是有点像可替换元素。

除了以上的这几种盒子,其实还有像table-ce的其他盒子,由于各种原因就不一一细说了。

containing block

对于CSS的盒子来说,父元素的box是很重要的,类似于编程的继承,子元素也会继承父元素的框架上下文(layout context)。在CSS中定义了一系列的规则来确定盒子的containing block。

来看个具体的例子:

 
  

This is a paragraph.

p的containing box就是div,而div的就是body。而这个body因为是第一个元素被称为初始的containing box,之所以这么特殊,单独命名因为视口viewport决定了该元素的布局大小,而不是由根元素的内容大小决定的。


调整element显示display

在css中应该是最重要的一个属性了:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第2张图片
t7-1.png
Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第3张图片
t7-2.png

改变默认的显示方式


nav默认谁inline的布局,如果我们想要改变他的显示方式,可以这样设置:

nav a {display: block;}

这会使所有的a元素都以block的元素来呈现。


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第4张图片
t7-2.png

下面再考虑另一种情况,就是把block的元素改变从inline的

  • Bob C.
  • Marcio G.
  • Eric M.
  • Kat M.
  • Tristan N.
  • Arun R.
  • Doron R.
  • Susie W.
#rollcall li {display: inline; border-right: 1px solid; padding: 0 0.33em;} 
#rollcall li:first-child {border-left: 1px solid;}
7-3.png

虽然大部分时候都可以这样来操作,但是h5本身是有限制的,即block元素包含inline元素可以,但是inline元素中包含block是不允许的,尤其是对于某些默认的inline和block元素,来看个例子:


  

this is wrong!

上面的强行转换其实是没用的,display只能改变元素的展示,而不乏改变元素的类型,所以有些跟类型强绑定的属性是无法通过display来修改的。
接下面我们就来看看不同的box:包括block box, inline box, inline-block box 和list-item box。

Block box

block 盒子其实用的是最多的布局元素,但有时候其显示会超出你的预期,这就需要对该盒子的某些边界有清楚的了解,来看看下面这张图:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第5张图片
7-4.png

默认来说,block box的宽度设置的是left inner edge 到right inner edge的距离,height同理。

不过我们可以通过设置box-sizing属性来修改这一规则:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第6张图片
t7-3.png

这个属性就是用来设置widht和height的定义规则的,默认的上面说了,如果设置为border-box,那么其宽度的界定将基于左右border边界的距离,同理可知padding-box的含义。


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第7张图片
7-5.png

box-sizing水平的变化

通过改变box-sizing会导致水平方向计算的变化,来看个例子:

wideness?

Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第8张图片
7-6.png

水平方向的属性

共有7个属性决定水平的长度:margin-left, border-left, padding-left, width, padding-right, border-right 和 margin-right。具体参照下图:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第9张图片
7-9.png

之前有提到过的一个containing block的概念,其宽度就是这7中长度的和。而在这7个值里面,只有三个是默认设置为auto的,那三个呢?左右的margin和width,其余的值都需要设置数值,有些的默认值为0.


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第10张图片
7-10.png

而width只能出现2中情况,auto和非负的数值。

使用auto

auto的意思就是自动调整,调整的目标就是子元素的整个长度等于父元素的宽度。

那有人就问啦,如果三个auto都设置了具体值,那怎么计算呢?这在CSS中有个专有名词overcontrained,意思就是限制过多了,那么css就用将margin-right强制设置为auto。

div {width: 500px;}
p {margin-left: 100px; margin-right: 100px;
width: 100px;} /* right margin forced to be 300px */
Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第11张图片
7-11.png

如果左右margin都设置了,但width为auto,那么width就承担起自动填充的任务:

p {margin-left: 100px; margin-right: 100px; width: auto;}

多个auto的情况

比如margin都设置为auto,那么左右都会设置相同的长度,来看个例子:

div {width: 500px;}
p {width: 300px; margin-left: auto; margin-right: auto;}
        /* each margin is 100 pixels wide, because (500-300)/2 = 100 */
Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第12张图片
7-13.png

所以很多想要居中的内容都是讲margin设置为auto来实现的。

最后一种情况就是三个都设置为auto,那么margin就会都被设置为0,width会尽量填充父元素宽度。

负的margin

来看个例子:

div {width: 500px; border: 3px solid black;}
p.wide {margin-left: 10px; width: auto; margin-right: -50px; }
Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第13张图片
7-16.png

看起来已经超出了父元素的范围,但在数学上还是对的:

10px+0+0+540px+0+0−50px = 500px

还记得之前说的auto么,在这里,我们同样可以通过设置auto来抵消子元素的边界超出问题:

div {width: 500px; border: 3px solid black;}
p.wide {margin-left: 10px; width: 600px; margin-right: auto;
border: 3px solid gray;}

对应的公式如下:

10px+3px+0+600px+0+3px−116px = 500px

记住padding, border 和width是不能有负数的。

百分比

有时候百分比还是很有用的,尤其是在动态确定宽度比例的情况下:

playing percentages

不过如果要混合使用百分比和具体数值的话会让人很困惑:

mixed lengths

值的注意的是border是不接受百分比值的。

可替换元素

对于图片元素这种可替换元素来说,如果width指定为auto,那么元素的width将会是元素内容的实际宽度:


当然我们应该设置图片的实际宽度:

 
 


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第14张图片
7-18.png

垂直方向的格式化

刚说完水平的,下来来看看垂直高度的几个有趣的地方。首先是一个元素的内容决定了元素的默认高度,同时内容的宽度也会影响高度。那就会出现两个问题,自己设置的高度高于内容高度,自己设置的高度低于内容高度。对于前者,会保留正常的空白;而对于后者,则依赖于另一个属性overflow:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第15张图片
7-19.png

垂直方向属性

对照水平方向,也是有7个属性:margin-top, border-top, padding-top, height, padding-bottom, border-bottom, and margin-bottom.


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第16张图片
7-20.png

跟水平一样,垂直方向的auto也是这三个:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第17张图片
7-21.png

auto的触发规则与水平方向是一样的。

百分比高度

Half as tall

其中p的高度就是3em。由于top和bottom的margin如果设置为auto都会被强制设置为0,因此想要垂直居中的方式就是各设置为25%。但万一父元素的高度没有设置,那么这个百分比高度就会被重置为auto:

NOT half as tall; height reset to auto

Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第18张图片
7-22.png

垂直方向margin的合并

合并(可能翻译不太准确,英文为collapsing), 只会发生在margin中,而不会在padding和border中。
举个例子:

li {margin-top: 10px; margin-bottom: 15px;}

在一串li中设置每个的上下margin间距,一般是不是都会以为每个li的间距应该是25px,而实际上结果却是15px。这是因为发生了合并,在两个相邻的margin中会选取其中大的那个。


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第19张图片
7-24.png

再来看个例子:

ul {margin-bottom: 15px;}
li {margin-top: 10px; margin-bottom: 20px;} 
h1 {margin-top: 28px;}

从上面可知,这次li和h1的实际间隔其实是28px


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第20张图片
7-25.png

负的margin和合并collapsing

Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第21张图片
7-27.png

来看另一个例子:

p.neg {margin-top: -50px; margin-right: 10px; margin-left: 10px; margin-bottom: 0; border: 3px solid gray;}

A paragraph.

A div.
Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第22张图片
7-28.png

再来看个margin为负的例子:

p.neg {margin-bottom: -50px; margin-right: 10px; margin-left: 10px; margin-top: 0;
border: 3px solid gray;}

A paragraph.

7-29.png

List Item

我们常用的list item本身其实是有不少特殊的显示规则的,比如marker,圆点和数字,而且这些都不在内容区域中,所以上面所说的一系列css规则在他们身上也是通用的:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第23张图片
7-31.png

内联元素

介绍完了block元素就可以来看看inline元素了,常见的有em和a标签,这两个都是不可替代的,而像image则是可替代的元素。注意我们后面讨论的内容不适用于table元素,在CSS2中引入了很多新的属性和行为来出来表单元素的显示,而这远远超过了本书的范围。

可替换和不可替换的元素在inline模式下CSS的处理是有所区别的。

Line Layout 线框

首先我们要确定的就是inline的内容是怎么放的,因为这不像block元素那么简单的创建个block 盒子,而且其他元素是不能共存在同一块区域的。那人们自然会很好奇,inline元素在block元素中是如何展示及修改样式的。

为了了解线是怎么生成的,首先来看下单行长文本的情况,如下图所示:

span {border: 1px dashed black;}
7-33.png

我们给span元素设置了一个简单的虚线边框。

基本概念

在我们进一步深入之前,让我们来回顾下线框中用到的基本概念:

  • 匿名文本:
    这个主要指的是没有包含在inline元素里面的内容,比如

I'm so happy!

其中的i'm happy!就是匿名文本,注意空格也算是字符。

  • Em box
    这是在给定字体中定义的,或者称为字符box。在CSS中期em box的高度由font-size来定义。

  • leading
    leading其实是font-size和line-height的差。一般来说,这个差值将会一分为二,均匀分布在内容区域的top和bottom部分。leading只会应用在不可替换的元素上面。

inline 不可替换元素

接下来我们就来一步步 看下inline元素的创建过程,首先引入的是font-size的大小来决定内容区域的高度。如果一个元素的font-size为15px的话,那么内容区域的高度就是15px,如下图所示:

Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第24张图片
7-36.png

接下来需要考虑的就是元素的行高,同时注意与font-size的高度差。如果元素的font-size=15px而line-height=21px那么这个差就是6px,接下来浏览器会将这6px均分到上下两部分,如下图所示:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第25张图片
7-37.png

让我们假定下面是没问题的:

This is text, some of which is emphasized, plus other text
which is strongly emphasized and which is
larger than the surrounding text.

可以看到,大多数文本的字体大小为12px,而strong的行高为24px,但由于行高是继承的,所以strong继承的行高为12px。对于strong来说line-height与font-size的差为-12px,所以上下都有-6px的分配,所以strong所代表的inline box是要小于内容区域的,最后的效果如下图所示。


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第26张图片
7-38.png
Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第27张图片
7-39.png

从上图看出,中间那行会比其他两行高,但却没有完全包裹全部的文本内容。

垂直对齐

如果我们改变inline box的垂直对齐方式,高度计算的原理还是一样的:

This is text, some of which is emphasized, plus other text
which is strongly emphasized and that is
larger than the surrounding text.

上面的变化同时抬升了storng元素的内容区域和inline box,因为strong元素决定这inline box的上边界,因此这一改变会同时抬升inline box的上边界:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第28张图片
7-40.png

让我们考虑另一种情况:

This is text, some of which is emphasized,
plus other text that is strong and tall and is
larger than the surrounding text.

Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第29张图片
7-41.png

虽然样式跟之前是一样的,但又没有发现tall文本的高度对齐到了inline box的上边界。因为tall的文本具有相同的fontsize和line-height。
再来看下:

This is text, some of which is emphasized,
plus other text that is strong and tall and is
larger than the surrounding text.

由于tall文本的行高小鱼font-size,tall文本的inline box小鱼内容其余,这一小小的改变改变了tall文本的高度:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第30张图片
7-42.png

再来看看设置tall行高高于font-size的情况:

This is text, some of which is emphasized, plus other text
that is strong and tall and that is
larger than the surrounding text.

最后结合本章内容总结下vertical-align的关键词:

  • top:对齐元素inline box的上边界
  • bottom: 对齐元素inline box的下边界
  • text-top: 对齐父元素文本上边界
  • text-bottom: 对齐父元素文本下边界
  • middle: 对齐元素inline box的垂直中点
  • super: 上移内容区域和inline box,具体依赖浏览器实现
  • sub:跟super一样,下移内容
  • <百分比>:基于line-height的百分比来移动

管理行高

为了防止重叠,我们建议使用em单位:

p {line-height: 1em;}
big {font-size: 250%; line-height: 1em;}

Not only does this paragraph have "normal" text, but it also
contains a line in which some big text is found.
This large text helps illustrate our point.

通过设置big的行高,我们增大了对应inline box,而且不用改变所有行的行高。同时1em正好对应字体的大小:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第31张图片
7-43.png

设置行高的比例因子

最好的设置行高的方式就是设置纯数字,可以被所有的元素所继承:

body {line-height: 1.5;}
p {font-size: 15px; line-height: 1.5;} small {font-size: 66%;}
big {font-size: 200%;}

This paragraph has a line-height of 1.5 times its font-size. In addition, any elements within it such as this small element also haveline-heights 1.5 times their font-size...and that includes this big element right here. By using a scaling factor, line-heights scale to match the font-size of any element.

p {font-size: 15px; line-height: 1.5;} small {font-size: 66%;}
big {font-size: 200%; line-height: 1em;}
Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第32张图片
7-45.png

添加box 属性

想看看为inline 元素添加border的效果么:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第33张图片
7-46.png

inline元素的border属性其实是由font-size控制的,而不是line-height。 换句话说,如果一个span元素的font-size为12px然后行高为36px,那么其实际的内容区域的高度还是12px。但是border还是会包裹在inline元素周围的.
接下来来看看padding属性,padding的添加并不会改变内容的高度

span {padding: 4px;}
Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第34张图片
7-47.png

改变breaking 行为

在上一节,我们看到了一个inline不可替代元素跨行显示的例子,它本身其实是单行的文本,每个字符被单独的box包围,行末被单独分割。这种默认的行为可以通过box-decoration-break来修改:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第35张图片
t7-4.png

就两个值:slice和clone。slice就是之前的默认值。而对于clone,其主要特定为将每个片段都作为独立得box,那这个独立是什么意思呢?来看个例子:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第36张图片
7-50.png

发现在下方的clone选项里面,背景图案不依赖文本独立克隆了背景信息。box-decoration-break属性虽然大多用在inline box中,不过其实它适用于任何的存在break的元素中。

inline 可替换元素

说到可替换元素,直接想到的就是img了。如下图所示:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第37张图片
7-51.png
p {font-size: 15px; line-height: 18px;}
img {height: 30px; margin: 0; padding: 0; border: none;}

可替换元素最大的特点就是就有自己的固有高度和宽度,而这是会影响布局的,在inline 元素中嵌入img,那么整行的line box就会被img的高度给撑开(假如img固有高度大于line-height)。上图中,由于图片没有margin,padding,border,因此inline box的高度就等于img的content 高度,也就是30px。

p {font-size: 15px; line-height: 18px;} 
img {vertical-align: 50%;}

the image in this sentence test image will be raised 9 pixels.

替代元素和baseline

从上面的讨论中可以明白inline的可替换元素默认情况下是沿着baseline来排布的。如果元素有底部的padding,margin或是border的话,那么内容区域也会相应的抬升。而由于替代元素自己是没有baseline的,所以对齐的就是inline box的baseline:

Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第38张图片
7-54.png

inline-block 元素

inline-block是在CSS2.1引入的聚合属性,融合了inline和block。那这个inline-block到底是什么意思呢?其核心就表现为对外显示inline属性,就像image一样,而对内则表现出block属性,可以设置相应的width和height属性。让我们来看个具体的例子:

This text is the content of a block-level level element. Within this block-level element is another block-level element.

Look, it's a block-level paragraph.

Here's the rest of the DIV, which is still block-level.
This text is the content of a block-level level element. Within this block-level element is an inline element.

Look, it's an inline paragraph.

Here's the rest of the DIV, which is still block-level.
This text is the content of a block-level level element. Within this block-level element is an inline-block element.

Look, it's an inline-block paragraph.

Here's the rest of the DIV, which is still block-level.

然后在上面的三个div分别应用下面的样式:

div {margin: 1em 0; border: 1px solid;}
p {border: 1px dotted;}
div#one p {display: block; width: 6em; text-align: center;}
div#two p {display: inline; width: 6em; text-align: center;} div#three p {display: inline-block; width: 6em; text-align: center;}
Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第39张图片
7-56.png

再举个具体的使用例子,比如在导航栏中有5个链接,一边想要他们inline显示,而同时要设置他们的宽度为父元素的20%,name就可以使用inline-block来设置:

nav a {display: inline-block; width: 20%;}

Flow 显示

flow和flow-root的属性还是值得一说的。其实CSS的显示分为两个类型:外部类型和内部类型。像之前说的inline,block都是控制外部类型显示的,而flow就表示内部元素的排列方式。
display:flow默认会同时绑定block和inline的外部框架,如果没有定义inline,name就以block形式展示:

#first {display: flow;} 
#second {display: block flow;} 
#third {display: inline flow;}

上面的例子中first和second显示结果为block,而third则表现为inline box。
所以一般在display后面的参数中,第一个表示外部类型,而第二个表示内部类型。比如:display: inline table。含义就是在外面以inline形式表示,而对内则生成一个table的上下文。

说完了flow,下面看看flow-root,这个值和flow不一样,默认就是block类型的。这个值一般是针对root 元素的,一般就是html。

最后来看下display 新老值得对应关系:

老的值 新的值
block block flow
inline inline flow
inline-block inline flow-root
list-item list-item inline flow
table block table
inline-table inline table
flex block flex
inline-flex inline flex
grid block grid
inline-grid inline grid

内容显示

另一个新增的display值就是contents,这个值的用处试讲元素从页面格式中去除。来看个例子:

ul {border: 1px solid red;} 
li {border: 1px solid silver;}

  • The first list item.
  • List Item II: The Listening.
  • List item the third.

上面的例子会渲染一个带红色白框的ul list,而如果我们在ul上加上display:contents,name浏览器在渲染的时候就会像忽略外框的ul一样,如图所示:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第40张图片
7-58.png

其他的display值

在本章中我们其实还有很多display的值没有被覆盖到,大多数都是跟ruby相关的值,直到2018年底也没得到很好的支持。

计算得出的值

如果元素设置为float或是position,那么计算出的display值也可能发生变化。事实上,display,position和float这三个值是有制约关系的。
如果一个元素的position设置为absolute,那么float就被自动设为none。而对于浮动和绝对定位的元素,其计算值由下表给出:


Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting_第41张图片
t7-2.png

小结

虽然CSS的format模型在有些地方是反直觉的,但随着使用的深入会慢慢理解它们。block元素是比较好理解的,而inline元素相比较就会显得比较麻烦。

你可能感兴趣的:(Css权威指南(4th,第四版中文翻译)-7.基本的Visual Formatting)