那些年被我们误解的 CSS

298 阅读7分钟

作者:初生

对于每个前端工程师来说,CSS 并不陌生,丰富多彩的 web 站点,大多都在使用它。

即便 CSS 进入 web 世界 24 年已久,我们依旧无法彻彻底底琢磨透它的心思。

CSS 就像一位面蒙薄纱的少女,时而楚楚动人,时而神秘莫测,好似身负沉重的包袱,仍一直努力追寻更好的生活。

不像大多数编程语言一样清朗刚烈、心性了然,CSS 如窖藏红酒一般,需要细细琢磨品味,才能领悟其中奥妙。

今天我们一起来了解一下,平日里大家对 CSS 的一些误解

名字来由

CSS,即层叠样式表(Cascading Style Sheets),是一种样式表语言,用来描述 HTML 或 XML 等文档内容的布局与排版。

从名字便可以看出它“层叠”的特性,这也是它打败了其他样式表,活到今天的原因之一。

CSS 的主要缔造者,哈肯·维姆·莱,他的母亲从事这她热爱的出版行业工作,在文件编排方面具有丰富的经验。也是受此影响,哈肯·维姆·莱将许多出版印刷领域的特性带到了 CSS 中,其中就包括“层叠”特性。

CSS 出现的目的,是为了解决在互联网诞生初期,HTML 无法像传统纸质印刷品一样,完美展现文档内容的排版问题。

哈肯·维姆·莱指出,传统纸质印刷品,属于后绑定,即内容创作者提供内容,出版公司负责排版。

而 web 世界中,HTML 携带者内容,到达每个用户的浏览器里面,最后才组合展现,这便是晚绑定(比后绑定更后)。

因而,web 页面的排版样式,可能会被多次解读:浏览器默认样式、开发者提供样式、用户自定义样式

这也是目前现代浏览器里面,CSS 覆盖的优先级,正是利用了 CSS 的层叠特性来实现的。

img

历史包袱

正式由于 CSS 诞生初期参考了印刷行业标准,所以引入了很多如今看来奇怪的特性,比如:floatmargin 边距折叠。

float

float 加入 CSS 的目的,是为了让图片更好地和文本融合,就好像我们在 word 中排版一样,让文本环绕于图片。

imgimg

由此可以看出,float 的设计初衷,是一种“排版属性”,而不是用来布局

但是在 CSS3 还没有广泛应用的时候,在 IE 还活着的时候,我们不得不使用 float 来完成布局工作。

使用 float 以后,会导致当前元素脱离常规文档流,还要考虑父元素如何清除浮动,给开发者带来的额外成本,我们本可以做得更优雅。

幸好现在 flex 已经普及,我们可以真正使用“布局属性”完成布局工作,让 float 回归本真。

margin 边距折叠

margin 表示盒模型中边框到最外层举例,叫做外边距。

margin 的边距折叠,是每个前端初学者必须经历的噩梦。

前文我们反复提到,CSS 设计初衷是为了让印刷排版在 web 上展现,而传统印刷更多的是文本排版,例如调整文字大小、段落缩进、行间距等。

在传统印刷排版中,margin 可以理解为相邻两个段落间的缝隙大小,即 word 中的段前/段后间距。

那么为什么垂直 margin 需要折叠?

假设我们想在 web 页面中还原设计稿,我们可以测量设计稿中两个段落间高度,赋给 margin-top / margin-bottom 即可。如果没有了折叠,那么我们就需要把 margin 的值减半再填入,不够直观。

那么为什么只有垂直方向 margin 折叠,水平方向不折叠呢?

据标准说,这样更好看,更符合设计师的需要。┓( ´∀` )┏

vertical-align

说道了排版,就不得不提 vertical-align 文本对齐的问题,已经有太多文章来讲其中的规则了,本文不再赘述。

但我们从属性分类角度看,vertical-align 仍然属于排版属性,而不是布局。术业有专攻,拿它来做文字排版以外的工作,当然是不适合的(比如图文混排的居中)。

被忽略的细节

除了历史包袱对开发者的迷惑,还有一些 CSS 标准的细节,容易被大家忽略,从而导致一些奇怪的 bug。

伪元素

伪元素顾名思义,就是“假的元素”。

伪元素的诞生,主要是为了满足开发人员,出于装饰的目的,想要向 DOM 插入节点(实际没有),但是又不想破坏 HTML 代码的需要。

也正是由于伪元素是展现相关,不存在于 DOM 中,所以当伪元素的父元素设置为 display: none 的时候,伪元素也是不存在的,通过 Chrome 的 devtools 仍然能看到父元素,但是看不到 ::before 或者 ::after

img

不过随着前端技术的发展,伪元素有了很多新的用法,例如直接将 DOM 属性值赋给 content。用这个功能,我们可以实现自定义 placeholder 给任意元素。

img

height: 100%

height: 100% 这段代码,我们经常在项目中使用,它总是奏效的吗?

从字面意思看,设置 100% 表示当前元素的高度和父元素相同。

但是使用百分比有一个前提,就是父元素的高度是可计算的。比如,父元素 height: 100pxheight: 50%。只有固定值或百分比,父元素的高度才是不依赖子元素的。否则父元素依赖子元素确定高度,子元素高度又等同于父元素,陷入死循环。

因而在 CSS 中使用百分比的时候,一旦可能造成死循环的场景,规则都会限制至少有一者是可以独立计算出来的,否则就会回退成默认值height: auto

引用路径

我们先思考一个小问题:

http://a.com/a/a.html 网站内,通过 <script src="http://b.com/b/b.js"></script>b.js 又在运行时请求了接口 ./c/c.get.json,请问 c.get.json 的完整路径是什么?

我想大多数小伙伴都能答出是 http://a.com/a/c/c.get.json,我们项目中经常这么使用。

如果是:

http://a.com/a/index.html 网站内,通过 <link href="http://b.com/b/b.css"></script>b.css 又引用了一张图片 ./c/c.jpg,请问 c.jpg 的完整路径是什么?

通过简单的 demo 验证,可以看出,图片的完整路径是 http://b.com/b/c/c.jpg

img

由此可见,外部链接引入的 js 请求的 xhr 内容,是相对于当前页面的 URL;而外部引入的 CSS 文件,则是相对于当前 CSS 文件 URL 本身的

发音错误

CSS 的属性和值大多很简短,读起来并不困难,但是还是有一小部分可能会被读错。

属性错误读音正确读音
margin/'mʌgɪn//ˈmɑːrdʒɪn/
width/waɪdθ//wɪdθ/
wrap/wɑːp//ræp/
align/ə'lɪn//ə'lain/

总结

web 标准化,一直是整个互联网领域各大厂商和科研机构努力的方向。正式由于如今标准化广泛普及,让开发者有更多时间创造在所有用户浏览器上,都能生动展现的 web 页面。

CSS 正是 web 世界的着色剂,丰富多彩的页面缺它不可。

我们要珍惜标准化给 web 生态带来的进步,尽量遵守标准,消除歧义和 bug,给用户带来更加统一的 web 体验。

参考

  1. 哈肯·维姆·莱:层叠样式表;cncuckoo.github.io/cssthesis

  2. 寸志:扒一扒 CSS 语言的诞生史;zhuanlan.zhihu.com/p/21740082

  3. 贺师俊;www.zhihu.com/question/25…

  4. MDN;developer.mozilla.org/zh-CN/docs/…