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

如何让文本在多条SVG路径上连续排布?(路径文本行为)

解决方案:文本沿多段曲线接续排版

一、手动拆分+适配(固定路径场景)

如果你的曲线是固定的几段(比如现有两段),可以先按语义拆分文本,再分别绑定到不同路径,结合响应式逻辑保证排版自然:

修改后代码示例

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="line-box" viewBox="0 -30 1200 1200" preserveAspectRatio="none">
  <path vector-effect="non-scaling-stroke" id="curve-1" d="M0 0C449.6667 0 857 0 1160 0"/>
  <path vector-effect="non-scaling-stroke" id="curve-2" d="M0 35C292 35 584 35 876 55 953.6667 55 1031.3333 55 1160 35"/>
  
  <text text-anchor="start" class="curve-text">
    <textPath xlink:href="#curve-1">Are you a human being? We apologize for the confusion, but we can't quite tell if you're a person or a script.</textPath>
  </text>
  <text text-anchor="start" class="curve-text">
    <textPath xlink:href="#curve-2">Please don't take this personally. Bots and scripts can be remarkably lifelike these days!</textPath>
  </text>
</svg>

CSS

body {
  margin: 1vw;
}
path {
  fill: none;
}
#line-box {
  position: fixed;
  left: 1vw;
  top: 0;
  width: 101vw;
}
.curve-text {
  fill: black;
  font-size: 1.3rem;
}

JS(优化响应式逻辑)

function adjustFontSize() {
  const baseSize = window.innerWidth * 0.015;
  const adjustSize = Math.max(0, (window.innerWidth - 1300) / -30);
  const myFontsize = baseSize + adjustSize;
  $(".curve-text").css("font-size", myFontsize);
}

$(function() {
  adjustFontSize();
});

$(window).resize(function() {
  adjustFontSize();
});

这种方式能保证文本按语义拆分,不会出现单词断裂,适合路径固定的场景。

二、自动拆分文本到多路径(动态适配场景)

如果需要根据路径长度自动拆分文本,可通过JS计算单词宽度,逐个分配到对应路径:

核心实现逻辑

  1. 预定义多条平行曲线路径(如curve-1、curve-2)
  2. 将文本拆分为单词数组
  3. 遍历单词,计算当前路径剩余容纳宽度,超出则切换到下一条路径
  4. 动态创建textPath元素,拼接对应单词

简化代码示例

function splitTextToCurves() {
  const text = "Are you a human being? We apologize for the confusion, but we can't quite tell if you're a person or a script. Please don't take this personally. Bots and scripts can be remarkably lifelike these days!";
  const words = text.split(" ");
  const paths = ["#curve-1", "#curve-2"];
  const svg = $("#line-box");
  let currentPathIndex = 0;
  let currentText = "";
  
  // 清空现有文本
  svg.find("text").remove();

  words.forEach(word => {
    // 临时拼接单词,计算实际宽度
    const tempText = currentText ? `${currentText} ${word}` : word;
    const tempSpan = $("<span>").text(tempText).css({fontSize: $(".curve-text").css("font-size"), position: "absolute", visibility: "hidden"});
    $("body").append(tempSpan);
    const textWidth = tempSpan.width();
    tempSpan.remove();

    // 获取当前路径实际长度
    const pathLength = document.querySelector(paths[currentPathIndex]).getTotalLength();
    const maxWidth = pathLength * 0.8; // 留余量避免溢出

    if (textWidth > maxWidth && currentPathIndex < paths.length - 1) {
      // 创建当前路径的文本节点
      const textEl = $("<text>").addClass("curve-text").attr("text-anchor", "start");
      const textPathEl = $("<textPath>").attr("xlink:href", paths[currentPathIndex]).text(currentText);
      textEl.append(textPathEl);
      svg.append(textEl);

      currentPathIndex++;
      currentText = word;
    } else {
      currentText = tempText;
    }
  });

  // 添加最后一段文本
  if (currentText) {
    const textEl = $("<text>").addClass("curve-text").attr("text-anchor", "start");
    const textPathEl = $("<textPath>").attr("xlink:href", paths[currentPathIndex]).text(currentText);
    textEl.append(textPathEl);
    svg.append(textEl);
  }
}

// 初始化与resize触发
$(function() {
  adjustFontSize();
  splitTextToCurves();
});

$(window).resize(function() {
  adjustFontSize();
  splitTextToCurves();
});

三、使用专门曲排库

如果不想手动处理复杂计算,可借助成熟的JS库:

  • TypeSVG:支持文本沿任意路径排版,自动处理换行、断词,还能调整字间距、对齐方式
  • SplitText:配合SVG使用,可将文本拆分为适配路径的片段,再绑定到多条路径

这些库会自动完成宽度计算、单词拆分等逻辑,减少开发工作量。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 20:48:14