Zoeken...  ⌘K GitHub

HeroParallax Hero

Full-bleed hero met achtergrondbeeld en donkere overlay, optioneel zwevend voorgrond-beeld, en tekst links (kop, sub, twee CTA's).

/hero-parallax
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