HeroAsymmetric Hero
Drie-koloms asymmetrisch grid: afbeeldingen links+rechts, tekst gecentreerd. Badges op afbeeldingen.
src/components/hero/HeroAsymmetric.astro
---
/**
* HeroAsymmetric
* 3-koloms asymmetrisch grid: tekst + 2 afbeeldingen met badge overlays.
* Editorial / Modern Retail mix — gedurfd layout, typografisch sterk.
*/
interface Props {
overline?: string;
headline: string;
sub: string;
ctaLabel?: string;
ctaHref?: string;
ctaSecondary?: string;
ctaSecondaryHref?: string;
image1: string;
image2: string;
badge1?: string;
badge2?: string;
}
const {
overline,
headline,
sub,
ctaLabel = 'Lees meer',
ctaHref = '#',
ctaSecondary,
ctaSecondaryHref = '#',
image1,
image2,
badge1,
badge2,
} = Astro.props;
---
<section class="has" data-component="hero-asymmetric">
<div class="has__inner">
<!-- Col 1: image tall -->
<div class="has__col has__col--img1">
<div class="has__img-wrap">
<img src={image1} alt="" class="has__img" loading="eager" />
{badge1 && <span class="has__badge has__badge--tl">{badge1}</span>}
</div>
</div>
<!-- Col 2: text centered -->
<div class="has__col has__col--text">
{overline && <p class="has__overline">{overline}</p>}
<h1 class="has__headline" set:html={headline} />
<p class="has__sub">{sub}</p>
<div class="has__ctas">
<a href={ctaHref} class="has__cta has__cta--primary">{ctaLabel}</a>
{ctaSecondary && (
<a href={ctaSecondaryHref} class="has__cta has__cta--link">
{ctaSecondary}
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 8h10M9 4l4 4-4 4"/></svg>
</a>
)}
</div>
</div>
<!-- Col 3: image shorter + badge -->
<div class="has__col has__col--img2">
<div class="has__img-wrap">
<img src={image2} alt="" class="has__img" loading="eager" />
{badge2 && <span class="has__badge has__badge--br">{badge2}</span>}
</div>
</div>
</div>
</section>
<style>
.has {
background: var(--color-bg, #fff);
padding: 4rem 1.5rem;
overflow: hidden;
}
.has__inner {
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-template-columns: 1fr 1.2fr 1fr;
gap: 1.5rem;
align-items: center;
min-height: 560px;
}
/* Images */
.has__col--img1 .has__img-wrap,
.has__col--img2 .has__img-wrap {
position: relative;
border-radius: calc(var(--radius, 0.5rem) * 2);
overflow: hidden;
}
.has__col--img1 {
align-self: stretch;
}
.has__col--img2 {
align-self: end;
}
.has__img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
min-height: 320px;
transition: transform 0.6s ease;
}
.has__col--img1 .has__img { height: 520px; }
.has__col--img2 .has__img { height: 360px; }
.has__img-wrap:hover .has__img {
transform: scale(1.03);
}
.has__badge {
position: absolute;
background: var(--color-accent, #6366f1);
color: #fff;
font-size: 0.75rem;
font-weight: 700;
padding: 0.4rem 0.875rem;
border-radius: 100px;
white-space: nowrap;
}
.has__badge--tl { top: 1rem; left: 1rem; }
.has__badge--br { bottom: 1rem; right: 1rem; }
/* Text */
.has__col--text {
padding: 1rem;
text-align: center;
}
.has__overline {
font-size: 0.75rem;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--color-accent, #6366f1);
margin-bottom: 1rem;
}
.has__headline {
font-size: clamp(2rem, 3.5vw, 3.25rem);
font-weight: 800;
line-height: 1.1;
letter-spacing: -0.03em;
color: var(--color-primary, #0a0a0a);
margin-bottom: 1.25rem;
}
.has__headline :global(em) {
font-style: normal;
color: var(--color-accent, #6366f1);
}
.has__sub {
font-size: 1rem;
line-height: 1.7;
color: var(--color-muted, #6b7280);
margin-bottom: 2rem;
}
.has__ctas {
display: flex;
gap: 1rem;
justify-content: center;
flex-wrap: wrap;
}
.has__cta {
text-decoration: none;
font-weight: 700;
font-size: 0.9375rem;
transition: all 0.2s;
}
.has__cta--primary {
display: inline-block;
background: var(--color-primary, #0a0a0a);
color: #fff;
padding: 0.8125rem 1.75rem;
border-radius: var(--radius, 0.5rem);
}
.has__cta--primary:hover {
background: var(--color-accent, #6366f1);
transform: translateY(-1px);
}
.has__cta--link {
display: inline-flex;
align-items: center;
gap: 0.35rem;
color: var(--color-primary, #0a0a0a);
padding: 0.8125rem 0;
opacity: 0.7;
}
.has__cta--link:hover {
opacity: 1;
color: var(--color-accent, #6366f1);
}
@media (max-width: 900px) {
.has__inner {
grid-template-columns: 1fr;
min-height: auto;
}
.has__col--img1 { order: 1; }
.has__col--text { order: 2; }
.has__col--img2 { order: 3; }
.has__col--img1 .has__img,
.has__col--img2 .has__img { height: 280px; }
}
</style>
Props
| Prop | Type | Default | Beschrijving |
|---|---|---|---|
headline * | string | — | H1 — gebruik <em> voor accent |
sub * | string | — | Subtitel |
image1 * | string | — | Hoge afbeelding links |
image2 * | string | — | Kortere afbeelding rechts |
overline | string | — | Kleine tekst boven headline |
badge1 | string | — | Badge op linker afbeelding |
badge2 | string | — | Badge op rechter afbeelding |
* = verplicht