Les Confins · SF role-playing club
The Mirage
Corvette class · ship sheet no. 12
- Crew 6
- Jump 3 parsecs
- Hull light, fast
A translucent 120 px square frame with an indigo edge that "breathes" (20 to 40 px glow in 3 s), crossed from top to bottom by a scanline (2 s) and by a rotating diagonal prismatic reflection (4 s) that stays inside the frame: a sci-fi hologram plate, empty, ready for your drawing or logo — CSS only, zero JavaScript, still and readable hologram when the user reduces motion.
Updated
This effect is free — the 3D category contains 50 effects total, including 8 free. Effect.Labs has 840 vanilla effects. Explore the category →
Les Confins · SF role-playing club
Corvette class · ship sheet no. 12
Magic show for kids
Sunday 3 pm · ages 4 and up · 50 min
Book seats
Middle school robotics club
Nine 8th and 9th graders, one robot built in the club room, and Bolt, our mascot.
The .fx-0045-root root is 250 px tall, background rgb(26,26,36), and centers .xr-holo-display, which fills it. In the middle, .xr-holo-box is the frame: 120 × 120 px, 8 px corners, 1 px indigo edge at 30%, indigo background at 5%, and overflow: hidden. It holds two layers, the .xr-holo-scanline line and the .xr-holo-prism reflection.
Three independent loops make the hologram. The frame animates its box-shadow over 3 s: a 20 px indigo glow at 20%, rising to 40 px at 40% with an inner glow, then back down. The 2 px scanline, a transparent → indigo → transparent gradient, moves from the top to the bottom of the frame in 2 s (a top animation from 0 to 100%), at constant speed, and starts again at the top. The reflection covers the whole frame (inset: 0): a diagonal indigo and violet band at 10%, between 30 and 70% of the gradient, that makes a full turn in 4 s.
The reflection is a rotating square: at 45°, its corners stick out of the frame by more than 20 px. overflow: hidden on the frame keeps the reflection inside; without it, two diamond tips show up above and below. The frame is empty: put your content (svg, image, text) as the first child of .xr-holo-box, before the line and the reflection, so they pass over it, as in the three examples above.
prefers-reduced-motion: reduce, a block scoped to .fx-0045-root stops all three loops: steady 30 px glow, scanline resting at mid-height, still reflection. The hologram stays recognizable. Measured: 0% of pixels change over 0.8 s in Chromium, Firefox and WebKit, versus 3.2% in normal mode.divs, ignored by screen readers. The content you place inside carries the information: give the image alt text, or aria-hidden="true" to a purely decorative drawing that comes with visible text.CSS only: box-shadow, top and transform: rotate() animations, linear gradients, no JavaScript, no dependency. Measured in Chromium 151, Firefox 153 and WebKit 26 (Safari's engine): same rendering, reflection kept inside the frame, same stop under reduced motion. Not checked on a real Safari.
No recent property: every current browser shows the frame, its glow, the scanline and the reflection. Without CSS animations, what remains is a translucent indigo frame with a line at the top and a diagonal band.
Copy the three blocks into your page. No dependencies.
<div class="fx-0045-root">
<div class="xr-holo-display">
<div class="xr-holo-box">
<div class="xr-holo-scanline"></div>
<div class="xr-holo-prism"></div>
</div>
</div>
</div>
.fx-0045-root,
.fx-0045-root *,
.fx-0045-root *::before,
.fx-0045-root *::after {
box-sizing: border-box
}
.fx-0045-root {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 250px;
overflow: hidden;
position: relative;
background: rgb(26, 26, 36);
color: rgb(255, 255, 255);
font-family: sans-serif;
}
.xr-holo-display {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
.xr-holo-box {
width: 120px;
height: 120px;
position: relative;
border: 1px solid rgba(99, 102, 241, 0.3);
border-radius: 8px;
background: rgba(99, 102, 241, 0.05);
/* Keeps the rotating prism reflection inside the frame */
overflow: hidden;
animation: xrHoloPulse 3s ease-in-out infinite;
}
.xr-holo-scanline {
position: absolute;
left: 0;
width: 100%;
height: 2px;
background: linear-gradient(90deg, transparent, rgba(99, 102, 241, 0.6), transparent);
animation: xrScanline 2s linear infinite;
}
.xr-holo-prism {
position: absolute;
inset: 0;
background: linear-gradient(135deg, transparent 30%, rgba(99, 102, 241, 0.1) 45%, rgba(168, 85, 247, 0.1) 55%, transparent 70%);
animation: xrPrism 4s linear infinite;
}
@keyframes xrScanline {
from {
top: 0;
}
to {
top: 100%;
}
}
@keyframes xrHoloPulse {
0%,
100% {
box-shadow: 0 0 20px rgba(99, 102, 241, 0.2);
}
50% {
box-shadow: 0 0 40px rgba(99, 102, 241, 0.4), inset 0 0 20px rgba(99, 102, 241, 0.1);
}
}
@keyframes xrPrism {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
/* Reduced motion: still hologram, scanline at mid-height, steady glow */
@media (prefers-reduced-motion: reduce) {
.fx-0045-root .xr-holo-box {
animation: none;
box-shadow: 0 0 30px rgba(99, 102, 241, 0.3), inset 0 0 10px rgba(99, 102, 241, 0.05);
}
.fx-0045-root .xr-holo-scanline {
animation: none;
top: 50%;
}
.fx-0045-root .xr-holo-prism {
animation: none;
}
}
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Frame size (CSS — .xr-holo-box) |
120 × 120 px | Go up to about 200 px: the line and the reflection follow, they use percentages. Beyond that, the 40 px glow looks thin; increase it in xrHoloPulse. |
| Color (CSS — edge, background, glow, line, reflection) | Indigo rgba(99,102,241,…) and violet rgba(168,85,247,.1) | Replace the same hue in all five places: cyan 34,211,238 for a tech screen, green 74,222,128 for a retro terminal. |
Scan speed (CSS — xrScanline 2s) |
2 s per pass | 1 s gives a nervous scan, 4 s a calm sweep. The line moves at constant speed (linear). |
Glow breathing (CSS — xrHoloPulse 3s) |
3 s, 20 to 40 px glow | Stretch to 5 s for an object at rest; raise the glow opacity for a lighter background. |
Content (HTML — inside .xr-holo-box) |
Empty frame | Place an svg, an image or text as the first child, with position: absolute, so the line and the reflection pass over it. Transparent or thin-stroked content keeps the projected look. |
Background and height (CSS — .fx-0045-root) |
rgb(26,26,36), 250 px | Remove the background and fixed height to set the hologram in your page; it stays visible on a dark background, much less on white. |
Add it as the first child of .xr-holo-box, with position: absolute (for example inset: 14%), before .xr-holo-scanline and .xr-holo-prism: the line and the reflection then pass over it, which gives the projected look. A thin-stroked svg with a translucent fill works better than an opaque photo.
The reflection is a square the size of the frame that spins on itself: at 45°, its corners stick out by more than 20 px. Without overflow: hidden, two diamond tips show above and below the frame. The trade-off: content you want to stick out of the frame will be clipped; place it next to the frame, not inside.
It animates top (the line) and box-shadow (the glow), two properties the browser repaints on every frame, unlike transform. For a 120 px frame, it does not matter. If you show dozens of holograms, animate the line with transform: translateY() instead and keep a steady glow.