CSS step-animation frames start stacking on top of each other on nearby hover in Chrome/Edge

2 days ago 1
ARTICLE AD BOX

I am facing an issue with a pure HTML/CSS text-typing animation sequence built using stacked, absolutely positioned layers. The effect works perfectly on Firefox and Safari, but breaks consistently on Chromium-based browsers (Chrome, Edge).

If possible, I want to solve this strictly without JavaScript (vanilla HTML and CSS only).

The layout has an inline-block wrapper (.anim-container) containing ~60 spans (.anim-layer), all positioned absolutely at top: 0; left: 0.

The animation sequence is triggered via a checkbox hack (#trigger-checkbox:checked).

Each span has a discrete animation step (steps(1, end)) with progressive animation delays to create a timeline of typing, pausing, and deleting text.

It uses animation-fill-mode: forwards so that when a frame finishes animating, it holds its end state (opacity: 0 for old text, or opacity: 1 for the final text).

Here is the generic structure:

<header> <input type="checkbox" id="trigger-checkbox"> <nav> <label for="trigger-checkbox" class="anim-container"> <span class="anim-layer anim-layer-0">mytextstate<span class="cursor">|</span></span> <span class="anim-layer anim-layer-1">mytextstat<span class="cursor">|</span></span> <span class="anim-layer anim-layer-2">mytextsta<span class="cursor">|</span></span> </label> </nav> </header> .anim-container { font-family: monospace; position: relative; display: inline-block; white-space: nowrap; } .anim-layer { display: none; position: absolute; top: 0; left: 0; white-space: nowrap; opacity: 0; animation: frame-step 0.05s steps(1, end) forwards; animation-play-state: paused; } #trigger-checkbox:checked ~ nav .anim-layer { display: inherit; animation-play-state: running; } @keyframes frame-step { 0% { opacity: 1; } 100% { opacity: 0; } } @keyframes frame-pause { 0%, 99.99% { opacity: 1; } 100% { opacity: 0; } } @keyframes frame-final { 0%, 100% { opacity: 1; } } /* Timeline mapping via delays */ .anim-layer-1 { animation: var(--pause-duration); animation-delay: 0.00s; } .anim-layer-2 { animation: var(--long-duration); animation-delay: 0.50s; } .anim-layer-3 { animation-delay: 1.50s; }

The animation plays fine on its own. However, if a user hovers the mouse over any other part of the page that triggers a new animation or transformation, the text layout inside the header completely glitches out in Chrome and Edge. Layers start to remain on screen after they are drawn, causing them to stack on top of each other and making the text completely unreadable.

visual Replication of the issue

I have tried several CSS modifications to force rendering boundaries or explicit timelines, but none have resolved the stacking behavior on hover:

1. Isolating Stacking Context & Containment:

header { contain: layout paint; isolation: isolate; } .anim-container { isolation: isolate; transform: translateZ(0); }

2. Explicit Z-Index Mapping: Adding strict sequential z-index properties to match the chronological timeline order.

3. Toggling Visibility/Display via Keyframes: using properties like visibility: hidden or display: none directly into the 100% keyframe markers.

What exactly is causing Chromium to fail to maintain the end state of these completed animation steps when a nearby transition triggers a repaint or layer promotion? Is there a known rendering bug or layout pipeline quirk that explains why already-drawn layers remain visible while they are supposed to become hidden?

Most importantly, is there a declarative, pure CSS/HTML workaround to prevent this behavior without using JavaScript event listeners to clean up the DOM?

Read Entire Article