CSS 中的魔法数字

Avatar of Chris Coyier
Chris Coyier 发表

DigitalOcean 为您的旅程的每个阶段提供云产品。 立即开始使用 200 美元的免费积分!

尽管名字听起来超级有趣,但魔法数字是一件坏事。 它是一个 老式的编程术语,指的是“未命名的数值常量”。 就像代码中插入的某个数字,它可能对程序正常运行至关重要,但对于不熟悉代码的人来说,很难理解它究竟是用来干什么的。 CSS 中充满了未命名的数值常量,但它们通常与属性和选择器一起出现,因此没什么神秘感。 不过,CSS 中确实存在魔法数字,而且它们依然很糟糕。

CSS 中的魔法数字指的是在某些情况下“有效”,但在这些情况发生变化时却很容易出错的数值。 它们通常都与字体 相关。 它们是由作者创建的,作者可能只在自己的浏览器中进行测试,并且是在理想条件下。 让我们来看一些例子,这样我们大家就能明白它们是什么,并希望在将来避免使用它们。


看看这个简单的选项卡集

每个选项卡都设置为 width: 100px;。 在这个例子中,100px 是我们的“魔法数字”。 有很多事情可能会出错。 只要添加另一个文本更长的选项卡就可以证明这一点

有点尴尬,而且可能不理想。 我们可以使用 white-space: nowrap; 来防止换行,但这可能更糟

如果我们使用 min-width 而不是宽度,我们的选项卡就不会那么容易出错

或者根本不设置宽度

如果你一定要让所有选项卡的大小都相同,你可以在 overflow: hidden;text-overflow: ellipsis; 上使用

在这种情况下,你可能需要一个 title 属性,这样就可以用某种方法显示整个选项卡名称。 你可能会认为可以通过内容管理系统来解决这个问题,只允许选项卡名称的字符数在一定范围内。 但是,那些为了可访问性而提高字体大小的用户怎么办? 这种固定大小可能对他们有害。


在最近的一篇文章 Line-On-Sides Headers 中,我使用了一个行高值,它是一个魔法数字。 假设你在带有精美 @font-face 字体的文本周围使用了这种技术。 假设该字体没有加载,或者用户覆盖了它,或者页面正在不支持 @font-face 的浏览器中查看。 备用字体将加载,而该备用字体的大小可能与自定义字体有很大不同。 备用字体外部的线条现在位置很尴尬,不像我们想要的那样居中。 魔法数字失败。

这个特定的例子 有点牵强,但我相信你们都见过 x-height 很疯狂的自定义字体。


假设你有许多内容不同的盒子。 你想把它们排列成网格,所以你把它们向左浮动。 有点乱

好吧,如果它们的高度都一样,那就没问题了!

也就是说,如果查看网站的用户与你具有完全相同的字体大小设置。 但是用户可以改变这一点。

现在出现一个大大的悲惨小号声

min-height 可以防止重叠的怪异现象,但这样一来,盒子的大小就不一样了,浮动问题又出现了。 我不会深入探讨解决方案,因为这已经很抽象了,但也许你可以使用盒子的滚动功能,或者使用一些 JavaScript 来调整大小,或者使用其他类型的布局。


Harry Roberts 在他的文章 Code smells in CSS 中指出了一个经典的魔法数字示例。

.site-nav > li:hover .dropdown{
  position: absolute;
  top: 37px;
  left: 0;
}

这将用于 CSS 驱动的下拉菜单。 菜单隐藏在屏幕外,直到父列表项被悬停,然后下拉菜单移动到视图中。 它应该放置在父菜单项的底部。 对于编写这段代码的开发人员来说,在他们当前的浏览器中,该菜单项的高度为 37px。 我相信你可以想象,情况并非总是如此。 37px 是一个魔法数字。 Harry 建议使用 top: 100% 而不是 top: 37px,这意味着“从顶部到底部”,这更不容易出错。


在文章 Fighting the Space Between Inline-Block Elements 中,-4px 是一个用于边距的数字,它可以关闭这些间隙。 这绝对是一个魔法数字。 4px 恰好是许多字体在默认 16px 的 font-size 下的空间宽度。

font-family 更改为 Monaco 之类的字体? 坏了。 将字体大小更改为更大的或更小的任何值? 坏了。

查看 那篇文章 以了解其他修复方法。

定义混淆

因为我们要说“不要使用这些”,所以我们必须正确地定义与 CSS 相关的术语。 我过去看到过许多帖子,其中并非所有人都站在同一条战线上。 (1) (2) (3)

以下是一些例子

-webkit-transform: translateZ(0);

魔法数字? 不。 只是我们过去为了提高性能而使用的一个小技巧。


.parent {
  padding: 22px;
}
.child {
  bottom: 22px;
  left: 22px;
}

魔法数字? 不。 它是一个奇怪的数字,但它不是魔法。 子元素被定位到元素的左下角,不带填充。 因为这些数字匹配,所以可以理解发生了什么。 如果它们都不一样,就意味着可能存在一些与 font-size 相关的微调部分,而这将是一个魔法数字。


top: 37px;

假设这是一个魔法数字,就像上面的下拉菜单示例一样。 我们能用 Sass 解决它吗?

$topDistance: 37px;

.dropdown {
  top: $topDistance;
}

它不再是一个“未命名的”数值常量,对吧,因为我们给它起了名字? 它仍然是 CSS 中的魔法数字。 它和以前一样脆弱。


letter-spacing: -.05em;

魔法数字? 不。 如果它是像素,它可能就是,因为像素值保持不变,所以它的效果会根据当前的字体大小而改变。 字体大小很大,几乎没有变化,字体大小很小,变化很大。 事实上,它是以相对单位表示的,这使得它不太脆弱。

最后总结

天哪,我讨厌博客文章中的这一部分,但有一个地方可以用来倾倒一些没有被整理好的小东西,感觉真好。

  • WordPress CSS 编码标准 指出 不应该使用它们。 还有其他标准吗?
  • 如果你使用的是图标字体,请记住它们是字体,所以它们会改变大小。 你不能在像素值中为它们“预留空间”,因为字体大小可以改变,但像素值不会改变。
  • 我希望这篇博客文章能不断更新,以提供魔法数字失败的良好示例,所以如果你有任何经典的例子,请在下面留言。
  • 如果你想将图像和文本居中。 vertical-align 的效果很好,但我发现它经常会偏离 1px 左右,所以我使用 postion: relative; top: 1px; 来进行调整。 这算是一个魔法数字吗? 不确定。