8

JavaScript 作为一个创始人拍脑袋 10 天搞出的语言,JS 中包含了很多在今天看来很多不应该出现在现代语言中的诡异特性。其实,作为 Web 中必不可少的 CSS 语言也不逞多让。今天我就来聊聊我认为的那些最诡异的 CSS 特性。

overflow-x: scrolloverflow-y: visible

overflow 有个很诡异的特性。标准 规定:当 overflow-x overflow-y 其中有一项不为 visible,另一项中的 visible 值被计算为 auto

http://jsfiddle.net/yrvk6104/

这个诡异的设定经常会导致设计一些包含子菜单的侧边栏时出问题。侧边栏的 overflow-y: scroll 会强制将 overflow-x 设置为 auto,导致绝对定位的二级菜单显示不出来。解决方案只能是把一级菜单的 position: relative 去除(或直接改用固定定位),然后使用 JS 计算二级菜单应该摆放的位置。

值得一提的是:最近刚通过了一项 CSS 规范允许 overflow 一次指定两个值:https://github.com/w3c/csswg-...,它只是 overflow-x overflow-y 两属性连用的简写而已,对现有行为没有影响。

外边距折叠(margin collapsing,或简称边距折叠)

据说这个诡异的特性最初设计是为简化文章排版的。

https://jsfiddle.net/u3roktvg/1/

如示例:p 标签上下都有 1em 的边距,由于边距折叠的特性,上下相邻的 p 标签只相距 1em。第一个 p 标签和外层的 h1 也发生的边距折叠。如果打开 p 标签外层 div 的边框,可以看到 p 标签距离 h1 还应该更远。

边距折叠有几个基本的要求:

  1. 只有上下边距会发生折叠
  2. 发生边距折叠元素的 边距 必须位置上相邻(注意这里是边距占用的空间相邻,包括相邻同级元素的边距重合,和父子级元素边距重合)。边距之间不能有非外边距占用空间(例如 borderpadding 等)阻隔

还有一种空元素的情况,我认为可以算是第二种情况的极端例子:https://jsfiddle.net/u3roktvg/2/

还有两个不发生边距折叠的情形:

  1. 拥有新的块级格式上下文的元素(display: flow-rootoverflow: hiddenposition: absolute 等)其子元素不会和其外部其他元素发生边距折叠
  2. 弹性布局元素的子元素之间不发生边距折叠

这两种情形通常可以用于规避边距折叠,给父元素设置 display: flex; flex-direction: column 可以解决一半以上边距折叠的情况了。

另外,css-tricks 上有一篇很好的文章:What You Should Know About Collapsing Margins

margin、padding 的百分比取值

规定:当元素的 margin、padding 取值为百分比时,其值始终按父元素的 宽度 计算,包括上下内外边距。

当然了,如果按照正常思维上下边距百分比取值基于父元素的高度计算,反而不如现在这样基于宽度计算有用:因为竟然有人想出了用这种特性实现保持元素的高宽比。

一个保持高宽比的例子:

https://jsfiddle.net/t75gnqwq/

不知道伟大的 CSS 之父设计这两个属性时是不是考虑到了这一层😂有人提出过一个名词叫“基于巧合的编程”,那么这种规范叫做“基于巧合的设计”再好不过了

transform 中的 position: fixed 元素

固定定位position: fixed)简而言之(不太规范的描述)就是 固定 基于视口绝对 定位

但是!!!标准又规定:当一个固定定位的元素的直接或间接父级有包含 transform 不为 none 的元素时,这个元素会改为基于该父级元素元素绝对定位。

我估计不少移动端开发者都多遇到这样的问题:某一天他终于受不了原生滚动的卡顿,痛定思痛上了 iscroll,然后发现其中所有的固定定位元素位置都跑掉了。WTF?

然而这个规范定义的却不太寻常:position: fixed 定义在 css-position 规范里。而后面的那个补充说明却写在 css-transforms 规范里,后面还附带了一个 ISSUE,好像标准的制定者似乎不太情愿指定这样的规范。我简单考据了一下,这个规范应该是浏览器先实现成了这样,然后倒逼标准制定者加了这一条规范,可以算是一个浏览器逆袭标准的例子。然而有人给 Chrome 开的 bug 已经被标记为 won't fix,情况不大可能(至少在短期内)有什么转变。

逆来顺受终归是程序员的命。

不过话说回来,就像 padding-top: 50% 一样,这个诡异的特性说不定也有用处:它提供了一种将绝对定位的参考元素跳过最近非 position: static 元素的一种方式。

http://jsfiddle.net/xnw59zcr/3/

示例中 当前显示第n个菜单项 这个 li 自身是放在二级菜单里的,直接使用 position: absolute 会跟随二级菜单的位置变化不符合需求,而如果使用 position: fixed 元素相对视口的未知又不固定。这时,position: fixedtransform: scale(1) 连用这个 trick 就派上了用场。

你还见过哪些诡异的 CSS 特性呢?

https://jsfiddle.net/1b4swamw/


CarterLi
1.3k 声望102 粉丝