样式定义了浏览器如何显示 HTML 元素。
它通常存储在单独的样式表中,再将样式引入到页面中,藉此解决内容与表现分离的问题。
…
CSS为HTML标记语言提供了一种样式描述,定义了其中元素的显示方式。CSS在Web设计领域是一个突破。利用它可以实现修改一个小的样式更新与之相关的所有页面元素。
样式定义了浏览器如何显示 HTML 元素。
它通常存储在单独的样式表中,再将样式引入到页面中,藉此解决内容与表现分离的问题。
要点
- HTML Parser 和 CSS Parser
- DOM 树与 Style Rules 会生成 Render Tree 渲染树
- HTML Parser 生成的 DOM 树和CSS Parser生成的Style Rules
- CSS从右往左解析
- computedStyle共用
- 内联样式和外部样式解析方式相同,但存在权重差别
CSS选择器
1 | div > div.jartto p span.yellow{ |
为什么从右往左解析:一个节点只有一个父级,但可以有多个子级
正向解析:例如「div div.jartto p span.yellow」,我们首先就要检查当前元素到 html 的整条路径,找到最上层的 div,再往下找div.jartto,如果遇到不匹配就必须回到 div,往下再去匹配选择器中的第一个 div.jartto,回溯若干次才能确定匹配与否,最终找到span.yellow效率很低。
CSS语法解析过程
先创建 CSSStyleSheet 对象。将 CSSStyleSheet 对象的指针存储到 CSSParser 对象中。
CSSParser 识别出一个 simple-selector ,形如 “div” 或者 “.class”。创建一个 CSSParserSelector 对象。
CSSParser 识别出一个关系符和另一个 simple-selecotr ,那么修改之前创建的 simple-selecotr, 创建组合关系符。
循环第3步直至碰到逗号或者左大括号。
如果碰到逗号,那么取出 CSSParser 的 reuse vector,然后将堆栈尾部的 CSSParserSelector 对象弹出存入 Vecotr 中,最后跳转至第2步。如果碰到左大括号,那么跳转至第6步。
识别属性名称,将属性名称的 hash 值压入解释器堆栈。
识别属性值,创建 CSSParserValue 对象,并将 CSSParserValue 对象存入解释器堆栈。
将属性名称和属性值弹出栈,创建 CSSProperty 对象。并将 CSSProperty 对象存入 CSSParser 成员变量m_parsedProperties 中。
如果识别处属性名称,那么转至第6步。如果识别右大括号,那么转至第10步。
将 reuse vector 从堆栈中弹出,并创建 CSSStyleRule 对象。CSSStyleRule 对象的选择符就是 reuse vector, 样式值就是 CSSParser 的成员变量 m_parsedProperties 。
把 CSSStyleRule 添加到 CSSStyleSheet 中。
清空 CSSParser 内部缓存结果。
如果没有内容了,那么结束。否则跳转值第2步。
什么是 computedStyle?
在特定情况下,浏览器会共享 computedStyle,网页中能共享的标签非常多,所以能极大的提升执行效率!如果能共享,那就不需要执行匹配算法了,执行效率自然非常高。
也就是说:如果两个或多个 element 的 computedStyle 不通过计算可以确认他们相等,那么这些 computedStyle 相等的 elements 只会计算一次样式,其余的仅仅共享该 computedStyle 。
通过window.getComputedStyle可获取到元素的最终样式
1 | var dom = document.getElementById("test"), |
那么有哪些规则会共享 computedStyle 呢?
该共享的element不能有id属性且CSS中还有该id的StyleRule.哪怕该StyleRule与Element不匹配
tagName和class属性必须一样
mappedAttribute必须相等
不能使用sibling selector,譬如:first-child, :last-selector, + selector
不能有style属性。哪怕style属性相等,它们也不共享
1
2<span><p style="color:red">paragraph1</span></p>
<span><p style="color:red">paragraph2</span></p>
高性能CSS选择器
http://selectors.turnwheel.com/slickspeed.php
不同的 CSS 选择器的组合,解析速度会不同
使用 id selector 非常的高效。在使用 id selector 的时候需要注意一点:因为 id 是唯一的,所以不需要既指定 id 又指定 tagName:
1
2
3
4
5Bad
p#id1 {color:red;}
Good
#id1 {color:red;}
当然,你非要这么写也没有什么问题,但这会增加 CSS 编译与解析时间,实在是不值当
避免深层次的 node ,譬如:
1
2
3
4
5Bad
div > div > div > p {color:red;}
Good
p-class{color:red;}慎用 ChildSelector
尽量不使用 attribute selector,如:p[att1=”val1”]。这样的匹配非常慢。更不要这样写:p[id=”id1”]。这样将 id selector 退化成 attribute selector
1
2
3
4
5
6
7Bad
p[id="id1"]{color:red;}
p[class="class1"]{color:red;}
Good
#id1{color:red;}
.class1{color:red;}理解依赖继承,如果某些属性可以继承,那么没必要再写一遍
1 | bad |