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

如何沿SVG路径将弯曲文本按路径上下区域分两种颜色?

实现沿动态路径弯曲文本的上下分色效果

核心思路是通过复制两份沿路径排列的文本,结合动态生成的裁剪区域,分别显示文本的上下部分并设置不同颜色,同时同步响应路径的实时变化:

完整实现代码

<svg>
    <!-- 基础路径,文本将沿此路径排列 -->
    <path id="Path" d="M 100 100 q 50 -100 230 0" stroke="#000" stroke-width="1" fill="none"></path>
    
    <!-- 上半部分文本的裁剪区域 -->
    <clipPath id="clipTop">
        <path id="clipPathTop" fill="white" />
    </clipPath>
    <!-- 下半部分文本的裁剪区域 -->
    <clipPath id="clipBottom">
        <path id="clipPathBottom" fill="white" />
    </clipPath>
    
    <!-- 上半部分文本(橙色) -->
    <text fill="#ff4500" font-size="64px" clip-path="url(#clipTop)">
        <textPath id="TextPathTop" alignment-baseline="middle" href="#Path">Example</textPath>
    </text>
    <!-- 下半部分文本(蓝色) -->
    <text fill="#1e90ff" font-size="64px" clip-path="url(#clipBottom)">
        <textPath id="TextPathBottom" alignment-baseline="middle" href="#Path">Example</textPath>
    </text>
</svg>
svg {
    width: 500px;
    height: 500px;
}
const path = document.getElementById("Path");
const textPathTop = document.getElementById("TextPathTop");
const textPathBottom = document.getElementById("TextPathBottom");
const clipPathTop = document.getElementById("clipPathTop");
const clipPathBottom = document.getElementById("clipPathBottom");
const fontSize = 64;
const halfFontSize = fontSize / 2;

// 生成偏移路径的工具函数:基于原路径生成上下偏移的闭合裁剪区域
function createOffsetClipPath(originalPath, offset) {
    const pathLength = originalPath.getTotalLength();
    const offsetPoints = [];
    const originalReversePoints = [];

    // 生成偏移后的路径点(沿路径切线垂直方向偏移)
    for (let i = 0; i <= pathLength; i += 2) {
        const currPoint = originalPath.getPointAtLength(i);
        const nextPoint = originalPath.getPointAtLength(Math.min(i + 1, pathLength));
        
        const dx = nextPoint.x - currPoint.x;
        const dy = nextPoint.y - currPoint.y;
        const tangentLength = Math.sqrt(dx * dx + dy * dy) || 1;
        // 计算垂直切线的单位向量(向上偏移取(dy, -dx),向下取(-dy, dx))
        const perpX = dy / tangentLength;
        const perpY = -dx / tangentLength;

        offsetPoints.push([
            currPoint.x + perpX * offset,
            currPoint.y + perpY * offset
        ]);
    }

    // 生成原路径的反向点,用于闭合裁剪区域
    for (let i = pathLength; i >= 0; i -= 2) {
        const p = originalPath.getPointAtLength(i);
        originalReversePoints.push([p.x, p.y]);
    }

    // 构建闭合路径的d属性
    let d = `M ${offsetPoints[0][0]} ${offsetPoints[0][1]}`;
    offsetPoints.slice(1).forEach(([x, y]) => d += ` L ${x} ${y}`);
    originalReversePoints.forEach(([x, y]) => d += ` L ${x} ${y}`);
    d += " Z";

    return d;
}

// 鼠标移动时同步更新所有元素
document.onmousemove = function(e) {
    // 更新基础路径
    path.setAttribute("d", `M 100 100 q ${e.x - 100} ${e.y - 100} 230 0`);
    const pathLength = path.getTotalLength();

    // 同步文本长度,保证文本完全适配路径
    textPathTop.setAttribute("textLength", `${pathLength}px`);
    textPathBottom.setAttribute("textLength", `${pathLength}px`);

    // 更新上下裁剪区域路径
    clipPathTop.setAttribute("d", createOffsetClipPath(path, halfFontSize));
    clipPathBottom.setAttribute("d", createOffsetClipPath(path, -halfFontSize));
};

关键说明

  1. 两份<textPath>完全同步,通过clip-path属性分别只显示文本的上半/下半区域
  2. createOffsetClipPath函数通过计算路径切线的垂直方向,生成贴合文本弯曲形态的闭合裁剪路径
  3. 鼠标移动时,同步更新基础路径、文本长度和裁剪路径,确保所有元素实时响应路径变化

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 23:05:17