fix: ohne JavaScript blieb der gesamte Seiteninhalt unter dem Hero unsichtbar
Hero, ScrollReveal und ProductCard starten mit opacity 0 und werden per motion/react eingeblendet. Diese Startwerte stehen als inline-style bereits im server-gerenderten HTML — auf wabenhain.com an 38 Elementen nachgezaehlt. Laeuft kein JavaScript, blendet sie niemand wieder ein: der Besucher sieht das Hero-Bild und darunter eine leere Seite. Kein Teilausfall, sondern der komplette Inhalt. Fuer Suchmaschinen war das unkritisch, der Text steht im HTML. Fuer Menschen mit deaktiviertem JavaScript war es ein Totalausfall. Die drei Bausteine tragen jetzt data-reveal, und ein noscript-Block im Root-Layout hebt darueber die Startwerte auf. Das Attribut statt eines Treffers auf [style*="opacity:0"] ist der Kern der Sache: Warenkorb-Schublade, Menue und Cookie-Banner blenden ueber AnimatePresence ebenfalls mit opacity 0 ein, sollen ohne JavaScript aber verborgen BLEIBEN. Sie tragen das Attribut nicht. !important ist hier notwendig und nicht nachlaessig — einen inline-style ueberschreibt sonst nichts. Grenze der Loesung: noscript deckt "JavaScript deaktiviert" ab. Laedt das Bundle dagegen und schlaegt erst spaeter fehl, greift es nicht; dafuer waere ein Zeitgeber noetig, der die Animation im Normalfall stoeren wuerde. tsc: 0 Fehler. vitest: 359/359 gruen. eslint: 0 Warnungen. next build: gruen. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
1 parent
c5e4978fad
commit
cc267ad8d4
4 files changed
+35
-5
No files matched your search
@@ -89,6 +89,28 @@ export default async function RootLayout({ children }: LayoutProps<"/">) {
|
||||
className={`${cormorant.variable} ${inter.variable} h-full antialiased`}
|
||||
>
|
||||
<body className="min-h-full flex flex-col bg-background text-ink">
|
||||
{/* Rettungsnetz fuer den Fall, dass kein JavaScript laeuft.
|
||||
|
||||
Hero, ScrollReveal und ProductCard starten mit opacity 0 und werden
|
||||
erst per motion/react eingeblendet. Weil diese Startwerte schon im
|
||||
server-gerenderten HTML als inline-style stehen, blieb ohne
|
||||
JavaScript alles unterhalb des Hero-Bildes dauerhaft unsichtbar —
|
||||
kein Teilausfall, sondern der komplette Seiteninhalt. Auf
|
||||
wabenhain.com waren das 38 Elemente.
|
||||
|
||||
!important ist hier notwendig und nicht nachlaessig: es gibt keine
|
||||
andere Moeglichkeit, einen inline-style zu ueberschreiben. Die
|
||||
Regel zielt ausschliesslich auf [data-reveal] — Ein- und
|
||||
Ausblendungen in AnimatePresence (Warenkorb-Schublade, Menue,
|
||||
Cookie-Banner) tragen das Attribut nicht und bleiben verborgen.
|
||||
|
||||
Deckt den Fall "JavaScript deaktiviert" ab. Laedt das Bundle
|
||||
dagegen und schlaegt erst spaeter fehl, greift noscript nicht —
|
||||
dafuer waere ein Zeitgeber noetig, der die Animation im Normalfall
|
||||
stoeren wuerde. */}
|
||||
<noscript>
|
||||
<style>{`[data-reveal]{opacity:1!important;transform:none!important}`}</style>
|
||||
</noscript>
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(localBusinessJsonLd).replace(/</g, "\\u003c") }}
|
||||
|
||||
@@ -119,18 +119,18 @@ export function Hero({
|
||||
variants={itemContainerVariants}
|
||||
>
|
||||
<motion.p
|
||||
variants={itemVariants}
|
||||
data-reveal="" variants={itemVariants}
|
||||
className="tracking-wide-caps text-xs text-honey-light mb-4"
|
||||
>
|
||||
{location}
|
||||
</motion.p>
|
||||
<motion.h1 variants={itemVariants} className="text-4xl md:text-6xl leading-tight">
|
||||
<motion.h1 data-reveal="" variants={itemVariants} className="text-4xl md:text-6xl leading-tight">
|
||||
{t.footer.tagline}
|
||||
</motion.h1>
|
||||
<motion.p variants={itemVariants} className="mt-6 text-cream/85 max-w-md leading-relaxed">
|
||||
<motion.p data-reveal="" variants={itemVariants} className="mt-6 text-cream/85 max-w-md leading-relaxed">
|
||||
{intro}
|
||||
</motion.p>
|
||||
<motion.div variants={itemVariants} className="mt-10 flex flex-wrap gap-4">
|
||||
<motion.div data-reveal="" variants={itemVariants} className="mt-10 flex flex-wrap gap-4">
|
||||
<LinkButton href="/shop">{t.home.hero.ctaPrimary}</LinkButton>
|
||||
<LinkButton
|
||||
href="/imkerei"
|
||||
@@ -140,7 +140,7 @@ export function Hero({
|
||||
{t.home.hero.ctaSecondary}
|
||||
</LinkButton>
|
||||
</motion.div>
|
||||
<motion.p variants={itemVariants} className="mt-8 text-xs text-cream/60 tracking-wide">
|
||||
<motion.p data-reveal="" variants={itemVariants} className="mt-8 text-xs text-cream/60 tracking-wide">
|
||||
{footnote}
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
|
||||
@@ -178,6 +178,8 @@ export function ProductCard({
|
||||
|
||||
return (
|
||||
<motion.article
|
||||
// Siehe scroll-reveal.tsx: Gegenstueck zum noscript-Block im Root-Layout.
|
||||
data-reveal=""
|
||||
initial={{ opacity: 0, y: 16 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: "-60px" }}
|
||||
|
||||
@@ -23,6 +23,12 @@ export function ScrollReveal({
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
// Markiert dieses Element als "startet unsichtbar und wird per
|
||||
// JavaScript eingeblendet". Der noscript-Block im Root-Layout hebt genau
|
||||
// darueber die Startwerte wieder auf — ohne das Attribut muesste er
|
||||
// blind auf [style*="opacity:0"] zielen und traefe damit auch
|
||||
// Ein-/Ausblendungen, die bewusst verborgen bleiben sollen.
|
||||
data-reveal=""
|
||||
className={className}
|
||||
initial={shouldReduceMotion ? false : { opacity: 0, y }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
|
||||
Reference in new issue
Block a user