相信系统学习过网页前端的你肯定知道,我们学习css是我们的基础课,提到css肯定有很多同学表示很不屑。然而CSS 入门容易,精通确很难。当前大多数前端开发人员或者后端转前端人员很少愿意花时间在 CSS 的研究和学习上,从而导致了很多糟糕的实现。
会讲到如下内容:
- 浏览器的组成部分
- 渲染引擎运行原理
- CSS 几大特性
- CSS 语法解析过程详解
- CSS 选择器执行顺序
- 如何高效的共享 ComputedStyle
- CSS 书写顺序对性能有影响吗
- 高效的 CSS 书写优化策略
- 共享 CSS 命名规范
一、浏览器的组成部分
一个完整的浏览器包括浏览器的外壳和浏览器内核,一般有8个模块组成。
2、浏览器引擎(Browser Engine) 可以在用户界面和渲染引擎之间传送指令或在客户端本地缓存中读写数据等,是浏览器中各个部分之间相互通信的核心。
3、渲染引擎(Rendering Engine) 解析DOM文档和CSS规则并将内容排版到浏览器中显示有样式的界面,也有人称之为排版引擎,我们常说的浏览器内核主要指的就是渲染引擎
4、网络(Networking) 实现HTTP和FTP等文件传输协议,在不同的字符集之间进行转换,为文件解析MIME媒体类型。 实现最近检索资源的缓存功能。
5、JavaScript解释器(JavaScript Interpreter) 能够解释并执行嵌入在网页中的JavaScript(又称ECMAScript)代码。 为了安全起见,浏览器引擎或渲染引擎可能会禁用某些JavaScript功能,如弹出窗口的打开。
6、XML解析器(XML Parser) XML解析器是浏览器架构中复用最多的子系统之一,它可以将XML文档解析成文档对象模型(Document Object Model,DOM)树。
7、显示后端(Display Backend) 显示后端提供绘图和窗口原语,包括:用户界面控件集合、字体集合。
8、数据持久层(Data Persistence)。 数据持久层也就是我们说的数据存储,它将与浏览会话相关联的各种数据存储在硬盘上。 这些数据可能是诸如:书签、工具栏设置等这样的高级数据,也可能是诸如:Cookie,安全证书、缓存等这样的低级数据。
说了这么多,归根揭底我们只要记住
浏览器的核心就是浏览器的内核,它包括:渲染引擎和js引擎。我们通常说一个浏览器的内核什么的,一般是指渲染引擎。
主流浏览器渲染引擎和js引擎:
| 浏览器 | 渲染引擎 | js引擎 |
|---|---|---|
| IE | Trident | Chakra |
| Firefox | Gecko | SpiderMonkey |
| Chrome | Webkit | V8 |
| Safri | Webkit | javascriptcore |
| Opera | Presto | Carakan |
二、渲染引擎运行原理
渲染引擎是解析DOM文档和CSS规则并将内容排版到浏览器中显示有样式的界面。
我们可以从3条线去关注下:
- XML解析器 解析HTML(XML)文档,主要作用是将HTML(XML)文档转换成DOM树。
- CSS解析器 将DOM中的各个元素对象进行计算,获取样式信息,用于渲染树的构建。
- JavaScript解释器 解释JavaScript代码,并通过DOM接口和CSSOM接口来修改网页内容、样式规则,从而改变渲染结果。
由上图我们可以看出,DOM创建之后,渲染引擎将其中的元素对象与样式规则进行结合,可以得到渲染树。最后,布局则是针对渲染树,计算其各个元素的大小、位置等布局信息,从而最终使图形库将布局计算后的渲染树绘制成可视化的图像结果,在显示器中呈现出来。
三、CSS 几大特性 1、层叠性 层叠性是指 CSS 样式在针对同一元素配置同一属性时,依据层叠规则(权重)来处理冲突,选择应用权重高的 CSS 选择器所指定的属性,一般也被描述为权重高的覆盖权重低的。
所以,层叠性就是看CSS的优先级,优先级(权重)高的会覆盖优先级(权重)低的同样重复的样式属性,不会覆盖不重复的属性,不重复的属性会合并下来。
代码示例:
<style>
div{width: 100px; height: 100px; margin-top: 10px; background: yellow;}
.boxred{background:red;width: 200px;}
.boxblue{background: blue; height: 200px;}
</style>
<body>
<div>
</div>
<div class="boxred">
</div>
<div class="boxblue">
</div>
</body>
效果展示:
2、优先级
优先级是CSS的重要特性之一,学会它你可以轻松玩转CSS。
CSS 优先级主要依赖就近原则(除去 !important 声明外)
!important > 行内样式(写在页面中的css) > ID 选择器 > 类选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性
!important是css的一种语法,定义在样式属性后面,代表这个属性不会被覆盖,最终生效的属性一定是!important标注的属性。 就如同特性1中的代码示例,我们在div的样式里加上!important,结构会如何显示呢?
css代码:
div{width: 100px; height: 100px; margin-top: 10px; background: yellow!important;}
效果图:
3、继承性
css样式表继承指的是,html元素可以从父元素那里继承一部分css属性,即使当前元素没有定义该属性。
比如一个子标签没有设置背景颜色,那么子标签会继承父标签的背景颜色。 但是,这里我们要注意可继承性的CSS属性是一部分不是全部。标签不会继承父标签的宽度、高度、边距属性。
可继承CSS属性:
- 字体类属性 (font,font-family,font-weight,font-size,font-style,font-variant,font-stretch,font-size-adjust)
- 文本类属性 (text-indent,text-align,text-shadow,line-height,word-spacing,letter-spacing,text-transform,direction,color)
- 背景类属性 (backgrong)
- 列表类属性 (list-style-type,list-style-image,list-style-position,list-style)
- 页面样式属性 (page,page-break-inside,windows,orphans)
- 表格布局类属性 (border-style,caption-side,border-collapse,empty-cells)
- 声音类属性 (speak,speak-punctuation,speak-numeral,speak-header,speech-rate、volume,voice-family,pitch,pitch-range,stress,richness,azimuth,elevation)
- 光标属性 (cursor)
- 元素可见属性 (visibility)
- 嵌套引用属性 (quotes)
css属性一旦继承了不能被取消,只能重新定义样式。
案例代码:
<div class="ycbox">
YCbox标题
<div class="jichengbox1">继承样式</div>
<div class="jichengbox2">不继承样式</div>
</div>
<style>
.ycbox{background:#666666;/*背景颜色可继承*/width: 200px;height: 300px;color: #ffffff;/*文字颜色可继承*/}
.jichengbox1{background: red;/*重置背景*/}
.jichengbox2{color: yellow;/*重置文字颜色*/}
</style>
效果展示 :
如何成功定义html元素的样式,需要正确的 CSS 语法书写。
- CSS语法:如下图
- 解析过程 CSS 被浏览器下载,CSS 解析器就会被打开来处理它遇到的任何CSS。这可以是单个文档内的CSS、标记内的CSS,也可以是 DOM 元素的style属性内嵌的 CSS。所 有CSS 都根据语法规范进行解析和标记。解析完成后,就会生成有一个包含所有选择器、属性和属性各自值的数据结构。
例如:
.ycbox {
background: blue;
border: 4px solid red;
font-size: 1px;
}
以上 CSS 片段将生成如下数据结构
| 属性 | 值 |
|---|---|
| background-color | rgb(0,0,255) |
| border-width | 4px |
| border-style | solid |
| border-color | rgb(255,0,0) |
| font-size | 1px |
浏览器将 background 和 border 的简写还原成普通写法,也就是一个一个属性的声明,因为简单写主要方便开发人员的编写,但从这里开始,浏览器只处理普通写法。完解析成之后,浏览器引擎继续构建 DOM 树。
这种解析器会将CSS文件解析成StyleSheet对象,并且每个对象都包含CSS规则。CSS规则里包含了CSS里的选择器和声明对象,以及其他与CSS语法对应的对象。
简单来说:CSS的解析过程会按照 CSS规则(Rule)和 CSS声明(Declaration)来 来解析。
浏览器 CSS 模块负责 CSS 脚本解析,并为每个 Element 计算出样式。CSS 模块虽小,但是计算量大,设计不好往往成为浏览器性能的瓶颈。
五、 CSS 选择器执行顺序
我们大家都知道
渲染引擎解析CSS选择器是从右往左进行的,因为这样可以减少无效匹配的次数,从而提高匹配速度、性能也更优秀。
如果你还不是很明白,我们不妨举例说明:
html代码
<div>
<div class="ycbox">
<ul>
<li><span>CSS选择器执行顺序</span></li>
<li><span>CSS选择器执行顺序</span></li>
<li><span class="blue">CSS选择器执行顺序</span></li>
<li><span>CSS选择器执行顺序</span></li>
</ul>
</div>
</div>
CSS选择器
div > div.ycbox > ul > li > span.blue{color:blue;}
对于上述例子,我们按照【从左到右】的执行顺序进行查找会怎样?
1.先找到所有的 div 节点; 2.在 div 节点内找到所有的子 div,并从中找到 class="ycbox" 的div; 3.再依次匹配 ul li span.blue 等情况; 4.遇到不匹配的情况,就必须回溯到一开始搜索的 div 或者 li 节点,然后去搜索下个节点,重复这样的过程。
这样听上去也蛮合理的,你有没有觉得这样很低效呢?那么问题出现在哪呢? 这样的搜索过程对于一个只是匹配很少节点的选择器来说,效率是极低的,因为我们花费了大量的时间在回溯匹配不符合规则的节点。
我们换个思路,倒推一下!
html代码
<div>
<div class="ycbox">
<ul>
<li><span>CSS选择器执行顺序</span></li>
<li><span>CSS选择器执行顺序</span></li>
<li><span class="blue">CSS选择器执行顺序</span></li>
<li><span>CSS选择器执行顺序</span></li>
</ul>
</div>
</div>
CSS选择器
div > div.ycbox > ul > li > span.blue{color:blue;}
我们按照【从右到左】的顺序进行执行分析:
1.直接查找 class="blue" 的 span 元素; 2.再检索父级节点 是否为 ul li 元素,如果不是则进入同级其它节点检索,如果是则继续匹配父级节点满足 class="ycbox" 的 div 容器; 3.这样就又减少了集合的元素,只有符合当前子规则才会匹配检索再上一条的规则。
所以综上所述,我们可以得出以下结论:
CSS 选择器执行顺序是以从右向左方式匹配节点的
这样做减少了无效的匹配次数,从而提高匹配速度,性能更加优秀。所以,我们在书写 CSS选择器 的时候,从右到左的 .class匹配节点 越少越好。
如果能共享,那就不需要执行匹配算法了,执行效率自然非常高。
六、如何高效的共享 ComputedStyle
浏览器还有一个非常棒的策略,在特定情况下,浏览器会共享 computedStyle ,网页中能共享的标签非常多,所以极大的提升执行效率!
再说的直观一些,所谓共享 ComputedStyle ,就是共同的css 表现,前段都知道的 公用样式,这样可以简练你的代码,减少不必要的冗余Css样式。
举一个最常见的例子:
<div class="ycbox">
<p style="color: red;">YC专注前段开发研究</p>
<p style="color: red;">YC专注前段开发研究</p>
</div>
这里的 color:red; 就不能共享 ComputedStyle;
这就是我们前段在学CSS的时候最基础的。表现与结构相分离,要让页面的表现层完全独立出来。这样既提高了页面的执行效率,同时也能让你的后期维护成本大大降低。
那么如何高效的使我们的页面高效共享 ComputedStyle 呢?
1.TagName 和 Class 属性必须一样;(尽量少用id,多用class类名,共享样式表现) 2.不能有 Style 属性。哪怕 Style 属性相等,他们也不共享;(就是上面的例子表现结构要分离) 3.不能使用 Sibling selector,譬如: first-child, :last-selector, + selector(伪类选择器不能共享) 4.mappedAttribute 必须相等;
针对4提到的情况可以共享,例子如下:
<div class="ycbox">
<p align="middle">YC专注前段开发研究</p>
<p align="middle">YC专注前段开发研究</p>
</div>
讲到这里,相信你对 “共享 ComputedStyle” 有了一些认识,不过想要写出更加精炼高效的代码,还得继续多加练习,结合实例会让你突飞猛进。我们以后有机会也会开设结合实例的分析 chat 。
七、 CSS 书写顺序对性能有影响吗
大家要知道,浏览器并不是一获取到 CSS 样式就直接开始解析,而是要根据 CSS 样式的书写顺序将它按照 DOM 树的结构进行 分布式渲染样式的,然后开始遍历每个结点的 CSS 样式进行解析,此时CSS样式的遍历顺序是完全按照之前的书写顺序。
在解析过程中,一旦浏览器发现某个元素的定位变化影响布局,则需要倒回去重新渲染。
例如:
width: 150px;
height: 150px;
font-size: 24px;
position: absolute;
当浏览器解析到 定位属性 position: absolute; 的时候,会发现这个元素是绝对定位,从而不得不从头重新渲染。
调整后:
position: absolute;
width: 150px;
height: 150px;
font-size: 24px;
这样就能让渲染引擎更高效的工作了。
所以,
CSS 书写顺序会对 CSS 性能是有一定的影响的。
那么,我们在实际的开发过程中,该如何书写才能保证我们的性能最优呢?
这里有个规范希望跟大家共勉:
1.css的定位属性:
- position
- display
- float
- left
- top
- right
- bottom
- overflow
- clear
- z-index
2.css的自身属性:
- width
- height
- padding
- border
- margin
- background
3.css的文字属性:
- ont-family
- font-size
- font-style
- font-weight
- font-varient
- color
4.css的文本属性:
- text-align
- vertical-align
- text-wrap
- text-transform
- text-indent
- text-decoration
- letter-spacing
- word-spacing
- white-space
- text-overflow
5.css3的新增属性:
- content
- box-shadow
- border-radius
- transform
八、高效的 CSS 书写优化策略
我们上面从本质上聊了那么多,相信大家也有了如何写出搞笑的CSS代码方案或想法。
我们可以从以下几点进行总结:
1.使用 id 要慎重;
使用 id selector 是非常高效的,在使用 id 选择器的时候要注意:因为 id 是具有唯一性的,所以不要指定id,又指定 tagName
示例代码:
<div class="ycbox">
<p><strong id="idfont">YC</strong>专注前段开发研究</p>
<p>YC专注前段开发研究</p>
</div>
CSS示例:
/*错误*/
strong#idfont{color:blue;}
/*正确*/
#idfont{color:blue;}
2.避免使用深层次的节点(node);
因为渲染引擎解析css就是【从左到右】寻找节点进行解析的。
示例代码:
<div class="ycbox">
<div>
<p><strong>YC</strong>专注前段开发研究</p>
<p><strong class="fontname">YC</strong>专注前段开发研究</p>
</div>
</div>
CSS示例:
/*错误*/
div > div > p > strong {color:blue;}
/*正确*/
strong.fontname{color:blue;}
3.尽量少使用 复选择器(attribute selector) 的写法 结合2上例提到的 strong.fontname{color:blue;} 可以进一步优化: CSS示例:
/*错误*/
strong.fontname{color:blue;}
/*正确*/
.fontname{color:blue;}
4.把兼容其它浏览器的 css hack 写在标准css的前面 css示例:
.ycbox {
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
}
5.遵守 CSSLint 规则
| 规则 | 说明 |
|---|---|
| font-faces | 不能使用超过5个web字体 |
| import | 禁止使用@import |
| regex-selectors | 禁止使用属性选择器中的正则表达式选择器 |
| universal-selector | 禁止使用通用选择器 |
| unqualified-attributes | 禁止使用不规范的属性选择器 |
| zero-units | 0后面不要加单位 |
| overqualified-elements | 使用相邻选择器时,不要使用不必要的选择器 |
| shorthand | 简写样式属性 |
| duplicate-background-images | 相同的url在样式表中不超过一次 |
6.减少 CSS 文档体积
- 移除空的 CSS 规则(Remove empty rules)
- 值为 0 不需要单位
- 使用缩写
- 属性值为浮动小数 0.**,可以省略小数点之前的0;
- 不给 h1-h6 元素定义过多的样式
7.提前设置默认样式
这样可以提前告知浏览器的默认样式,使用一个专用的属性来通知浏览器留意接下来的变化,从而优化和分配内存。
8.不要使用 @import
使用 @import 引入 CSS 会影响浏览器的并行下载。使用 @import 引用的 CSS 文件只有在引用它的那个 CSS 文件被下载、解析之后,浏览器才会知道还有另外一个 CSS 需要下载,这时才去下载,然后下载后开始解析、构建 Render Tree 等一系列操作。
多个 @import 会导致下载顺序紊乱。在 IE 中,@import 会引发资源文件的下载顺序被打乱,即排列在 @import 后面的 JS 文件先于 @import 下载,并且打乱甚至破坏 @import 自身的并行下载。
9.不要过分依赖重排元素
常见的重排元素有:
| width | height | border | border-width |
|---|---|---|---|
| padding | margin | top | position |
| font-size | float | text-align | overflow-y |
| font-weight | overflow | left | font-family |
| line-height | vertical-align | right | clear |
| white-space | bottom | min-height |
10.高效利用共享 ComputedStyle
- 公共类
- 慎用 ChildSelector
- 尽可能共享
11.少使用让页面发送重绘的属性
当页面发生重绘时,它们会降低浏览器的渲染性能。所以在编写 CSS 时,我们应该尽量减少这些属性,如:
- box-shadow
- border-radius
- filter
- :nth-child
12.多依赖css继承属性
如果某些属性可以继承,那么自然没有必要在写一遍,这样减少冗余样式属性。
可继承属性如下:
如果忘了,请返回继续深入查看 七 CSS 书写顺序对性能有影响吗
总结:我们要真正的从本质了解 CSS 的具体实现原理,这样我们在平日的工作当中,时刻注意以上所提到的规则,相信我们写出来的 CSS代码 一点是最高效的。
九、 共享 CSS 命名规范
俗话说从css的命名可以看出一个前端从业者的专业性。好的命名习惯,不仅可以提高可读性,同时也能提高日后维护的工作效率。
CSS命名规则:
- 使用类选择器,放弃ID选择器
- NEC特殊字符:"-"连字符
- 分类的命名方法:使用单个字母+"-"为前缀
- 后代选择器命名
- 命名应简约而不失语义
- 相同语义的不同类命名
- 模块和元件的扩展类的命名方法
- 模块和元件的后代选择器的扩展类
- 分组选择器有时可以代替扩展方法
- 防止污染和被污染
统一语义理解和命名:
布局
| 语义 | 命名 | 简写 |
|---|---|---|
| 文档 | doc | doc |
| 头部 | head | hd |
| 主体 | body | bd |
| 尾部 | foot | ft |
| 主栏 | main | mn |
| 主栏子容器 | mainc | mnc |
| 侧栏 | side | sd |
| 侧栏子容器 | sidec | sdc |
| 盒容器 | wrap/box | wrap/box |
模块元件
| 语义 | 命名 | 简写 |
|---|---|---|
| 导航 | nav | nav |
| 子导航 | subnav | snav |
| 面包屑 | crumb | crm |
| 菜单 | menu | menu |
| 选项卡 | tab | tab |
| 标题区 | head/title | hd/tt |
| 内容区 | body/content | bd/ct |
| 列表 | list | lst |
| 表格 | table | tb |
| 表单 | form | fm |
| 热点 | hot | hot |
| 排行 | top | top |
| 登录 | login | log |
| 标志 | logo | logo |
| 广告 | advertise | ad |
| 搜索 | search | sch |
| 幻灯 | slide | sld |
| 提示 | tips | tips |
| 帮助 | help | help |
| 新闻 | news | news |
| 下载 | download | dld |
| 注册 | regist | reg |
| 投票 | vote | vote |
| 版权 | copyright | cprt |
| 结果 | result | rst |
| 标题 | title | tt |
| 按钮 | button | btn |
| 输入 | input | ipt |
功能
| 语义 | 命名 | 简写 |
|---|---|---|
| 浮动清除 | clearboth | cb |
| 向左浮动 | floatleft | fl |
| 向右浮动 | floatright | fr |
| 内联块级 | inlineblock | ib |
| 文本居中 | textaligncenter | tac |
| 文本居右 | textalignright | tar |
| 文本居左 | textalignleft | tal |
| 垂直居中 | verticalalignmiddle | vam |
| 溢出隐藏 | overflowhidden | oh |
| 完全消失 | displaynone | dn |
| 字体大小 | fontsize | fs |
| 字体粗细 | fontweight | fw |
ui皮肤
| 语义 | 命名 | 简写 |
|---|---|---|
| 字体颜色 | fontcolor | fc |
| 背景 | background | bg |
| 背景颜色 | backgroundcolor | bgc |
| 背景图片 | backgroundimage | bgi |
| 背景定位 | backgroundposition | bgp |
| 边框颜色 | bordercolor | bdc |
状态
| 语义 | 命名 | 简写 |
|---|---|---|
| 选中 | selected | sel |
| 当前 | current | crt |
| 显示 | show | show |
| 隐藏 | hide | hide |
| 打开 | open | open |
| 关闭 | close | close |
| 出错 | error | err |
| 不可用 | disabled | dis |