You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

主内容区与侧边gutter经文编号的垂直滚动对齐及交互实现

实现方案:左侧对齐的经文编号与Hover高亮

核心思路

利用CSS绝对定位实现编号与经文开头的精准垂直对齐,通过CSS选择器完成hover高亮,结合动态DOM生成适配跨多行/共享行场景,全程仅在动态渲染环节使用JS(排版逻辑纯CSS)。

1. HTML结构设计

采用「经文块容器+编号+文本」的三层结构,支持单个经文独占一行、多个经文共享一行两种场景:

<div class="scripture-container">
  <!-- 单个经文独占一行 -->
  <div class="verse-block">
    <span class="verse-number" data-ref="创1:1">1</span>
    <span class="verse-text">起初神创造天地。</span>
  </div>

  <!-- 多个经文共享一行 -->
  <div class="verse-inline-group">
    <div class="verse-block">
      <span class="verse-number" data-ref="创1:2">2</span>
      <span class="verse-text">地是空虚混沌,渊面黑暗;神的灵运行在水面上。</span>
    </div>
    <div class="verse-block">
      <span class="verse-number" data-ref="创1:3">3</span>
      <span class="verse-text">神说:「要有光」,就有了光。</span>
    </div>
  </div>

  <!-- 跨多行的经文 -->
  <div class="verse-block">
    <span class="verse-number" data-ref="创1:4">4</span>
    <span class="verse-text">神看光是好的,就把光暗分开了。神称光为「昼」,称暗为「夜」。有晚上,有早晨,这是头一日。</span>
  </div>
</div>

2. CSS实现核心效果

/* 整体容器:左侧预留编号 gutter 空间 */
.scripture-container {
  max-width: 800px;
  margin: 0 auto;
  padding-left: 3.5em; /* 编号区域宽度,可按需调整 */
  line-height: 1.6; /* 统一行高保证对齐精度 */
}

/* 经文块:作为编号的相对定位参照 */
.verse-block {
  position: relative;
  margin-bottom: 0.3em; /* 经文间垂直间距 */
}

/* 共享行容器:让多个经文横向排列 */
.verse-inline-group {
  display: flex;
  gap: 1.2em; /* 经文间水平间距 */
  flex-wrap: wrap; /* 空间不足时自动换行 */
}

/* 经文编号:固定到左侧 gutter */
.verse-number {
  position: absolute;
  left: -3.5em; /* 与容器padding-left对应,刚好移入gutter */
  top: 0;
  width: 3em;
  text-align: right;
  color: #666;
  cursor: pointer;
  user-select: none; /* 禁止选中编号文本 */
}

/* Hover编号时高亮对应经文(纯CSS实现,无JS) */
.verse-number:hover + .verse-text {
  background-color: #f5f5f5;
  border-radius: 3px;
  padding: 0 0.2em; /* 优化高亮视觉效果 */
}

3. 动态生成DOM(适配数据驱动场景)

通过JS循环经文数据自动生成上述结构,支持自定义经文分组逻辑(比如短经文合并到同一行):

// 示例经文数据结构
const scriptureData = {
  book: '创',
  chapter: 1,
  verses: [
    { number: 1, text: '起初神创造天地。' },
    { number: 2, text: '地是空虚混沌,渊面黑暗;神的灵运行在水面上。' },
    { number: 3, text: '神说:「要有光」,就有了光。' },
    { number: 4, text: '神看光是好的,就把光暗分开了。神称光为「昼」,称暗为「夜」。有晚上,有早晨,这是头一日。' }
  ]
};

// 渲染主函数
function renderScripture(data) {
  const container = document.querySelector('.scripture-container');
  container.innerHTML = '';

  let inlineGroup = [];
  data.verses.forEach(verse => {
    // 自定义分组规则:文本长度<30的经文加入共享行组
    if (verse.text.length < 30) {
      inlineGroup.push(verse);
    } else {
      // 先渲染之前的共享行组
      if (inlineGroup.length > 0) {
        container.appendChild(createInlineGroup(inlineGroup));
        inlineGroup = [];
      }
      // 渲染单独经文
      container.appendChild(createVerseBlock(verse));
    }
  });

  // 处理剩余的共享行组
  if (inlineGroup.length > 0) {
    container.appendChild(createInlineGroup(inlineGroup));
  }
}

// 创建单个经文块
function createVerseBlock(verse) {
  const block = document.createElement('div');
  block.className = 'verse-block';

  const number = document.createElement('span');
  number.className = 'verse-number';
  number.dataset.ref = `${scriptureData.book}${scriptureData.chapter}:${verse.number}`;
  number.textContent = verse.number;

  const text = document.createElement('span');
  text.className = 'verse-text';
  text.textContent = verse.text;

  block.appendChild(number);
  block.appendChild(text);
  return block;
}

// 创建共享行组
function createInlineGroup(verses) {
  const group = document.createElement('div');
  group.className = 'verse-inline-group';
  verses.forEach(v => group.appendChild(createVerseBlock(v)));
  return group;
}

// 执行渲染
renderScripture(scriptureData);

方案优势

  • 精准对齐:编号始终与经文第一行开头垂直对齐,不受经文行数影响;
  • 场景适配:完美支持跨多行经文、共享行经文的排版需求;
  • 无JS高亮:纯CSS实现hover编号高亮对应经文,性能优异;
  • 动态友好:完全基于数据生成DOM,无需硬编码,可灵活适配任意经卷/章节数据。

内容的提问来源于stack exchange,提问作者Scott Sauyet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 14:05:56