CSS `Line Clamping` (文本截断) (`-webkit-line-clamp`) 原理与跨浏览器兼容

各位观众老爷,晚上好!今天咱们聊点儿前端的“掐头去尾”小技巧——CSS Line Clamping(文本截断)。

这玩意儿啊,说白了,就是让文本在超过指定行数后自动截断,再加个省略号“…”意思意思。听起来简单,但要做到完美兼容,那可得好好琢磨琢磨。

1. 什么是 Line Clamping?

想象一下,你的网页上有一块区域,用来显示文章标题或者简介。但是呢,有些标题死长死长的,直接把你的布局给撑爆了。这时候,Line Clamping 就派上用场了。它可以控制文本显示的行数,超过指定行数后自动截断,避免撑爆布局。

2. -webkit-line-clamp:曾经的王者

早期,Line Clamping 主要靠 -webkit-line-clamp 这个非标准的 CSS 属性来实现。顾名思义,这是个带 -webkit- 前缀的属性,也就是说,它主要针对 WebKit 内核的浏览器(比如 Chrome、Safari)。

用法是这样的:

.clamp {
  overflow: hidden; /* 必须,超出隐藏 */
  text-overflow: ellipsis; /* 必须,显示省略号 */
  display: -webkit-box; /* 必须,将对象作为弹性伸缩盒子模型显示 */
  -webkit-line-clamp: 3; /* 必须,限制在一个块元素显示的文本的行数 */
  -webkit-box-orient: vertical; /* 必须,设置或检索伸缩盒对象的子元素的排列方式 */
}

解释一下:

  • overflow: hidden;: 必须的!超出容器的部分隐藏掉。
  • text-overflow: ellipsis;: 必须的!超出部分显示省略号。
  • display: -webkit-box;: 必须的!将元素设置为弹性盒子模型。注意,这里用的是带 -webkit- 前缀的。
  • -webkit-line-clamp: 3;: 必须的!限制显示的行数。这里设置为 3 行。
  • -webkit-box-orient: vertical;: 必须的!设置弹性盒子的方向为垂直方向。

HTML 示例:

<div class="clamp">
  这是一段非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常普通情非常非常非常非常好非常非常非常好,我们就要开始喽!

### 3. 标准的 `line-clamp` (`overflow:overlay`)

好消息是,`line-clamp` 已经标准化了!现在,我们可以使用标准的 `line-clamp` 属性了,不过,它需要搭配 `overflow: overlay` 使用,才能在更多浏览器中工作。

```css
.clamp {
  overflow: overlay;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}

注意:这里的 overflow 属性设置为 overlay,它和 hidden 的区别在于,overlay 在滚动条出现时,不会占用布局空间,而是覆盖在内容之上。这可以避免一些布局问题。

4. 兼容性问题:永远的痛

虽然 line-clamp 已经标准化了,但是兼容性仍然是个问题。

  • Chrome/Safari: 表现良好,基本没问题。
  • Firefox: 对不起,不支持。
  • Edge: 支持,但可能需要使用 -webkit- 前缀。
  • IE: 别想了,放弃吧。

所以,为了兼容所有浏览器,我们需要一些额外的手段。

5. JavaScript 辅助:终极解决方案

既然 CSS 靠不住,那就祭出 JavaScript 大法!

思路是这样的:

  1. 获取需要截断的文本内容。
  2. 计算文本的实际高度。
  3. 根据指定的行数和行高,计算出最大高度。
  4. 如果实际高度超过最大高度,就截断文本,并添加省略号。

代码示例:

function clampText(element, lineHeight, lines) {
  const text = element.textContent;
  const maxHeight = lineHeight * lines;
  element.style.height = maxHeight + 'px';
  element.style.overflow = 'hidden';
  element.style.display = 'block'; // 或者 'inline-block',根据你的需求
  const actualHeight = element.scrollHeight;

  if (actualHeight > maxHeight) {
    // 找到最后一个合适的字的位置
    let lastIndex = text.length;
    while (element.scrollHeight > maxHeight && lastIndex > 0) {
      lastIndex--;
      element.textContent = text.substring(0, lastIndex) + "...";
    }
  }
}

// 使用方法:
const element = document.querySelector('.clamp');
clampText(element, 20, 3); // 行高 20px,显示 3 行

解释一下:

  • clampText(element, lineHeight, lines) 函数接受三个参数:
    • element: 需要截断的 DOM 元素。
    • lineHeight: 行高(像素)。
    • lines: 显示的行数。
  • element.textContent 获取元素的文本内容。
  • maxHeight 计算最大高度。
  • element.scrollHeight 获取元素的实际高度。
  • 如果实际高度超过最大高度,就循环截断文本,直到实际高度小于等于最大高度。

这种方法虽然比较麻烦,但是兼容性最好。

6. CSS 和 JavaScript 的结合:优雅的降级

我们可以将 CSS 和 JavaScript 结合起来,实现优雅的降级。

.clamp {
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  /* 针对不支持 -webkit-line-clamp 的浏览器 */
  height: 60px; /* 3 行的固定高度 */
}

.no-line-clamp .clamp {
  /* 禁用 CSS 的 Line Clamping */
  display: block;
  -webkit-line-clamp: unset;
  -webkit-box-orient: unset;
}
// 检测是否支持 -webkit-line-clamp
function supportsLineClamp() {
  return 'webkitLineClamp' in document.documentElement.style;
}

// 如果不支持,添加 no-line-clamp class 到 body 上
if (!supportsLineClamp()) {
  document.body.classList.add('no-line-clamp');
  // 运行 JavaScript 的 Line Clamping
  const element = document.querySelector('.clamp');
  clampText(element, 20, 3); // 行高 20px,显示 3 行
}

解释一下:

  1. 首先,我们使用 CSS 的 line-clamp 属性,如果浏览器支持,就直接生效。
  2. 然后,我们使用 JavaScript 检测浏览器是否支持 line-clamp 属性。
  3. 如果不支持,就添加 no-line-clamp class 到 body 上,并使用 JavaScript 实现 line-clamp 的效果。
  4. 在 CSS 中,我们针对 no-line-clamp class,禁用 CSS 的 line-clamp 属性,这样就可以避免 CSS 的 line-clamp 属性在不支持的浏览器中产生影响。

这种方法可以保证在支持 line-clamp 的浏览器中使用 CSS 实现,在不支持的浏览器中使用 JavaScript 实现,从而实现优雅的降级。

7. 其他一些小技巧

  • 使用 word-break: break-all;: 这个属性可以强制单词换行,避免长单词撑爆布局。
  • 使用 white-space: nowrap;: 这个属性可以禁止文本换行,常用于单行文本截断。
  • 根据不同的屏幕尺寸,设置不同的行数: 可以使用媒体查询,根据屏幕尺寸,设置不同的 -webkit-line-clamp 值,以适应不同的屏幕。

8. 总结

CSS Line Clamping 是一个非常有用的文本截断技术,可以帮助我们更好地控制文本的显示。虽然兼容性仍然是个问题,但是我们可以使用 JavaScript 辅助,或者 CSS 和 JavaScript 结合的方式,来实现兼容所有浏览器的效果。

表格总结:

技术 优点 缺点 兼容性 适用场景
-webkit-line-clamp 简单易用 兼容性差,非标准属性 Chrome, Safari, Edge (可能需要 -webkit-) 快速原型开发,或者只考虑 WebKit 内核的浏览器
line-clamp (标准) 简单易用,标准化属性 兼容性仍需测试,需要搭配 overflow: overlay Chrome, Safari, Edge (可能需要 -webkit-), 部分 Firefox 现代浏览器,并进行充分的兼容性测试
JavaScript 兼容性好,灵活可控 实现复杂,性能略差 所有浏览器 需要兼容所有浏览器,或者需要更灵活的控制
CSS + JavaScript 优雅降级,兼顾性能和兼容性 实现相对复杂 最佳方案,兼顾性能和兼容性 追求最佳用户体验,需要兼容各种浏览器

好了,今天的讲座就到这里。希望大家有所收获,以后再遇到文本截断的问题,就能游刃有余地解决了! 记住:兼容性永远是前端开发的“老大难”问题,多测试,多尝试,才能找到最佳解决方案!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注