HeroParallax Hero
Full-bleed hero met achtergrondbeeld en donkere overlay, optioneel zwevend voorgrond-beeld, en tekst links (kop, sub, twee CTA's).
src/components/hero/HeroParallax.astro
---
/**
* HeroParallax
* Full-bleed hero met achtergrondbeeld + donkere overlay, optioneel zwevend
* voorgrond-beeld, en tekst links (kop met cursief accent, sub, twee CTA's).
* Content ligt op de pagina-rail (.bl-inner). Parallax + reveal zijn progressive
* enhancement: zonder JS rendert alles zichtbaar en statisch.
*
* Props: zie interface. Alle copy is prop-driven.
*/
interface Props {
bgImage: string;
fgImage?: string;
headline: string;
accent?: string;
sub?: string;
primaryCta?: { label: string; href: string };
ghostCta?: { label: string; href: string };
}
const {
bgImage,
fgImage,
headline,
accent,
sub,
primaryCta,
ghostCta,
} = Astro.props;
---
<section class:list={['bl-section', 'hpar__root']} aria-label="Hero">
<div class="hpar__bg">
<img data-allow-img src={bgImage} alt="" class="hpar__bg-img" loading="eager" fetchpriority="high" aria-hidden="true" decoding="async" />
<div class="hpar__overlay" aria-hidden="true"></div>
</div>
{fgImage && (
<div class="hpar__fg" aria-hidden="true">
<img data-allow-img src={fgImage} alt="" class="hpar__fg-img" loading="eager" fetchpriority="high" decoding="async" />
</div>
)}
<div class="bl-inner hpar__content">
<div class="hpar__inner">
<h1 class="hpar__headline">{headline}{accent && <em> {accent}</em>}</h1>
{sub && <p class="hpar__sub">{sub}</p>}
{(primaryCta || ghostCta) && (
<div class="hpar__actions">
{primaryCta && <a href={primaryCta.href} class="hpar__cta hpar__cta--primary">{primaryCta.label}</a>}
{ghostCta && <a href={ghostCta.href} class="hpar__cta hpar__cta--ghost">{ghostCta.label}</a>}
</div>
)}
</div>
</div>
</section>
<style>
.hpar__root{position:relative;width:100%;min-height:100svh;overflow:hidden;display:flex;align-items:center;background:var(--color-primary, #0a0a0a);padding-block:0}
.hpar__bg{position:absolute;inset:-15% 0;will-change:transform;z-index:0}
.hpar__bg-img{width:100%;height:100%;object-fit:cover;display:block}
.hpar__overlay{position:absolute;inset:0;background:#00000073}
.hpar__fg{position:absolute;right:6%;top:50%;transform:translateY(-50%);width:clamp(220px, 22vw, 300px);aspect-ratio:4 / 5;border-radius:calc(var(--radius, .5rem) * 2);overflow:hidden;box-shadow:0 32px 80px #00000080,0 8px 24px #00000059;will-change:transform;z-index:2}
.hpar__fg-img{width:100%;height:100%;object-fit:cover;display:block}
.hpar__content{position:relative;z-index:3}
.hpar__inner{max-width:min(640px,55vw)}
.hpar__headline{font-size:clamp(3rem, 6vw, 5rem);font-weight:900;line-height:1.04;letter-spacing:-.03em;color:#fff;margin:0 0 1.25rem}
.hpar__headline em{font-style:normal;color:var(--color-accent, #6366f1)}
.hpar__sub{font-size:clamp(1.0625rem,1.5vw,1.25rem);color:#e8e8e8;line-height:1.65;margin:0 0 2.5rem;max-width:48ch}
.hpar__actions{display:flex;flex-wrap:wrap;gap:.875rem;align-items:center}
.hpar__cta{display:inline-flex;align-items:center;justify-content:center;padding:.8125rem 2rem;border-radius:var(--radius, .5rem);font-size:.9375rem;font-weight:600;text-decoration:none;transition:opacity .2s,transform .2s;white-space:nowrap}
.hpar__cta:hover{opacity:.88;transform:translateY(-1px)}
.hpar__cta--primary{background:var(--color-accent, #6366f1);color:#fff}
.hpar__cta--ghost{background:transparent;color:#fff;border:1.5px solid rgba(255,255,255,.4)}
.hpar__cta--ghost:hover{border-color:#ffffffb3}
@media (max-width:768px){
.hpar__inner{max-width:100%}
.hpar__fg{display:none}
}
</style>
Props
| Prop | Type | Default | Beschrijving |
|---|---|---|---|
bgImage * | string | - | Achtergrondbeeld (full-bleed) |
fgImage | string | - | Zwevend voorgrond-beeld rechts |
headline * | string | - | H1-kop |
accent | string | - | Cursief accent direct na de kop |
sub | string | - | Ondertitel |
primaryCta | { label: string; href: string } | - | Primaire knop |
ghostCta | { label: string; href: string } | - | Ghost-knop |
* = verplicht