2020版w3c css specifications全解

1,016 阅读1小时+

这是前言

这可能是你见过的最全的一篇讲原生css的文章了

并推荐一篇讲原生css以外知识的文章,两个搭配可以包含我们需要的绝大部分css内容。

关于css的参考资料,我们能查到的资料里,要么讲奇淫技巧、华而不实,要么讲某几个热门知识点,要么已经过时很多年了,甚至很多同学还把css3作为新技术或者不知道css到底包括什么。

鉴于此,本文的目的是将css完整的呈现给大家,会从css的规范w3c specifications(相当于js的ecma262)说起,讲

  • css到底是什么
  • css规范的制定流程
  • 最新浏览器应实现的规范有哪些
  • 最新的规范包括哪些内容

因为相关内容很多,不可能在这两万字中全部讲清楚,建议搭配文中相关链接规范原文食用。

另,本文为第一版,后期会对其中的内容进行补充和订正,对其中存在的问题欢迎指出,并会及时修改。


正文开始

css specs是W3C为用户代理(比如浏览器)厂商等编写的实现规范,直接的目标用户并不是一般前端开发者,因此很多内容对于我们是无意义且难以理解的。
但其包括对css最系统最原始的描述,如果进行进一步解读会对深入理解css有比较大的帮助,也可以获取最新发布的css功能,这就是这篇文章的目的,如果对其感兴趣想对其深入阅读可以参考How to Read W3C Specs

什么是css

css,即层叠样式表(cascading style sheets)是一个style sheet语言,可以使开发者和用户为结构化文档(比如html或xml)添加样式(比如字体)。通过将文档的样式和文档内容分开可以简化页面开发。

关于css我们最近几年听过最多的就是css3,那么css3是什么呢?css的整个标准化流程是什么呢?下面介绍规范相关的一些背景知识

Level

css没有传统意义上版本的说法,在这里被称为level,css3即是css level 3。
每个level的css都建立在前一个level之上,改进了定义并添加了特性。高level的特性是低level的超集,因此用户代理(比如浏览器)只要符合高level的也就符合所有低level。

level 1

CSS1 specification 已经过时,其涉及到特性被level 2包含在内。

level 2

旧的 CSS2 specification 是w3c的推荐版本,但是后来发现了很多错误,因此又推出了修订版本1- CSS 2.1 specification,以及修订版本2- CSS 2.2 specification ,它们都对前一个版本中存在的问题做了订正。

level 3及以上

css2使用了9年(2002-2011)才到了Recommendation状态,主要原因是一些次要的特性影响了整个规范的进程推进,为了加快没有问题特性的标准化进程,根据Beijing doctrine的决定,将css分成了更小的组件,即modules,这些modules的每一个都独立的向前发展。

此即人们常说的css3,它是css2以后各模块的统称,官方并没有css3对应的版本,其中基于css2向后发展的模块将会有独立的level,比如Selectors Level 3,之前的规范中没有的新特性则作为新的level 1发布,比如Flexible box layout module level 1

Finding the latest state of CSS

用户代理开发商都需要知道当前哪些特性应该被实现,哪些不应该被实现,这个问题可参考从2007年开始w3c公布的snapshots,当前最新的snapshots是CSS Snapshot 2018

值得注意的是,即使某个特性已经称为标准,也不一定被所有用户代理实现,这一点我们作为css的使用者要明白,这也是css出现兼容性问题的原因。

Document statuses

前面介绍的module和snapshot都是document,为了表示这些文档的稳定性,w3c引入了以下状态:

1. Working Draft (WD)

WD在规范起草过程中发布,用来向w3c和公众征求意见,经常是不稳定且不完整的。

2. Candidate Recommendation (CR)

通过发布CR来表示该规范已经完整,并解决了已知的问题,供各厂商实现并接受实践的检验。

3. Proposed Recommendation (PR)

从CR到PR,规范需要一个全面的测试和实现报告以证明每个特性至少在两个发布实现中实现了客户操作性,w3c成员需要进行最后一次review。

4. Recommendation (REC)

这是最后一个阶段,成为标准,这时候不会再改了。但是后面可能会推出勘误或者修订版本,并可能会被新的标准取代。

注意

这些状态的流转并不是线性的,比如即使进了CR,也可能因为遇到问题而退回到WD阶段,因此CSS Snapshot不一定包括所有CR:工作组知道有些CR需要被修订。

本文会涉及到css的哪些规范

本文会参考最新版Snapshot(这也是用户代理厂商在进行实现时参考的版本,更接近我们实际的开发环境),即CSS Snapshot 2018,对当前我们正在使用的css作较全面的解读。顺序大致对应css2.2的章节顺序(其中包括css2.2的内容以及后面对应的单独模块,并且会省略对于前端开发者用处不大的章节),在snapshot 2018中出现但没在css2.2中的模块以在snapshot出现的顺序为准,具体为(标黑的为重点):

  1. 值与单位,包括CSS Values and Units Level 3(取代了CSS2§4.3)。

  2. 选择器和各种选择器的specificity,包括Selectors Level 3 (取代了CSS2§5 and CSS2§6.4.3)。

  3. 层叠和继承,包括CSS Cascading and Inheritance Level 3(取代了CSS2§1.4.3 and CSS2§6)

  4. 媒体类型,包括CSS2§7.1CSS Conditional Rules Level 3(取代了CSS2§7.2)、Media Queries Level 3(取代了CSS2§7.3)

  5. 盒子模型和视觉格式化模型,包括CSS2§8(不包括CSS2§8.5)、CSS2§9、CSS2§10以及CSS Backgrounds and Borders Level 3中取代CSS2§8.5的部分。

  6. 视觉效果,包括CSS2§11

  7. 生成内容、自动编号和列表,包括CSS2§12

  8. 颜色和背景,包括CSS Color Level 3(取代了CSS2§4.3.6, CSS2§14.1, and CSS2§18.2),CSS Backgrounds and Borders Level 3中取代CSS2§14.2的部分。

  9. 字体,包括CSS Fonts Level 3(取代了CSS2§15)。

  10. 文本,包括CSS2§16

  11. 表格,包括CSS2§17(这里暂不展开)

  12. ui,包括CSS User Interface Module Level 3(取代了CSS2§18.1 and CSS2§18.4,另外CSS2§18.2在颜色与背景一节中讲述)。 以下为css2中没有定义的特性

  13. 样式属性,包括CSS Style Attributes

  14. namespace,包括CSS Namespaces

  15. 图像和可替换内容,包括CSS Image Values and Replaced Content Level 3

  16. 多列布局,包括CSS Multi-column Layout Level 1

  17. 组合和混合,包括CSS Compositing and Blending Level 1

  18. 书写模式,包括CSS Writing Modes Level 3

  19. 弹性盒模型,包括CSS Flexible Box Module Level 1

  20. 变量,包括CSS Custom Properties for Cascading Variables Module Level 1

  21. 变换,包括CSS Transforms Level 1 以下规范虽然细节没有完成,但已经被浏览器广泛实现

  22. 过渡,包括CSS Transitions Level 1

  23. 动画,包括 CSS Animations Level 1

  24. 网格布局,包括CSS Grid Layout Module Level 1

  25. 文本,包括CSS Text Module Level 3

  26. will-change属性,包括CSS Will Change Level 1

  27. 过滤效果,包括Filter Effects Module Level 1

另外两个虽然不在以上范围但是有必要提及的,只做概述,不详细展开。

  1. cssom,包括CSSOM View Module
  2. css object,包括CSS Object Model

下面对以上提及的规范和对应知识点一一解读。

值与单位

这里讲作为属性值的单位和函数符号,规范中关于值的部分主要用于读懂规范其他部分,可以参考Understanding The CSS Property Value Syntax,这里不赘述。

单位

  • 长度单位
    • 相对长度
      • 相对对应元素字体的长度,如果在元素以外的上下文使用,比如在媒体查询,这些单位就会对应font属性的initial值,作为元素的font-size属性值使用时对应父元素的font-size或initial。
        • em 当前元素font-size属性计算值的倍数
        • ex 当前元素x的高度
        • ch 当前元素数字0的高度或宽度,一般是0的宽度,即0.5em
        • rem 根元素(在html文档中是html元素)font-size属性的计算值
      • 相对视口的长度,视口是指包含文档的一个窗口
        • vw 视口宽度的1%
        • vh 视口高度的1%
        • vmin vw和vh高度较小的一个
        • vmax vw和vh高度较大的一个
    • 绝对长度,分为视角单位和物理单位两种,前者用于屏幕媒介,包括px,后者用于打印媒介,包括除px以外的其他绝对长度,这里只介绍一个in,其他请点击
      • in inches,1in = 2.54cm = 96px
      • px pixels px和其他物理单位在css1中的单位换算并不是固定的,物理单位以实际测量为准,而px会不断变化以匹配reference pixel。而现在很多已存在的内容都是基于96pdi的假设,如果修改这种假设会破坏那些内容,因此就将两种单位换算固定下来了。也正是因为这样,在一个实际的设备上,两者的换算并不一定符合这种比例。
        其中reference pixel指的是一个96dpi的设备的1px距离一胳膊的距离时的视角,一个胳膊长度通常71cm,这个视角也就是大约0.0213度。因此当距离为1胳膊时1px为为1/96 inch,其他距离时1px对应其他长度。

        另外一个px单位并不一定等于一设备像素,在高分辨率的设备上一px单位可能是由多个设备象速组成的。
  • 角度
    1. deg(degrees,度),360度为一圈
    2. grad(Gradians,梯度),400梯度为一圈
    3. rad(Radians,弧度),2π弧度为一圈
    4. turn,1trun为1圈
  • 时间
    1. s 秒
    2. ms 毫秒
  • 频率
    1. Hz 赫兹
    2. kHz 千赫兹
  • 分辨率
    • dpi,Dots per inch,每英寸的物理像素数
    • dpcm,Dots per centimeter
    • dppx,Dots per px. 相当于dpr

函数表达式

就是用一个函数返回的值,这里只介绍两种,其他请参考CSS Functional Notation-mdn

  • calc() 数学表达式,可以对各种带单位的数值进行加减乘除运算,其中+-符号两侧要有空格,*/不要求。比如width: calc(100% - 80px);
  • attr() 获取元素的属性用于css样式中,目前只支持在content上用,比如
p:before {
    content:attr(data-foo) " ";
}
<p data-foo="hello">world</p>

选择器与specificity

选择器selector是一种在tree中匹配元素的模式,可以用于在文档中选择节点。

简单选择器

类型选择器

  • E 一个类型为E的元素 通用选择器
  • * 匹配任何元素

属性选择器

  • [foo] 一个有foo属性的元素
  • [foo="bar"] 属性foo等于bar的元素
  • [foo~="bar"] includes,属性foo的值列表中包括bar
  • [foo^="bar"] prefixMatch 属性foo包含bar的前缀
  • [foo$="bar"] suffixMatch 属性foo包含bar的后缀
  • [foo*="bar"] substring 属性foo包含bar子串
  • [foo|="en"] dashMatch 属性是en或以en-为前缀 类选择器
  • .warning class属性是warning的元素
    id选择器
  • #myid id属性是myid的元素

伪类(pseudo-class)是添加到一个选择器上的关键字,用来指定元素的特定状态,由冒号(:)+伪类名组成。

  • 动态伪类
    • 用来区分链接是否访问过
      • :link 没被访问过
      • :visited 被访问过
    • 表示用户动作
      • :hover
      • :active 一个元素被激活,比如被点击时
      • :focus
  • target伪类 :target 点击锚点表示的链接时匹配到的元素(锚点匹配对应id)
  • 语言伪类 :lang() 选择lang属性为对应参数的元素
  • 可用性伪类
    • :enabled
    • :disabled
  • 结构化伪类,其中的序号从1开始
    • :root 文档的根元素
    • :nth-child(n) 第几n子元素,其中的参数可以是
      • 关键字odd(单数)、even(双数)
      • 表达式An+B,A表示整数步长,B表示偏移,n是自然数,表示第An+B个元素
    • :nth-last-child(n) 倒数第n个子元素
    • :nth-of-type(n) 第n个对应选择器类型的元素
    • :nth-last-of-type(n)
    • :first-child 等效于:nth-child(1)
    • :last-child 等效于:nth-last-child(1)
    • :first-of-type 等效于:nth-of-type(1)
    • :last-of-type 等效于 :nth-last-of-type(1)
    • :only-child 等效于:first-child:last-child
    • :only-of-type 等效于:first-of-type:last-of-type
    • :empty 一个元素没有内容
    • :not() 参数是另一个选择器,表示非

伪元素(pseudo-element )也是添加到一个选择器后面,用来指定选择元素的一部分,由两个冒号(::)+伪元素名组成。

组合

  • E F 后代
  • E > F 子元素
  • 相邻元素
    • E + F 下一个
    • E ~ F 之后的所有对应同级元素

计算specificity

一个选择器的优先级按如下计算:

  • 把id选择器记为a
  • class选择器、属性选择器和伪类选择器记为b
  • 类型选择器和伪元素选择器记为c

将对应的选择器加起来,按照a-b-c的顺序组成一个数,最大的选择器组合优先级最高,比如

*               /* a=0 b=0 c=0 -> specificity =   0 */
LI              /* a=0 b=0 c=1 -> specificity =   1 */
UL LI           /* a=0 b=0 c=2 -> specificity =   2 */
UL OL+LI        /* a=0 b=0 c=3 -> specificity =   3 */
H1 + *[REL=up]  /* a=0 b=1 c=1 -> specificity =  11 */
UL OL LI.red    /* a=0 b=1 c=3 -> specificity =  13 */
LI.red.level    /* a=0 b=2 c=1 -> specificity =  21 */
#x34y           /* a=1 b=0 c=0 -> specificity = 100 */
#s12:not(FOO)   /* a=1 b=0 c=1 -> specificity = 101 */

注意style属性中的样式优先级最高

层叠与继承

Cascading and Inheritance,Cascading是多个样式表同时作用于一个文档的展示。当不同的声明作用于同一元素或组合时,这个冲突需要解决。
相反的,如果一个元素或组合没有设置属性值则需要找继承或者初始值。
cascading和defaulting过程会处理一系列声明输入,为每个元素的每个属性输出一个specified value。
本模块就是描述怎么通过cascading和inheritance处理所有的样式规则,为每个元素的所有属性赋值的。

引入样式表

语法,其中样式表url可以是url()形式,也可以是直接的url字面量,media-query-list指媒体查询

@import [ <url> | <string> ] <media-query-list>? ;

样式表的Content-Type

对引入的样式表的处理取决于链接资源的实际类型,如果这个资源没有Content-Type metadata或者host文档是quick模式并且和引入的样式表是同源,则该资源的类型就是text/css,否则就从Content-Type metadata中读取。
如果资源的类型是text/css,则会被解释为css样式文档,否则会被解释为网络错误。

重置所有属性

可以利用all属性重置除了direction and unicode-bidi以外的非自定义属性,这个属性只接受CSS-wide keywords(即initial, inherit and unset)。
比如在一个元素上设置all:initial,将会阻止所有继承值,使用初始值。

值的处理

一旦用户代理将文档解析成文档树。必须为树中的每个元素每个盒子(盒子的概念参考后文的盒模型)的每个属性赋予一个对应媒体类型的值。一个元素或盒子最后的值要经过以下步骤的计算(其中涉及到的名词在本模块后面部分有介绍):

  1. 首先收集一个元素对应的所有declared values,对应元素上的每个属性都可能有0或多个declared values。
  2. 通过Cascading生成 cascaded value,每个元素的每个属性最多有一个 cascaded value。
  3. 通过Defaulting生成 specified value,每个元素的每个属性有且仅有一个specified value。
  4. 解析值得依赖关系生成 computed value,每个元素得每个属性有且仅有一个 computed value。
  5. 格式化文档生成used value,如果一个属性应用到元素才会有一个used value。
  6. 最后used value基于展示环境得限制被转化为 actual value,和used value一样,一个元素的给定属性可能有actual value,也可能没有。

1. declared values

每个应用到元素的属性声明都会贡献一个declared values

2. Cascaded Values

Cascaded Values是cascade得结果,在所有的declared values中生成一个优先级最高的值。

3. Specified Values

将Cascaded Values通过defaulting处理,来保证每个元素的每个属性都有一个Specified Values。
大多数情况,Specified Values是Cascaded Values,但是如果根本没有Cascaded Values,Specified Values就是defaulted(见Defaulting)。

4. Computed Values

是解析specified value得结果,通常是绝对化一个值用于继承,比如将em转化为px.

5. Used Values

使用Computed Values做进一步得计算获取绝对值,如果这个属性没有应用到元素上,这个元素就没有used value。
比如在不知道祖先元素布局的情况下无法将width:auto计算出确切长度,因此omputed Values仍然为auto,在这里可以进一步计算。
比如flex属性用在不是flex item得元素上则没有sed Values。

6. Actual Values

一个used value原则上已经可以使用了,但是用户代理在给定环境可能不能用used value,比如边框的宽度只能是整数像素,因此需要做调整。

7. 例如

Filtering

为了找到所有的declared values,首先需要确定所有应用到每个元素的声明。一个声明应用到一个元素,如果

  • 它属于应用到当前文档的样式表
  • 符合conditional rule
  • 属于选择器匹配到的样式,当浏览器解析选择器时顺序从右到左,参考Why Browsers Read Selectors Right to Left
  • 是一个语法上的有效声明

这个过程对每个元素的每个属性生成一个declared values列表,供cascade排序,可能为空。

Cascading

cascade将一个declared values列表排序,生成一个单一的cascaded value.

按照以下规则排序,优先级降序

Origin and Importance

origin是样式的来源,有以下五种

  • Author Origin:前端开发者指定的样式
  • User Origin:用户代理使用者指定的样式
  • User-Agent Origin:用户代理默认的样式
  • Animation Origin:执行css动画生成的效果
  • Transition Origin:执行css过渡生成的效果 importance是声明带有!important,比如[hidden] { display: none !important; }

具体顺序为

  1. Transition declarations
  2. Important user agent declarations
  3. Important user declarations
  4. Important author declarations
  5. Animation declarations
  6. Normal author declarations
  7. Normal user declarations
  8. Normal user agent declarations

Specificity

优先级,见前面选择器部分。

Order of Appearance

出现顺序,后面出现的胜出

Defaulting

当cascade没有产生一个值时,specified value要想其他办法来生成,比如继承值和初始值。

Initial Values

每个属性都有一个初始值,如果该属性不是可继承的并且没有cascaded value,则specified value就是initial value。
一个属性的具体初始值去看相关属性在规范中的定义

Inheritance

继承值从父元素传递到子元素,元素继承的是父元素上属性的computed value。对于没有父元素的root元素,其属性的继承值就是初始值。

显式Defaulting

所有的属性都可以接受这些值

重置一个属性,initial关键字

如果一个属性的cascaded value是initial,则其specified value就是它的initial value

继承,inherit关键字

如果一个属性的cascaded value是inherit,则specified and computed values 都是inherit value

去除所有声明,unset关键字

如果一个属性的cascaded value是unset,如果是一个可继承属性,则其为inherit,否则就是initial

媒体类型

介绍

样式表的一个最重要的特性就是可以在不同media中分别指定展示方式。
某些css只能应用于某些media,或者同一属性在不同media中取不同的值。
媒体类型包括‘embossed’ ,‘speech’, ‘braille’, ‘handheld’, ‘print’, ‘projection’, ‘screen’, ‘tty’, ‘tv’,另外可以用all表示所有媒体类型。

Media Queries

在当前可以对媒体类型应用特定样式的基础上,媒体查询使用更多精确的标签对其进行了扩展,比如可以通过判断设备尺寸来应用对应样式。
一个媒体查询包括一个媒体类型和多个条件表达式判断相关媒体的特征。比如

<link rel="stylesheet" media="print and (min-width: 25cm)" href="http://…" />
@media handheld and (min-width: 20em), 
  screen and (min-width: 20em) { … }

媒体特性置于小括号内,不同条件之间用逻辑操作符连接。

逻辑操作符

用于组合复杂的媒体查询,当使用not 或 only时媒体类型是必选的

  • and 组合多个媒体特性到一个媒体查询,每个都返回true整体才返回true
  • not 对整个媒体查询取反
  • ,(逗号),相当于or
  • only 用于防止不支持媒体查询功能的旧版浏览器应用其类型,如果不用only旧版浏览器会把媒体特性部分忽略。

媒体特性

包括width、height,具体请参考media

Conditional Rules

添加了类似于@media的另一个条件组规则,用来查询浏览器对相关规范的支持情况。由一组样式声明和支持条件构成,支持条件由一条或多条由逻辑操作符连接构成。
逻辑操作符包括and、or、not。比如以下表示如果display:grid有效,则使用后面的样式声明

@supports (display: grid) {
  div {
    display: grid;
  }
}

盒子模型和视觉格式化模型

这一节我认为是css中最核心的部分,描述了用户代理怎么处理每个元素和文档树。

盒模型

盒模型(box model)描述了文档树中每个元素生成的矩形盒子,这个盒子会根据视觉格式化模型进行布局。

盒子尺寸

每个盒子有一个内容区域,以及可选的padding,border和margin,如图,四种edge围起来的区域又分别称为content box,padding box,border box,margin box。
注意对于行内元素(除可替换元素)上下margin无效,上下border和padding虽然存在,但是不占用空间,其占用空间由line-height决定(参考box model:mdn)。

margin属性

用来指定盒子的margin,其中margin-top和margin-bottom对非替换行内元素无效。Collapsing margins在本部分最后讲。

border属性

border分别包括border-color,border-style,border-width三个子属性 border可以是一个预定义的样式(none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset),也可以是图片(通过border-image)。

border-radius

圆角,有四个子属性border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius.

border-image

可以用一个图片替换border-style,如果该属性设为none或无法显式,则使用border-style.注意在border-image后面添加border属性会重写border-image属性。 其包含五个子属性border-image-source, border-image-slice, border-image-width, border-image-outset and border-image-repeat,具体用法参考border-image:mdn

padding属性

指定padding区域的宽度

box-shadow

用于在box的周围添加阴影,包含X轴偏移量(右为正)、Y轴偏移量(下为正)、模糊半径(默认0)、扩散半径(默认0)和颜色、inset(内嵌)。其中两个半径和inset可以省略。

视觉格式化模型

介绍

视觉格式化模型(visual formatting model)用来描述用户代理怎么处理文档树。
在这个模型中,文档树中的每个元素都会根据box model生成0或多个boxs。这些盒子的布局由以下条件控制:

  • box尺寸和类型
  • 定位方案(normal flow, float, and absolute positioning)
  • 文档树中元素之间的关系
  • 外部信息(比如viewport size,图片的内在尺寸等)

注意该模型并没有格式化所有方面,比如没指定字母间距的算法,各种浏览器的实现也会有所不同。

viewport

用户代理为用户提供了一个viewport(一个窗口或者屏幕上的其他可视化区域),用户可以通过它查阅文档。当viewport改变时用户代理也会改变文档的布局。

Containing blocks

在css2.2中,很多盒子的位置和尺寸都是相对于一个矩形盒子的边缘计算的,这个矩形盒子就被称为容器块(containing block)。
每一个盒子都相对于容器块有个位置,但并不限于这个包含块,它可能会overflow。 容器块的识别过程如下

  1. 根元素所在的容器块叫最初容器块(initial containing block),对于屏幕媒体就是指的viewport,后者的direction属性和根元素一样。
  2. 对于其他元素,如果一个元素的position是relative或static,它的容器盒子是最近的建立一个fc的块容器。
  3. 如果一个元素的position是fixed,容器盒和根元素的一样
  4. 如果一个元素的position是absolute,容器盒按照以下方法被最近的position为'absolute', 'relative' or 'fixed'的祖先生成
    1. 如果这个祖先是一个行内元素,如果这个元素没被拆分成多行,那就是padding box,否则就是undefined
    2. 否则容器盒是这个元素的padding box。 如果没有这么一个祖先,包含盒子就是最初容器盒子。

盒子的类型

display属性描述了一个盒子的类型,该属性的某些值会导致元素生成一个主盒(principal box ),其包含子盒及生成的内容,也是在各种布局方案中涉及到盒子。由一些元素除了主盒还会生成另外的盒子,比如list-item,这些另外的盒子相对于主盒放置。

Block-level elements and block boxes

块级元素(Block-level elements)生成一个块级主盒,display属性的值中可以使一个元素变成块级的值包括'block', 'list-item', and 'table。
块级盒子(Block-level boxes)就是那些参与bfc的盒子。
在css2.2,一个块级盒子(除了table box或者可替换元素的主盒)也是一个块容器盒(block container box),这个块容器盒要么只包含块级盒子要么建立一个ifc从而只包含行级盒子。
一个元素的主盒是一个块级容器盒的话就是一个块级容器元素(block container element)。display的值'block', 'list-item' and 'inline-block'可以使非可替换元素称为块容器盒子。
并不是所有的块容器盒子都是块级盒子:非可替换行内块和非可替换table cell都是块容器但不是块级。
即是块级盒子,又是块容器的称为块盒子(block boxes)。
当没有异议的情况下,"block-level box," "block container box," and "block box"都简称块(block). 如果一个块容器中含有块级盒子,那么为了使它只有块级盒子,如果块级盒子两边有内容会生成匿名块盒子。

Inline-level elements and inline boxes

行内级元素(Inline-level elements)是那些不会形成内容块得的元素,其内容会按行分配。display的'inline', 'inline-table', and 'inline-block'值可以使一个元素变成行内级。
行内级元素生成行内级盒子(inline-level boxes),行内级盒子参与ifc。
行内盒子(inline box)是那些即是行内级盒子,其内容又参与其包含的ifc,一个display属性为inline的非替换元素生成一个行内盒。
那些不是行内盒(可替换的行内级元素,行内块元素和inline-table元素)的行内级盒子被称为原子行内级盒(atomic inline-level boxes),因为它们作为一个单独的不透明盒(不会被分成多行拆成多个盒子)参与它们的ifc.

如果一个块容器中只有文本和行内盒子,就会把块容器中没在行内盒子的文本放在匿名行内盒子中。

行内元素的高度和宽度无效,上下margin无效;当取值百分数时计算结果是容器块长度的百分比。

display属性

确定盒子的类型,在css2.2中的可选值为 inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | none | inherit
后面其他模块还会介绍其他值。

Positioning schemes

在css2.2有三种定位方案:

  • normal flow 包含bfc中的块级盒子,ifc中的行内级盒子以及相对定位的块级和行内级盒子
  • float 在浮动模型中,一个盒子首先根据normal flow布局,然后尽可能脱离文档流向左或向右移动。内容可能沿着一侧浮动。
  • absolute positioning,在绝对定位模型中,一个盒子完全脱离normal flow,根据containing block进行布局。

如果一个元素是浮动的、绝对定位或者是root元素,则被称为脱离文档流(out of flow ,或叫流外),否则称为在文档流(in flow,或叫流内),元素A的文档流(flow of an element A)是一系列包含a和所有其最近的流外元素是a的流内元素的合集。

position属性

用来选择定位方案,position和float属性决定怎么计算一个盒子的位置,可选值 static | relative | absolute | fixed | inherit,初始值static

  • static 这个盒子是一个normal box,根据normal flow定位,'top', 'right', 'bottom', and 'left'属性没用
  • relative 相对于normal flow定位,会相对现在的位置进行偏移(offset)
  • absolute 盒子的位置(可能还有尺寸)由'top', 'right', 'bottom', and 'left'根据其容器盒子确定。
  • fixed 根据absolute模型定位,即在屏幕媒体上根据viewport定位,不会随滚动条移动。
盒子偏移'top', 'right', 'bottom', 'left'

如果一个盒子的postion不是static,则根据四个偏移属性定位,

normal flow

normal flow中的盒子都属于一个格式化上下文(fc),在css2.2中有三种fc,其中块级盒子参与bfc,行内级盒子参与ifc,table fc将在table一节中描述。

bfc

下面几种盒子可以为它们的内容生成新的BFC(block formatting contexts)

  • Floats elements
  • absolutely positioned elements,即position属性为'absolute' or 'fixed'
  • 非块盒的块容器盒(比如inline-blocks, table-cells, and table-captions,相关概念参考上面盒子的类型
  • overflow属性不是visible的块盒(除非这个值已经传递到viewport)

在一个bfc中,盒子从上到下依次沿容器盒摆放,上下两个盒子的距离决定于margin属性,在一个bfc中两个块级盒子的垂直margin会折叠

ifc

一个不包含块级盒子的块容器盒子创建一个ifc(inline formatting context),在一个ifc中盒子从容器盒嘴上面一个接一个平行放置,这些盒子在垂直方向可能以不同方式对齐。
包含这些盒子形成的一行组成的矩形叫做行盒(line box),它的宽度决定于容器盒盒浮动情况,它的高度决定于line-height。一个行盒总是足够高以包含所有其中的盒子,甚至比最高的还高(比如因为对齐方式引起的)。当其中一个盒子低于行高时,它的垂直方向对齐方式取决于vertical-align属性。当多个行内级盒子不能水平装进一个行盒时,它们将被分到两个或多个垂直的行盒,因此一个段落可能是一个垂直的行盒堆叠,除非特别指定,堆叠的行盒之间垂直方向不会分开,也不会重叠。
当行内盒的总长度小于包含它们的行框时,行盒内的水平分布取决于text-align属性。当一个行内盒超过行盒的宽度时会被分到多个行盒,如果一个行内盒不能拆分(比如含有一个单词),行内盒就会溢出行盒

相对定位

一旦一个盒子根据normal flow定位或者浮动,它就会相对这个位置移动,这被称为相对定位(position属性为relative),移动相对定位的元素对其周围的元素无影响。

浮动

浮动是一个盒子移动到当前行的左或者右,其中的内容可能会向另一侧流动,或者通过clear属性使内容避免流向一侧(注意clear属性只应用于块级元素)。
一个流动的盒子会一直往左或右偏移,一直到容器盒子边缘或者遇到另一个浮动元素的边缘。如果那里是一个行盒会和其顶端对齐。如果没有充足的水平空间,它就会下降直到空间充足或者没有其他浮动元素。
由于浮动没在流内,因此没有定位的块盒会在其前后垂直排列,就像浮动元素不存在一样,但是当前和后面的行框会变短以给浮动元素留空间,如果变得太短不能放任何东西就会下移直到适合某些内容或者没有浮动元素。
在同一个bfc下,浮动元素的margin box不能和以下元素border box重叠

  • table
  • 块级可替换元素
  • 在normal flow中建立一个新bfc的元素
    在具体的实现中,浮动元素旁边如果有足够的空间,它们可以被放置在旁边,但是比常规计算结果要窄。
float属性

这个属性指定一个盒子浮动情况,除了绝对定位的元素,其他盒子都可以设置浮动,可以取值 left | right | none | inherit

clear属性,控制浮动旁边的流

这个属性指示一个盒子的哪一侧不能与一个之前的浮动元素相邻。仅适用于块级元素,这个属性不能处理这个元素内部或者其他bfc中的浮动。可取值none | left | right | both | inherit
除了none以外都可以引入clearance,后者可以避免margin collapsing,比如下图box1和box2是非浮动元素,右侧有个浮动元素,当给box2设置clear:right时,box2会向下移动,此时便可能会引入clearance,当然这个clearance根据实际情况可能为0或者负数,具体参考Clearance as a barrier to margin collapse(右侧注释部分)

绝对定位

在一个绝对定位(position属性为'absolute' or 'fixed')模型里, 一个盒子会相对于它的容器盒显式偏移,完全脱离文档流。一个绝对定位的盒子会为流内和绝对定位(除了fixed)的后代盒子建立新的容器盒子。 fixed定位是绝对定位的子集,唯一区别是其容器盒子是viewport。

'display', 'position', and 'float'之间的关系

这三个盒子都会影响一个盒子的生成和布局,具体关系如下

  1. 如果display为none,position和float不会应用,不会生成盒子
  2. 否则,如果position为fixed或absolute,盒子会绝对定位,float的计算值为none,display被设置成对应的盒子,盒子的位置被 'top', 'right', 'bottom' and 'left' 的值和盒子的容器盒子决定。
  3. 否则,如果浮动不是none,盒子会浮动并生成对应盒子
  4. 否则,如果元素是root元素,则被设置成对应盒子,否则就是undefined。
  5. 否则,display设置成指定的值

分层显示

利用z-index属性为已定位的元素指定层级。
在css2.2,每个盒子都是三维的,除了水平和垂直还有个z轴,这部分就是讲一个盒子怎么沿z轴定位。

渲染树绘制到画布的顺序根据层叠上下文的描述确定,层叠上下文可以包含另外的层叠上下文,从父层叠上下文的角度看,其子层叠上下文是原子性的,
每个盒子都属于一个层叠上下文,每个定位后的元素都有一个整数(可以是负的)的层级,这个层级是在同一个层叠上下文的z轴的相对位置,数越大越靠前。

在每个层叠上下文中,以后到前的顺序是

  1. 元素的背景和border生成了这个层叠上下文
  2. 负层级的子层叠上下文
  3. 流内、非行内级且没定位的后代
  4. 没定位的浮动元素
  5. 流内、行内级且没定位的后代,包含行内表格和行内块
  6. 0层级的子层叠上下文和0层级的定位后的后代
  7. 正的子层叠上下文

这个绘制顺序会在每个层叠上下文递归处理,具体顺序见附录E

文本方向

directionunicode-bidi属性,共同决定文本渲染方向,具体可以点击查看,这里不赘述。

line-height和vertical-align

行内级盒会被会被分成多个垂直堆叠的行盒,行盒的高度按以下步骤计算: 1.计算行盒内的各种行级盒子的高度,其中可替换元素、inline-block和inline-table按margin-box,行内盒子按line-height。
2. 行级盒子根据vertical-align属性垂直排列,当沿top或bottom排列时,它必须对齐来最小化行盒的高度。css2.2并没有定义行盒baseline的位置(即strut的位置) 3. 行盒的高度就是盒子最高点到最低点的距离。

css假设每种字体都有font metrics来指定基线以上的特征高度和基线以下的深度,下面我们把特征高度称为A,深度称为D,AD为A+D,即top到bottom的距离。
在一个非可替换行内盒中,用户代理必须将基线将字形对齐。注意单个元素中的字形可能是不同字体,因此需要有相同的A和D.如果行内盒子不包含字形,它将包含一个带有A和D的strut(一个零宽度的不可见字形)。
每个字形还要添加leading L(可以是负的),其中L=line-height-AD,一半的leading被添加到A上面,另一半添加到D下面。
行内框的高度包含所有字形和它们的leading,准确的说是line-height。其子元素的盒子不会影响这个高度。
尽管非替换元素的margin,border和padding不被算到行盒的高度计算中,仍然会渲染到行盒周围,这意味着如果指定的line-height少于内容的容器盒高度,背景言和和padding,border的颜色会被混入旁边的行盒(注意因为绘制顺序造成的影响)。

line-height
当取值百分数时参考的是元素的font-size
在一个内容是行内级元素的块容器元素中,line-height指的是该元素内部行盒的最小高度,这个最小高度包含基线下面的最小高度和基线上面的最小高度,就像每个行框都以一个带有零宽字体的行内盒开始,我们将这个想象的盒子为strut。
基线上下的高度和深度被认为是包含在字体的metrics中。
在一个非可替换行内元素,line-height用于指定计算其行盒的高度。
当一个元素以多于一种字体字体渲染,用户代理可能以最大的字体决定normal和line-height的值。

vertical-align
应用于行内级元素和table-cell元素,当取值为百分数时参考元素本身的line-height,初始值为baseline。
这个属性影响在一个行盒中行内级元素的垂直位置。
其中的值分两类,其中一类只相对于父行内元素或者父块容器元素的strut有效。在这些定义中,对于行内非可替换元素,用于对齐的盒子是高度为line-height的盒子(包含盒子的字形和两端的一半leading);对于其他元素,用于对齐的是margin box。

  • baseline 将这个盒子的基线与父盒子的基线对齐,如果这个盒子没有baseline,将它的下margin和父元素的基线对齐。
  • middle 将盒子的垂直中点和父元素基线+x高度的一半对齐 另外还有sub,super,text-top,text-bottom,<percentage>和<length>

第二种值是将元素相对于行盒对齐,因为这个元素可能有子元素相对于它对齐(子元素的子元素也类似),这些值使用对齐子树的边界进行对齐,包括行盒的上top和下bottom。
inline-block元素的基线是normal flow中最后一个行盒的基线,除非没有流内行盒或者overflow属性的计算值不是visible,这时基线是下margin的边界。

更多请参考Vertical-Align: All You Need To Know

Collapsing margins

在css中,两个或多个盒子的相邻margin可以合并为一个margin,margin被合并的方式称为折叠(collapse),折叠的结果被称为折叠后的margin(collapsed margin)。其中margin只在垂直方向折叠。

注意一个折叠后的margin和其他margin相邻,则可以认为折叠后margin的成员也和其他margin相邻。

为什么折叠

关于这个问题在css1的Section 4.1.1提过,即通过折叠垂直方向的margin可以视觉上更好,且更符合设计的预期。在css1发布时的1996年,网站大部分主要是一块块文本,如果不存在margin折叠,以下文档会不齐

  • headings, with margin: 10px
  • paragraphs, with margin: 5px
  • figures, with margin: 10px 我们知道了原因后,就会理解margin折叠的其他特性的初衷。

例外

相邻的垂直margin会折叠,除非

  • root元素的margin不会折叠
  • 如果一个带有clearance的元素上margin或下margin相邻(即两个margin中间没有其他东西隔着,比如border),它会和下面相邻的元素margin折叠,但是折叠后的margin不会和父块的下margin折叠。
  • 如果一个元素的top margin和最后一个流内子元素的下margin折叠,一旦该元素的min-height的计算值不为0或height为auto,则这个元素的下margin不会和刚才的子元素的下margin折叠。

折叠的条件

两个margin折叠当且仅当

  • 两个元素都属于同一个bfc中的流内块级盒子
  • 没有行盒,没有clearance,没有padding,没有border将它们分开
  • 两个都属于垂直相邻的盒子,比如以下的情况
    • 一个盒子的上margin和第一个流内子元素的上margin
    • 一个盒子的下margin和下一个流内的相邻元素的上margin
    • 一个margin为auto的元素的下margin和流内最后一个子元素的下margin
    • 一个没有建立起新的bfc的盒子的上margin和下margin,并且这个盒子有一个min-height的0计算值,或height为auto或没有流内元素

当两个或多个margin折叠时,最终的margin宽度是折叠的margin中最大的一个;如果是有负margin则是最大正margin减去最大负margin绝对值的宽度;如果没有正的margin则从0中减去绝对值最大的margin。

如果一个盒子的上和下margin相邻,margin可能会collapse through这个盒子,这时候这个元素的位置取决于和其他margin正在折叠盒子的关系

  • 如果这个元素的margin和父元素的上margin折叠,这个盒子和父元素公用一个border
  • 否则,要么父元素不参与margin折叠,要么只有下margin参与,元素的上border的位置和元素的下border非零时的位置相同
    注意collapsed through的元素位置对于其他边框折叠的盒子位置没有任何影响。

其中的细节注释请参考Annotated CSS Spec:Collapsing margins

视觉效果

溢出和剪切

通常来说,一个块盒子的内容受限于盒子的内容边界,有时候一个盒子可能会溢出,这意味着它的内容或部分或全部在盒子外面。比如

  • 一行不能被断,造成行盒比块盒宽
  • 块级盒子对于容器块太宽(或太高),比如设置一个超过容器块的宽度(高度)
  • 后代定位绝对定位
  • 后代盒有负margin
  • text-indent属性造成行内盒溢出 当溢出发生时,overflow属性指定一个盒子是不是被padding edge剪切,如果是则会提供一个滚动机制来查看被剪切的内容。

overflow属性

应用于块容器或建立bfc的盒子,可选 visible | hidden | scroll | auto | inherit,默认visible.
即使overflow是visible,内容也可能被用户代理的文档窗口剪切。
ua一定要把root元素的overflow属性应用到viewport,如果root元素的对应值是visible,则将body元素的overflow属性值应用到viewport。如果应用到viewport的值是visible则会翻译成auto,被应用到viewport的元素overflow属性的used value为visible。

clip属性
剪切区域定义了一个元素border box的哪一部分可见,默认元素不被剪切,但是可以被clip属性指定
应用于绝对定位的元素,可取值 | auto | inherit,初始值auto.
对于shape,在css2.2唯一有效的是rect(, , , )用来指定一个矩形。

visibility属性
用来指定盒子是否渲染,不可见的盒子仍然会会影响布局,可选值visible | hidden | collapse | inherit,默认visible

生成内容、自动编号和列表

有时候我们想让用户代理不是来自document tree的内容,比如数字列表。在css2.2内容会以两种机制生成

  • content属性,用伪元素:before and :after
  • 使用display的list-item属性

content

用于:before and :after 伪元素用于生成内容,可选值

  • none 不生成伪元素
  • normal 计算成none
  • 文本内容
  • 外部资源比如图片,如果用户代理不能显式这些东西,则需要当作未指定或者提示加载失败
  • 可以指定两种不同的函数:counter() 或 counters()。前面一个有两种形式:counter(name) 或 counter(name,style) 。产生的内容是该伪类元素指定名称的最小范围的计数;格式由style指定(默认是'decimal'——十进制数字)。后一个函数同样也有两种形式:counters(name,string) 或 counters(name,string,style) 。
  • attr(X) 将元素的X属性以字符串形式返回。如果该元素没有 X 属性,则返回一个空字符串。
  • open-quote | close-quote 这些值会被quotes属性中定义的字符串替换。
  • no-open-quote and no-close-quote 不引入内容只是添加引号

quotes

指定引号的样式,可取值[<string> <string>]+ | none | inherit,其中 [ ]+指一组或者多组 的值对应 open-quote and close-quote. 第一对表示引号的外层,第二对表示第一个嵌套层,下一对表示第三层,依此类推。 比如

   .ask {
        quotes: '提问: "' '"';
      }
      .answer {
        quotes: '回答: "' '"';
      }

自动计数和编号

css2.2中的自动编号受两个属性控制, 'counter-increment' and 'counter-reset'(可取值均为 [ ? ]+ | none | inherit)。计算器被这些属性定义并且用于content属性中的counter() and counters()函数 其中counter-reset用于创建或重定义计数器,后面的整数是当前的数 counter-increment表示递增哪个计算器和增幅
比如Section 1"、"1.1"、"1.2这种编号

列表

一个元素display属性为list-item时会为内容生成一个主块盒,另外还会根据list-style生成一个标记盒用来表示列表。实现的效果为修改li或ol元素前面的标记。具体使用参考list-style.

颜色和背景

color

initial值依赖用户代理,用于设置文本内容的前景色,另外还为值currentColor设置颜色,如果设置值为currentColor,则相当于设置initial。
注意opacity属性可用作后置操作,即将元素和后代渲染成离屏图像后指定怎么将其和当前的合成渲染混合。可选值为alpha值([0,1]区间的数字),表示透明度。

可选的颜色包括

基本颜色关键字

包括aqua, black, blue, fuchsia, gray, green, lime, maroon, navy, olive, purple, red, silver, teal, white, and yellow

数值颜色

  • rgb值,可以表示为
em { color: #f00 }              /* #rgb */
em { color: #ff0000 }           /* #rrggbb */
em { color: rgb(255,0,0) }
em { color: rgb(100%, 0%, 0%) }
  • rgba值,在rga的基础上添加alpha参数
em { color: rgb(255,0,0) }      /* integer range 0 - 255 */
em { color: rgba(255,0,0,1)     /* the same, with explicit opacity of 1 */
em { color: rgb(100%,0%,0%) }   /* float range 0.0% - 100.0% */
em { color: rgba(100%,0%,0%,1) } /* the same, with explicit opacity of 1 */
  • transparent 关键字,表示完全透明,等效于rgba(0,0,0,0)
  • HSL值,css3添加了hue-saturation-lightness (HSL) 值,因为rgb值是面向硬件的且非直觉的。hsl将颜色分为色相、饱和度和亮度,具体算法参考HSL cylindrical-coordinate .
  • HSLA,在hsl基础上添加了alpha。

扩展后的关键字

其他关键字表示的颜色,参考svg-color

currentColor 关键字

表示color属性的值

系统颜色

在css2中由一些系统颜色,比如桌面背景的颜色(Background),在css3中已废弃。

background

每个盒子都有一个背景层,默认完全透明,也可以填充一个颜色或者一个或多个图片。 在css3中一个盒子可以有多个背景层,层数决定于background-image用逗号分隔的值,即使是none也会产生一层,设置的第一层离读者最近
每个图片的尺寸、位置和平铺方式都由其他对应属性决定,也是各自用逗号分隔 改属性是个简称,语法为

<bg-layer> = <bg-image> || <bg-position> [ / <bg-size> ]? || <repeat-style> || <attachment> || <box> || <box>

<final-bg-layer> =  <‘background-color’> || <bg-image> || <bg-position> [ / <bg-size> ]? || <repeat-style> || <attachment> || <box> || <box>

其中最后一层必须有背景颜色,其他具体含义见下面

background-color

设置背景颜色,会在所有背景图片下面。

background-image

即<bg-image> ,设置背景图片,当设置背景图片后也应该设置背景颜色避免背景图片不可用。如果图片不可见,用户代理应该优化成不下载和绘制。

background-position

即<bg-position> ,如果背景图片被指定,这个属性指定指定它们的初始位置,用两个值分别表示水平位置和垂直距离,如果只有一个值则第二个默认为center。当为百分数时,计算方式如75% 50%表示


当为绝对值时则表示偏移量。

background-size

即<bg-size> ,定义背景图片的尺寸,可取值[ | auto ]{1,2} | cover | contain,分别表示

  • [ | auto ]{1,2} 两个值时表示宽高,如果一个值另一个表示auto。百分比指的是相对于background positioning的区域;当有一个auto时,使用内在比例和另一个指定的尺寸计算而得,失败的话用图片内在尺寸,再失败的话用100%;当有两个auto时,则用内在尺寸,失败的话作为contain处理。不可以为负值。
  • contain 按内在比例伸缩图片,使宽高最大的一边和background position对齐
  • cover 按内在比例伸缩图片,使宽高最小的一边和background position对齐

background-repeat

即<repeat-style>,在背景图片sized and positioned后指定重复方法(水平和垂直方向),可以用repeat-x表示repeat no-repeat,repeat-y表示no-repeat repeat,其他使用一个值表示时供两个方向复用。
具体语法为repeat-x | repeat-y | [repeat | space | round | no-repeat]{1,2}

background-attachment

即<attachment>,表示背景图片的按照什么固定,可取值scroll(滚动条) | fixed(viewport) | local(内容)

background-origin

即<box>,规定相对于什么定位,可选值为border-box|padding-box|content-box

background-clip

第二个<box>,规定绘制区域,如果没有设置则使用background-origin的值。

特殊元素的背景

文档的画布是一个用于文档渲染的无限大的界面,因为没有元素对应,所以css把body元素的background传播到了画布上。

字体

字体提供了字符用来可视化表示的资源,在最简单的水平上,它包含了字符编码到形状(被称为字形glyphs)的映射。共享一个通用设计风格的字体被分类成各种font families。在一个family中,一个给定字符的形状可以根据其他性质(比如weight)变化。
一个独立的font face(face可以被翻译成外观)被一个独特的属性组合描述。对一段文本,css font属性用于选择一个font family并指定其中的一个font face来渲染。比如为了使用bold样式的Helvetica,可以用

body {
    font-family: Helvetica;
    font-weight: bold;
}

字体资源可以使用在本地安装的也可以使用可下载的。font families通常不会为每个可能的属性变体提供一个单独的face,css字体选择机制描述了怎么样匹配一系列css字体属性到一个单一的font face。

基本字体属性

一个元素上指定的font-family和其他属性决定了渲染哪种font face。

font-family

定义一个font family names或者 generic family names的优先级列表。可选值为[ | ] #,初始值依赖用户代理实现。其中family-name指的一个font family的name,比如Helvetica or Verdana。generic-family指的是以下关键字:serif, sans-serif, cursive, fantasy, and monospace,用来当指定的字体不可用时作为一个通用的回退机制,开发者应该在后面添加。

具体使用时font family中如果带有空格、数字或连字符以外的标点需要带引号,和关键字相同的也要带引号。generic family names使用的都是关键字不用带引号。

上面介绍的五种generic family分别是

  • serif 衬线字体,笔画结尾有特殊的装饰线或衬线
  • sans-serif 无衬线字体,即笔画结尾是平滑的字体
  • monospace 等宽字体,即字体中每个字宽度相同
  • cursive 草书字体。这种字体有的有连笔,有的还有特殊的斜体效果
  • fantasy 主要是那些具有特殊艺术效果的字体

font-weight

指定字形的weight,即黑度或粗细的程序,可选值 normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900。
对于有些字体只有很少的weight可用,当指定的weight没有对应face,就会选择一个接近的。

font-stretch

从一个font family中选择一个normal,condensed或者expanded的face,可取值normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded,对应的拉伸程度

效果

font-style

用来选择 italic or oblique的face,前者本质上是cursive,后者是正常字体的人为倾斜。

font-size

指示字体的字形高度,百分比参考的是父元素的字号

font-size-adjust

调整当前字体小写字母相对于大写字母(即当前字号)的比例

font

简写语法为 [ [ <‘font-style’> || || <‘font-weight’> || <‘font-stretch’> ]? <‘font-size’> [ / <‘line-height’> ]? <‘font-family’> ]
其中<font-variant-css21>是[normal | small-caps],在css2中使用,css3中定义的font-variant不能用于简写。

font-synthesis

设置是否允许浏览器合成bold或oblique的font face

字体资源

@font-face规则

用于链接一个需要时可以下载和激活的字体,这使得我们可以选择一个接近设计目标的字体,而不是限制在平台的可用字体列表中。用font-family指定字体名字,用src指定下载路径,用unicode-range指定支持Unicode字符的范围,用font-feature-settings(后面会介绍)指定初始设置,用 font-style, font-weight, font-stretch指定其他属性。
比如

@font-face {
  font-family: "Open Sans";
  src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2"),
       url("/fonts/OpenSans-Regular-webfont.woff") format("woff");
}

字体加载指南

@font-face 被设置成懒加载

字体获取需求

对于字体加载,用户代理必须使用fetch规范中定义的potentially CORS-enabled fetch method,当下载字体时,用户代理需要使用匿名模式,将referrer source设置为样式表的url,将 origin 设置为包含文档的url。这使得除非字体响应中设置了允许跨域,否则不能使用跨域加载。

字体匹配算法

参考Font Matching Algorithm,这里暂不展开

字体特性属性

现代字体的技术支持很多新功能,为了使我们控制这些功能,css3将font-variant扩展使用,包括

  • font-kerning 控制字形之间的距离
  • font-variant-ligatures 控制连字特征
  • font-variant-position 用来作为作为上标(super)或下标(sub)
  • font-variant-caps 控制大写字母特殊字符的使用
  • font-variant-numeric 控制数字的显示
  • font-variant-east-asian 控制东亚字形

以上属性的简称为font-variant 另外可以通过font-feature-settings控制OpenType字体中的高级印刷功能,是偏底层的接口,一般不推荐。

文本

这部分的属性会影响字符、空格、单词和段落的视觉展示。

text-indent

用在块容器中指定第一行文本的缩进,可取值<length> | <percentage> | inherit

text-align

用在块容器描述行内级内容怎么水平方向对齐,可取值left | right | center | justify | inherit

text-decoration

用来修饰文本外观,可取值none | [ underline || overline || line-through || blink ] | inherit

letter-spacing

字母间距,可取值normal | <length> | inherit

word-spacing

单词间距,可取值normal | <length> | inherit

text-transform

控制大小写,可取值capitalize | uppercase | lowercase | none | inherit

white-space

声明元素中的空格怎么处理,可取值normal | pre | nowrap | pre-wrap | pre-line | inherit,不同属性的区别是

用户界面

box-sizing

指定一个元素的width或height怎么计算,根据box modal,一个元素的width和height应用于content box,这里可以设置为 content-box | border-box,默认content-box

outline属性

outline很像border,有两个区别

  • 不占据空间
  • 可以是非矩形
  • 用户代理经常在:focus状态渲染outline

是 outline-style, outline-width 和 outline-color的简写
另外可以使用outline-offset设置outline与border边框的距离

resize

用来设置是否允许用户调整元素的大小,可取值none | both | horizontal | vertical,用于overflow不是visible得元素

text-overflow

适用于块包含盒,用于指定行内内容溢出时怎么显示,搭配white-space: pre;overflow: hidden;等属性产生溢出后才能生效,可取值clip | ellipsis,分别表示隐藏和三个点

cursor

用来指定光标类型,可选项及其效果参考cursor

caret-color

指定插入光标的颜色,可选值auto |

样式属性

有些文档格式有style属性,允许我们直接在特定元素上应用样式,这个属性接受css作为它的值,用法如下

<p style="color: #090; line-height: 1.2">...</p>

在层叠中,这些样式的优先级比选择器指定的要高。

namespace

使用@namespace处理命名空间,具体可参考@namespace

图像和可替换内容

本部分在用url()表示图像的基础上添加了其他方式,比如gradient,另外还定义了一些关于可替换元素的属性。

gradient

渐变是一个图片,其从一个颜色平滑渐变到另一个颜色,包括linear-gradient 线性渐变、radial-gradient 径向渐变等。具体使用参考Using CSS gradients

图像尺寸和css中的对象

css中的对象包括图片(git等二进制、svg、渐变等)、video及嵌入的文档(这些都是可替换元素)等,这些对象本身会提供一些尺寸信息,最终的布局会结合指定的样式和这些自身的样式得出最终结果,默认的算法参考default Sizing Algorithm
另外还提供了手动影响算法的属性

object-fit

指定可替换元素的内容怎么和它的height/width建立的盒子相适应。可取值

  • fill 默认,不保证比例,充满
  • contain 保持原有尺寸比例。内容被缩放。
  • cover 保持原有尺寸比例。但部分内容可能被剪切。
  • none 保留原有元素内容的长度和宽度,也就是说内容不会被重置。
  • scale-down 保持原有尺寸比例。内容的尺寸与 none 或 contain 中的一个相同,取决于它们两个之间谁得到的对象尺寸会更小一些。

object-position

规定了可替换元素在其它所处的盒子中的对齐,其值可以参考background-position.

image-orientation

修改图片的方向,

image-rendering

设置图片缩放算法

多列布局

这里介绍一种布局方式,将内容分为多列,可以避免一行内容过长,相关概念和使用参考CSS多列布局

组合和混合

这里分为两部分,一部分是合成属性,第二部分是Porter Duff(这是两个人名,即Alpha compositing)合成和混合的算法,这部分暂不讨论。

相关属性

mix-blend-mode

定义了颜色和背景混合时的公式,可取值为normal | multiply | screen | overlay | darken | lighten | color-dodge | color-burn | hard-light | soft-light | difference | exclusion | hue | saturation | color | luminosity

isolation

定义该元素是否必须创建一个新的层叠上下文(stacking context).
该属性的主要作用是当和background-blend-mode属性一起使用时,可以只混合一个指定元素栈的背景:它允许使一组元素从它们后面的背景中独立出来,只混合这组元素的背景。
可取值为auto | isolate

书写模式

这里定义了一系列书写模式,包括从右到左,垂直书写等,使用较少,仅参考不展开

弹性盒模型

现在很常用的布局。参考弹性盒布局

变量

大的文档和应用包含很多css,其中的很多值是重复数据,比如一个网站会重复使用三到四个颜色,不易维护。
这里引入了一系列开发者自己定义的属性集合作为自定义属性,然后通过var()函数用来引用

:root {
  --main-color: #06c;
  --accent-color: #006;
}
/* The rest of the CSS file */
#foo h1 {
  color: var(--main-color);
}

当使用js操作时,和正常操作属性一样处理

// 获取一个 Dom 节点上的 CSS 变量
element.style.getPropertyValue("--my-var");

// 获取任意 Dom 节点上的 CSS 变量
getComputedStyle(element).getPropertyValue("--my-var");

// 修改一个 Dom 节点上的 CSS 变量
element.style.setProperty("--my-var", jsVar + 4);

使用--*来定义

一个自定义属性以--开头,可以定义一个根级变量,然后由其他元素继承,也可以在定义本地变量

:root {
  --header-color: #06c;
}
div { --color: green; }

使用var()读取

使用语法是

var( <custom-property-name> [, <declaration-value> ]? )

第一个参数是要获取的属性名,第二个是默认值.

变换

css的视觉格式化模型描述了每个元素内的坐标系,向右向下为正。使用transform可以修改此坐标系,可变换元素这里指的是除了非可替换行内元素、table相关之外的其他被盒模型管理的元素。
通过transform属性将变换应用到元素渲染到的坐标系,这个属性包含一个函数列表,一个坐标系最终转换到的值是通过转换每个函数到对应的矩阵(在 Mathematical Description of Transform Functions定义)然后相乘获得。
可取值为none | <transform-list>

将变换函数之前,我们先介绍几个相关属性

transform-box

所有的变换都是相对于这个属性代表的reference box来进行的,在非svg的环境里只需要关心border-box和content-box

transform-origin

指定变换的坐标系原点,其中0 0代表reference box的左上角,默认值50% 50% 像这样

变换函数

这里只介绍2d转换,3d转换比2d多了一个z轴

  • matrix() 以转换矩阵的方式定义转换,较少用到
  • translate() 在平面移动位置,两个参数分别表示x轴和y轴偏移,如果只有一个参数,则表示y轴偏移为0
    另外translateX()表示x轴偏移,translateY()表示y轴偏移
  • scale() 对指定坐标进行缩放
    同样有另外scaleX()、scaleY()两个函数
  • rotate() 按原点(transform-origin指定的)旋转指定角度,顺时针为正 ,逆时针为负
  • skew() 将指定轴倾斜对应角度,原点不动。另外两个函数是skewX()、skewY()。

过渡

一般来说,当一个css属性值变化时渲染结果会立刻更新,这个特性可以使css属性在给定时间内从一个值平滑的变成另外一个值。

transition

是一个过渡的简写,格式为 [ none | <single-transition-property> ] || <time> || <timing-function> || <time> ,其中第一个时间是过渡持续时间,第二个是延迟时间

transition-property

即<single-transition-property>, 指定过渡的属性

transition-duration

过渡的持续时间

transition-timing-function

过渡的transition-timing-function,描述了过渡时的中间值计算方法。可选值比如ease, ease-in, ease-out, ease-in-out,效果为

transition-delay

延误时间

动画

动画在过渡的基础上通过关键帧(keyframes)增加了对属性变化过程中的控制。使用方法大致如

div {
  animation-name: diagonal-slide;
  animation-duration: 5s;
  animation-iteration-count: 10;
}

@keyframes diagonal-slide {

  from {
    left: 0;
    top: 0;
  }

  to {
    left: 100px;
    top: 100px;
  }

}

注意,根据样式的层叠,动画设置的属性会被标记为!important和过渡的属性覆盖。

animation

是一个逗号分隔的动画列表的简写,可以同时指定多个动画。每个动画的组成是 <time> || <timing-function> || <time> || <single-animation-iteration-count> || <single-animation-direction> || <single-animation-fill-mode> || <single-animation-play-state> || [ none | <keyframes-name> ] 注意,第一个时间作为持续时间,第二个时间作为延误时间

@keyframes

动画中的<keyframes-name> 指的是一系列关键帧,即一个@keyframes规则组,语法是@keyframes <keyframes-name> { <rule-list> } 其中的每帧包含一个发生的时间,和指定的特性。时间可用百分数指定,也可用from和to关键字。可参考上面的例子。

animation-name

指的是使用哪个动画,即@keyframes的名字

animation-duration

动画持续时间

animation-timing-function

可参考过渡中的timing-function

animation-iteration-count

动画次数

animation-direction

要不要在运动周期反向运动,可取值 normal | reverse | alternate | alternate-reverse

animation-play-state

定义运动状态,暂停还是运行,即running | paused,用于控制运行状态

animation-delay

延误时间

animation-fill-mode

规定当动画不播放时(当动画完成时,或当动画有一个延迟未开始播放时),要应用到元素的样式,可取值none | forwards | backwards | both

网格布局

新的布局方式,将一个区域像表格一样划分成不同区域,相关概念和使用请参考网格布局

文本

因为这个模块还在测试阶段,因此就没和css2中对应内容合并,部分内容会有重叠。

text-transform

转换文本样式,可取值none | [capitalize | uppercase | lowercase ] || full-width || full-size-kana

white-space

怎么处理元素中的空格,可取值 normal | pre | nowrap | pre-wrap | break-spaces | pre-line

tab-size

自定义制表符的宽度,可取值 |

word-break

指定当需要时怎么样断开单词,可取值normal | keep-all | break-all | break-word

line-break

怎么断开一行,可取值auto | loose | normal | strict | anywhere

hyphens

告知浏览器在换行时如何使用连字符连接单词,可取值none | manual | auto

overflow-wrap, word-wrap

用来说明当一个不能被分开的字符串太长而不能填充其包裹盒时,为防止其溢出,浏览器是否允许这样的单词中断换行,可取值normal | break-word | anywhere

text-align

行内级内容怎么在块容器中对齐,可选值start | end | left | right | center | justify | match-parent | justify-all

text-align-last

描述的是一段文本中最后一行在被强制换行之前的对齐规则,可选值auto | start | end | left | right | center | justify | match-parent

text-justify

定义的是当文本的 text-align 属性被设置为 justify 时的对齐方法,可选auto | none | inter-word | inter-character

word-spacing

指定单词间另外的空间,可取值 normal |

letter-spacing

指定字母间另外的空间,可取值 normal |

text-indent

文本缩进,可取值[ ] && hanging? && each-line?,当添加hanging关键字时表示第一行以外缩进

hanging-punctuation

指定了标点符号应该放在文本句子的开头还是结尾。可选值 none | [ first || [ force-end | allow-end ] || last ]

will-change属性

用该属性提前告诉用户代理,元素将要做何种变化,这使得用户代理提前做好优化。但是用好这个属性并不简单,甚至会造成负面效果,比如设置为will-change: transform,用户代理会将该元素独立于其他元素渲染,但是将元素设置在一个新层里是个昂贵的操作,可能是变换推迟。

不同的浏览器的对应优化方式不同

用好will-change

  • 不要在很多元素上使用,这不会帮助很多但会消耗很多用来前期优化的性能
  • 在样式表中节制使用,在样式表中使用意味着目标元素离变化总有很短的时间,但实际上我们并不是表达这个意思,可以通过脚本等控制。另外对于确实随时会动的元素在样式表添加是可取的,比如滚动条或者确实一直在动的元素。
  • 给优化充足的时间
  • 不要在已经停止变化的元素上浪费资源

will-change属性

默认auto,另外还可以取值

  • scroll-position 表示将要使用滚动条
  • contents 将要变动内容
  • 将要改变的属性,比如transform

过滤效果

即filter effect,也可以翻译为滤镜,是一种元素显示于文档之前对其进行处理的方法,这里只介绍简单的几种滤镜处理

filter属性

可以将模糊或者颜色偏移应用到一个元素,通常用于调整图片背景和border,可选值为 []* | none,其中滤镜函数具体为

  • blur() 将高斯模糊应用到图片上,参数是模糊半径,只能接受css长度不接受百分比
  • brightness() 将线性乘法器应用到图片,0为黑,100%为没变化,可为倍数
  • contrast() 调整对比度,0为完全灰,100%不变
  • drop-shadow() 应用阴影,包含四个参数分别为<offset-x> <offset-y> <blur-radius> <color>
  • grayscale() 调整灰度,取值0% 到100%,0不变,100%完全灰
  • hue-rotate() hue转换,取值0到360deg
  • invert() 反相,0不变,100%完全相反
  • opacity() 透明度,0到100%
  • saturate() 饱和度
  • sepia()处理成棕褐色

具体效果参考filter,多个函数可以同时使用

cssom

CSSOM View Module介绍的是css给开发者的一些检查和操作试图的api,比如通过window访问的

partial interface Window {
    [NewObject] MediaQueryList matchMedia(DOMString query);
    [SameObject, Replaceable] readonly attribute Screen screen;

    // browsing context
    void moveTo(long x, long y);
    void moveBy(long x, long y);
    void resizeTo(long x, long y);
    void resizeBy(long x, long y);

    // viewport
    [Replaceable] readonly attribute long innerWidth;
    [Replaceable] readonly attribute long innerHeight;

    // viewport scrolling
    [Replaceable] readonly attribute double scrollX;
    [Replaceable] readonly attribute double pageXOffset;
    [Replaceable] readonly attribute double scrollY;
    [Replaceable] readonly attribute double pageYOffset;
    void scroll(optional ScrollToOptions options);
    void scroll(unrestricted double x, unrestricted double y);
    void scrollTo(optional ScrollToOptions options);
    void scrollTo(unrestricted double x, unrestricted double y);
    void scrollBy(optional ScrollToOptions options);
    void scrollBy(unrestricted double x, unrestricted double y);

    // client
    [Replaceable] readonly attribute long screenX;
    [Replaceable] readonly attribute long screenY;
    [Replaceable] readonly attribute long outerWidth;
    [Replaceable] readonly attribute long outerHeight;
    [Replaceable] readonly attribute double devicePixelRatio;
};

css object

CSS Object Model定义了访问Media Queries, Selectors, and of course CSS itself的api。
比如CSSStyleSheet对象,可通过document.styleSheets来获取

interface CSSStyleSheet : StyleSheet {
  readonly attribute CSSRule? ownerRule;
  [SameObject] readonly attribute CSSRuleList cssRules;
  unsigned long insertRule(DOMString rule, unsigned long index);
  void deleteRule(unsigned long index);
};

结束语

已经看到了最后,辛苦了😅。
现在可能对css的知识架构有了比较新的认识,现在可以到项目中运用一下,或者看一下这篇文章巩固一下css相关的其他知识。