前端 / 技术 · 2022年1月8日 0

CSS 为什么那么难学?

这是知乎上的一个问题:

有很多大佬做了回答,其中提到一个名词:正交性。

这个词我是在《程序员修炼之道》(第一版)中看到的,那先说下什么是正交性:

这是一个从几何学中借来的术语。如果两条直线相交成直角,它们就是正交的,比如图中的坐标轴。用向量术语说,这两条直线互不依赖。沿着某一条直线移动,你投影到另一条直线上的位置不变。

在计算技术中,该术语用于表示某种不相依赖性或是解耦性。如果两个或更多事物中的一个发生变化,不会影响其他事物,这些事物就是正交的。

《程序员修炼之道》书中举了一个不正交系统的例子:搭乘直升机时,驾驶员突然晕倒,乘客以为可以简单的把直升机降落,谁知道他面对的是一个让人难以置信的复杂系统,任何的控制输入都有次级效应,也就是每一项改变都会影响所有其他的输入。

所以我们要尽量消除无关事物之间的影响,来设计一个正交的系统,这样我们就可以得到两个主要好处:提高生产率和降低风险。

提高生产率

  • 改动得以局部化,所以开发时间和测试时间得以降低。
  • 促进复用。
  • 正交组件组合使用,生产率会有相当微妙的提高。

降低风险

  • 正交的途径能降低任何开发中固有的风险。
  • 代码区域被隔离开来。
  • 系统更健壮。
  • 更容易的测试。
  • 与第三方平台隔离。

那接下来看看大佬们是怎么说的吧,我这里挑选了方应杭的回答:

CSS 不正交并不是对 CSS 的指责,如果能正交它肯定会做到正交的,现在的设计虽然不完美,但可能是最好的设计。下文列举的问题能在规范里找到解释不能说明 CSS 是正交的,因为正不正交应该是从表面上就能看出来的。正交一般都是对接口的约束,具体实现我不管的。本答案可以很好地解释「为什么你会觉得 CSS 难学」,至于不难的学习方式,其实是不存在的。要么你大量练习从实践中总结,要么你大量阅读文档从理论中领悟,反正 CSS 就是很难学。我是这么觉得的,如果有人问 CSS 为什么这么难学,我们就应该好好回答 CSS 为什么这么难学;至于 CSS 多牛逼,应该另开一个问题。

短答案:因为 CSS 不正交。

长答案:我先来解释一下什么是正交。你调过显示器的「亮度」、「色调」和「饱和度」吧。

  • 「亮度」就是明暗程度,值越大,屏幕越亮。
  • 「色调」就是颜色,你通过调色调,可以把红色调成绿色。
  • 「饱和度」就是鲜艳程度,值越大越鲜艳。

「正交」就是,你调节这三者中的一个时,不影响其他两个效果。

  • 你调节「亮度」的时候「色调」和「饱和度」不会变化。
  • 你调节「色调」的时候「亮度」和「饱和度」不会变化。
  • 你调节「饱和度」的时候「亮度」和「色调」不会变化。

「正交」看起来应该是理所当然的,对吧。

想象一下「不正交」的情况:你调节「亮度」的时候,「色调」和「饱和度」会跟着无规律的变化。如果是这样,你会调得想死,因为你很难调到你想要的效果。

而 CSS,就是「不正交」的。我以 width 对 margin-left 的影响为例,假设有如下代码:

.parent 里面的 .child 宽度为 300px,现在我给他添加一个 margin-left: -10px,会发现

整个 .child 左移 10 像素

好的,于是我们知道 margin-left: -10px 会让元素整体左移。

真的是这样吗?

这个时候把 width 去掉重新做实验,这是在添加 margin-left 之前:

这是在添加 margin-left 之后:

我们发现 margin-left: -10px 并没有让整个元素左移,只是让左边缘左移了,右边缘并没有动。

现在来总结一下:

  • 如果指定了 width,那么 margin-left: 10px 会使元素整体左移
  • 如果没有指定 width,那么 margin-left: 10px 只会使做边缘左移(也就是宽度扩大)

看到这里,你就会觉得 CSS 特别不正交:

  1. 为什么 width 的存在与否会影响 margin-left 的作用?
  2. 有没有 width 之外的其他属性也会影响 margin-left 的作用?恐怕你无法得知。

这就是不正交的恐怖之处,你只有把所有属性与 margin-left 一起用一下,才能得知 margin-left 的真正规律。

这还只是两个属性的影响,你能想象三个属性互相影响的情况吗?

P.S. 有些前端老手已经能「感性」地理解 width: auto 的意义,觉得这不是「不正交」。其实我只是举例说明「你无法只看一个属性就知道这个属性对应的效果,你必须结合另一个属性一起来看」。

我再举第二个例子,大家都知道 position: fixed 是相对于视口(viewport)定位的。但是这个「真理」会受另一个元素的影响……对,我知道你很震惊……

先看正常情况:

网页右边是一个 iframe,红色的 .fixed 元素相对于 iframe 视口左上角定位,与我们预期一致。

接下来我在 .box 上面加一个 CSS3 中的属性,就会改变你的认知:

父容器加了 transform 之后,fixed 定位的元素居然相对于父容器定位。

天知道以后 CSS 会不会加更多元素来影响我已经认为是真理的事情?

我说一个更实际的问题吧,你敢在接手一个项目时,在任意一个元素上加 transform 属性吗? 你不敢!除非你把它的每个子元素的属性都检查一遍……确定没有 fixed 定位。这就是「不正交」的恶心之处。

我再举一个例子,大家都知道给固定宽度的 div 加 margin: 0 auto 可以让它水平居中,很多人就问,那为什么 margin: auto 0(注意 auto 和 0 的位置反过来了)不能做到垂直居中呢?

其实是可以的:

但是必须是在当前元素有 position: absolute; top: 0; bottom:0; 的情况下才能垂直居中。或者与 flex 结合起来用也行。

这就很「不正交」了……

还有一些很常见的例子我就不一一详细列举了:

1. border、padding、overflow、display:table、display:inline-block 会影响 margin 
2. position: absolute 会影响 display 和 float
3. transform 会影响 z-index 
4. display 会影响 li 前面的小黑点 

关键在于这些例子,要一个一个记,各属性被影响的情况都不一样!

CSS 最不正交的地方就是明明有 BFC,却非要把 BFC 藏起来,然后用 overflow:hidden 和 display: inline-block 等属性来触发 BFC。但用这些属性触发 BFC 总是会有副作用,这就是典型的不正交。

要触发 BFC 就单独发明一个触发 BFC 的属性不就好了。display: flow-root; 不就是在填这个坑嘛?所以你们说 CSS 是正交的,我肯定是不服的。

怎么学习「不正交」的东西?

有一个办法:

你试的组合情况越多,就越能了解各种奇怪的现象。其实不用那么悲观,常用的组合也就几十种吧,都试出来并记下来就行了。

目前我们知道

  1. 不同属性的组合会有不同的效果;
  2. 新的属性会影响你已经学会的知识;
  3. 这些规律,毫无逻辑可言,你只能试出来。

这,就是 CSS 难学的原因。以我的经验,越是理性的人,越难理解 CSS;越是感性的人,越容易理解 CSS。这就是为什么大部分后端程序员能学会 JS,却学不会 CSS——他们太理性了。

你想用学编程的思路来学 CSS?放弃吧!你需要用学画画的思路来学习 CSS——每天不停地画画,一个鸡蛋用不同的方式画一千遍,就成了。

所以我在课上说过一句话:CSS 不是科学,CSS 是艺术。不过凡事都有例外,如果你愿意老老实实看完 CSS 规格文档,然后再写 CSS,可能就不觉得有那么多不正交的地方了,但是有多少人有这个能力和精力呢?

以上就是其中一个知乎的回答,更多的请参考:

https://www.zhihu.com/question/66167982

作为一个多年前端开发人员,确实没有正儿八经的看过 CSS 标准,多数经验是靠 出来的,也就是经验。还有一点 CSS 知识不具有积累性,特别是兼容性问题,比如之前前端噩梦 ie 的解决方法,放到现在好像也没啥用了。要是想学好 CSS 还是要好好看看标准,这里推荐一本书:

《CSS权威指南(第四版)》 https://u.dangdang.com/iAFuI

我这里还是第三版本的,今年计划系统的看看CSS的知识。