首页 >web前端 >css教程 >使用 SVG 的

我做了一些研究,发现了多种方法:

  1. 使用背景图像(TinyMCE 就是这样做的,使用 PNG)
  2. 使用
      ;有序列表。

我一个都不喜欢!第一个看起来不清晰 - 并且与我已经为我的

第二个需要一堆 JavaScript 来维护有序列表:动态添加/删除

  • 元素、同步滚动事件等等。

    所以我最终创建了一个混合体。

    它是动态生成的 SVG,存储为 CSS 自定义属性 — 并用作背景图像,从其父

    Line Numbers for <textarea> 使用 SVG

    让我们开始吧。


    JavaScript

    一、main方法:

    lineNumbers(element, numLines = 50, inline = false)
    

    元素是

    接下来,我们为自定义属性定义一个前缀:

    const prefix = '--linenum-';
    

    在继续之前,我们检查是否重新使用任何现有财产:

    if (!inline) {
      const styleString = document.body.getAttribute('style') || '';
      const regex = new RegExp(`${prefix}[^:]*`, 'g');
      const match = styleString.match(regex);
    
      if (match) {
        element.style.backgroundImage = `var(${match[0]})`;
        return;
      }
    }
    

    接下来,我们从元素中提取样式,使用相同的字体系列、字体大小、行高等渲染 SVG。:

    const bgColor = getComputedStyle(element).borderColor;
    const fillColor = getComputedStyle(element).color;
    const fontFamily = getComputedStyle(element).fontFamily;
    const fontSize = parseFloat(getComputedStyle(element).fontSize);
    const lineHeight = parseFloat(getComputedStyle(element).lineHeight) / fontSize;
    const paddingTop = parseFloat(getComputedStyle(element).paddingTop) / 2;
    const translateY = (fontSize * lineHeight).toFixed(2);
    

    我们的财产也需要一个随机 ID:

    const id = `${prefix}${Math.random().toString(36).substr(2, 6)}`;
    

    现在是时候渲染 SVG 了:

    const svg = `<svg xmlns="http://www.w3.org/2000/svg">
      <style>
        svg { background: ${bgColor}; }
        text {
          fill: hsl(from ${fillColor} h s l / 50%);
          font-family: ${fontFamily};
          font-size: ${fontSize}px;
          line-height: ${lineHeight};
          text-anchor: end;
          translate: 0 calc((var(--n) * ${translateY}px) + ${paddingTop}px);
        }
      </style>
      ${Array.from({ length: numLines }, (_, i) => `<text x="90%" style="--n:${i + 1};">${i + 1}</text>`).join("")}
    </svg>`;
    

    让我们来分解一下:

    最后一部分迭代从 numLines 创建的数组,并将 元素附加到主 SVG。

    我们快到了!


    要将生成的 SVG 用作 url() 属性,我们需要对其进行编码

    const encodedURI = `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
    

    最后,我们在元素或文档主体上设置该属性:

    const target = inline ? element : document.body;
    target.style.setProperty(id, encodedURI);
    element.style.backgroundImage = `var(${id})`;
    

    就是这样!

    还不错,只有 610 字节,经过缩小和压缩!


    演示

    您可以在此处查看演示,并在此处下载完整脚本。

    下面是一个简化的 Codepen,未使用内联属性逻辑:


    优点和缺点

    有优点和缺点吗?当然有!

    就我个人而言,对于我当前的项目,我需要一种简单、清晰的方法来将行号添加到

    优点

    减少 DOM 操作

    此方法不依赖于操作 DOM。行号生成为单个 SVG,存储在 CSS 自定义属性中。

    自动同步

    由于行号是背景图像的一部分,它们会自动随文本内容滚动,无需手动同步逻辑。

    跨元素的可重用性

    通过将生成的 SVG 存储在 CSS 自定义属性中,它可以在多个元素之间重复使用。这意味着如果多个元素需要相同的行号,它们都可以引用相同的自定义属性,从而避免冗余的 SVG 生成。

    可扩展性

    SVG 的矢量特性确保行号在任何缩放级别下都保持清晰。

    缺点

    无障碍

    屏幕阅读器和辅助技术更容易访问有序列表,而基于 SVG 的行号可能会被忽略或误解。

    定制复杂性

    对有序列表中的各个行号进行样式设置和交互非常简单。相比之下,SVG 方法使得自定义或向特定行号添加交互性变得更加困难。

    浏览器兼容性

    SVG 和 CSS 自定义属性可能无法在所有浏览器中一致地呈现 - 当前的实现在 Safari 中存在问题,我们需要从 translateY 中扣除 (paddingTop / 10)。

    动态内容处理

    有序列表可以更灵活地处理动态内容更新,例如添加或删除行,而 SVG 方法可能需要重新生成并重新应用整个背景图像。

  • 以上是使用 SVG 的