JavaScript 作为一个创始人拍脑袋 10 天搞出的语言,JS 中包含了很多在今天看来很多不应该出现在现代语言中的诡异特性。其实,作为 Web 中必不可少的 CSS 语言也不逞多让。今天我就来聊聊我认为的那些最诡异的 CSS 特性。
overflow-x: scroll
和 overflow-y: visible
overflow
有个很诡异的特性。标准 规定:当 overflow-x
overflow-y
其中有一项不为 visible
,另一项中的 visible
值被计算为 auto
这个诡异的设定经常会导致设计一些包含子菜单的侧边栏时出问题。侧边栏的 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 还应该更远。
边距折叠有几个基本的要求:
- 只有上下边距会发生折叠
- 发生边距折叠元素的 边距 必须位置上相邻(注意这里是边距占用的空间相邻,包括相邻同级元素的边距重合,和父子级元素边距重合)。边距之间不能有非外边距占用空间(例如
border
、padding
等)阻隔
还有一种空元素的情况,我认为可以算是第二种情况的极端例子:https://jsfiddle.net/u3roktvg/2/
还有两个不发生边距折叠的情形:
- 拥有新的块级格式上下文的元素(
display: flow-root
、overflow: hidden
、position: absolute
等)其子元素不会和其外部其他元素发生边距折叠 - 弹性布局元素的子元素之间不发生边距折叠
这两种情形通常可以用于规避边距折叠,给父元素设置 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: fixed
和 transform: scale(1)
连用这个 trick
就派上了用场。
完
你还见过哪些诡异的 CSS 特性呢?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。