Search code examples
cssreactjstailwind-csscss-animations

Text fill effect but controlled by percentage


I'm attempting to create a text fill effect that will be controlled by a useState. I have the following text:

enter image description here

According to a state I want it to be filled from left to right, although the last letter from the first text will be in a different color, for example:

enter image description here

The following code seems to work by half, but the fill is not syncronized and not with different colors:

'use client'

import React, { useState } from 'react'

const Intro = () => {
  const [percentage, setPercentage] = useState(0)

  // Function to dynamically create the gradient based on percentage
  const getGradient = (percentage) => {
    return `linear-gradient(to right, white ${percentage}%, transparent ${percentage}%)`
  }

  return (
    <div className="w-full h-[100vh] flex items-center justify-center">
      <div className="flex flex-col">
        <div>
          <span
            className="text-transparent italic text-[148px] text-stroke"
            style={{
              lineHeight: 0.8,
              backgroundImage: getGradient(percentage),
              WebkitBackgroundClip: 'text',
              backgroundClip: 'text',
            }}
          >
            PO
          </span>
          <span
            className="text-transparent italic pr-2 text-[148px] text-stroke"
            style={{
              lineHeight: 0.8,
              backgroundImage: getGradient(percentage),
              WebkitBackgroundClip: 'text',
              backgroundClip: 'text',
            }}
          >
            S
          </span>
        </div>
        <span
          className="text-transparent text-[30px] italic text-stroke-less"
          style={{
            lineHeight: 1,
            letterSpacing: 5.7,
            marginLeft: 6,
            backgroundImage: getGradient(percentage),
            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


Solution

  • From the information provided in your comment, it seems that you want to make POS synchronize with PERFORMANCE for a left-to-right gradient animation. If so, try this:

    <div class="flex h-dvh flex-col items-center justify-center bg-black">
      <article class="relative">
        <!-- text stroke -->
        <section class="absolute inset-0 flex flex-col items-center px-10 text-transparent">
          <div class="text-[148px] italic"><span style="-webkit-text-stroke: 1px white">PO</span><span style="-webkit-text-stroke: 1px #3b82f6">S</span></div>
          <span class="text-[40px] italic" style="-webkit-text-stroke: 1px white">PERFORMANCE</span>
        </section>
        <!-- current fill pivot: 50%; 10% gradient effect -->
        <section class="flex flex-col items-center px-10 text-white" style="mask:linear-gradient(to right, black 50%, transparent calc( 50% + 10% ));">
          <div class="text-[148px] italic">PO<span class="text-blue-500">S</span></div>
          <span class="text-[40px] italic">PERFORMANCE</span>
        </section>
      </article>
    </div>
    

    Static DEMO on Tailwind Play.

    You can achieve the animation effect by dynamically modifying the percentage:

    <div
      className="flex flex-col items-center px-10 text-white"
      style={{
        mask: `linear-gradient(to right, black ${percentage}%, transparent calc( ${percentage}% + 10% ))`,
      }}
    >
      <!-- ... -->
    </div>