Background fill
Sweep-fill hover effect from left, right, or center using scaleX on a pseudo-element.
Quick implementation
/* HTML: <a class="bgfill-link"><span>Link text</span></a> */
.bgfill-link {
position: relative;
display: inline-block;
padding: 0.75rem 2rem;
border: 2px solid oklch(0.72 0.19 265);
border-radius: 0.5rem;
color: oklch(0.72 0.19 265);
font-weight: 600;
overflow: hidden;
transition: color 0.3s ease;
}
.bgfill-link::before {
content: '';
position: absolute;
inset: 0;
background: oklch(0.72 0.19 265);
transform: scaleX(0);
transform-origin: left; /* left | right | center */
transition: transform 0.3s ease;
z-index: 0;
}
.bgfill-link:hover::before,
.bgfill-link:focus-visible::before {
transform: scaleX(1);
}
.bgfill-link:hover,
.bgfill-link:focus-visible {
color: oklch(1 0 0);
}
/* Text must sit above the fill */
.bgfill-link span { position: relative; z-index: 1; }
@media (prefers-reduced-motion: reduce) {
.bgfill-link, .bgfill-link::before { transition: none; }
}
Prompt this to your LLM
Includes role, constraints, two framework variants, and edge cases to handle.
You are a senior frontend engineer building interactive hover effects.
Goal: A background fill hover animation using a ::before pseudo-element that scales from 0 to full width — no JavaScript.
Technical constraints:
- Use scaleX(0) → scaleX(1) on ::before, not width animation (transform is GPU-composited).
- transform-origin controls direction: left, right, or center.
- Text must sit above the fill with position: relative and z-index: 1.
- Color transitions from border color to white on hover using oklch().
- Include :focus-visible so keyboard users see the fill.
- Use oklch() for all colors, not hex or rgba().
- Wrap transitions in @media (prefers-reduced-motion: reduce).
Framework variant (pick one):
A) Vanilla HTML + CSS only.
B) React component — accept children, fillDirection (left | right | center), color (oklch string), and as (a | button) props.
Edge cases to handle:
- Multi-line text: fill should cover the full element, not just one line.
- RTL languages: left origin should become right automatically (use logical properties if possible).
- Ensure the fill doesn't extend outside rounded corners (overflow: hidden).
- Disabled state: no fill, muted colors.
Return HTML + CSS.
Why this matters in 2026
The background fill is one of the most popular button/link hover effects on the web. The old approach — animating width or background-size — triggers layout recalculation on every frame. Using scaleX on a pseudo-element keeps the animation on the GPU compositor, delivering smooth 60fps even on mobile. It's a one-line origin change to switch between left, right, and center fill directions.
The logic
The ::before pseudo-element covers the full area with inset: 0 and starts at scaleX(0). The transform-origin property controls which edge the fill grows from. On hover, scaleX(1) makes it fill the entire element. The text sits above via z-index: 1, and the element's overflow: hidden clips the fill at the border radius. The color transition happens simultaneously — from the accent color to white — creating a seamless swap.
Accessibility & performance
The :focus-visible selector triggers the same fill for keyboard navigation. The @media (prefers-reduced-motion: reduce) query removes transitions so the fill appears instantly. Using transform: scaleX() instead of width or background-size means the animation runs entirely on the compositor — no layout, no paint, just compositing. This is the same optimization principle browsers use for CSS animations on transform and opacity.