10 / 20
All 20 in 20 CSS 3D Effects
- 01CSS 3D Transform Pipeline Reference Build
- 02Perspective Property Versus Perspective Function
- 03Perspective Origin as the Camera Position
- 04Transform Function Order Changes the Result
- 05Backface Visibility and Two Sided Elements
- 06Preserve 3D and What Flattens a Scene
- 07Building a CSS Cube from Six Faces
- 08Transform Origin in Three Dimensions
- 09TranslateZ Versus Scale for Depth
- 10Z Fighting on Coplanar 3D Surfaces
- 11Rotate3d and the Transform Matrix
- 12Ring Layout with Rotate and TranslateZ
- 13Depth Layering with Stacked Z Planes
- 14Pointer Tilt Cards with Parallax Depth Layers
- 15Page Turn Flipbook with Hinged Rotation
- 16Cube Face Navigation with Drag and Auto Rotate
- 17Extruded Synth Panel with Draggable Faders
- 18Perspective Floor Grid Geometry
- 19Nested 3D Contexts in a Pointer Steered Scene
- 20Helix Distribution with Trigonometric Angles
Z Fighting on Coplanar 3D Surfaces
Two surfaces at the same Z depth give the renderer no way to decide which is in front, so it picks per frame and the result flickers — often only on some GPUs, which makes it maddening to reproduce. The failure is shown next to the three fixes that actually work: a sub-pixel Z separation, z-index in a flattened context, and restructuring so nothing is coplanar.
Untitled UI Pro: a 10,000+ component Figma UI kit · from $129 one-time
Untitled UI · Affiliate link
The code
<section class="d3-10" aria-labelledby="d3-10-title">
<h2 class="d3-10__sr" id="d3-10-title">Z fighting on coplanar surfaces</h2>
<div class="d3-10__theme">
<input class="d3-10__theme-input" type="checkbox" id="d3-10-theme">
<label class="d3-10__theme-label" for="d3-10-theme">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor"/></svg>
<span class="d3-10__sr">Toggle dark theme</span>
</label>
</div>
<div class="d3-10__stage">
<div class="d3-10__viewport">
<header class="d3-10__head">
<span class="d3-10__kicker">Late Show — poster wall</span>
<strong>The stamp that flickers</strong>
<p>Identical markup on both, one property apart. On the left the stamp sits at exactly the face's depth, so nothing decides which draws in front and the seam stitches or flickers frame to frame — how badly depends on the GPU. On the right fourteen pixels of clearance make the answer deterministic everywhere, and the stamp picks up a shadow and its own parallax as the poster turns.</p>
</header>
<div class="d3-10__pair">
<article class="d3-10__slot">
<div class="d3-10__scene">
<div class="d3-10__poster d3-10__poster--fight">
<span class="d3-10__face" aria-hidden="true"></span>
<span class="d3-10__night">Fri 12 Sep</span>
<b class="d3-10__act">Vela<br>Sound</b>
<span class="d3-10__venue">The Foundry · 21:00</span>
<span class="d3-10__stamp">Sold out</span>
</div>
</div>
<p class="d3-10__cap"><b class="d3-10__badge d3-10__badge--no">Fighting</b> same depth as the face, <code>translateZ(0)</code></p>
</article>
<article class="d3-10__slot">
<div class="d3-10__scene">
<div class="d3-10__poster d3-10__poster--fixed">
<span class="d3-10__face" aria-hidden="true"></span>
<span class="d3-10__night">Sat 13 Sep</span>
<b class="d3-10__act">Halden<br>Trio</b>
<span class="d3-10__venue">The Foundry · 20:30</span>
<span class="d3-10__stamp">Sold out</span>
</div>
</div>
<p class="d3-10__cap"><b class="d3-10__badge d3-10__badge--ok">Resolved</b> lifted clear of it, <code>translateZ(14px)</code></p>
</article>
</div>
</div>
</div>
</section><section class="d3-10" aria-labelledby="d3-10-title">
<h2 class="d3-10__sr" id="d3-10-title">Z fighting on coplanar surfaces</h2>
<div class="d3-10__theme">
<input class="d3-10__theme-input" type="checkbox" id="d3-10-theme">
<label class="d3-10__theme-label" for="d3-10-theme">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor"/></svg>
<span class="d3-10__sr">Toggle dark theme</span>
</label>
</div>
<div class="d3-10__stage">
<div class="d3-10__viewport">
<header class="d3-10__head">
<span class="d3-10__kicker">Late Show — poster wall</span>
<strong>The stamp that flickers</strong>
<p>Identical markup on both, one property apart. On the left the stamp sits at exactly the face's depth, so nothing decides which draws in front and the seam stitches or flickers frame to frame — how badly depends on the GPU. On the right fourteen pixels of clearance make the answer deterministic everywhere, and the stamp picks up a shadow and its own parallax as the poster turns.</p>
</header>
<div class="d3-10__pair">
<article class="d3-10__slot">
<div class="d3-10__scene">
<div class="d3-10__poster d3-10__poster--fight">
<span class="d3-10__face" aria-hidden="true"></span>
<span class="d3-10__night">Fri 12 Sep</span>
<b class="d3-10__act">Vela<br>Sound</b>
<span class="d3-10__venue">The Foundry · 21:00</span>
<span class="d3-10__stamp">Sold out</span>
</div>
</div>
<p class="d3-10__cap"><b class="d3-10__badge d3-10__badge--no">Fighting</b> same depth as the face, <code>translateZ(0)</code></p>
</article>
<article class="d3-10__slot">
<div class="d3-10__scene">
<div class="d3-10__poster d3-10__poster--fixed">
<span class="d3-10__face" aria-hidden="true"></span>
<span class="d3-10__night">Sat 13 Sep</span>
<b class="d3-10__act">Halden<br>Trio</b>
<span class="d3-10__venue">The Foundry · 20:30</span>
<span class="d3-10__stamp">Sold out</span>
</div>
</div>
<p class="d3-10__cap"><b class="d3-10__badge d3-10__badge--ok">Resolved</b> lifted clear of it, <code>translateZ(14px)</code></p>
</article>
</div>
</div>
</div>
</section>.d3-10 {
--d3-10-bg: #000000;
--d3-10-surf: #0c0c0e;
--d3-10-line: #23232a;
--d3-10-ink: #f4f4f6;
--d3-10-mut: #8e8e99;
--d3-10-acc: #ff2d4f;
--d3-10-acc: oklch(64% 0.24 22);
--d3-10-acc2: #ffe14d;
--d3-10-acc2: oklch(90% 0.16 100);
--d3-10-ok: #33d17a;
--d3-10-ok: oklch(78% 0.16 152);
--d3-10-font-display: "Archivo Narrow", "Arial Narrow", "Oswald", system-ui, sans-serif;
width: 100%;
min-height: 100vh;
display: block;
position: relative;
box-sizing: border-box;
background: radial-gradient(46rem 24rem at 78% -12%, color-mix(in oklab, var(--d3-10-acc) 24%, transparent), transparent 60%), var(--d3-10-bg);
color: var(--d3-10-ink);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.5;
}
.d3-10 *,
.d3-10 *::before,
.d3-10 *::after {
box-sizing: border-box;
}
.d3-10__sr {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.d3-10:has(.d3-10__theme-input:checked) {
--d3-10-bg: #f4f4f6;
--d3-10-surf: #ffffff;
--d3-10-line: #d9d9e0;
--d3-10-ink: #0b0b0d;
--d3-10-mut: #5d5d68;
--d3-10-acc: #c40024;
--d3-10-acc: oklch(48% 0.22 22);
--d3-10-acc2: #8a6a00;
--d3-10-acc2: oklch(56% 0.13 100);
--d3-10-ok: #067a45;
--d3-10-ok: oklch(50% 0.14 152);
}
@media (prefers-color-scheme: light) {
.d3-10:has(.d3-10__theme-input:checked) {
--d3-10-bg: #f4f4f6;
--d3-10-surf: #ffffff;
--d3-10-line: #d9d9e0;
--d3-10-ink: #0b0b0d;
--d3-10-mut: #5d5d68;
--d3-10-acc: #c40024;
--d3-10-acc: oklch(48% 0.22 22);
--d3-10-acc2: #8a6a00;
--d3-10-acc2: oklch(56% 0.13 100);
--d3-10-ok: #067a45;
--d3-10-ok: oklch(50% 0.14 152);
}
}
@media (prefers-color-scheme: dark) {
.d3-10:has(.d3-10__theme-input:checked) {
--d3-10-bg: #f4f4f6;
--d3-10-surf: #ffffff;
--d3-10-line: #d9d9e0;
--d3-10-ink: #0b0b0d;
--d3-10-mut: #5d5d68;
--d3-10-acc: #c40024;
--d3-10-acc: oklch(48% 0.22 22);
--d3-10-acc2: #8a6a00;
--d3-10-acc2: oklch(56% 0.13 100);
--d3-10-ok: #067a45;
--d3-10-ok: oklch(50% 0.14 152);
}
}
.d3-10__theme {
position: absolute;
inset-block-start: clamp(0.75rem, 3vw, 1.5rem);
inset-inline-end: clamp(0.75rem, 3vw, 1.5rem);
z-index: 20;
}
.d3-10__theme-input {
position: absolute;
opacity: 0;
inline-size: 100%;
block-size: 100%;
margin: 0;
cursor: pointer;
}
.d3-10__theme-label {
display: grid;
place-items: center;
inline-size: 44px;
block-size: 44px;
border: 1px solid var(--d3-10-line);
border-radius: 4px;
background: var(--d3-10-surf);
color: var(--d3-10-ink);
cursor: pointer;
}
.d3-10__theme-label svg {
inline-size: 20px;
block-size: 20px;
}
.d3-10__theme-input:focus-visible + .d3-10__theme-label {
outline: 2px solid var(--d3-10-acc);
outline-offset: 3px;
}
.d3-10__stage {
display: grid;
grid-template-columns: minmax(0, 1fr);
place-items: center;
min-block-size: 100vh;
padding: clamp(3.5rem, 9vw, 5rem) clamp(0.75rem, 4vw, 2.5rem);
}
.d3-10__viewport {
inline-size: 100%;
max-inline-size: 58rem;
overflow: hidden;
display: grid;
gap: clamp(1.1rem, 3.5vw, 1.8rem);
}
.d3-10__head {
display: grid;
gap: 0.3rem;
max-inline-size: 44ch;
}
.d3-10__kicker {
font: 700 0.64rem/1.4 ui-monospace, Menlo, monospace;
letter-spacing: 0.24em;
text-transform: uppercase;
color: var(--d3-10-acc);
}
.d3-10__head strong {
font: 700 clamp(1.5rem, 5.4vw, 2.7rem)/1 var(--d3-10-font-display);
letter-spacing: 0.005em;
text-transform: uppercase;
}
.d3-10__head p {
margin: 0.2rem 0 0;
font: 500 clamp(0.74rem, 2vw, 0.85rem)/1.5 system-ui, sans-serif;
color: var(--d3-10-mut);
text-wrap: pretty;
}
.d3-10__pair {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
gap: clamp(0.9rem, 3vw, 1.6rem);
}
.d3-10__slot {
display: grid;
gap: 0.6rem;
}
.d3-10__scene {
perspective: 620px;
perspective-origin: 50% 42%;
block-size: clamp(15.5rem, 46vw, 22rem);
display: grid;
place-items: center;
}
.d3-10__poster {
position: relative;
inline-size: min(100%, 13.5rem);
aspect-ratio: 0.74;
padding: clamp(0.8rem, 2.6vw, 1.1rem);
display: grid;
align-content: space-between;
transform-style: preserve-3d;
animation: d3-10-sway 11s ease-in-out infinite;
color: #fff;
}
.d3-10__face {
position: absolute;
inset: 0;
transform: translateZ(0);
background: linear-gradient(170deg, #14060a 0%, #2a0710 55%, #470a16 100%);
border: 1px solid var(--d3-10-line);
box-shadow: 0 30px 60px -28px #000;
}
.d3-10__night,
.d3-10__act,
.d3-10__venue {
transform: translateZ(3px);
}
@keyframes d3-10-sway {
0%,
100% {
transform: rotateX(11deg) rotateY(-27deg);
}
50% {
transform: rotateX(2deg) rotateY(27deg);
}
}
.d3-10__night {
font: 600 0.62rem/1.4 ui-monospace, Menlo, monospace;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--d3-10-acc2);
}
.d3-10__act {
font: 700 clamp(1.4rem, 4.6vw, 2.15rem)/0.92 var(--d3-10-font-display);
text-transform: uppercase;
letter-spacing: -0.01em;
}
.d3-10__venue {
font: 500 0.66rem/1.3 ui-monospace, Menlo, monospace;
color: rgba(255, 255, 255, 0.68);
}
.d3-10__stamp {
position: absolute;
inset-block-start: 68%;
inset-inline-start: 26%;
white-space: nowrap;
padding: 0.3rem 0.7rem;
border: 3px solid #ff5c74;
border-radius: 6px;
color: #ff8595;
font: 800 clamp(0.72rem, 2.1vw, 0.9rem)/1 var(--d3-10-font-display);
letter-spacing: 0.12em;
text-transform: uppercase;
transform: rotate(-11deg);
background: #1b0308;
}
.d3-10__poster--fixed .d3-10__stamp {
transform: translateZ(14px) rotate(-11deg);
box-shadow: 0 12px 24px -6px #000;
}
.d3-10__cap {
margin: 0;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.4rem;
font: 500 clamp(0.72rem, 1.95vw, 0.8rem)/1.3 system-ui, sans-serif;
color: var(--d3-10-mut);
}
.d3-10__cap code {
font: 600 0.95em/1 ui-monospace, Menlo, monospace;
color: var(--d3-10-ink);
}
.d3-10__badge {
padding: 0.18rem 0.5rem;
border-radius: 3px;
font: 800 0.62rem/1.5 ui-monospace, Menlo, monospace;
letter-spacing: 0.1em;
text-transform: uppercase;
color: #000;
}
.d3-10__badge--no {
background: var(--d3-10-acc);
color: #fff;
}
.d3-10__badge--ok {
background: var(--d3-10-ok);
}
@media (prefers-reduced-motion: reduce) {
.d3-10__poster {
animation: none;
transform: rotateX(9deg) rotateY(-24deg);
}
}.d3-10 {
--d3-10-bg: #000000;
--d3-10-surf: #0c0c0e;
--d3-10-line: #23232a;
--d3-10-ink: #f4f4f6;
--d3-10-mut: #8e8e99;
--d3-10-acc: #ff2d4f;
--d3-10-acc: oklch(64% 0.24 22);
--d3-10-acc2: #ffe14d;
--d3-10-acc2: oklch(90% 0.16 100);
--d3-10-ok: #33d17a;
--d3-10-ok: oklch(78% 0.16 152);
--d3-10-font-display: "Archivo Narrow", "Arial Narrow", "Oswald", system-ui, sans-serif;
width: 100%;
min-height: 100vh;
display: block;
position: relative;
box-sizing: border-box;
background: radial-gradient(46rem 24rem at 78% -12%, color-mix(in oklab, var(--d3-10-acc) 24%, transparent), transparent 60%), var(--d3-10-bg);
color: var(--d3-10-ink);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.5;
}
.d3-10 *,
.d3-10 *::before,
.d3-10 *::after {
box-sizing: border-box;
}
.d3-10__sr {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.d3-10:has(.d3-10__theme-input:checked) {
--d3-10-bg: #f4f4f6;
--d3-10-surf: #ffffff;
--d3-10-line: #d9d9e0;
--d3-10-ink: #0b0b0d;
--d3-10-mut: #5d5d68;
--d3-10-acc: #c40024;
--d3-10-acc: oklch(48% 0.22 22);
--d3-10-acc2: #8a6a00;
--d3-10-acc2: oklch(56% 0.13 100);
--d3-10-ok: #067a45;
--d3-10-ok: oklch(50% 0.14 152);
}
@media (prefers-color-scheme: light) {
.d3-10:has(.d3-10__theme-input:checked) {
--d3-10-bg: #f4f4f6;
--d3-10-surf: #ffffff;
--d3-10-line: #d9d9e0;
--d3-10-ink: #0b0b0d;
--d3-10-mut: #5d5d68;
--d3-10-acc: #c40024;
--d3-10-acc: oklch(48% 0.22 22);
--d3-10-acc2: #8a6a00;
--d3-10-acc2: oklch(56% 0.13 100);
--d3-10-ok: #067a45;
--d3-10-ok: oklch(50% 0.14 152);
}
}
@media (prefers-color-scheme: dark) {
.d3-10:has(.d3-10__theme-input:checked) {
--d3-10-bg: #f4f4f6;
--d3-10-surf: #ffffff;
--d3-10-line: #d9d9e0;
--d3-10-ink: #0b0b0d;
--d3-10-mut: #5d5d68;
--d3-10-acc: #c40024;
--d3-10-acc: oklch(48% 0.22 22);
--d3-10-acc2: #8a6a00;
--d3-10-acc2: oklch(56% 0.13 100);
--d3-10-ok: #067a45;
--d3-10-ok: oklch(50% 0.14 152);
}
}
.d3-10__theme {
position: absolute;
inset-block-start: clamp(0.75rem, 3vw, 1.5rem);
inset-inline-end: clamp(0.75rem, 3vw, 1.5rem);
z-index: 20;
}
.d3-10__theme-input {
position: absolute;
opacity: 0;
inline-size: 100%;
block-size: 100%;
margin: 0;
cursor: pointer;
}
.d3-10__theme-label {
display: grid;
place-items: center;
inline-size: 44px;
block-size: 44px;
border: 1px solid var(--d3-10-line);
border-radius: 4px;
background: var(--d3-10-surf);
color: var(--d3-10-ink);
cursor: pointer;
}
.d3-10__theme-label svg {
inline-size: 20px;
block-size: 20px;
}
.d3-10__theme-input:focus-visible + .d3-10__theme-label {
outline: 2px solid var(--d3-10-acc);
outline-offset: 3px;
}
.d3-10__stage {
display: grid;
grid-template-columns: minmax(0, 1fr);
place-items: center;
min-block-size: 100vh;
padding: clamp(3.5rem, 9vw, 5rem) clamp(0.75rem, 4vw, 2.5rem);
}
.d3-10__viewport {
inline-size: 100%;
max-inline-size: 58rem;
overflow: hidden;
display: grid;
gap: clamp(1.1rem, 3.5vw, 1.8rem);
}
.d3-10__head {
display: grid;
gap: 0.3rem;
max-inline-size: 44ch;
}
.d3-10__kicker {
font: 700 0.64rem/1.4 ui-monospace, Menlo, monospace;
letter-spacing: 0.24em;
text-transform: uppercase;
color: var(--d3-10-acc);
}
.d3-10__head strong {
font: 700 clamp(1.5rem, 5.4vw, 2.7rem)/1 var(--d3-10-font-display);
letter-spacing: 0.005em;
text-transform: uppercase;
}
.d3-10__head p {
margin: 0.2rem 0 0;
font: 500 clamp(0.74rem, 2vw, 0.85rem)/1.5 system-ui, sans-serif;
color: var(--d3-10-mut);
text-wrap: pretty;
}
.d3-10__pair {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
gap: clamp(0.9rem, 3vw, 1.6rem);
}
.d3-10__slot {
display: grid;
gap: 0.6rem;
}
.d3-10__scene {
perspective: 620px;
perspective-origin: 50% 42%;
block-size: clamp(15.5rem, 46vw, 22rem);
display: grid;
place-items: center;
}
.d3-10__poster {
position: relative;
inline-size: min(100%, 13.5rem);
aspect-ratio: 0.74;
padding: clamp(0.8rem, 2.6vw, 1.1rem);
display: grid;
align-content: space-between;
transform-style: preserve-3d;
animation: d3-10-sway 11s ease-in-out infinite;
color: #fff;
}
.d3-10__face {
position: absolute;
inset: 0;
transform: translateZ(0);
background: linear-gradient(170deg, #14060a 0%, #2a0710 55%, #470a16 100%);
border: 1px solid var(--d3-10-line);
box-shadow: 0 30px 60px -28px #000;
}
.d3-10__night,
.d3-10__act,
.d3-10__venue {
transform: translateZ(3px);
}
@keyframes d3-10-sway {
0%,
100% {
transform: rotateX(11deg) rotateY(-27deg);
}
50% {
transform: rotateX(2deg) rotateY(27deg);
}
}
.d3-10__night {
font: 600 0.62rem/1.4 ui-monospace, Menlo, monospace;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--d3-10-acc2);
}
.d3-10__act {
font: 700 clamp(1.4rem, 4.6vw, 2.15rem)/0.92 var(--d3-10-font-display);
text-transform: uppercase;
letter-spacing: -0.01em;
}
.d3-10__venue {
font: 500 0.66rem/1.3 ui-monospace, Menlo, monospace;
color: rgba(255, 255, 255, 0.68);
}
.d3-10__stamp {
position: absolute;
inset-block-start: 68%;
inset-inline-start: 26%;
white-space: nowrap;
padding: 0.3rem 0.7rem;
border: 3px solid #ff5c74;
border-radius: 6px;
color: #ff8595;
font: 800 clamp(0.72rem, 2.1vw, 0.9rem)/1 var(--d3-10-font-display);
letter-spacing: 0.12em;
text-transform: uppercase;
transform: rotate(-11deg);
background: #1b0308;
}
.d3-10__poster--fixed .d3-10__stamp {
transform: translateZ(14px) rotate(-11deg);
box-shadow: 0 12px 24px -6px #000;
}
.d3-10__cap {
margin: 0;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.4rem;
font: 500 clamp(0.72rem, 1.95vw, 0.8rem)/1.3 system-ui, sans-serif;
color: var(--d3-10-mut);
}
.d3-10__cap code {
font: 600 0.95em/1 ui-monospace, Menlo, monospace;
color: var(--d3-10-ink);
}
.d3-10__badge {
padding: 0.18rem 0.5rem;
border-radius: 3px;
font: 800 0.62rem/1.5 ui-monospace, Menlo, monospace;
letter-spacing: 0.1em;
text-transform: uppercase;
color: #000;
}
.d3-10__badge--no {
background: var(--d3-10-acc);
color: #fff;
}
.d3-10__badge--ok {
background: var(--d3-10-ok);
}
@media (prefers-reduced-motion: reduce) {
.d3-10__poster {
animation: none;
transform: rotateX(9deg) rotateY(-24deg);
}
}Here's a working CSS 3D Effect 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: Z Fighting on Coplanar 3D Surfaces
Source: https://codefronts.com/design-styles/css-3d/z-fighting-on-coplanar-3d-surfaces/
Two surfaces at the same Z depth give the renderer no way to decide which is in front, so it picks per frame and the result flickers — often only on some GPUs, which makes it maddening to reproduce. The failure is shown next to the three fixes that actually work: a sub-pixel Z separation, z-index in a flattened context, and restructuring so nothing is coplanar.
## HTML
```html
<section class="d3-10" aria-labelledby="d3-10-title">
<h2 class="d3-10__sr" id="d3-10-title">Z fighting on coplanar surfaces</h2>
<div class="d3-10__theme">
<input class="d3-10__theme-input" type="checkbox" id="d3-10-theme">
<label class="d3-10__theme-label" for="d3-10-theme">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor"/></svg>
<span class="d3-10__sr">Toggle dark theme</span>
</label>
</div>
<div class="d3-10__stage">
<div class="d3-10__viewport">
<header class="d3-10__head">
<span class="d3-10__kicker">Late Show — poster wall</span>
<strong>The stamp that flickers</strong>
<p>Identical markup on both, one property apart. On the left the stamp sits at exactly the face's depth, so nothing decides which draws in front and the seam stitches or flickers frame to frame — how badly depends on the GPU. On the right fourteen pixels of clearance make the answer deterministic everywhere, and the stamp picks up a shadow and its own parallax as the poster turns.</p>
</header>
<div class="d3-10__pair">
<article class="d3-10__slot">
<div class="d3-10__scene">
<div class="d3-10__poster d3-10__poster--fight">
<span class="d3-10__face" aria-hidden="true"></span>
<span class="d3-10__night">Fri 12 Sep</span>
<b class="d3-10__act">Vela<br>Sound</b>
<span class="d3-10__venue">The Foundry · 21:00</span>
<span class="d3-10__stamp">Sold out</span>
</div>
</div>
<p class="d3-10__cap"><b class="d3-10__badge d3-10__badge--no">Fighting</b> same depth as the face, <code>translateZ(0)</code></p>
</article>
<article class="d3-10__slot">
<div class="d3-10__scene">
<div class="d3-10__poster d3-10__poster--fixed">
<span class="d3-10__face" aria-hidden="true"></span>
<span class="d3-10__night">Sat 13 Sep</span>
<b class="d3-10__act">Halden<br>Trio</b>
<span class="d3-10__venue">The Foundry · 20:30</span>
<span class="d3-10__stamp">Sold out</span>
</div>
</div>
<p class="d3-10__cap"><b class="d3-10__badge d3-10__badge--ok">Resolved</b> lifted clear of it, <code>translateZ(14px)</code></p>
</article>
</div>
</div>
</div>
</section>
```
## CSS
```css
.d3-10 {
--d3-10-bg: #000000;
--d3-10-surf: #0c0c0e;
--d3-10-line: #23232a;
--d3-10-ink: #f4f4f6;
--d3-10-mut: #8e8e99;
--d3-10-acc: #ff2d4f;
--d3-10-acc: oklch(64% 0.24 22);
--d3-10-acc2: #ffe14d;
--d3-10-acc2: oklch(90% 0.16 100);
--d3-10-ok: #33d17a;
--d3-10-ok: oklch(78% 0.16 152);
--d3-10-font-display: "Archivo Narrow", "Arial Narrow", "Oswald", system-ui, sans-serif;
width: 100%;
min-height: 100vh;
display: block;
position: relative;
box-sizing: border-box;
background: radial-gradient(46rem 24rem at 78% -12%, color-mix(in oklab, var(--d3-10-acc) 24%, transparent), transparent 60%), var(--d3-10-bg);
color: var(--d3-10-ink);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.5;
}
.d3-10 *,
.d3-10 *::before,
.d3-10 *::after {
box-sizing: border-box;
}
.d3-10__sr {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.d3-10:has(.d3-10__theme-input:checked) {
--d3-10-bg: #f4f4f6;
--d3-10-surf: #ffffff;
--d3-10-line: #d9d9e0;
--d3-10-ink: #0b0b0d;
--d3-10-mut: #5d5d68;
--d3-10-acc: #c40024;
--d3-10-acc: oklch(48% 0.22 22);
--d3-10-acc2: #8a6a00;
--d3-10-acc2: oklch(56% 0.13 100);
--d3-10-ok: #067a45;
--d3-10-ok: oklch(50% 0.14 152);
}
@media (prefers-color-scheme: light) {
.d3-10:has(.d3-10__theme-input:checked) {
--d3-10-bg: #f4f4f6;
--d3-10-surf: #ffffff;
--d3-10-line: #d9d9e0;
--d3-10-ink: #0b0b0d;
--d3-10-mut: #5d5d68;
--d3-10-acc: #c40024;
--d3-10-acc: oklch(48% 0.22 22);
--d3-10-acc2: #8a6a00;
--d3-10-acc2: oklch(56% 0.13 100);
--d3-10-ok: #067a45;
--d3-10-ok: oklch(50% 0.14 152);
}
}
@media (prefers-color-scheme: dark) {
.d3-10:has(.d3-10__theme-input:checked) {
--d3-10-bg: #f4f4f6;
--d3-10-surf: #ffffff;
--d3-10-line: #d9d9e0;
--d3-10-ink: #0b0b0d;
--d3-10-mut: #5d5d68;
--d3-10-acc: #c40024;
--d3-10-acc: oklch(48% 0.22 22);
--d3-10-acc2: #8a6a00;
--d3-10-acc2: oklch(56% 0.13 100);
--d3-10-ok: #067a45;
--d3-10-ok: oklch(50% 0.14 152);
}
}
.d3-10__theme {
position: absolute;
inset-block-start: clamp(0.75rem, 3vw, 1.5rem);
inset-inline-end: clamp(0.75rem, 3vw, 1.5rem);
z-index: 20;
}
.d3-10__theme-input {
position: absolute;
opacity: 0;
inline-size: 100%;
block-size: 100%;
margin: 0;
cursor: pointer;
}
.d3-10__theme-label {
display: grid;
place-items: center;
inline-size: 44px;
block-size: 44px;
border: 1px solid var(--d3-10-line);
border-radius: 4px;
background: var(--d3-10-surf);
color: var(--d3-10-ink);
cursor: pointer;
}
.d3-10__theme-label svg {
inline-size: 20px;
block-size: 20px;
}
.d3-10__theme-input:focus-visible + .d3-10__theme-label {
outline: 2px solid var(--d3-10-acc);
outline-offset: 3px;
}
.d3-10__stage {
display: grid;
grid-template-columns: minmax(0, 1fr);
place-items: center;
min-block-size: 100vh;
padding: clamp(3.5rem, 9vw, 5rem) clamp(0.75rem, 4vw, 2.5rem);
}
.d3-10__viewport {
inline-size: 100%;
max-inline-size: 58rem;
overflow: hidden;
display: grid;
gap: clamp(1.1rem, 3.5vw, 1.8rem);
}
.d3-10__head {
display: grid;
gap: 0.3rem;
max-inline-size: 44ch;
}
.d3-10__kicker {
font: 700 0.64rem/1.4 ui-monospace, Menlo, monospace;
letter-spacing: 0.24em;
text-transform: uppercase;
color: var(--d3-10-acc);
}
.d3-10__head strong {
font: 700 clamp(1.5rem, 5.4vw, 2.7rem)/1 var(--d3-10-font-display);
letter-spacing: 0.005em;
text-transform: uppercase;
}
.d3-10__head p {
margin: 0.2rem 0 0;
font: 500 clamp(0.74rem, 2vw, 0.85rem)/1.5 system-ui, sans-serif;
color: var(--d3-10-mut);
text-wrap: pretty;
}
.d3-10__pair {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
gap: clamp(0.9rem, 3vw, 1.6rem);
}
.d3-10__slot {
display: grid;
gap: 0.6rem;
}
.d3-10__scene {
perspective: 620px;
perspective-origin: 50% 42%;
block-size: clamp(15.5rem, 46vw, 22rem);
display: grid;
place-items: center;
}
.d3-10__poster {
position: relative;
inline-size: min(100%, 13.5rem);
aspect-ratio: 0.74;
padding: clamp(0.8rem, 2.6vw, 1.1rem);
display: grid;
align-content: space-between;
transform-style: preserve-3d;
animation: d3-10-sway 11s ease-in-out infinite;
color: #fff;
}
.d3-10__face {
position: absolute;
inset: 0;
transform: translateZ(0);
background: linear-gradient(170deg, #14060a 0%, #2a0710 55%, #470a16 100%);
border: 1px solid var(--d3-10-line);
box-shadow: 0 30px 60px -28px #000;
}
.d3-10__night,
.d3-10__act,
.d3-10__venue {
transform: translateZ(3px);
}
@keyframes d3-10-sway {
0%,
100% {
transform: rotateX(11deg) rotateY(-27deg);
}
50% {
transform: rotateX(2deg) rotateY(27deg);
}
}
.d3-10__night {
font: 600 0.62rem/1.4 ui-monospace, Menlo, monospace;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--d3-10-acc2);
}
.d3-10__act {
font: 700 clamp(1.4rem, 4.6vw, 2.15rem)/0.92 var(--d3-10-font-display);
text-transform: uppercase;
letter-spacing: -0.01em;
}
.d3-10__venue {
font: 500 0.66rem/1.3 ui-monospace, Menlo, monospace;
color: rgba(255, 255, 255, 0.68);
}
.d3-10__stamp {
position: absolute;
inset-block-start: 68%;
inset-inline-start: 26%;
white-space: nowrap;
padding: 0.3rem 0.7rem;
border: 3px solid #ff5c74;
border-radius: 6px;
color: #ff8595;
font: 800 clamp(0.72rem, 2.1vw, 0.9rem)/1 var(--d3-10-font-display);
letter-spacing: 0.12em;
text-transform: uppercase;
transform: rotate(-11deg);
background: #1b0308;
}
.d3-10__poster--fixed .d3-10__stamp {
transform: translateZ(14px) rotate(-11deg);
box-shadow: 0 12px 24px -6px #000;
}
.d3-10__cap {
margin: 0;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.4rem;
font: 500 clamp(0.72rem, 1.95vw, 0.8rem)/1.3 system-ui, sans-serif;
color: var(--d3-10-mut);
}
.d3-10__cap code {
font: 600 0.95em/1 ui-monospace, Menlo, monospace;
color: var(--d3-10-ink);
}
.d3-10__badge {
padding: 0.18rem 0.5rem;
border-radius: 3px;
font: 800 0.62rem/1.5 ui-monospace, Menlo, monospace;
letter-spacing: 0.1em;
text-transform: uppercase;
color: #000;
}
.d3-10__badge--no {
background: var(--d3-10-acc);
color: #fff;
}
.d3-10__badge--ok {
background: var(--d3-10-ok);
}
@media (prefers-reduced-motion: reduce) {
.d3-10__poster {
animation: none;
transform: rotateX(9deg) rotateY(-24deg);
}
}
```Here's a working CSS 3D Effect 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: Z Fighting on Coplanar 3D Surfaces
Source: https://codefronts.com/design-styles/css-3d/z-fighting-on-coplanar-3d-surfaces/
Two surfaces at the same Z depth give the renderer no way to decide which is in front, so it picks per frame and the result flickers — often only on some GPUs, which makes it maddening to reproduce. The failure is shown next to the three fixes that actually work: a sub-pixel Z separation, z-index in a flattened context, and restructuring so nothing is coplanar.
## HTML
```html
<section class="d3-10" aria-labelledby="d3-10-title">
<h2 class="d3-10__sr" id="d3-10-title">Z fighting on coplanar surfaces</h2>
<div class="d3-10__theme">
<input class="d3-10__theme-input" type="checkbox" id="d3-10-theme">
<label class="d3-10__theme-label" for="d3-10-theme">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor"/></svg>
<span class="d3-10__sr">Toggle dark theme</span>
</label>
</div>
<div class="d3-10__stage">
<div class="d3-10__viewport">
<header class="d3-10__head">
<span class="d3-10__kicker">Late Show — poster wall</span>
<strong>The stamp that flickers</strong>
<p>Identical markup on both, one property apart. On the left the stamp sits at exactly the face's depth, so nothing decides which draws in front and the seam stitches or flickers frame to frame — how badly depends on the GPU. On the right fourteen pixels of clearance make the answer deterministic everywhere, and the stamp picks up a shadow and its own parallax as the poster turns.</p>
</header>
<div class="d3-10__pair">
<article class="d3-10__slot">
<div class="d3-10__scene">
<div class="d3-10__poster d3-10__poster--fight">
<span class="d3-10__face" aria-hidden="true"></span>
<span class="d3-10__night">Fri 12 Sep</span>
<b class="d3-10__act">Vela<br>Sound</b>
<span class="d3-10__venue">The Foundry · 21:00</span>
<span class="d3-10__stamp">Sold out</span>
</div>
</div>
<p class="d3-10__cap"><b class="d3-10__badge d3-10__badge--no">Fighting</b> same depth as the face, <code>translateZ(0)</code></p>
</article>
<article class="d3-10__slot">
<div class="d3-10__scene">
<div class="d3-10__poster d3-10__poster--fixed">
<span class="d3-10__face" aria-hidden="true"></span>
<span class="d3-10__night">Sat 13 Sep</span>
<b class="d3-10__act">Halden<br>Trio</b>
<span class="d3-10__venue">The Foundry · 20:30</span>
<span class="d3-10__stamp">Sold out</span>
</div>
</div>
<p class="d3-10__cap"><b class="d3-10__badge d3-10__badge--ok">Resolved</b> lifted clear of it, <code>translateZ(14px)</code></p>
</article>
</div>
</div>
</div>
</section>
```
## CSS
```css
.d3-10 {
--d3-10-bg: #000000;
--d3-10-surf: #0c0c0e;
--d3-10-line: #23232a;
--d3-10-ink: #f4f4f6;
--d3-10-mut: #8e8e99;
--d3-10-acc: #ff2d4f;
--d3-10-acc: oklch(64% 0.24 22);
--d3-10-acc2: #ffe14d;
--d3-10-acc2: oklch(90% 0.16 100);
--d3-10-ok: #33d17a;
--d3-10-ok: oklch(78% 0.16 152);
--d3-10-font-display: "Archivo Narrow", "Arial Narrow", "Oswald", system-ui, sans-serif;
width: 100%;
min-height: 100vh;
display: block;
position: relative;
box-sizing: border-box;
background: radial-gradient(46rem 24rem at 78% -12%, color-mix(in oklab, var(--d3-10-acc) 24%, transparent), transparent 60%), var(--d3-10-bg);
color: var(--d3-10-ink);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.5;
}
.d3-10 *,
.d3-10 *::before,
.d3-10 *::after {
box-sizing: border-box;
}
.d3-10__sr {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.d3-10:has(.d3-10__theme-input:checked) {
--d3-10-bg: #f4f4f6;
--d3-10-surf: #ffffff;
--d3-10-line: #d9d9e0;
--d3-10-ink: #0b0b0d;
--d3-10-mut: #5d5d68;
--d3-10-acc: #c40024;
--d3-10-acc: oklch(48% 0.22 22);
--d3-10-acc2: #8a6a00;
--d3-10-acc2: oklch(56% 0.13 100);
--d3-10-ok: #067a45;
--d3-10-ok: oklch(50% 0.14 152);
}
@media (prefers-color-scheme: light) {
.d3-10:has(.d3-10__theme-input:checked) {
--d3-10-bg: #f4f4f6;
--d3-10-surf: #ffffff;
--d3-10-line: #d9d9e0;
--d3-10-ink: #0b0b0d;
--d3-10-mut: #5d5d68;
--d3-10-acc: #c40024;
--d3-10-acc: oklch(48% 0.22 22);
--d3-10-acc2: #8a6a00;
--d3-10-acc2: oklch(56% 0.13 100);
--d3-10-ok: #067a45;
--d3-10-ok: oklch(50% 0.14 152);
}
}
@media (prefers-color-scheme: dark) {
.d3-10:has(.d3-10__theme-input:checked) {
--d3-10-bg: #f4f4f6;
--d3-10-surf: #ffffff;
--d3-10-line: #d9d9e0;
--d3-10-ink: #0b0b0d;
--d3-10-mut: #5d5d68;
--d3-10-acc: #c40024;
--d3-10-acc: oklch(48% 0.22 22);
--d3-10-acc2: #8a6a00;
--d3-10-acc2: oklch(56% 0.13 100);
--d3-10-ok: #067a45;
--d3-10-ok: oklch(50% 0.14 152);
}
}
.d3-10__theme {
position: absolute;
inset-block-start: clamp(0.75rem, 3vw, 1.5rem);
inset-inline-end: clamp(0.75rem, 3vw, 1.5rem);
z-index: 20;
}
.d3-10__theme-input {
position: absolute;
opacity: 0;
inline-size: 100%;
block-size: 100%;
margin: 0;
cursor: pointer;
}
.d3-10__theme-label {
display: grid;
place-items: center;
inline-size: 44px;
block-size: 44px;
border: 1px solid var(--d3-10-line);
border-radius: 4px;
background: var(--d3-10-surf);
color: var(--d3-10-ink);
cursor: pointer;
}
.d3-10__theme-label svg {
inline-size: 20px;
block-size: 20px;
}
.d3-10__theme-input:focus-visible + .d3-10__theme-label {
outline: 2px solid var(--d3-10-acc);
outline-offset: 3px;
}
.d3-10__stage {
display: grid;
grid-template-columns: minmax(0, 1fr);
place-items: center;
min-block-size: 100vh;
padding: clamp(3.5rem, 9vw, 5rem) clamp(0.75rem, 4vw, 2.5rem);
}
.d3-10__viewport {
inline-size: 100%;
max-inline-size: 58rem;
overflow: hidden;
display: grid;
gap: clamp(1.1rem, 3.5vw, 1.8rem);
}
.d3-10__head {
display: grid;
gap: 0.3rem;
max-inline-size: 44ch;
}
.d3-10__kicker {
font: 700 0.64rem/1.4 ui-monospace, Menlo, monospace;
letter-spacing: 0.24em;
text-transform: uppercase;
color: var(--d3-10-acc);
}
.d3-10__head strong {
font: 700 clamp(1.5rem, 5.4vw, 2.7rem)/1 var(--d3-10-font-display);
letter-spacing: 0.005em;
text-transform: uppercase;
}
.d3-10__head p {
margin: 0.2rem 0 0;
font: 500 clamp(0.74rem, 2vw, 0.85rem)/1.5 system-ui, sans-serif;
color: var(--d3-10-mut);
text-wrap: pretty;
}
.d3-10__pair {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
gap: clamp(0.9rem, 3vw, 1.6rem);
}
.d3-10__slot {
display: grid;
gap: 0.6rem;
}
.d3-10__scene {
perspective: 620px;
perspective-origin: 50% 42%;
block-size: clamp(15.5rem, 46vw, 22rem);
display: grid;
place-items: center;
}
.d3-10__poster {
position: relative;
inline-size: min(100%, 13.5rem);
aspect-ratio: 0.74;
padding: clamp(0.8rem, 2.6vw, 1.1rem);
display: grid;
align-content: space-between;
transform-style: preserve-3d;
animation: d3-10-sway 11s ease-in-out infinite;
color: #fff;
}
.d3-10__face {
position: absolute;
inset: 0;
transform: translateZ(0);
background: linear-gradient(170deg, #14060a 0%, #2a0710 55%, #470a16 100%);
border: 1px solid var(--d3-10-line);
box-shadow: 0 30px 60px -28px #000;
}
.d3-10__night,
.d3-10__act,
.d3-10__venue {
transform: translateZ(3px);
}
@keyframes d3-10-sway {
0%,
100% {
transform: rotateX(11deg) rotateY(-27deg);
}
50% {
transform: rotateX(2deg) rotateY(27deg);
}
}
.d3-10__night {
font: 600 0.62rem/1.4 ui-monospace, Menlo, monospace;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--d3-10-acc2);
}
.d3-10__act {
font: 700 clamp(1.4rem, 4.6vw, 2.15rem)/0.92 var(--d3-10-font-display);
text-transform: uppercase;
letter-spacing: -0.01em;
}
.d3-10__venue {
font: 500 0.66rem/1.3 ui-monospace, Menlo, monospace;
color: rgba(255, 255, 255, 0.68);
}
.d3-10__stamp {
position: absolute;
inset-block-start: 68%;
inset-inline-start: 26%;
white-space: nowrap;
padding: 0.3rem 0.7rem;
border: 3px solid #ff5c74;
border-radius: 6px;
color: #ff8595;
font: 800 clamp(0.72rem, 2.1vw, 0.9rem)/1 var(--d3-10-font-display);
letter-spacing: 0.12em;
text-transform: uppercase;
transform: rotate(-11deg);
background: #1b0308;
}
.d3-10__poster--fixed .d3-10__stamp {
transform: translateZ(14px) rotate(-11deg);
box-shadow: 0 12px 24px -6px #000;
}
.d3-10__cap {
margin: 0;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.4rem;
font: 500 clamp(0.72rem, 1.95vw, 0.8rem)/1.3 system-ui, sans-serif;
color: var(--d3-10-mut);
}
.d3-10__cap code {
font: 600 0.95em/1 ui-monospace, Menlo, monospace;
color: var(--d3-10-ink);
}
.d3-10__badge {
padding: 0.18rem 0.5rem;
border-radius: 3px;
font: 800 0.62rem/1.5 ui-monospace, Menlo, monospace;
letter-spacing: 0.1em;
text-transform: uppercase;
color: #000;
}
.d3-10__badge--no {
background: var(--d3-10-acc);
color: #fff;
}
.d3-10__badge--ok {
background: var(--d3-10-ok);
}
@media (prefers-reduced-motion: reduce) {
.d3-10__poster {
animation: none;
transform: rotateX(9deg) rotateY(-24deg);
}
}
```How this works
Z-fighting is a tie the renderer has to break arbitrarily. Two surfaces at identical depth in the same 3D context have no defined order, so the compositor picks one — and can pick differently between frames, between engines, and between GPUs on the same engine. The symptom is a flicker or a torn seam along the overlap. The cause is geometry, not CSS syntax, which is why nothing in DevTools points at it.
The cheapest fix is a sub-pixel separation. translateZ(0.02px) on the surface that should win is far too small to change the projection at any realistic perspective value, and it removes the ambiguity completely. Use a real value rather than 0.001px; some engines round very small transforms away and the tie comes back.
The structural fix is to stop being in a 3D context at all. Inside an element that is not preserve-3d, painting is flat and ordinary z-index decides. If two surfaces genuinely belong in the same plane — a label over a panel, a badge over a face — flatten their wrapper and stack them with z-index. That is usually the right answer for UI, and it costs one fewer promoted layer.
Where this bites in practice: cube faces. All six faces of a cube are coplanar through the centre before their translateZ is applied, so a missing or mistyped translate on one face produces flicker rather than a missing face. Coplanar shadow plates and a floor grid drawn as two overlapping planes are the other two common sources — and both are fixed by the same sub-pixel offset.
Make it yours
- Change
--d3-10-nudgeto see how small a separation still resolves the tie in your target engines. - Slow
--d3-10-beatto inspect the torn seam frame by frame on the broken tile. - Swap the flattened tile's
z-indexvalues to reverse which surface wins — the point is that it is now defined at all. - Give the nested-fix tile a real offset to show that a child of a surface never fights with its parent.
- Add a fifth tile with three coplanar surfaces; the flicker gets worse in a way that is genuinely hard to debug.
- Recolour with the two
--d3-10-accdeclarations, hex first then oklch.
Gotchas — read before shipping
- The flicker is GPU and engine dependent, so it can pass review on the reviewer's machine and fail on a tester's phone. Treat coplanar surfaces as a bug even when you cannot see it.
- Very small nudges such as
0.001pxcan be rounded away, restoring the tie. Use a value like0.02px, and verify on the lowest-powered target device you support. z-indexhas no effect between siblings in apreserve-3dcontext — depth decides there. Reaching for z-index without flattening is the most common failed fix.- The safest tie-break for cube faces is to derive every
translateZfrom the size token, as demo 07 does. A hand-typed set of six is exactly how a coplanar face slips in.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 114+ | 17.5+ | 121+ | 114+ |
Floor set by :has(), oklch(), color-mix(), text-wrap as this demo is written. The core technique itself goes back further — Chrome 111+.
oklch() and the :has() theme toggle set the floor; the depth-sorting behaviour and the sub-pixel translateZ fix have worked since 3D transforms shipped (Chrome 36, Safari 9, Firefox 16). Note that the flicker itself is renderer dependent by nature, so the stepped animation here reproduces the ambiguity deterministically. Below the oklch() floor tokens use the sRGB hex declared first.