Shine Effect
A translucent white sheen crosses the element left to right in 0.5s on hover — one pass only, ::before pseudo-element, pure CSS.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Hover has 48 effects, including 5 free. Explore the category →
3 usage examples



How it works
The .fx-0346-root wrapper centres a 200 px button. A ::before pseudo-element the same size as the button carries a horizontal gradient: transparent → rgba(255,255,255,0.2) → transparent — a narrow white highlight at its centre. At rest it is positioned at left: -100% (hidden to the left). On hover, left: 100% moves it off to the right. transition: left 0.5s animates this move: the sheen crosses the element once in a soft sweep, with no loop.
overflow: hidden on the element clips the sheen as it exits. The single-pass behaviour (no looping @keyframes) is intentional: the sheen should not animate continuously so it doesn't distract. Under reduced motion the move is suppressed and the pseudo-element stays hidden at left: -100%. :focus-visible triggers the same transit as hover.
Accessibility
- Reduced motion: under
prefers-reduced-motion: reduce, the transition is disabled and the pseudo-element stays hidden (left: -100%) even on hover. No motion, no sheen. The element keeps its resting appearance. - Keyboard: the element is a natively focusable
<button>.:focus-visibletriggers the sheen and adds a 2 px indigo outline. The translating sheen may be subtle — the outline serves as the main signal for keyboard users. - Touch: on touchscreens, a tap may not trigger the
:hovertransition on all browsers. The effect is a visual enhancement — functional interaction does not depend on it. - Decorative role: the sheen is purely cosmetic. No information is carried by the pseudo-element's motion. The element remains readable and usable without the effect.
Browser compatibility
Pure CSS. Properties: ::before, left (transition), overflow: hidden, :focus-visible. Verified in Chromium and Firefox: sheen visible, two independent copies, 0 errors. The left transition triggers a repaint — for better performance, replace with transform: translateX (see FAQ).
Without :focus-visible (before 2021), keyboard focus may trigger the sheen via :focus only if the browser supports it — the effect may also appear on click in some browsers.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0346-root">
<button class="shn-box shn-shine" type="button">
<span>Your text</span>
</button>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Sheen intensity (CSS — rgba(255,255,255,0.2)) |
20% white | 0.1 is nearly invisible; 0.4 is very bright. On light backgrounds, reduce opacity or use a colour other than pure white. |
Duration (CSS — 0.5s) |
0.5 s | 0.25 s creates a quick flash; 0.8 s a slow sweep. |
Sheen width (CSS — width: 100% on ::before) |
100% of element | Reducing to 50% creates a narrower, more visible highlight. Adjust the gradient to keep the white peak at the centre. |
Performance (replace left with transform) |
left transition (repaint) | Replace left: -100%/100% with transform: translateX(-200%)/translateX(200%) on ::before to use the compositor layer and avoid repaint — especially useful when multiple elements animate simultaneously. |
Repeat (add a looping @keyframes) |
one pass on hover | For a continuous sheen, replace the transition with animation: shn-loop 2s linear infinite with a keyframe animating left from -100% to 100%. Enable the animation on hover and disable it on leave. |
FAQ
left: -100% → 100% animation ends off-screen. For multiple passes, use a @keyframes on translateX with iteration-count: 2 or infinite, triggered on :hover.overflow: hidden on the element clips the sheen as soon as it exits its bounds. Remove this property if you want the sheen to overflow (e.g. on an image without a strict frame).::before: background: linear-gradient(60deg, transparent, rgba(255,255,255,0.2), transparent), and increase the pseudo-element width to 150–200% so the sheen fully crosses the element.