HeadingCentered heading
Gecentreerde sectie-aanhef: eyebrow, headline en sub. Optionele decoratieve lijn. 4 groottes.
src/components/heading/HeadingCentered.astro
---
interface Props {
eyebrow?: string;
headline: string;
sub?: string;
align?: 'center' | 'left';
size?: 'sm' | 'md' | 'lg' | 'xl';
divider?: boolean;
maxWidth?: string;
}
const {
eyebrow,
headline,
sub,
align = 'center',
size = 'md',
divider = false,
maxWidth = '640px',
} = Astro.props;
---
<section class={`hcn__section hcn__align-${align} hcn__size-${size}`}>
<div class="hcn__inner" style={`max-width: ${maxWidth}`}>
{eyebrow && (
<span class="hcn__eyebrow">
{eyebrow}
{divider && <span class="hcn__divider" aria-hidden="true"></span>}
</span>
)}
<h2 class="hcn__headline" set:html={headline} />
{sub && <p class="hcn__sub">{sub}</p>}
</div>
</section>
<script>
const sections = document.querySelectorAll<HTMLElement>('.hcn__section');
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('hcn--visible');
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.15 }
);
sections.forEach((el) => observer.observe(el));
</script>
<style>
:root {
--color-primary: #0a0a0a;
--color-accent: #6366f1;
--color-bg: #fff;
--color-muted: #6b7280;
--radius: 0.5rem;
}
.hcn__section {
padding: 5rem 1.5rem;
opacity: 0;
transform: translateY(24px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.hcn__section.hcn--visible {
opacity: 1;
transform: translateY(0);
}
.hcn__align-center {
text-align: center;
}
.hcn__align-left {
text-align: left;
}
.hcn__inner {
margin: 0 auto;
display: flex;
flex-direction: column;
gap: 1rem;
}
.hcn__align-center .hcn__inner {
align-items: center;
}
.hcn__align-left .hcn__inner {
align-items: flex-start;
}
.hcn__eyebrow {
display: flex;
flex-direction: column;
align-items: inherit;
gap: 0.75rem;
font-size: 0.75rem;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--color-accent);
}
.hcn__divider {
display: block;
width: 40px;
height: 3px;
background: var(--color-accent);
border-radius: 2px;
}
.hcn__headline {
margin: 0;
font-weight: 800;
letter-spacing: -0.02em;
color: var(--color-primary);
line-height: 1.1;
}
.hcn__headline em {
font-style: italic;
color: var(--color-accent);
}
/* Size variants */
.hcn__size-sm .hcn__headline {
font-size: clamp(1.5rem, 3vw, 2rem);
}
.hcn__size-md .hcn__headline {
font-size: clamp(2rem, 4vw, 3.5rem);
}
.hcn__size-lg .hcn__headline {
font-size: clamp(2.5rem, 5vw, 4rem);
}
.hcn__size-xl .hcn__headline {
font-size: clamp(2.5rem, 6vw, 5rem);
}
.hcn__sub {
margin: 0;
font-size: 1.125rem;
line-height: 1.7;
color: var(--color-muted);
max-width: 580px;
}
@media (prefers-reduced-motion: reduce) {
* {
animation: none !important;
transition: none !important;
}
}
</style>
Props
| Prop | Type | Default | Beschrijving |
|---|---|---|---|
headline * | string | — | Sectie H2 — gebruik <em> voor accent |
eyebrow | string | — | Klein label boven headline |
sub | string | — | Beschrijvende ondertekst |
divider | boolean | false | Decoratieve lijn onder eyebrow |
size | 'sm' | 'md' | 'lg' | 'xl' | 'md' | Headline grootte |
align | 'center' | 'left' | 'center' | Uitlijning |
* = verplicht