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

基于百分比控制的React文字填充效果实现问题

解决文字同步填充与单个字符颜色区分问题

问题分析

  1. 填充不同步:原代码中所有文本块共用同一个percentage值,但每个文本块的宽度不同,导致各自的填充进度无法统一,整体看起来不是从左到右连贯填充。
  2. 单个字符颜色无法区分:未对第一行最后一个字母"S"做单独的颜色处理逻辑,无法实现填充时的颜色差异。

解决方案

  1. 统一整体填充进度:通过获取所有文本元素的总宽度,将百分比进度转换为实际像素宽度,再为每个文本块计算对应的填充百分比,确保整体从左到右连贯填充。
  2. 单独处理字符颜色:将第一行的"S"拆分为两层——底层保持基础描边,上层使用不同颜色的渐变填充,当进度覆盖到该字符时显示对应颜色。

完整代码实现

'use client'

import React, { useState, useRef, useEffect } from 'react'

const Intro = () => {
  const [percentage, setPercentage] = useState(0)
  const [totalWidth, setTotalWidth] = useState(0)
  const textRefs = useRef({
    po: null,
    s: null,
    performance: null
  })

  // 计算所有文本元素的总宽度
  useEffect(() => {
    const calcTotalWidth = () => {
      const poWidth = textRefs.current.po?.offsetWidth || 0
      const sWidth = textRefs.current.s?.offsetWidth || 0
      const performanceWidth = textRefs.current.performance?.offsetWidth || 0
      setTotalWidth(poWidth + sWidth + performanceWidth)
    }

    calcTotalWidth()
    window.addEventListener('resize', calcTotalWidth)
    return () => window.removeEventListener('resize', calcTotalWidth)
  }, [])

  // 为每个文本块计算对应的填充进度
  const getElementFillPercentage = (elementRef) => {
    if (!elementRef || totalWidth === 0) return 0
    const elementStart = elementRef.offsetLeft
    const elementEnd = elementStart + elementRef.offsetWidth
    const fillPixel = (percentage / 100) * totalWidth

    if (fillPixel <= elementStart) return 0
    if (fillPixel >= elementEnd) return 100
    return ((fillPixel - elementStart) / elementRef.offsetWidth) * 100
  }

  // 生成基础填充渐变
  const getBaseGradient = (fillPercent) => {
    return `linear-gradient(to right, white ${fillPercent}%, transparent ${fillPercent}%)`
  }

  // 生成"S"的特殊颜色渐变
  const getSGradient = (fillPercent) => {
    return `linear-gradient(to right, #4299e1 ${fillPercent}%, transparent ${fillPercent}%)`
  }

  const poFill = getElementFillPercentage(textRefs.current.po)
  const sFill = getElementFillPercentage(textRefs.current.s)
  const performanceFill = getElementFillPercentage(textRefs.current.performance)

  return (
    <div className="w-full h-[100vh] flex items-center justify-center">
      <div className="flex flex-col relative">
        <div ref={(el) => textRefs.current.po = el} className="inline-block">
          <span
            className="text-transparent italic text-[148px] text-stroke"
            style={{
              lineHeight: 0.8,
              backgroundImage: getBaseGradient(poFill),
              WebkitBackgroundClip: 'text',
              backgroundClip: 'text',
            }}
          >
            PO
          </span>
        </div>
        <div className="inline-block relative" ref={(el) => textRefs.current.s = el}>
          {/* 底层保持描边,上层用蓝色填充 */}
          <span className="text-transparent italic pr-2 text-[148px] text-stroke">
            S
          </span>
          <span
            className="text-transparent italic pr-2 text-[148px] absolute inset-0"
            style={{
              lineHeight: 0.8,
              backgroundImage: getSGradient(sFill),
              WebkitBackgroundClip: 'text',
              backgroundClip: 'text',
            }}
          >
            S
          </span>
        </div>
        <span
          ref={(el) => textRefs.current.performance = el}
          className="text-transparent text-[30px] italic text-stroke-less"
          style={{
            lineHeight: 1,
            letterSpacing: 5.7,
            marginLeft: 6,
            backgroundImage: getBaseGradient(performanceFill),
            WebkitBackgroundClip: 'text',
            backgroundClip: 'text',
          }}
        >
          PERFORMANCE
        </span>
      </div>
      <input
        type="range"
        min="0"
        max="100"
        value={percentage}
        onChange={(e) => setPercentage(e.target.value)}
        className="mt-4"
      />
    </div>
  )
}

export default Intro

关键说明

  • 总宽度计算:通过useRef获取每个文本元素的宽度,结合resize事件确保窗口大小变化时仍能准确计算总宽度。
  • 单个元素填充进度:根据当前百分比对应的像素填充位置,计算每个元素的填充比例,保证整体填充连贯同步。
  • 字符颜色区分:将"S"设置为双层结构,底层是默认描边样式,上层使用不同颜色的渐变填充,实现该字符填充时的颜色差异。

内容的提问来源于stack exchange,提问作者Nilton Schumacher F

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 18:13:14