当前位置:首页 > 行业动态 > 正文

highlight.js行号

highlight.js 默认不自带行号功能,需结合额外样式或插件实现,可通过 CSS 伪元素配合 pre 包裹代码块手动添加 号,或使用 highlightjs-line-numbers.js 等插件自动生成,需注意样式兼容性和性能影响

Highlight.js行号实现原理与实践指南

基础概念解析

  1. 核心功能定位
    Highlight.js作为轻量级代码高亮库,核心聚焦于语法着色功能,其默认配置不包含行号渲染模块,需通过扩展开发实现该特性。

  2. 技术实现路径
    | 实现方式 | 技术特点 | 适用场景 |
    |—————-|————————————————————————–|————————–|
    | CSS伪元素方案 | 利用::before/::after,依赖Flex布局对齐 | 简单静态页面,行数固定 |
    | JavaScript生成 | 动态计算代码行数,通过DOM操作插入编号元素 | 动态内容或复杂排版 |
    | 第三方插件 | 集成专用行号组件(如prism-line-numbers),开箱即用但增加依赖 | 企业级项目需要快速集成 |

  3. 跨浏览器兼容性

    • 现代浏览器:Flex布局+CSS变量方案覆盖率达98%
    • IE11:需降级使用float布局,配合@supports条件注释
    • 移动端:注意行高与触摸区域适配,建议行号宽度≥30px

CSS伪元素实现方案

<pre><code class="hljs">
const arr = [1,2,3];
arr.map(item => {
  return item  2;
});
</code></pre>
pre {
  position: relative;
  padding-left: 40px; / 为行号预留空间 /
  counter-reset: line-number;
}
pre::before {
  content: attr(data-start) " "; / 起始行号 /
  position: absolute;
  left: 0;
  width: 30px;
  text-align: right;
  padding-right: 10px;
  color: #999;
}
.hljs-ln { / 每行代码前插入行号 /
  position: relative;
}
.hljs-ln::before {
  counter-increment: line-number;
  content: counter(line-number) " ";
  position: absolute;
  left: 0;
  width: 30px;
  text-align: right;
  color: #aaa;
}

关键实现要点:

  1. counter-reset初始化计数器
  2. position: relative建立定位上下文
  3. ::before伪元素绝对定位实现左侧对齐
  4. text-align: right保证数字右对齐
  5. padding-left防止代码覆盖行号

JavaScript动态生成方案

function addLineNumbers(block) {
  const lines = block.innerText.split('
');
  const ol = document.createElement('ol');
  ol.className = 'line-numbers';
  ol.style.width = '30px';
  ol.style.margin = '0';
  ol.style.padding = '0';
  ol.style.border = 'none';
  ol.style.listStyle = 'none';
  ol.style.counterReset = 'line-number';
  lines.forEach((line, index) => {
    const li = document.createElement('li');
    li.textContent = index + 1;
    li.style.textAlign = 'right';
    li.style.paddingRight = '10px';
    li.style.color = '#999';
    ol.appendChild(li);
  });
  block.parentNode.insertBefore(ol, block);
}
document.querySelectorAll('pre code').forEach(block => {
  addLineNumbers(block);
});

性能优化策略:

  • 批量修改DOM:使用DocumentFragment减少重排
  • 虚拟列表:只渲染可视区域行号(需配合滚动事件)
  • 缓存机制:对相同代码块复用行号容器
  • 懒加载:监测元素进入视口再生成行号

高级定制方案

  1. 主题化样式配置

    :root {
      --line-number-color: rgba(150, 150, 150, 0.7);
      --line-number-bg: rgba(238, 238, 238, 0.1);
      --line-padding: 8px;
    }
    .line-numbers {
      background: var(--line-number-bg);
      padding: var(--line-padding);
      border-right: 1px solid #eee;
    }
  2. 响应式设计适配
    | 屏幕尺寸 | 行号宽度 | 字体大小 | 对齐方式 |
    |—————|———-|———-|———-|
    | >1200px | 40px | 14px | right |
    | 768px-1200px | 30px | 12px | right |
    | <768px | 25px | 10px | center |

  3. 特殊场景处理

    • 代码折叠:监听折叠状态变化,动态调整行号显示范围
    • 多语言混排:识别代码块语言标签,应用不同高亮规则
    • 异步加载:使用MutationObserver监测新增代码块

常见问题解决方案

Q1:行号与代码垂直错位
A:检查以下样式属性:

  • 确保line-height与代码行高一致
  • 清除ol的默认margin
  • 统一font-familyfont-size设置
  • 使用display: flex对齐方式:
    pre {
      display: flex;
      align-items: baseline; / 根据实际效果调整 /
    }
    .line-numbers {
      display: flex;
      flex-direction: column;
      justify-content: flex-start; / 根据文本方向调整 /
    }

Q2:长代码导致行号渲染卡顿
A:实施性能优化方案:

  1. 虚拟滚动:仅渲染可视区域行号

    const visibleCount = Math.ceil(container.clientHeight / lineHeight);
    const startIndex = Math.max(0, currentScroll visibleCount);
    const fragment = document.createDocumentFragment();
    for (let i = startIndex; i < startIndex + visibleCount; i++) {
      const li = document.createElement('li');
      li.textContent = i + 1;
      fragment.appendChild(li);
    }
  2. 请求动画帧:平滑滚动时的重绘

    let ticking = false;
    container.addEventListener('scroll', () => {
      if (!ticking) {
        window.requestAnimationFrame(() => {
          // 执行行号更新逻辑
          ticking = false;
        });
        ticking = true;
      }
    });
  3. Web Workers:后台计算行号数据

    const worker = new Worker('lineNumberWorker.js');
    worker.postMessage(codeString); // 发送完整代码字符串
    worker.onmessage = (e) => {
      renderLineNumbers(e.data); // 接收计算好的行号数组
    };

最佳实践建议

  1. 渐进增强策略

    • 基础方案:CSS伪元素实现基本行号显示
    • 增强方案:JS动态生成支持复杂交互
    • 降级处理:不支持JS时保留基础可读性
  2. 无障碍设计考量

    • 添加aria-hidden="true"避免屏幕阅读器干扰
    • 确保颜色对比度≥4.5:1(WCAG标准)
    • 提供键盘导航支持(tab键焦点管理)
  3. 性能监控指标
    | 指标类型 | 理想值范围 | 检测方法 |
    |—————-|——————|————————–|
    | 首次渲染耗时 | <150ms | Performance.now()计时 |
    | 内存占用 | <5MB/千行代码 | Chrome DevTools分析 |
    | 滚动响应延迟 | <60ms | requestAnimationFrame测试 |

  4. 版本兼容矩阵
    | highlight.js版本 | CSS Grid支持 | ES6语法支持 | 推荐方案 |
    |——————|————–|————-|————————-|
    | v10+ | Yes | Full | CSS+JS混合方案 |
    | v9-v10 | Partial | Limited | CSS伪元素优先 |
    | v8及以下 | No | ES5 | 纯CSS方案+

0