30 CSS Text Animations13 / 30
CSS 3D Flip Text Reveal Animation
Real 3D typography: a split-flap departures board whose tiles slam upright one by one on load, and an endlessly turning four-sided word prism for slide-change moments — both driven only by perspective, rotateX and transform-style:preserve-3d.
Published Updated
The code
<div class="cat-13-group">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400..800&display=swap" rel="stylesheet">
<section class="cat-13a" aria-label="Split flap board text reveal">
<div class="cat-13a__board">
<p class="cat-13a__label" aria-hidden="true">NOW BOARDING — GATE 27</p>
<h1 class="cat-13a__row" aria-label="AMSTERDAM">
<span aria-hidden="true"><i style="--i:0">A</i><i style="--i:1">M</i><i style="--i:2">S</i><i style="--i:3">T</i><i style="--i:4">E</i><i style="--i:5">R</i><i style="--i:6">D</i><i style="--i:7">A</i><i style="--i:8">M</i></span>
</h1>
</div>
</section>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap" rel="stylesheet">
<section class="cat-13b" aria-label="Rotating 3D word prism">
<div class="cat-13b__stage">
<h1 class="cat-13b__line" aria-label="We help you build, ship, scale, repeat">We help you
<span class="cat-13b__scene" aria-hidden="true"><span class="cat-13b__drum"><span class="cat-13b__face" style="--n:0">build.</span><span class="cat-13b__face" style="--n:1">ship.</span><span class="cat-13b__face" style="--n:2">scale.</span><span class="cat-13b__face" style="--n:3">repeat.</span></span></span>
</h1>
</div>
</section>
</div><div class="cat-13-group">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400..800&display=swap" rel="stylesheet">
<section class="cat-13a" aria-label="Split flap board text reveal">
<div class="cat-13a__board">
<p class="cat-13a__label" aria-hidden="true">NOW BOARDING — GATE 27</p>
<h1 class="cat-13a__row" aria-label="AMSTERDAM">
<span aria-hidden="true"><i style="--i:0">A</i><i style="--i:1">M</i><i style="--i:2">S</i><i style="--i:3">T</i><i style="--i:4">E</i><i style="--i:5">R</i><i style="--i:6">D</i><i style="--i:7">A</i><i style="--i:8">M</i></span>
</h1>
</div>
</section>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap" rel="stylesheet">
<section class="cat-13b" aria-label="Rotating 3D word prism">
<div class="cat-13b__stage">
<h1 class="cat-13b__line" aria-label="We help you build, ship, scale, repeat">We help you
<span class="cat-13b__scene" aria-hidden="true"><span class="cat-13b__drum"><span class="cat-13b__face" style="--n:0">build.</span><span class="cat-13b__face" style="--n:1">ship.</span><span class="cat-13b__face" style="--n:2">scale.</span><span class="cat-13b__face" style="--n:3">repeat.</span></span></span>
</h1>
</div>
</section>
</div>.cat-13-group {
display: flex;
flex-wrap: wrap;
align-items: stretch;
width: 100%;
}
.cat-13-group > section {
flex: 1 1 480px;
min-width: min(100%,360px);
}
.cat-13a,
.cat-13a *,
.cat-13a *::before,
.cat-13a *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cat-13a {
--amber: oklch(0.82 0.15 80);
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: #101216;
font-family: 'JetBrains Mono',ui-monospace,Menlo,monospace;
}
.cat-13a__board {
background: #181b21;
border: 1px solid rgba(255,255,255,.07);
border-radius: 16px;
padding: 34px 34px 40px;
box-shadow: 0 40px 80px -40px rgba(0,0,0,.9),inset 0 1px 0 rgba(255,255,255,.05);
}
.cat-13a__label {
font-size: 10.5px;
letter-spacing: .3em;
color: rgba(235,200,120,.55);
margin-bottom: 20px;
}
.cat-13a__row span {
display: flex;
gap: 6px;
perspective: 700px;
}
.cat-13a__row i {
display: grid;
place-items: center;
width: 1.5em;
height: 2em;
font-size: clamp(20px,3.6vw,40px);
font-style: normal;
font-weight: 700;
color: var(--amber);
background: linear-gradient(180deg,#23272f 48.5%,#191c22 48.5% 51.5%,#20242b 51.5%);
border-radius: 6px;
box-shadow: inset 0 1px 0 rgba(255,255,255,.06),0 4px 10px -4px rgba(0,0,0,.8);
transform: rotateX(-88deg);
animation: cat-13a-flip .65s cubic-bezier(.3,1.4,.5,1) calc(var(--i)*95ms + .4s) both;
}
@keyframes cat-13a-flip {
to {
transform: rotateX(0);
}
}
@media (prefers-reduced-motion: reduce) {
.cat-13a__row i {
animation: none;
transform: none;
}
}
.cat-13b,
.cat-13b *,
.cat-13b *::before,
.cat-13b *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cat-13b {
--pink: oklch(0.74 0.19 350);
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: linear-gradient(170deg,#131018,#0b0a10);
font-family: 'Space Grotesk','Segoe UI',system-ui,sans-serif;
}
.cat-13b__line {
font-size: clamp(30px,5.4vw,62px);
font-weight: 600;
color: #efeaf7;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: .35em;
align-items: baseline;
}
.cat-13b__scene {
display: inline-block;
perspective: 800px;
height: 1.3em;
line-height: 1.3;
}
.cat-13b__drum {
position: relative;
display: inline-block;
min-width: 4.6ch;
height: 100%;
transform-style: preserve-3d;
animation: cat-13b-turn 8s cubic-bezier(.68,-0.3,.32,1.3) infinite;
}
.cat-13b__face {
position: absolute;
inset: 0;
display: flex;
align-items: center;
color: var(--pink);
font-weight: 700;
backface-visibility: hidden;
transform: rotateX(calc(var(--n)*90deg)) translateZ(.65em);
}
@keyframes cat-13b-turn {
0%,
17% {
transform: rotateX(0);
}
25%,
42% {
transform: rotateX(-90deg);
}
50%,
67% {
transform: rotateX(-180deg);
}
75%,
92% {
transform: rotateX(-270deg);
}
100% {
transform: rotateX(-360deg);
}
}
@media (prefers-reduced-motion: reduce) {
.cat-13b__drum {
animation: none;
}
}.cat-13-group {
display: flex;
flex-wrap: wrap;
align-items: stretch;
width: 100%;
}
.cat-13-group > section {
flex: 1 1 480px;
min-width: min(100%,360px);
}
.cat-13a,
.cat-13a *,
.cat-13a *::before,
.cat-13a *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cat-13a {
--amber: oklch(0.82 0.15 80);
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: #101216;
font-family: 'JetBrains Mono',ui-monospace,Menlo,monospace;
}
.cat-13a__board {
background: #181b21;
border: 1px solid rgba(255,255,255,.07);
border-radius: 16px;
padding: 34px 34px 40px;
box-shadow: 0 40px 80px -40px rgba(0,0,0,.9),inset 0 1px 0 rgba(255,255,255,.05);
}
.cat-13a__label {
font-size: 10.5px;
letter-spacing: .3em;
color: rgba(235,200,120,.55);
margin-bottom: 20px;
}
.cat-13a__row span {
display: flex;
gap: 6px;
perspective: 700px;
}
.cat-13a__row i {
display: grid;
place-items: center;
width: 1.5em;
height: 2em;
font-size: clamp(20px,3.6vw,40px);
font-style: normal;
font-weight: 700;
color: var(--amber);
background: linear-gradient(180deg,#23272f 48.5%,#191c22 48.5% 51.5%,#20242b 51.5%);
border-radius: 6px;
box-shadow: inset 0 1px 0 rgba(255,255,255,.06),0 4px 10px -4px rgba(0,0,0,.8);
transform: rotateX(-88deg);
animation: cat-13a-flip .65s cubic-bezier(.3,1.4,.5,1) calc(var(--i)*95ms + .4s) both;
}
@keyframes cat-13a-flip {
to {
transform: rotateX(0);
}
}
@media (prefers-reduced-motion: reduce) {
.cat-13a__row i {
animation: none;
transform: none;
}
}
.cat-13b,
.cat-13b *,
.cat-13b *::before,
.cat-13b *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cat-13b {
--pink: oklch(0.74 0.19 350);
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: linear-gradient(170deg,#131018,#0b0a10);
font-family: 'Space Grotesk','Segoe UI',system-ui,sans-serif;
}
.cat-13b__line {
font-size: clamp(30px,5.4vw,62px);
font-weight: 600;
color: #efeaf7;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: .35em;
align-items: baseline;
}
.cat-13b__scene {
display: inline-block;
perspective: 800px;
height: 1.3em;
line-height: 1.3;
}
.cat-13b__drum {
position: relative;
display: inline-block;
min-width: 4.6ch;
height: 100%;
transform-style: preserve-3d;
animation: cat-13b-turn 8s cubic-bezier(.68,-0.3,.32,1.3) infinite;
}
.cat-13b__face {
position: absolute;
inset: 0;
display: flex;
align-items: center;
color: var(--pink);
font-weight: 700;
backface-visibility: hidden;
transform: rotateX(calc(var(--n)*90deg)) translateZ(.65em);
}
@keyframes cat-13b-turn {
0%,
17% {
transform: rotateX(0);
}
25%,
42% {
transform: rotateX(-90deg);
}
50%,
67% {
transform: rotateX(-180deg);
}
75%,
92% {
transform: rotateX(-270deg);
}
100% {
transform: rotateX(-360deg);
}
}
@media (prefers-reduced-motion: reduce) {
.cat-13b__drum {
animation: none;
}
}/* No JavaScript — tiles share one perspective, start edge-on at rotateX(-88deg) and flip upright with overshoot, staggered 95ms apart; the gradient stripe fakes the flap hinge. */ /* No JavaScript — four faces sit at rotateX(n*90deg) translateZ(.65em) inside a preserve-3d drum; a hold-segment keyframe turns it one face at a time. */
/* No JavaScript — tiles share one perspective, start edge-on at rotateX(-88deg) and flip upright with overshoot, staggered 95ms apart; the gradient stripe fakes the flap hinge. */
/* No JavaScript — four faces sit at rotateX(n*90deg) translateZ(.65em) inside a preserve-3d drum; a hold-segment keyframe turns it one face at a time. */Here's a working CSS Text Animation from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS 3D Flip Text Reveal Animation
Source: https://codefronts.com/motion/css-text-animations/css-3d-text-flip-animation/
Real 3D typography: a split-flap departures board whose tiles slam upright one by one on load, and an endlessly turning four-sided word prism for slide-change moments — both driven only by perspective, rotateX and transform-style:preserve-3d.
## HTML
```html
<div class="cat-13-group">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400..800&display=swap" rel="stylesheet">
<section class="cat-13a" aria-label="Split flap board text reveal">
<div class="cat-13a__board">
<p class="cat-13a__label" aria-hidden="true">NOW BOARDING — GATE 27</p>
<h1 class="cat-13a__row" aria-label="AMSTERDAM">
<span aria-hidden="true"><i style="--i:0">A</i><i style="--i:1">M</i><i style="--i:2">S</i><i style="--i:3">T</i><i style="--i:4">E</i><i style="--i:5">R</i><i style="--i:6">D</i><i style="--i:7">A</i><i style="--i:8">M</i></span>
</h1>
</div>
</section>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap" rel="stylesheet">
<section class="cat-13b" aria-label="Rotating 3D word prism">
<div class="cat-13b__stage">
<h1 class="cat-13b__line" aria-label="We help you build, ship, scale, repeat">We help you
<span class="cat-13b__scene" aria-hidden="true"><span class="cat-13b__drum"><span class="cat-13b__face" style="--n:0">build.</span><span class="cat-13b__face" style="--n:1">ship.</span><span class="cat-13b__face" style="--n:2">scale.</span><span class="cat-13b__face" style="--n:3">repeat.</span></span></span>
</h1>
</div>
</section>
</div>
```
## CSS
```css
.cat-13-group {
display: flex;
flex-wrap: wrap;
align-items: stretch;
width: 100%;
}
.cat-13-group > section {
flex: 1 1 480px;
min-width: min(100%,360px);
}
.cat-13a,
.cat-13a *,
.cat-13a *::before,
.cat-13a *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cat-13a {
--amber: oklch(0.82 0.15 80);
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: #101216;
font-family: 'JetBrains Mono',ui-monospace,Menlo,monospace;
}
.cat-13a__board {
background: #181b21;
border: 1px solid rgba(255,255,255,.07);
border-radius: 16px;
padding: 34px 34px 40px;
box-shadow: 0 40px 80px -40px rgba(0,0,0,.9),inset 0 1px 0 rgba(255,255,255,.05);
}
.cat-13a__label {
font-size: 10.5px;
letter-spacing: .3em;
color: rgba(235,200,120,.55);
margin-bottom: 20px;
}
.cat-13a__row span {
display: flex;
gap: 6px;
perspective: 700px;
}
.cat-13a__row i {
display: grid;
place-items: center;
width: 1.5em;
height: 2em;
font-size: clamp(20px,3.6vw,40px);
font-style: normal;
font-weight: 700;
color: var(--amber);
background: linear-gradient(180deg,#23272f 48.5%,#191c22 48.5% 51.5%,#20242b 51.5%);
border-radius: 6px;
box-shadow: inset 0 1px 0 rgba(255,255,255,.06),0 4px 10px -4px rgba(0,0,0,.8);
transform: rotateX(-88deg);
animation: cat-13a-flip .65s cubic-bezier(.3,1.4,.5,1) calc(var(--i)*95ms + .4s) both;
}
@keyframes cat-13a-flip {
to {
transform: rotateX(0);
}
}
@media (prefers-reduced-motion: reduce) {
.cat-13a__row i {
animation: none;
transform: none;
}
}
.cat-13b,
.cat-13b *,
.cat-13b *::before,
.cat-13b *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cat-13b {
--pink: oklch(0.74 0.19 350);
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: linear-gradient(170deg,#131018,#0b0a10);
font-family: 'Space Grotesk','Segoe UI',system-ui,sans-serif;
}
.cat-13b__line {
font-size: clamp(30px,5.4vw,62px);
font-weight: 600;
color: #efeaf7;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: .35em;
align-items: baseline;
}
.cat-13b__scene {
display: inline-block;
perspective: 800px;
height: 1.3em;
line-height: 1.3;
}
.cat-13b__drum {
position: relative;
display: inline-block;
min-width: 4.6ch;
height: 100%;
transform-style: preserve-3d;
animation: cat-13b-turn 8s cubic-bezier(.68,-0.3,.32,1.3) infinite;
}
.cat-13b__face {
position: absolute;
inset: 0;
display: flex;
align-items: center;
color: var(--pink);
font-weight: 700;
backface-visibility: hidden;
transform: rotateX(calc(var(--n)*90deg)) translateZ(.65em);
}
@keyframes cat-13b-turn {
0%,
17% {
transform: rotateX(0);
}
25%,
42% {
transform: rotateX(-90deg);
}
50%,
67% {
transform: rotateX(-180deg);
}
75%,
92% {
transform: rotateX(-270deg);
}
100% {
transform: rotateX(-360deg);
}
}
@media (prefers-reduced-motion: reduce) {
.cat-13b__drum {
animation: none;
}
}
```
## JavaScript
```js
/* No JavaScript — tiles share one perspective, start edge-on at rotateX(-88deg) and flip upright with overshoot, staggered 95ms apart; the gradient stripe fakes the flap hinge. */
/* No JavaScript — four faces sit at rotateX(n*90deg) translateZ(.65em) inside a preserve-3d drum; a hold-segment keyframe turns it one face at a time. */
```Here's a working CSS Text Animation from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS 3D Flip Text Reveal Animation
Source: https://codefronts.com/motion/css-text-animations/css-3d-text-flip-animation/
Real 3D typography: a split-flap departures board whose tiles slam upright one by one on load, and an endlessly turning four-sided word prism for slide-change moments — both driven only by perspective, rotateX and transform-style:preserve-3d.
## HTML
```html
<div class="cat-13-group">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400..800&display=swap" rel="stylesheet">
<section class="cat-13a" aria-label="Split flap board text reveal">
<div class="cat-13a__board">
<p class="cat-13a__label" aria-hidden="true">NOW BOARDING — GATE 27</p>
<h1 class="cat-13a__row" aria-label="AMSTERDAM">
<span aria-hidden="true"><i style="--i:0">A</i><i style="--i:1">M</i><i style="--i:2">S</i><i style="--i:3">T</i><i style="--i:4">E</i><i style="--i:5">R</i><i style="--i:6">D</i><i style="--i:7">A</i><i style="--i:8">M</i></span>
</h1>
</div>
</section>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap" rel="stylesheet">
<section class="cat-13b" aria-label="Rotating 3D word prism">
<div class="cat-13b__stage">
<h1 class="cat-13b__line" aria-label="We help you build, ship, scale, repeat">We help you
<span class="cat-13b__scene" aria-hidden="true"><span class="cat-13b__drum"><span class="cat-13b__face" style="--n:0">build.</span><span class="cat-13b__face" style="--n:1">ship.</span><span class="cat-13b__face" style="--n:2">scale.</span><span class="cat-13b__face" style="--n:3">repeat.</span></span></span>
</h1>
</div>
</section>
</div>
```
## CSS
```css
.cat-13-group {
display: flex;
flex-wrap: wrap;
align-items: stretch;
width: 100%;
}
.cat-13-group > section {
flex: 1 1 480px;
min-width: min(100%,360px);
}
.cat-13a,
.cat-13a *,
.cat-13a *::before,
.cat-13a *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cat-13a {
--amber: oklch(0.82 0.15 80);
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: #101216;
font-family: 'JetBrains Mono',ui-monospace,Menlo,monospace;
}
.cat-13a__board {
background: #181b21;
border: 1px solid rgba(255,255,255,.07);
border-radius: 16px;
padding: 34px 34px 40px;
box-shadow: 0 40px 80px -40px rgba(0,0,0,.9),inset 0 1px 0 rgba(255,255,255,.05);
}
.cat-13a__label {
font-size: 10.5px;
letter-spacing: .3em;
color: rgba(235,200,120,.55);
margin-bottom: 20px;
}
.cat-13a__row span {
display: flex;
gap: 6px;
perspective: 700px;
}
.cat-13a__row i {
display: grid;
place-items: center;
width: 1.5em;
height: 2em;
font-size: clamp(20px,3.6vw,40px);
font-style: normal;
font-weight: 700;
color: var(--amber);
background: linear-gradient(180deg,#23272f 48.5%,#191c22 48.5% 51.5%,#20242b 51.5%);
border-radius: 6px;
box-shadow: inset 0 1px 0 rgba(255,255,255,.06),0 4px 10px -4px rgba(0,0,0,.8);
transform: rotateX(-88deg);
animation: cat-13a-flip .65s cubic-bezier(.3,1.4,.5,1) calc(var(--i)*95ms + .4s) both;
}
@keyframes cat-13a-flip {
to {
transform: rotateX(0);
}
}
@media (prefers-reduced-motion: reduce) {
.cat-13a__row i {
animation: none;
transform: none;
}
}
.cat-13b,
.cat-13b *,
.cat-13b *::before,
.cat-13b *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cat-13b {
--pink: oklch(0.74 0.19 350);
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: linear-gradient(170deg,#131018,#0b0a10);
font-family: 'Space Grotesk','Segoe UI',system-ui,sans-serif;
}
.cat-13b__line {
font-size: clamp(30px,5.4vw,62px);
font-weight: 600;
color: #efeaf7;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: .35em;
align-items: baseline;
}
.cat-13b__scene {
display: inline-block;
perspective: 800px;
height: 1.3em;
line-height: 1.3;
}
.cat-13b__drum {
position: relative;
display: inline-block;
min-width: 4.6ch;
height: 100%;
transform-style: preserve-3d;
animation: cat-13b-turn 8s cubic-bezier(.68,-0.3,.32,1.3) infinite;
}
.cat-13b__face {
position: absolute;
inset: 0;
display: flex;
align-items: center;
color: var(--pink);
font-weight: 700;
backface-visibility: hidden;
transform: rotateX(calc(var(--n)*90deg)) translateZ(.65em);
}
@keyframes cat-13b-turn {
0%,
17% {
transform: rotateX(0);
}
25%,
42% {
transform: rotateX(-90deg);
}
50%,
67% {
transform: rotateX(-180deg);
}
75%,
92% {
transform: rotateX(-270deg);
}
100% {
transform: rotateX(-360deg);
}
}
@media (prefers-reduced-motion: reduce) {
.cat-13b__drum {
animation: none;
}
}
```
## JavaScript
```js
/* No JavaScript — tiles share one perspective, start edge-on at rotateX(-88deg) and flip upright with overshoot, staggered 95ms apart; the gradient stripe fakes the flap hinge. */
/* No JavaScript — four faces sit at rotateX(n*90deg) translateZ(.65em) inside a preserve-3d drum; a hold-segment keyframe turns it one face at a time. */
```How this works
The board sets perspective on the row so every tile shares one vanishing point; tiles start at rotateX(-88deg) (edge-on, invisible) and flip to 0 with a small overshoot, staggered by --i. A gradient hinge line across the tile's middle sells the split-flap mechanic.
The prism builds a 4-faced drum: each face is rotated rotateX(90deg * n) then pushed out with translateZ; the shared radius is (face-height / 2), from r = h/2 · cot(180°/n) with n = 4. A keyframe with hold segments (0%, then −90°, −180°, −270°, −360°) turns the drum one face at a time:
.face{transform:rotateX(calc(var(--n)*90deg)) translateZ(.62em)}
@keyframes turn{0%,18%{transform:rotateX(0)}
25%,43%{transform:rotateX(-90deg)} …}Make it yours
- Perspective distance: 600px is dramatic, 1200px is subtle.
- Board: randomize --i order for a chaotic flap; sequential for boarding-board calm.
- Prism: any word count — n faces at 360/n° with translateZ = h/2·cot(180/n).
- Add a tick-tock timing feel with steps() on the hinge shadow.
Gotchas — read before shipping
- preserve-3d must sit on the parent of the faces, and no overflow/filter on that element (they flatten 3D).
- backface-visibility:hidden stops mirrored text ghosting through.
- Screen readers: expose one word list via aria-label; hide the rotating duplicates.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 15.4+ | 113+ | 111+ |
Floor set by oklch() as this demo is written. The core technique itself goes back further — Chrome 36+.
3D transforms are universal in evergreen browsers. Without 3D support the words render flat and readable.