Shutter Reveal
A colored overlay (indigo-to-violet gradient) covers the element at rest; hovering fades it out in 500 ms to reveal text on a dark background. No JavaScript, two pseudo-elements.
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-0353-root root centers a .hover-box.hover-shutter block of 200 × 200 px on a #0a0a0f background. The main element has a dark var(--bg-card) background. A ::before pseudo-element positioned at inset: 0 covers the element with a linear-gradient(135deg, #6366f1, #d946ef) gradient at opacity: 1 at rest.
On hover (or focus), two transitions play simultaneously: the ::before goes from opacity: 1 to opacity: 0 over 500 ms, revealing the dark background; the span goes from opacity: 0 to opacity: 1 with a 200 ms delay to appear after the overlay starts fading. The text has a z-index: 1 above the pseudo-element (z-index: 0).
Measured in Chromium 151: overlay visible at rest, text visible on hover, two copies on the same page work independently. The effect is an opacity fade — no clip-path, no real shutters.
Accessibility
- Reduced motion: under
prefers-reduced-motion: reduce, all transitions are cancelled; the overlay stays in place on hover and the text does not animate. The state change is absent under reduced motion — for a critical use (action button), provide visible text at rest. - Keyboard: the element is a natively focusable
<button>. The:focus-visiblerule triggers the same effect as hover (overlay fades, text visible), with an indigo outline. - Hidden content at rest: the text under the overlay is in the DOM and readable by screen readers even though it is invisible to the eye. Do not put essential information in the
spanwithout an alternative. - Touch: on mobile, the first touch triggers the CSS hover and reveals the text.
Browser compatibility
Pure CSS (opacity, linear-gradient, ::before, transition, :focus-visible, prefers-reduced-motion), no JavaScript. Measured in Chromium 151: overlay, reveal, two independent copies. Works in all modern browsers.
Without opacity (very old browsers), the overlay always stays visible and the text never appears. Without transition, the change is instant but functional.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0353-root">
<button class="hover-box hover-shutter" type="button">
<span>…</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 |
|---|---|---|
Overlay color (CSS — background of ::before) |
linear-gradient(135deg, #6366f1, #d946ef) |
Replace the gradient with a solid color (#10b981) or another gradient. The overlay color can encode a category (green = finance, blue = tech). |
Fade duration (CSS — transition: opacity .5s) |
500 ms | .3s makes the reveal snappier; .8s makes it more dramatic. The span delay (transition: opacity .3s .2s) keeps the text hidden at the start of the fade. |
Text appearance delay (CSS — second value of transition on span) |
200 ms | .4s delays the text further, creating a two-step effect; 0s makes the text appear at the same time as the overlay fades. |
Element background (CSS — background of .hover-shutter) |
var(--bg-card) (dark) |
A white background (#fff) reveals dark text on a white background instead of dark — also invert the span text color. |
Element shape (CSS — border-radius) |
var(--radius-xl) = 1 rem |
50% for a circular reveal (avatar, badge); 0 for a sharp rectangle. |
FAQ
span is in the DOM with opacity: 0, not display: none: screen readers read it. If the text content is critical, also provide visible text at rest.background-image on .hover-shutter or embed an ![]()
with z-index: 0. Check that the ::before (z-index 0) stays in front of the image (z-index −1).