你了解 CSS 吗?在六个月前,我提供了一个在线免费 CSS 测试系统。测试结果表明很多一线开发者并没有如他们所想的那样了解 CSS。目前有超过 3,000 人参加了该项测试,平均成绩只有 55 分。
但是,嘿,平均分本身并没有什么意思。我更加关心大家都栽到了哪些问题上。这篇文章中,按照出错的程度将其中三个问题列出来。我会和你讨论每个问题,告诉你哪个答案被选择的最多,然后解释正确答案。
可以肯定地说,如果你读完这篇文章后参加测试,将会有不公平的优势!
第一个问题对于有文本样式常规操作经验的开发者来说应该很简单:
想要让站点内文字默认为双倍行距。下面哪个 line-height 值是最佳实现方式?
对于这4个答案,你可能觉得仅仅凭运气也会有 25% 的人会答对,但仅仅 31% 的人回答正确!花上一分钟时间选择你认为的正确答案,然后继续。
首先排除,double 只是用来混淆你。 line-height 接受的唯一关键字是 normal。我很高兴地说,仅仅有 9% 被这个选项蒙蔽。尽管,剩下的三个答案都非常得普遍。
大多数测试者选择了 2em(39%)。实际上,2em 确实会将它所应用的元素内的文本渲染为双倍行距;不过 200% ,仅仅有 21% 选择了这个答案!或者 em 相比百分数更加流行, 又或者人们根本就没有理解它们。
然而,正确答案是 2。
这是一个很久以前的一个教训,那时我第一次学习 CSS。确保将 line-height 指定为一个无单位的数值;这样一来,指定了不同 font-size 的子元素将会继承这个数值而不是一个固定的高度。
我们假设页面默认的 font-size 是 12pt ,不过它也会包含了一个 font-size 为 24pt 的头部。如果你将 body 的 line-height 设置为2em 或者 200%,那样在文档中(当然也包括头部)就会得到一个 24pt 的行高(body 的 font-size 的 2 倍)。因而,头部就是单倍行距,而不是双倍!
相反,将 line-height 设置为 2 会告知浏览器保持 font-size/line-height 比例,即便文字的尺寸发生变化。body 的行高将是 24pt,而头部的文字为 24pt,行高也将自动增长为 48pt。
这个问题有一点棘手。需要一些 CSS 布局常用到的“奇技淫巧”:
仅仅借助下面的哪个 CSS 属性,可以实现 HTML 元素部分重叠?
请选择一个你认为的正确答案?OK,我们深入看一下。
同样,有一个很容易排除的选项: background。除了 2% 的测试者外都避开了它,知道它控制背景颜色和图像。
很不幸,很多测试者直接选择了 z-index。几乎有 46% 栽倒在这个选项上。我猜测是因为他们没有真正地理解 z-index的工作原理。实际上,自身设置 z-index 属性根本无济于事;你还需要设置元素的 position 属性让 z-index 起作用。简而言之, z-index 控制了部分重叠元素间的堆放顺序,不过前提是它们要重叠。MDN 上有一篇非常棒的文章叫做《理解 CSS z-index》,非常值得仔细阅读。
如果你曾用到过,overflow 同样也很容易排除。它用来在一个固定尺寸的盒子内控制内部元素的行为:是否被遮盖,是否在盒子边框外部展示,等等。而且,这会需要一些其他 CSS 属性所控制的盒子尺寸;仅仅通过它是不会导致部分遮盖的。然而,22% 的测试者认为它可以。
剩下的就是 margin,也就是正确答案。仅仅 30% 的测试者选择了它。你可能好奇究竟一个属性如何做到元素间的相互遮盖。如果你具备一些 CSS 布局的经验,答案应该很明显:负值 margin 让它们相互遮盖。
为了演示这个,我创建了一个仅有两个 div 元素的页面。将第二个 div 的 margin-top 值设置成负值,比如 -100px。砰!现在第二个 div 覆盖了第一个 div 100 像素。
实际上,你几乎不会有意地这样覆盖一个区块,不过负值 margin 在处理外层空间小于 HTML 元素大小的情况时出奇地好用。
对 web 设计历史爱好者来讲,在 2005 年负值 margin 实现的部分覆盖元素使得三列页面布局成为可能,比如所谓的One True Layout(以及后来的圣杯布局)。
最后一个问题有一点卑劣,我承认。不过只有 23% 的测试者回答正确(比碰运气还糟糕!)。毫无疑问,它挖出了一个疑点。
下面哪个效果可以通过伪元素很好地实现?
当用户将鼠标悬停在超链接上时,为其添加一个投影;
其中三个效果需要借助伪类实现;仅仅有一个需要伪元素。你能区分出不同吗?
伪类是一个真实 HTML 元素上的一个特殊的状态。可以认为是浏览器在特定条件下将一个虚拟的类自动应用于某个元素。
伪元素是 HTML 文档的一部分,尽管它不是真实的 HTML 元素,但是 CSS 允许你为它设置样式。就像是虚拟的 HTML 元素——尽管它没有真实的 HTML 标签,但你仍可以为其添加样式。
先记住这点,我们再来看看下面的选项:
超链接是一个真是的 HTML 元素。仅仅在特殊情况下(鼠标悬停)为其应用样式,也就是说我们需要使用伪类。该情况下你应该使用 :hover 伪类。
22% 的测试者误认为这是伪元素。
一样不对, label 是一个真实的 HTML 元素,不是虚拟的。当复选框被选中时,浏览器会将 :checked 伪类应用于它。然后,你就能够在选择器中使用它为复选框添加样式,甚至和它相邻的 label 元素(比如:使用相邻元素选择器 +)。
20% 的测试者认为这是一个伪元素。
这着实愚弄了很多人,不过重申一遍我们讨论的是将样式应用于真实的 HTML 元素(在本例中是 tr 元素)。在各自父元素包含的子元素中的偶数或者奇数行的 tr 只是另外一种符合伪类的情景。
在这个示例中,对于偶数行伪类是 :nth-child(even)(或者 :nth-child(2n)),对于奇数行则是 :nth-child(odd) (或者 :nth-child(2n+1))。
我猜测它仅仅因为 :nth-child 和伪元素听起来都和真实的 CSS 特性很相似,但是 36% 的测试者将它选择成伪元素。
很明显,这是正确答案。现在,但愿我们的讨论足够清晰。在弹性布局中,你无法看到页面中的 HTML 代码只能假想“里面仅仅包含段落文本的第一行”。浏览器会根据段落的宽度进行换行,这在弹性布局中是你无法控制的。
:first-line 是允许你将样式应用于文本块第一行的伪元素,无论第一行是在何处换到第二行。
如果你正在想“OK,确实讲得通,但是拜托——没一个人知道伪元素和伪类之间有什么区别”,确实 W3C 也同意你的观点。CSS3 选择器规范中,在区分二者上做了一次尝试,改变了语法——伪元素选择器使用两个冒号(::first-line),而伪类依旧使用一个(:hover)。当然,为了向后兼容,浏览器必须支持这两个版本。
是滴,如我所说:卑劣。不过,如果你和我一样是一个 CSS 骇客,我确信你了解伪元素和伪类的区别。
这就是测试中三个棘手的问题。如果你仅仅对一个有信心,还可以。两个?做得不错。答对了三个,我非常乐意听到!现在,我已经公布了这些问题的答案,同样也可以用这些观点解决更棘手的 CSS 问题。请在评论中留言。
如果你享受这些问题,或许你可以尝试一下测试的其他部分。请放心,其他的问题比这些要简单许多许多!
Kevin Yank 于 1995 年接触 Web 开发,是一位备受尊重的技术类作者。Kev 更是一位知名作家、演说家和 JavaScript 专家。他热衷于让每个人都能轻易地理解 Web 技术。是的,包括你!
原文:3 Things (Almost) No One Knows About CSS
阅读详情 -> 关于CSS[几乎]没人知道的3件事 – 前端外刊评论 – 知乎专栏.