fix: render animated background via portal at z-index:-1 to stop implicit compositing

Previous isolation:isolate fix didn't work because:
- position:fixed elements still see through isolation boundary
- backdrop-filter samples all rendered content regardless of stacking context
- The real issue: animated background at z-index:0 with will-change:transform
  forces Chrome to implicitly composite EVERY overlapping element

Fix: render BackgroundRenderer via createPortal on document.body with
z-index:-1, placing it below the root stacking context. This eliminates
implicit compositing entirely.

Also:
- Remove backdrop-blur-xl from desktop header (was resampling bg 60fps)
- Remove will-change:opacity from card ::after pseudo-element
- Replace transition-all with transition-colors on header buttons
This commit is contained in:
Fringg
2026-02-27 08:14:20 +03:00
parent 04eacf6421
commit 12c97a2c5e
3 changed files with 150 additions and 149 deletions

View File

@@ -1,4 +1,5 @@
import { Suspense, useMemo } from 'react';
import { createPortal } from 'react-dom';
import { useQuery } from '@tanstack/react-query';
import { brandingApi } from '@/api/branding';
import type { AnimationConfig, BackgroundType } from '@/components/ui/backgrounds/types';
@@ -83,20 +84,25 @@ export function BackgroundRenderer() {
? reduceMobileSettings(effectiveConfig.settings)
: effectiveConfig.settings;
return (
// Render via portal on document.body with z-index: -1.
// This places the animated background BELOW the root stacking context,
// preventing Chrome's implicit compositing from promoting every
// overlapping element to its own GPU layer (the root cause of flickering).
return createPortal(
<div
className="pointer-events-none fixed inset-0 z-0"
className="pointer-events-none fixed inset-0"
style={{
zIndex: -1,
opacity: effectiveConfig.opacity,
filter: effectiveConfig.blur > 0 ? `blur(${effectiveConfig.blur}px)` : undefined,
contain: 'strict',
willChange: 'transform',
transform: 'translateZ(0)',
backfaceVisibility: 'hidden',
}}
>
<Suspense fallback={null}>
<Component settings={settings} />
</Suspense>
</div>
</div>,
document.body,
);
}