众所周知,MDN 于 3 月份 推出了新的设计。它非常漂亮!并且其中包含一些有趣的 CSS 宝石,值得一看。其中一个宝石是卡片组件如何处理截断文本。

很酷,对吧?我很快就会将其拆解,但有几件事让我对这种方法产生了兴趣。
- 这是一个有意截断内容的例子。我们在其他地方将其称为 CSS 数据丢失。虽然数据丢失通常是一件坏事,但我喜欢它在这里的用法,因为摘录旨在作为完整内容的预告。
- 这与使用
text-overflow: ellipsis
截断文本不同,这个话题最近在 Eric Eggert 分享 他对此的担忧时被提及。反对它的主要论点是,无法恢复在截断中被截断的文本——辅助技术会宣布它,但有视力障碍的用户无法恢复它。MDN 的方法在这方面提供了更多控制,因为截断仅仅是视觉上的。
那么,MDN 是如何做到的呢?就 HTML 而言,这里没有什么太花哨的,只是一个包含段落的容器。
<div class="card">
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Inventore consectetur temporibus quae aliquam nobis nam accusantium, minima quam iste magnam autem neque laborum nulla esse cupiditate modi impedit sapiente vero?</p>
</div>
我们可以添加一些基本样式来巩固内容。
同样,没有什么太花哨的。我们的目标是在第三行之后截断内容。我们可以为段落设置一个 max-height
并隐藏该溢出内容。
.card p {
max-height: calc(4rem * var(--base)); /* Set a cut-off point for the content */
overflow: hidden; /* Cut off the content */
}
等等,calc()
是怎么回事?请注意,我在前面设置了一个 --base
变量,它可以用作通用乘数。我用它来计算 font-size
、line-height
、卡片的 padding
,以及现在段落的 max-height
。我发现使用常量值更容易,尤其是在我需要的尺寸像这样真正基于比例时。我注意到 MDN 使用了类似的 --base-line-height
变量,可能是出于同样的目的。
让第三行文本淡出?这是段落 :after
伪元素上的经典 linear-gradient()
,它固定在卡片的右下角。因此,我们可以设置它。
.card p:after {
content: ""; /* Needed to render the pseudo */
background-image: linear-gradient(to right, transparent, var(--background) 80%);
position: absolute;
inset-inline-end: 0; /* Logical property equivalent to `right: 0` */
}
请注意,我调用了一个 --background
变量,该变量设置为与 .card
本身使用的相同背景颜色值。这样,文本看起来像是淡入背景。我发现我需要调整渐变中的第二个颜色停止点,因为当渐变完全混合到 100% 时,文本不会完全隐藏。我发现 80%
对我的眼睛来说是一个最佳点。
是的,:after
需要 height
和 width
。height
是 --base
变量再次发挥作用的地方,因为我们希望将其按比例缩放至段落的 line-height
,以便使用 :after
的高度覆盖文本。
.card p:after {
/* same as before */
height: calc(1rem * var(--base) + 1px);
width: 100%; /* relative to the .card container */
}
添加一个额外的像素高度似乎可以解决问题,但是当我查看 DevTools 时,MDN 能够在没有它的情况下实现它。再说一遍,我也不会使用 top
(或 inset-block-start
)来沿该方向偏移渐变。🤷♂️
现在 p:after
是绝对定位的,我们需要在段落上显式声明相对定位以保持 :after
在其流中。否则,:after
将完全从文档流中移除,并最终出现在卡片之外。这将成为 .card
段落的完整 CSS。
.card p {
max-height: calc(4rem * var(--base)); /* Set a cut-off point for the content */
overflow: hidden; /* Cut off the content */
position: relative; /* needed for :after */
}
我们完成了,对吧?不!该渐变似乎没有处于正确的位置。
我承认我在这一点上犯了一个错误,并在 MDN 上启动了 DevTools 以查看我错过了什么。哦,是的,:after
需要显示为块级元素。当为它添加红色边框时,这一点一目了然。🤦♂️
.card p:after {
content: "";
background: linear-gradient(to right, transparent, var(--background) 80%);
display: block;
height: calc(1rem * var(--base) + 1px);
inset-block-end: 0;
position: absolute;
width: 100%;
}
现在都放在一起了!
并且,是的,VoiceOver 看起来听起来尊重完整文本。不过,我还没有测试任何其他屏幕阅读器。

我还注意到,MDN 的实现从 p:after
中删除了 pointer-events
。这可能是一种很好的防御策略,可以防止在选择文本时出现奇怪的行为。我添加了它,并且在 Safari、Firefox 和 Chrome 中,选择文本确实感觉更流畅了一些。
在示例中仅使用
lch()
看起来有点傻,因为在撰写本文时,只有 Safari 支持它。回退会很好,因为在我这边所有示例看起来都坏了。但除此之外,文章写得很好 :)
非常正确。这实际上是我试图让自己习惯编写语法,但让我们改用一些 hsl()。
这是我使用蒙版的想法 :)
演示:https://codepen.io/t_afif/pen/jOzamEB
使用蒙版的额外好处是,您不必关心背景,因为您将拥有真正的透明度。
哇,太棒了!
有没有轻量级的方法来检测文本是否溢出并有条件地应用此类技术?否则,淡出可能会发生在本来可以很好地适应的短段落上。使用
overflow: ellipsis
的原因之一是免费获得该溢出检测功能。我真的很希望我们有一个选择器用于此:
::overflow-mark
一如既往,好文章,但应该命名为“即使可以,也绝不能做的事情”。:)
溢出省略号的目的是隐藏由于视图约束而不可见的文本,且没有任何方法。它有助于更有效地呈现文本并使其看起来自然(就像任何溢出隐藏一样)。它不会向任何想要访问内容的人隐藏内容,因为引擎不会修改您的 DOM。
提出的解决方案只会通过添加无意义的工作来降低渲染速度。这就是为什么现代网站如此愚蠢的原因。没有内容、72pt 字体、4K 背景、随机服务工作者、来自随机域名(你好谷歌)的随机服务工作者以及漂亮的“省略号”。
PS:无冒犯之意,我可能只是太老了,并且不断抱怨损坏或必须简单的事情。它们曾经是并且在“UX”专家开始搞乱我屏幕上的每个像素、每个操作系统之前工作得很好。
它当然可以归类于类似的东西。我通常不愿轻易否定某件事,因为新的用例和场景会不断出现。也许这种效果在其他地方会派上用场。就我个人而言,这种方法之所以让我感兴趣,是因为它解决了人们对
text-overflow: ellipsis
的一些担忧。Weber 能否详细说明 CSS 中使用的此基本乘数的想法?
很久以前就做过了。
我认为需要设置
display:block;
值得解释一下。起初这对我来说非常奇怪,因为绝对定位的元素默认情况下表现得几乎像是块级元素(例如可以调整大小),并且在类似情况下我从未这样做过。问题在于
:after
没有水平定位,而是保持其在文本流中的位置。如果您将其设置为display:block;
,它当然会从文本流中分离出来并形成自己的行,并在左侧水平定位。如果您使用旧式
right:0; bottom:0;
进行定位,则不会遇到此问题。作为display:block;
的替代方案(并且比right:0;
或left:0;
更现代),您可以使用inset-inline-end:0;
,这可能更直观。MDN 的示例看起来不错。
在使用 Brave 浏览器 1.42.88(使用 Chromium 104.0…)时,效果不起作用。