⑥浏览器的工作原理(中)

1 浏览器的工作原理

1.2.5 创建包含CSS样式信息的DOM树 ★

1.2.5.1 CSS简介

 层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言;CSS共有两种规则,一种是选择器、属性和值组合的普通规则,另一种被称为 at-rule,也就是带@的规则。

1.2.5.2 CSS语法部分

 普通规则部分:


CSS普通规则
1.2.5.2.1 属性

属性的名字是一个合法的标识符,它们是CSS语法中的关键字。例如:color是文本的颜色属性,而text-indent则规定了段落的缩进,要掌握一个属性的用法,有六个方面需要了解。具体叙述如下:
该属性的合法属性值(legal value);显然段落缩进属性text-indent只能赋给一个表示长度的值,而表示背景图案的background.image属性则应该取一个表示图片位置链接的值或者是关键字none表示不用背景图案;
该属性的默认值(initial value);当在样式表单中没有规定该属性,而且该属性不能从它的父级元素那儿继承的时候,则浏览器将认为该属性取它的默认值;
该属性所适用的元素(Applies to);有的属性只适用于某些个别的元素,比如white-space属性就只适用于块级元素;white-space属性可以取normalprenowrap三个值。;当取normal的时候,浏览器将忽略掉连续的空白字符,而只显示一个空白字符;当取pre的时候,则保留连续的空白字符;而取nowrap的时候,连续的空白字符被忽略,而且不自动换行;
该属性的值是否被下一级继承(inherited);
如果该属性能取百分值(percentage),那么该百分值将如何解释;也就是百分值所相对的标准是什么;如margin属性可以取百分值,它是相对于margin所存元素的容器的宽度;
该属性所属的媒介类型组(media groups)。

1.2.5.2.2 选择器 ★

CSS的各类选择器用于选择网页中的各种元素,可以分为①②③④⑤:
① 简单选择器(根据特定的条件约束选择元素)

简单选择器

 <1> 类型选择器(也叫标签选择器)
 它根据元素的标签名来选中元素:

div {}

/* 选择标签名为div的元素 */

 <2> 全体选择器
 选择全部元素:

* {
    background-color: yellow;
}

/* 选择所有元素,并设置其背景色 */

div * {
    background-color: green;
}

/* 全体选择器也可以选择一个特定元素内的所有元素: */

 <3> id选择器和class选择器
 id选择器和class选择器都是针对特定属性的选择器:

#myid {
    stroke: blue;
    stroke-width: 1;
}

/* id选择器是“#”号后面跟随id名 */

.mycls {
    font-size: 40px
}

/* class选择器是“.”后面跟随class名 */
<html>
    <head>
        <style>
            .a {
                color: red;
            }
        </style>
    </head>
    <body>
        <a class="a b c">xxx</a>
        <!-- 在这个例子中,元素带有用空格分隔的class属性,样式部分使用“.a”“.b”或者“.c”就能够选中元素,也可以使用多个class选择器来要求元素具有多个class属性 -->
    </body>
</html>

 <4> 属性选择器(只有在规定了 !DOCTYPE 时,IE7 和 IE8 才支持属性选择器。在 IE6 及更低的版本中,不支持属性选择)
 属性选择器根据HTML元素的属性来选中元素:

[title] {
    color: red;
}

/* [attribute]  用于选取带有指定属性的元素 */
[title=a] {
    border: 5px solid blue;
}

/* [attribute=value]  用于选取带有指定属性和值的元素 */
[title~=hello] {
    color: red;
}

/* [attribute~=value]  用于选取属性值中包含指定词汇的元素,适用于由空格分隔的属性值 */
[lang|=en] {
    color: red;
}

/* [attribute|=value]  用于选取带有以指定值开头的属性值的元素,适用于由连字符分隔的属性值,该值必须是整个单词 */
div[class^="test"] {
    background: #ffff00;
}

/* [attribute^=value]  匹配属性值以指定值开头的每个元素 */
div[class$="test"] {
    background: #ffff00;
}

/* [attribute$=value]  匹配属性值以指定值结尾的每个元素 */
div[class*="test"] {
    background: #ffff00;
}

/* [attribute*=value]  匹配属性值中包含指定值的每个元素 */

<5> 伪类(用于向某些选择器添加特殊的效果,以冒号开头,可以分成4种类型) ★

 1> 树结构关系伪类选择器
 树结构关系伪类通过文档树结构的相互关系来匹配特定的元素:

:root {
     background:#ff0000;
}

/* 设置HTML文档的背景色,:root 伪类表示树的根元素,在HTML中根元素始终是HTML元素,但是随着scoped css和shadow root等场景出现,选择器可以针对某一子树来选择,这时候就很需要:root 伪类了 */
p:empty
{
    background:#ff0000;
}

/* 指定空的p元素的背景色,:empty 伪类表示没有子节点的元素 */

 3 :nth-child伪类和:nth-last-child伪类都是函数型的伪类,它们的区别仅仅是从后往前数。

:nth-child 伪类

 4 :first-child伪类和:last-child伪类分别表示第一个和最后一个元素。
 5 :only-child伪类表示唯一一个子元素,要使这个伪类生效,所指定的元素必须有父元素,且该元素是父元素唯一子元素。
 6 of-type系列伪类,是一个变形的语法糖,S:nth-of-type(An+B):nth-child(|An+B| of S)的另一种写法;以此类推,还有nth-last-of-typefirst-of-typelast-of-typeonly-of-type

 2> 链接与行为伪类选择器
 链接与行为是第一批设计出来的伪类,也是最常用的一批伪类:
 1 :any-link伪类表示任意的链接,包括aarealink标签都可能匹配到这个伪类;
 2 :link伪类表示未访问过的链接,:visited伪类表示已经访问过的链接;
 3 :hover伪类表示鼠标悬停在上的元素;
 4 :active伪类表示用户正在激活这个元素,如用户按下按钮,鼠标还未抬起时,这个按钮就处于激活状态;
 5 :focus伪类表示焦点落在这个元素之上;
 6 :target伪类用于选中浏览器URL的hash部分所指示的元素;
 7 :target-within:focus-within等伪类,用于表示target或者focus的父容器。

 3> 逻辑伪类选择器
 仅介绍:not伪类:

:not(p)
{ 
    background:#ff0000;
}

/* 为每个并非<P>元素的元素设置背景颜色 */

 4> 其他一些不常用的伪类
 1 :dir:lang伪类,前者是匹配特定文字书写方向的元素,后者是匹配lang属性值等于en(English)或者it(Italian)的元素;
 2 :play:pause伪类,用于区分音视频播放状态;
 3 :current:past:future伪类,用于配合读屏软件等时序性客户端;
 4 :nth-col:nth-last-col伪类,用于处理table的列。

 至此,简单选择器结束。

② 复合选择器(连续写在一起的简单选择器,表示简单选择器中“且”的关系)

p.special
{
    color:red;
}

/* 例子中的“ p.special ”,表示选择的元素必须同时具有p标签和.special属性,如:<p class="special"> */

③ 复杂选择器(由“(空格)”“ >”“ ~”“ +”“ ||”等符号连接的复合选择器,主要针对节点关系,如选择特定父元素中的特定子元素)
 <1> “空格”:后代,表示选中所有符合条件的后代节点, 例如“div p”表示选中<div>元素内的所有<p>元素;
 <2> “>” :子代,表示选中符合条件的子节点,例如“div>p”表示选中所有父级是<div>元素的<p>元素;
 <3> “~” : 后继,表示选中所有符合条件的后继节点,后继节点即跟当前节点具有同一个父元素,并出现在它之后的节点,例如“.a~.b”表示选中所有选择class为a的元素之后的每一个class为b的元素;
 <4> “+”:直接后继,表示选中符合条件的直接后继节点,直接后继节点即nextSlibling。例如 “div+p”表示选中所有紧接着<div>元素之后的<p>元素;
 <5> “||”:列选择器,表示选中对应列中符合条件的单元格,这个比较少用,实际使用时,比较常用的连接符号是“空格”和“>”。

④ 选择器列表(由逗号分隔的复杂选择器,表示“或”的关系)
 选择器列表有着像四则运算一样的运算符优先级,如.c,.a>.b.d,先算没有连接符的部分.c.a.b.d,再算像
“ >”这样的符号部分,最后算逗号。

⑤ 伪元素(伪元素的语法跟伪类相似,但实际产生的效果却是创造关于文档语言能够指定的文档树之外的抽象)
 例如:文档语言有着不能提供访问元素内容第一字或者第一行的机制,而使用伪元素能够访问:
 <1> ::first-line,表示元素的第一行,CSS标准规定了first-line必须出现在最内层的块级元素之内,否则不生效;
 <2> ::first-letter,表示元素的第一个字母,它在所有标签之内都可生效;

first-line 和 first-letter 所能实现的属性

 伪元素还提供样式设计师给在源文档中不存在的内容分配样式,是真正的无中生有: ★
 <3> ::before,表示在元素内容之前插入一个虚拟的元素,它和::after伪元素所在的CSS规则都必须指定了content属性才会生效;
 <4> ::after,表示在元素内容之后插入一个虚拟的元素,::before::after里面的content属性还支持counter;实际开发中,这两个伪元素非常有用,有了这两个伪元素,一些修饰性元素,可以使用纯粹的CSS代码添加进去,这能够很好地保持HTML代码中的语义,既完成了显示效果,又不会让DOM中出现很多无语义的空元素。。

1.2.5.2.3 选择器的优先级 ★

 CSS选择器是基于规则生效的,同一个元素命中多条规则是非常常见的事情;当发生冲突时,就需要去比较选择器的优先级。
 每个选择器的优先级可以转化成(A,B,C,D)这样的数组,转化规则:
 ① 如果存在内联样式,那么 A = 1,否则 A = 0;
 ② B的值等于ID选择器出现的次数;
 ③ C的值等于类选择器和属性选择器和伪类出现的总次数;
 ④ D的值等于标签选择器和伪元素出现的总次数。

 例子:#nav-global > ul > li > a.nav-link的优先级为(0, 1, 1, 3);

比较规则:
 从左往右依次进行比较 ,较大者胜出,如果相等,则继续往右移动一位进行比较 。如果4位全部相等,则后面的会覆盖前面的。

优先级比较的特殊情况:
 ① 当两个选择器的比较级相同时,遵循“后面的覆盖前面的”原则,如:

<div id="my" class="x y">text<div>
.x {
    background-color:lightblue;
}
.y {
    background-color:lightgreen;
}

/* y 生效 */

 ② 使用!important会提升整条样式的优先级,而且此优先级会高于内联样式;
 ③ 选择器的优先级计算不会合并选择器列表中所有选择器,会根据逗号分开计算。

实际开发当中:
 建议根据id选择器选中单个元素、class和class的组合选成组元素、标签选择器确定页面风格,根据这样的简单原则来使用选择器,不要搞出过于复杂的选择器,最好可以使用BEM规范

1.2.5.2.4 属性和属性值(CSS Variables标准

属性是由中划线、下划线、字母等组成的标识符,CSS还支持使用反斜杠转义。我们需要注意的是:属性不允许使用连续的两个中划线开头,这样的属性会被认为是CSS变量:

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

属性值可能是以下类型:
CSS范围的关键字:initial,unset,inherit,任何属性都可以的关键字;
字符串:比如content属性;
URL:使用url() 函数的URL值;
整数/实数:比如flex属性;
维度:单位的整数/实数,比如width属性;
百分比:大部分维度都支持;
颜色:比如background-color属性;
图片:比如background-image属性;
2D位置:比如background-position属性;
函数:来自函数的值,比如transform属性。

CSS支持的常用函数:
calc()
calc()函数是基本的表达式计算,它支持加减乘除四则运算。在针对维度进行计算时,calc()函数允许不同单位混合运算,非常有用:

section {
    float: left;
    margin: 1em; border: solid 1px;
    width: calc(100%/3 - 2*1em - 2*1px);
}

max()
 用于比较数值的大小并取出最大的那个:

.logo {
    width: max(50vw, 300px);
}

min()
 用于比较数值的大小并取出最小的那个:

div {
    width:min(10% + 20px, 300px);
}

clamp()
 给一个值限定一个范围,超出范围外则使用范围的最大或者最小值

p {
    font-size: clamp(1rem, 0.5rem, 1.5rem);
}

/* 返回1,第二个参数是最小值,第三个是最大值*/

toggle()
toggle()函数在规则选中多于一个元素时生效,它会在几个值之间来回切换,比如我们要让一个列表项的样式圆点和方点间隔出现,可以使用下面代码:

ul {
    list-style-type: toggle(circle, square);
}

attr()
attr()用于操作属性值,可以返回属性值,在CSS2.1中attr()总是返回一个字符串。在CSS3中attr()可以返回多种不同的类型:

<p data-foo="hello">world</p>
a:after {
    content: " (" attr(href) ")";
}
p::before {
    content: attr(data-foo) " ";
}
1.2.5.2.5 带@的规则 ★

常用规则:
@charset
@charset用于提示CSS文件使用的字符编码方式,它如果被使用,必须出现在最前面。这个规则只在给出语法解析阶段前使用,并不会影响页面上的展示效果:

@charset "utf-8";

@import
@import用于引入一个CSS文件,除了@charset规则不会被引入,@import可以引入另一个文件的全部内容:

@import "mystyle.css";
@import url("mystyle.css");

@import [ <url> | <string> ]
        [ supports( [ <supports-condition> | <declaration> ] ) ]?
        <media-query-list>? ;
/* import还支持 supports 和 media query 形式 */

@media
@media就是大名鼎鼎的media query使用的规则了,它能够对设备的类型进行一些判断。在media的区块内,是普通规则列表:

@media print {
    body { font-size: 10pt }
}

@page
@page用于分页媒体访问网页时的表现设置,页面是一种特殊的盒模型结构,除了页面本身,还可以设置它周围的盒:

@page {
    size: 8.5in 11in;
    margin: 10%;

    @top-left {
        content: "Hamlet";
      }
    @top-right {
        content: "Page " counter(page);
      }
}

@counter-style
@counter-style产生一种数据,用于定义列表项的表现:

@counter-style triangle {
    system: cyclic;
    symbols: ‣;
    suffix: " ";
}

@keyframes
@keyframes产生一种数据,用于定义动画关键帧:

@keyframes diagonal-slide {

    from {
        left: 0;
        top: 0;
    }

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

}

@fontface
@fontface用于定义一种字体,icon font技术就是利用这个特性来实现的:

@font-face {
    font-family: Gentium;
    src: url(http://example.com/fonts/Gentium.woff);
}

p { font-family: Gentium, serif; }

@supports
@support用于检查环境的特性,它与media比较类似。
@namespace
 用于跟XML命名空间配合的一个规则,表示内部的CSS选择器全都带上特定命名空间。

 自此,CSS语法部分完毕。