多行文本溢出显示省略号方案对比

52 阅读8分钟

前言

今天我们聊一个看似简单,实则暗藏玄机的小需求 —— 文本溢出显示省略号。单行省略我们早就用得滚瓜烂熟,但多行省略,你是不是也曾经在兼容性和效果之间反复横跳?今天我们就结合具体的代码实现,拆解多种方案的优缺点,帮你一次性选对!

首先,我们先看一个前提:为什么需要文本省略?其实很简单,就是为了页面布局的整洁性。想象一下,一个列表页里,有的标题一行,有的标题五行,整个页面会变得非常杂乱。所以,控制文本的显示行数,加上省略号,是前端开发里的高频需求。

一、 方案 1:单行文本省略 —— 稳定到可以闭眼用

我们先从最简单的单行省略开始。对应的 CSS 代码是这样的:

  .single-line {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

效果展示:

这三行 CSS 堪称黄金组合,缺一不可。white-space: nowrap 强制文本不换行,overflow: hidden 隐藏超出容器的部分,text-overflow: ellipsis 就是让超出的部分显示省略号。

优点

  1. 兼容性拉满:不管是 Chrome、Firefox,还是 IE 浏览器,都能完美支持。毕竟这是 CSS 2.1 就有的属性,历史悠久,稳定性极高。
  2. 使用简单:三行代码搞定,不需要计算高度,不需要额外的 DOM 结构,直接给文本元素加类名就行。
  3. 自适应容器:不管容器宽度怎么变,只要文本超出,省略号就会自动出现,适配性极强。

缺点

这个方案的缺点也很明显 —— 只能单行。如果产品需求是 “最多显示 2 行 / 3 行”,那它就完全没用了。

二、 方案 2:WebKit 内核多行省略 —— 好用但有 “门槛”

接下来是我们日常开发中用得比较多的多行省略方案,也就是 -webkit-line-clamp 方案。代码长这样:

  .multi-line {
    display: -webkit-box;
    line-clamp: 3;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

效果展示:

核心属性是 -webkit-line-clamp: 3,意思就是最多显示 3 行,超出的部分省略。当然,要配合 display: -webkit-box-webkit-box-orient: vertical 这两个 WebKit 内核的私有属性才能生效。

优点

  1. 效果完美:省略号是直接加在最后一行文本的末尾,不会像某些方案那样,省略号单独占一行或者盖住文字,视觉体验非常好。
  2. 无需计算高度:不需要手动设置 height,浏览器会根据 line-height 和行数自动计算,自适应程度高。
  3. 使用便捷:几行 CSS 搞定,不需要额外的伪元素或者 JS 辅助,开发效率高。

缺点

  1. 兼容性是硬伤:这个方案是 WebKit 内核私有属性,也就意味着,只在 Chrome、Safari、Edge(Chromium 内核)这些浏览器里生效。如果你的项目需要兼容 Firefox 或者更老的 IE,那这个方案直接 pass。
  2. 属性有 “耦合性” :必须同时设置 display: -webkit-box-webkit-box-orient: vertical,缺一不可,而且这些属性可能会和其他布局属性(比如 flex)冲突,使用的时候需要注意。

三、 方案 3:通用型多行省略 —— 兼容所有浏览器,但有点 “麻烦”

既然 WebKit 方案有兼容性问题,那有没有能适配所有浏览器的方案?当然有!就是我们今天的第三种 —— 基于 height 和伪元素的通用方案。代码如下:

  .multi-line-generic {
    position: relative;
    line-height: 1.4em;
    height: 4.2em; /* 3行 * 1.4em 行高 */
    overflow: hidden;
  }
  .multi-line-generic:after {
    content: '...';
    position: absolute;
    bottom: 0;
    right: 0;
    padding: 0 5px;
    background-color: #f9f9f9;
  }

效果展示:

这个方案的原理很简单:通过 line-height 乘以行数,算出容器的 height,超出部分用 overflow: hidden 隐藏,再用伪元素 :after 在容器右下角加上省略号,并用背景色盖住最后一行的多余文字。

优点

  1. 全浏览器兼容:不管是 WebKit 内核,还是 Firefox、IE,都能正常显示,完美解决兼容性问题。
  2. 灵活性高:理论上可以适配任意行数,只要计算好对应的 height 就行。

缺点

  1. 需要手动计算高度:这是最麻烦的一点。height 的值必须是 line-height * 行数,如果后期产品要求把 3 行改成 2 行,你必须手动修改 height 值,维护成本高。
  2. 省略号位置可能 “翻车” :伪元素的省略号是固定在右下角的,如果最后一行的文字很短,省略号可能会盖住部分文字,或者和文字之间有间隙,视觉效果不如 WebKit 方案自然。
  3. 背景色必须一致:伪元素的 background-color 必须和文本容器的背景色相同,否则会露出底下的文字,破坏效果。如果你的文本背景是透明或者渐变色,这个方案就很难处理。

四、 方案 4:多行文本省略方案 (JavaScript 二分法精准截断)

如果既想要全浏览器兼容,又想让省略号精准贴合文本末尾,那纯 CSS 方案已经满足不了了。这时候就该 JavaScript 出场 —— 用二分法精准计算截断位置,完美解决前面方案的痛点。核心代码如下:

/**
   * 多行文本省略 - 二分法精准截断函数
   * @param {HTMLElement} element - 需要截断的文本元素
   * @param {number} maxLines - 最大显示行数(默认3行)
   */
  // JavaScript实现多行文本省略
  function truncateText(element, maxLines) {
    // 保存原始文本
    const originalText = element.textContent;

    // 获取元素的计算样式
    const style = window.getComputedStyle(element);
    const lineHeight =
      parseFloat(style.lineHeight) || parseFloat(style.fontSize) * 1.4;
    const maxHeight = lineHeight * maxLines;

    // 先恢复原始文本,确保有内容可以测量
    element.textContent = originalText;

    // 如果内容高度超过最大高度,开始截断
    if (element.scrollHeight > maxHeight) {
      // 1. 初始化二分法的边界和最优值
      let start = 0; // 左边界:最小截取字符数(0个)
      let end = originalText.length; // 右边界:最大截取字符数(全部文本)
      let bestFit = 0; // 记录最优的截取位置(初始为0)

      // 2. 二分法循环:只要左边界 ≤ 右边界,就继续查找
      while (start <= end) {
        // 3. 计算中间位置:取当前范围的中间值(向下取整)
        const middle = Math.floor((start + end) / 2);

        // 4. 临时设置文本:截取前middle个字符 + 省略号
        element.textContent = originalText.substring(0, middle) + '...';

        // 5. 判断当前文本高度是否超限
        if (element.scrollHeight > maxHeight) {
          // 5.1 超限:说明middle太大,缩小右边界(找更小的数)
          end = middle - 1;
        } else {
          // 5.2 未超限:记录当前middle为最优值,扩大左边界(找更大的数)
          bestFit = middle;
          start = middle + 1;
        }
      }

      // 找到合适的截断位置后,添加省略号
      if (bestFit > 0) {
        element.textContent = originalText.substring(0, bestFit) + '...';
      } else {
        // 如果无法找到合适的位置,至少显示一部分文本
        element.textContent = originalText.substring(0, 10) + '...';
      }
    }
  }

  // 页面加载完成后执行
  document.addEventListener('DOMContentLoaded', function () {
    // 获取所有需要截断的元素
    const elements = document.querySelectorAll('.multi-line-js');

    // 对每个元素执行截断操作
    elements.forEach(element => {
      // 设置最大行数(可以根据需要调整)
      const maxLines = 3;
      // 执行截断
      truncateText(element, maxLines);
    });
  });

效果展示:

这个方案的核心逻辑是:先计算出 “最大行数对应的容器高度”,再用二分法快速查找 “文本 + 省略号” 高度刚好不超限的最长文本长度,最后截断文本并添加省略号。二分法的优势在于,哪怕文本有上千字符,也只需要十几次循环就能找到最优解,效率远高于逐字符截断。

优点

  1. 无兼容限制:不依赖任何浏览器私有属性,Chrome、Firefox、Edge、IE9+ 全兼容,甚至能适配移动端各种小众浏览器。
  2. 省略号位置精准:不会出现 “盖住文字”“单独占行”“留白” 等问题,省略号紧贴最后一行文本末尾,视觉效果和 WebKit 方案一致。
  3. 适配复杂背景:不需要伪元素背景色覆盖,哪怕文本容器是透明、渐变或图片背景,也能完美显示,解决了通用 CSS 方案的背景适配痛点。
  4. 无需手动算高度:只需要指定 “最大显示行数”,代码会自动根据元素的 line-height 计算高度阈值,后期改行数只需改一个参数,维护成本低。

缺点

  1. 依赖 JavaScript 执行:如果用户禁用了 JS,或者页面 JS 加载失败,这个方案就会失效。建议搭配方案 3 做降级兜底(比如先加载 CSS 通用方案,JS 执行后再替换为精准截断)。
  2. 首次渲染有计算开销:批量处理大量元素时,会有轻微的 DOM 操作开销(每次循环修改文本触发重绘),但二分法的低循环次数让这个影响几乎可以忽略,也可以通过防抖、延迟执行进一步优化。
  3. 动态内容需重新调用:如果文本内容是异步加载(比如接口返回),或者后期动态更新,需要手动调用 truncateText 函数重新截断,不能自动生效。

总结

方案 4 是 “兼容性 + 视觉效果” 的终极解,适合对跨浏览器支持、视觉精度有高要求的场景(比如 ToB 系统、全端适配的产品)。如果你的项目只需要支持现代浏览器,方案 2(WebKit)足够轻便;如果需要兼容老浏览器且对视觉要求一般,方案 3(通用 CSS)够用;如果既要全兼容又要精准效果,方案 4 就是最优选择。