何时避免使用 text-decoration 简写属性

Avatar of Šime Vidas
Šime Vidas

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

在我最近一篇关于 Chrome 中 CSS 下划线错误 的文章中,我讨论了 text-decoration-thicknesstext-underline-offset,这两个相对较新且广泛支持的 CSS 属性,它们使我们能够更好地控制下划线的样式。

让我在一个简单的示例中演示 text-decoration-thickness 的实用性。 Ubuntu 网页字体 具有相当粗的默认下划线。我们可以像这样使该下划线变细

:any-link {
  text-decoration-thickness: 0.08em;
}
Showing two links, a default and one that decreases the text-decoration-thickness.

/explanation 在本文中,我将使用 :any-link 选择器而不是 a 元素来匹配超链接。使用 a 标签作为选择器的问题在于它匹配所有 <a> 元素,即使那些没有 href 属性且因此 不是超链接 的元素。:any-link 选择器仅匹配是超链接的 <a> 元素。Web 浏览器在其用户代理样式表中也使用 :any-link 而不是 a

悬停下划线

许多网站,包括 Google 搜索和维基百科,都会从链接中删除下划线,并且仅在用户将鼠标悬停在链接上时才显示它们。从正文中的链接中删除下划线 不是一个好主意,但在链接间隔较大的地方(导航、页脚等)这样做可能是有意义的。综上所述,以下是在网站标题中为链接实现悬停下划线的简单方法

header :any-link {
  text-decoration: none;
}

header :any-link:hover {
  text-decoration: underline;
}

但是,存在一个问题。如果我们在浏览器中测试此代码,我们会注意到标题中的下划线具有默认粗细,而不是我们之前声明的较细样式。为什么在添加悬停下划线后 text-decoration-thickness 停止工作了?

让我们再次查看完整的 CSS 代码。您能否想到自定义 thickness 不适用于悬停下划线的原因?

:any-link {
  text-decoration-thickness: 0.08em;
}

header :any-link {
  text-decoration: none;
}

header :any-link:hover {
  text-decoration: underline;
}

这种行为的原因是 text-decoration 是一个简写属性,而 text-decoration-thickness 是其关联的长写属性。将 text-decoration 设置为 noneunderline 会产生重新初始化其他三个文本装饰组件(thicknessstylecolor)的副作用。这在 CSS 文本装饰模块 中定义。

text-decoration 属性是用于在一个声明中设置 text-decoration-linetext-decoration-thicknesstext-decoration-styletext-decoration-color 的简写。省略的值将设置为其初始值。

您可以在浏览器的 DevTools 中确认这一点,方法是在 DOM 检查器中选择其中一个超链接,然后在 CSS 面板中展开 text-decoration 属性。

DevTools screenshot showing text-decoration styles on the :any-link pseudo-selector.

为了使 text-decoration-thickness 在悬停下划线上起作用,我们需要对上述 CSS 代码进行一些小的更改。实际上,有多种方法可以实现这一点。我们可以

  • text-decoration 之后设置 text-decoration-thickness
  • text-decoration 简写中声明粗细,或者
  • 使用 text-decoration-line 代替 text-decoration

选择最佳的 text-decoration 选项

我们首先想到的可能是简单地在 :hover 状态中重复 text-decoration-thickness 声明。这是一个快速简单的修复方法,确实有效。

/* OPTION A */

header :any-link {
  text-decoration: none;
}

header :any-link:hover {
  text-decoration: underline;
  text-decoration-thickness: 0.08em; /* set thickness again */
}

但是,由于 text-decoration 是一个简写,而 text-decoration-thickness 是其关联的长写,因此实际上无需同时使用两者。作为简写,text-decoration 允许在一个声明中同时设置下划线本身和下划线的粗细。

/* OPTION B */

header :any-link {
  text-decoration: none;
}

header :any-link:hover {
  text-decoration: underline 0.08em; /* set both line and thickness */
}

如果您觉得此代码不熟悉,则可能是因为将 text-decoration 用作简写的想法相对较新。此属性只是随后在 CSS 文本装饰模块 中变成了简写。在 CSS 2 时代,text-decoration 是一个简单的属性。

不幸的是,Safari 尚未完全赶上这些变化。在 WebKit 浏览器引擎中,text-decoration 的简写变体仍然带有前缀(-webkit-text-decoration),并且它尚不支持 thickness 值。有关更多信息,请参阅 WebKit 错误 230083

这排除了 text-decoration 简写语法。即使我们添加了 -webkit- 前缀,上述代码在 Safari 中也不会起作用。幸运的是,还有另一种方法可以避免重复 text-decoration-thickness 声明。

text-decoration 变为简写时,引入了新的 text-decoration-line 长写来接管其旧工作。我们可以使用此属性来隐藏和显示下划线,而不会影响其他三个文本装饰组件。

/* OPTION C */

header :any-link {
  text-decoration-line: none;
}

header :any-link:hover {
  text-decoration-line: underline;
}

由于我们仅更新 text-decoration 值的 line 组件,因此之前声明的 thickness 保持不变。我认为这是实现悬停下划线的最佳方法。

注意简写

请记住,当您设置简写属性(例如,text-decoration: underline)时,值中任何缺失的部分都会重新初始化。这也是为什么如果您随后设置 background: url(flower.jpg),则样式(如 background-repeat: no-repeat)会被撤消的原因。有关此行为的更多示例,请参阅文章 “意外的 CSS 重置”