Fix blink root cause: eliminate position:fixed GPU compositing layers
Chrome promotes ALL position:fixed elements to GPU compositing layers for scroll
performance, regardless of whether they have animations. The body::before scanline
overlay (position:fixed, z-index:9999, full-viewport) and body::after watermark
(position:fixed) were both on GPU layers. Every CPU repaint from any hover state
change required a compositor re-blend pass → one-frame blink at compositor sync.
Fixes:
- Move scanlines from body::before (position:fixed) into body { background-image }
— same visual, no separate element, no GPU layer promotion
- Set body::before { display:none } and body::after { display:none } in both
dashboard.css and base.css
- Remove animation:matrix-rain from .stat-card:hover::before — background-position
animation is not GPU-composited, caused CPU repaints every frame while hovered
plus GPU texture uploads when animation started/stopped on cursor enter/exit
- Scope a { transition: all } → transition: color in base.css
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -171,7 +171,7 @@ body {
|
|||||||
a {
|
a {
|
||||||
color: var(--terminal-green);
|
color: var(--terminal-green);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: var(--transition-fast);
|
transition: color 0.15s ease;
|
||||||
}
|
}
|
||||||
a:hover {
|
a:hover {
|
||||||
color: var(--terminal-amber);
|
color: var(--terminal-amber);
|
||||||
@@ -185,37 +185,21 @@ img, svg { display: block; max-width: 100%; }
|
|||||||
03. CRT & TERMINAL EFFECTS
|
03. CRT & TERMINAL EFFECTS
|
||||||
---------------------------------------------------------------- */
|
---------------------------------------------------------------- */
|
||||||
|
|
||||||
/* Horizontal scanline overlay — fixed over the entire viewport */
|
/* Scanlines baked into body background — position:fixed overlay removed because
|
||||||
body::before {
|
Chrome promotes all position:fixed elements to GPU compositing layers, causing
|
||||||
content: '';
|
a compositor re-blend blink on every CPU repaint triggered by hover states. */
|
||||||
position: fixed;
|
body {
|
||||||
inset: 0;
|
background-image: repeating-linear-gradient(
|
||||||
background: repeating-linear-gradient(
|
|
||||||
0deg,
|
0deg,
|
||||||
rgba(0, 0, 0, 0.15) 0px,
|
rgba(0, 0, 0, 0.15) 0px,
|
||||||
rgba(0, 0, 0, 0.15) 1px,
|
rgba(0, 0, 0, 0.15) 1px,
|
||||||
transparent 1px,
|
transparent 1px,
|
||||||
transparent 2px
|
transparent 2px
|
||||||
);
|
);
|
||||||
pointer-events: none;
|
|
||||||
z-index: var(--z-overlay);
|
|
||||||
animation: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Binary data-stream watermark — bottom-right corner */
|
|
||||||
body::after {
|
|
||||||
content: '10101010';
|
|
||||||
position: fixed;
|
|
||||||
bottom: 10px;
|
|
||||||
right: 14px;
|
|
||||||
font-family: var(--font-mono);
|
|
||||||
font-size: 0.55rem;
|
|
||||||
color: var(--terminal-green);
|
|
||||||
opacity: 0.07;
|
|
||||||
pointer-events: none;
|
|
||||||
letter-spacing: 2px;
|
|
||||||
animation: data-stream 3s steps(1) infinite;
|
|
||||||
}
|
}
|
||||||
|
body::before { display: none; }
|
||||||
|
/* body::after binary watermark also suppressed — was position:fixed (GPU layer) */
|
||||||
|
body::after { display: none; }
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
04. TYPOGRAPHY
|
04. TYPOGRAPHY
|
||||||
|
|||||||
@@ -96,28 +96,29 @@ body {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: var(--spacing-md);
|
padding: var(--spacing-md);
|
||||||
background-color: var(--bg-primary);
|
background-color: var(--bg-primary);
|
||||||
color: var(--text-primary);
|
/* Scanlines baked into body background — avoids position:fixed GPU layer */
|
||||||
position: relative;
|
background-image: repeating-linear-gradient(
|
||||||
}
|
|
||||||
|
|
||||||
/* CRT Scanline Effect - Subtle retro terminal look */
|
|
||||||
body::before {
|
|
||||||
content: '';
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: repeating-linear-gradient(
|
|
||||||
0deg,
|
0deg,
|
||||||
rgba(0, 0, 0, 0.15),
|
rgba(0, 0, 0, 0.15) 0px,
|
||||||
rgba(0, 0, 0, 0.15) 1px,
|
rgba(0, 0, 0, 0.15) 1px,
|
||||||
transparent 1px,
|
transparent 1px,
|
||||||
transparent 2px
|
transparent 2px
|
||||||
);
|
);
|
||||||
pointer-events: none;
|
color: var(--text-primary);
|
||||||
z-index: var(--z-overlay);
|
position: relative;
|
||||||
animation: none;
|
}
|
||||||
|
|
||||||
|
/* body::before was the CRT scanline overlay (position:fixed, z-index:9999).
|
||||||
|
Chrome promotes all position:fixed elements to GPU compositing layers, so
|
||||||
|
every hover-triggered CPU repaint caused a compositor re-blend blink.
|
||||||
|
Scanlines moved to body background-image above. */
|
||||||
|
body::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Suppress body::after binary text watermark (also position:fixed → GPU layer) */
|
||||||
|
body::after {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Screen Flicker Effect */
|
/* Screen Flicker Effect */
|
||||||
@@ -293,7 +294,6 @@ a:not(.btn):hover::after {
|
|||||||
|
|
||||||
.stat-card:hover::before {
|
.stat-card:hover::before {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
animation: matrix-rain 2s linear infinite;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes matrix-rain {
|
@keyframes matrix-rain {
|
||||||
|
|||||||
Reference in New Issue
Block a user