Zoeken...  ⌘K GitHub

HeroBoldSplit Hero

Oversized editorial headline links, full-bleed afbeelding rechts. Outline tekst effect via <strong>. Puur CSS animaties.

/hero-bold-split
src/components/hero/HeroBoldSplit.astro
---
/**
 * HeroBoldSplit
 * Oversized editorial headline links, full-bleed afbeelding rechts.
 * Geen padding overhead — tekst raakt de randen. Snel: puur CSS animaties.
 */
interface Props {
  preHeadline?: string;
  headline: string;
  sub?: string;
  ctaLabel?: string;
  ctaHref?: string;
  secondaryLabel?: string;
  secondaryHref?: string;
  imageSrc: string;
  imageAlt?: string;
  accentWord?: string; /** woord in headline dat accentkleur krijgt */
}

const {
  preHeadline,
  headline,
  sub,
  ctaLabel = 'Aan de slag',
  ctaHref = '#',
  secondaryLabel,
  secondaryHref = '#',
  imageSrc,
  imageAlt = '',
} = Astro.props;
---

<section class="hbs" data-component="hero-bold-split">
  <div class="hbs__left">
    <div class="hbs__content">
      {preHeadline && (
        <p class="hbs__pre">
          <span class="hbs__pre-dot"></span>
          {preHeadline}
        </p>
      )}
      <h1 class="hbs__headline" set:html={headline} />
      {sub && <p class="hbs__sub">{sub}</p>}
      <div class="hbs__actions">
        <a href={ctaHref} class="hbs__cta">{ctaLabel}</a>
        {secondaryLabel && (
          <a href={secondaryHref} class="hbs__secondary">
            {secondaryLabel}
            <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
              <path d="M2 7h10M8 3l4 4-4 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
            </svg>
          </a>
        )}
      </div>
    </div>
  </div>

  <div class="hbs__right">
    <div class="hbs__img-wrap">
      <img src={imageSrc} alt={imageAlt} class="hbs__img" loading="eager" fetchpriority="high" />
      <div class="hbs__img-overlay"></div>
    </div>
  </div>
</section>

<style>
  .hbs {
    display: grid;
    grid-template-columns: 1fr 1fr;
    min-height: 100vh;
    overflow: hidden;
    background: var(--color-bg, #fff);
  }

  /* Left */
  .hbs__left {
    display: flex;
    align-items: center;
    padding: 5rem 4rem 5rem 5vw;
    background: var(--color-bg, #fff);
  }

  .hbs__content { max-width: 560px; }

  .hbs__pre {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--color-muted, #6b7280);
    margin-bottom: 1.5rem;
    animation: hbs-fade-up 0.5s 0.1s cubic-bezier(0.22,1,0.36,1) both;
  }

  .hbs__pre-dot {
    width: 8px; height: 8px;
    border-radius: 50%;
    background: var(--color-accent, #6366f1);
    flex-shrink: 0;
  }

  .hbs__headline {
    font-size: clamp(3rem, 6vw, 6rem);
    font-weight: 800;
    line-height: 1.0;
    letter-spacing: -0.045em;
    color: var(--color-primary, #0a0a0a);
    margin-bottom: 1.5rem;
    animation: hbs-fade-up 0.65s 0.2s cubic-bezier(0.22,1,0.36,1) both;
  }

  .hbs__headline :global(em) {
    font-style: normal;
    color: var(--color-accent, #6366f1);
  }

  /* Outlined accent variant */
  .hbs__headline :global(strong) {
    -webkit-text-stroke: 2px var(--color-primary, #0a0a0a);
    color: transparent;
    font-weight: 800;
  }

  .hbs__sub {
    font-size: 1.0625rem;
    line-height: 1.65;
    color: var(--color-muted, #6b7280);
    margin-bottom: 2.5rem;
    max-width: 40ch;
    animation: hbs-fade-up 0.6s 0.35s cubic-bezier(0.22,1,0.36,1) both;
  }

  .hbs__actions {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    animation: hbs-fade-up 0.6s 0.45s cubic-bezier(0.22,1,0.36,1) both;
  }

  .hbs__cta {
    display: inline-flex;
    align-items: center;
    background: var(--color-primary, #0a0a0a);
    color: #fff;
    padding: 0.9375rem 2rem;
    border-radius: var(--radius, 0.5rem);
    font-weight: 700;
    font-size: 0.9375rem;
    text-decoration: none;
    transition: background 0.2s, transform 0.2s;
  }

  .hbs__cta:hover {
    background: var(--color-accent, #6366f1);
    transform: translateY(-2px);
  }

  .hbs__secondary {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--color-primary, #0a0a0a);
    text-decoration: none;
    opacity: 0.6;
    transition: opacity 0.2s, gap 0.2s;
  }

  .hbs__secondary:hover { opacity: 1; gap: 0.6rem; }

  /* Right */
  .hbs__right { position: relative; overflow: hidden; }

  .hbs__img-wrap {
    position: absolute;
    inset: 0;
    animation: hbs-scale-in 1s 0.1s cubic-bezier(0.22,1,0.36,1) both;
  }

  .hbs__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }

  .hbs__img-overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(to right, var(--color-bg, #fff) 0%, transparent 15%);
    pointer-events: none;
  }

  /* Animations — compositor-only (transform + opacity) */
  @keyframes hbs-fade-up {
    from { opacity: 0; transform: translateY(28px); }
    to   { opacity: 1; transform: translateY(0); }
  }

  @keyframes hbs-scale-in {
    from { opacity: 0; transform: scale(1.05); }
    to   { opacity: 1; transform: scale(1); }
  }

  @media (prefers-reduced-motion: reduce) {
    .hbs__pre, .hbs__headline, .hbs__sub, .hbs__actions, .hbs__img-wrap {
      animation: none;
    }
  }

  @media (max-width: 900px) {
    .hbs {
      grid-template-columns: 1fr;
      min-height: auto;
    }
    .hbs__right {
      height: 55vw;
      min-height: 280px;
      position: relative;
    }
    .hbs__left {
      padding: 3.5rem 1.5rem;
      order: 2;
    }
    .hbs__right { order: 1; }
    .hbs__img-overlay {
      background: linear-gradient(to bottom, transparent 60%, var(--color-bg, #fff) 100%);
    }
  }
</style>

Props

Prop Type Default Beschrijving
headline * string H1 — gebruik <em> voor accentkleur, <strong> voor outline effect
imageSrc * string Rechts afbeelding (full-bleed)
preHeadline string Klein label boven headline met dot
sub string Ondertitel
ctaLabel string 'Aan de slag' Primaire CTA
secondaryLabel string Secundaire tekstlink

* = verplicht