精通CSS意味着不仅能写出可用的标记和样式,还能让代码好阅读、方便移植、易维护。
1.外部代码质量:调试CSS
外部代理质量就是用户能体验到的最终结果。主要体现在几个方面。
- 正确性。CSS属性名都写对了吗?浏览器能否支持?
- 健壮性。声明两套属性,其中一套用作旧版浏览器的后备。
- 性能。页面加载快不快?动画和滚动是否平滑?
我们要善于利用浏览器的开发者工具。
1.1 浏览器如何解析CSS
浏览器在加载一个网站时,首先会收到网址对应的一个HTML文件。然后浏览器把这个HTML文件解析为一个对象(节点)树。这就是文档对象模型(DOM,document object model)。
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test Document</title>
</head>
<body>
<h1>This is a test.</h1>
<p>This is a paragraph.</p>
<p>This is anothr paragraph.</p>
</body>
</html>
浏览器在碰到HTML中指向CSS文件的链接时,会获取并解析CSS文件。类似于把HTML转换成DOM,CSS文件会被浏览器转换为CSS对象模型(CSSOM,CSS object model)。
不仅是外部CSS,内部style元素或行内style属性中的CSS也会被解析并添加到CSSOM中。
每个CSS选择符都会匹配一个DOM节点,然后浏览器会基于层叠、继承和特殊性来计算每个DOM节点的最终样式。
在渲染树中,每个节点表示要渲染到屏幕上的信息。
在构建完成的渲染树中,节点都应该知道了自己是什么颜色、文本使用哪种字体显示,以及是否有明确的宽度,等等。
浏览器会遍历渲染树,确定每个对象显示在页面上的什么位置,这个过程叫布局(layout)或重排(reflow)。
确定了每个渲染对象的位置和属性后,浏览器可以计算出它们在屏幕上占据的像素数,这个过程叫绘制。
浏览器如果发现最终图像的某一部分不影响页面其他内容的显示,也可能决定把绘制拆分成不同的任务,每个任务负责绘制页面上特定的部分,或者叫层。应用了滤镜或混合模式的元素,需要确定如何与其他层混合。这个先拆分为层,再组合起来的过程叫合成(compositing)。
1.2 优化渲染性能
为保证屏幕上的页面能平滑变化,最好能在16毫秒以内完成重绘。16毫秒对应的屏幕刷新率为60Hz。
有些变化几乎不会影响性能,比如滚动页面。这时候浏览器只要把整个渲染结果重新绘制到不同位置即可。如果某些变化会导致页面上的样式改变,那么就可能会影响性能。
2.内部代码质量:以人为本
代码的内部质量从几个方面来衡量:
- 复用性。如果修改某个方案,是否需要修改很多地方?
- 可读性。其他人阅读你的代码时,是否能很快读懂?
- 可移植。你写的一段代码是可以独立使用,还是必须依赖项目的其他代码才能用?
- 模块化。能否将你的代码以不言自明的方式组织起来,放到其他地方重用?
2.1 理解CSS
CSS很容易学会。作为一个设计师,应该能做到拿起一个网页就可以给它应用样式。换句话说,使用它不需要多高深的软件编写知识。
如果只是做一个原型草稿,那么代码质量倒无所谓,能用就行。然而,一旦涉及线上的产品,代码质量就可能产生深远的影响。它关系到维护成本的高低,出现bug的可能性,以及新人上手的难易。
2.2 代码质量的例子
<div id="pink-box">
<p>This is alert message implementation one</p>
</div>
div#pink-box {
border-radius: .5em;
padding: 1em;
border: .25em solid #d9c7cc;
background-color: #ffeded;
color: #373334;
}
ID选择符主要是用于页内链接,或作为JavaScript的接入点。当然把它们用作CSS选择符也完全可行,但ID选择符的高特殊性导致难以覆盖它们的样式。
选择符前面还加了div
,目的是限定ID选择符。这种元素与ID或类选择符共用的情形也很常见,但通常是用于覆盖某些太过特殊的选择符的。
改进的实现:
<div class="message">
<p>This is a <code>message</code> box</p>
</div>
<div class="message message-warning">
<p>This is a <code>message message-warning</code> box</p>
</div>
<div class="message message-success">
<p>This is a <code>message message-success</code> box</p>
</div>
.message {
border-radius: .5em;
padding: 1em;
border: .25em solid rgba(0, 0, 0, 0.15);
background-color: #ffffed;
color: rgba(0, 0, 0, 0.8);
}
.message-warning {
background-color: #ffeded;
}
.message-success {
background-color: #edffed;
}
.message + .message {
margin-top: 1em;
}
2.3 管理层叠
我们可以归纳几条有助于提升代码质量的原则:
- 以类名作为应用样式的主要手段;
- 类名要顾名思义,清晰明了;
- 通过拆分出单一用途的规则来避免不必要的重复;
- 不要把元素类型和样式规则绑定在一起。
这几条原则有一个共性,即限制层叠效应,主要是通过控制特殊性实现的。
2.4 管理复杂性
CSS方法论归根结底是为了管理复杂性。
即使没有CSS(包括JavaScript),网页本身也应该能传达自身的信息。
HTML规范中关于类名的描述:
作者给class属性赋什么值并没有限制,但我们推荐使用能够描述内容本质而非描述内容表现的名称。
CSS规范中对类名的描述:
CSS为class属性赋予了太多能力,作者可以完全自主地设计他们自己的“文档语言”,以几乎没有什么表现性倾向的元素(如HTML中的div和span)为基础,并通过class属性指定样式信息。作者不应该这样做,因为文档语言的结构化元素通常具有公认的含义,作者定义的类则没有。
3.工具与流程
CSS没有通用编程语言的语法,循环、函数、列表、变量,这些都没有。
有人为CSS写了另一种语法,叫预处理器,它能把基于通用编程语言的语法编写的样式转换成CSS。目前常见的预处理器有Sass、Less、Stylus、PostCSS等。
Sass(syntactically awesome style sheets,语法超帅的样式表)是最流行的。编写Sass最常用的方式使用CSS的超集,叫SCSS。换句话说,SCSS支持一切有效的CSS语法,此外又加上了Sass特有的功能。
4.工作流工具
使用Node和Gulp构建CSS工作流
Node是JavaScript在浏览器之外的实现,可用于任何需要编程实现的任务。自从Node问世以来,大量前端开发工具都是基于JavaScript的,正所谓“一客不烦二主”。
说到前端工作流,有很多Node工具,像Grunt、Gulp、Broccolli,都是专注于实现构建任务的。这些工具都是可配置的,而且多任务之间可以连缀输出,共同实现完整的流程。
5.未来的CSS语法与结构
CSS特性受到浏览器支持的程度并不一致,在使用新特性时要考虑渐进增强这一原则(尽管很多特性已经得到普遍支持,但对于确实不支持它们的浏览器,应该也有相应的备用实现)。
Web组件指的是一组规范,可以让开发者把HTML、CSS和JavaScript打包成一个真正完备、可重用的组件,就像原生的元素一样。Web组件可以直接放到项目里使用,不必担心样式或脚本会发生命名冲突。
参考资料:
- 《精通CSS》— [英] 安迪·巴德、[瑞典] 埃米尔·比约克隆德