Opent in een nieuw tabblad

CSS-lab · Hero's

Kinetische typografie-hero

Een hero met een gigantische uppercase kop waarvan de regels om en om van links en rechts inschuiven, met één woord dat acid oplicht.

  • Gemiddeld
  • Pure CSS
  • MIT-licentie
  • @keyframes
  • animation-delay calc()
  • custom properties
  • container queries (cqi)
  • clamp()
HTML
<section class="kt-hero">
  <div class="kt-inner">
    <p class="kt-kicker"><span class="kt-dot" aria-hidden="true"></span>Studio voor interactief webdesign</p>
    <h2 class="kt-title">
      <span class="kt-line" style="--i:0"><span>Websites</span></span>
      <span class="kt-line kt-line--r" style="--i:1"><span>die <mark class="kt-mark">bewegen</mark></span></span>
      <span class="kt-line" style="--i:2"><span>en raken</span></span>
    </h2>
    <div class="kt-foot">
      <p class="kt-intro">We ontwerpen en bouwen sites waarin typografie, ritme en beweging samen het verhaal vertellen. Snel, toegankelijk en tot op de pixel verzorgd.</p>
      <div class="kt-actions">
        <a href="#" class="kt-btn kt-btn--primary">Start een project</a>
        <a href="#" class="kt-btn kt-btn--ghost">Bekijk ons werk</a>
      </div>
    </div>
  </div>
</section>
CSS
/* Kinetische typografie-hero - prefix .kt- */
.kt-hero {
  --bg: #0C0C0D;
  --ink: #F9F8F6;
  --muted: rgba(249, 248, 246, 0.7);
  --accent: #C6FF3D;
  --speed: 0.9s;
  --stagger: 0.14s;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  container-type: inline-size;
  display: grid;
  align-items: center;
  width: 100%;
  min-height: 520px;
  overflow: hidden;
  color: var(--ink);
  background: var(--bg);
}

.kt-inner {
  width: 100%;
  padding: clamp(32px, 6vw, 80px) clamp(20px, 5vw, 72px);
  padding: clamp(32px, 6cqi, 80px) clamp(20px, 5cqi, 72px);
}

.kt-kicker {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 clamp(16px, 3cqi, 32px);
  font: 600 0.8rem/1.2 ui-monospace, Menlo, Consolas, monospace;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
}

.kt-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  animation: kt-blink 1.6s steps(2, jump-none) infinite;
}

/* Gigantische kop, schaalt met de breedte van de hero */
.kt-title {
  margin: 0;
  font-family: "Arial Black", "Helvetica Neue", Impact, system-ui, sans-serif;
  font-weight: 900;
  font-size: clamp(2.2rem, 8.5vw, 7.5rem);
  font-size: clamp(2.2rem, 8.5cqi, 7.5rem);
  line-height: 0.92;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}

/* Elke regel is een venster, de span schuift erin */
.kt-line {
  display: block;
  overflow: hidden;
  padding-block: 0.04em;
}

.kt-line--r {
  text-align: right;
}

.kt-line > span {
  display: inline-block;
  animation: kt-in-l var(--speed) var(--ease) both;
  animation-delay: calc(var(--i) * var(--stagger));
}

.kt-line--r > span {
  animation-name: kt-in-r;
}

/* Acid-markering vult na de laatste regel */
.kt-mark {
  padding: 0 0.08em;
  color: var(--accent);
  background: linear-gradient(var(--accent), var(--accent)) no-repeat 0 0 / 0% 100%;
  animation: kt-mark 0.6s var(--ease) forwards;
  animation-delay: calc(var(--speed) + var(--stagger) * 2);
}

.kt-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin-top: clamp(24px, 4cqi, 48px);
  animation: kt-fade 0.8s ease both;
  animation-delay: calc(var(--speed) + var(--stagger) * 2);
}

.kt-intro {
  max-width: 44ch;
  margin: 0;
  font: 400 1.05rem/1.6 system-ui, sans-serif;
  color: var(--muted);
}

.kt-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.kt-btn {
  padding: 16px 24px;
  font: 700 0.95rem/1 system-ui, sans-serif;
  text-decoration: none;
  border: 2px solid var(--ink);
  transition: background-color 0.2s, color 0.2s, border-color 0.2s;
}

.kt-btn--primary {
  color: var(--bg);
  background: var(--accent);
  border-color: var(--accent);
}

.kt-btn--ghost {
  color: var(--ink);
}

.kt-btn:hover {
  color: var(--bg);
  background: var(--ink);
  border-color: var(--ink);
}

.kt-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
}

@keyframes kt-in-l {
  from { transform: translateX(-110%); }
}

@keyframes kt-in-r {
  from { transform: translateX(110%); }
}

@keyframes kt-mark {
  to {
    color: var(--bg);
    background-size: 100% 100%;
  }
}

@keyframes kt-fade {
  from { opacity: 0; transform: translateY(12px); }
}

@keyframes kt-blink {
  50% { opacity: 0.2; }
}

@media (prefers-reduced-motion: reduce) {
  .kt-line > span,
  .kt-mark,
  .kt-foot,
  .kt-dot {
    animation: none;
  }

  .kt-mark {
    color: var(--bg);
    background-size: 100% 100%;
  }
}

Wat het is en waar je het gebruikt

In deze hero is de typografie het beeld. Een gigantische kop in hoofdletters bouwt zichzelf op: de eerste regel schuift van links binnen, de tweede van rechts en de derde weer van links. Daarna wordt één woord gemarkeerd met een acid-lime vlak dat van links naar rechts invult. Onder de kop verschijnen een korte intro en twee knoppen. Er zijn geen afbeeldingen nodig, alleen tekst, ritme en timing.

Het patroon past bij studio’s, agencies, persoonlijke portfolio’s en productlanceringen waar de boodschap sterk genoeg is om alleen te staan. Omdat alles uit HTML-tekst bestaat, laadt hij snel en blijft de kop gewoon vindbaar en vertaalbaar.

Zo werkt het

  • Elke regel is een .kt-line met overflow: hidden. Daarin staat een span met display: inline-block die met transform: translateX(-110%) vanuit het niets binnenschuift. Regels met .kt-line--r staan rechts uitgelijnd en komen met translateX(110%) van de andere kant.
  • De stagger komt uit een inline --i per regel en animation-delay: calc(var(--i) * var(--stagger)). Met animation-fill-mode: both staat elke regel al buiten beeld tijdens de wachttijd.
  • De markering op .kt-mark is een linear-gradient als achtergrond. De keyframes kt-mark laten de background-size groeien van 0% 100% naar 100% 100% en draaien de tekstkleur om.
  • De hero is een container-type: inline-size. De kop schaalt met clamp() en cqi-eenheden mee met de breedte van de hero zelf, niet met het scherm. Dat werkt ook in een smalle kolom of een kaart. Browsers zonder container units gebruiken de vw-waarde ervoor.
  • De hoogte is min-height: 520px in plaats van 100vh. Zo blijft de hero beheersbaar in elke layout.

Aanpassen

Op .kt-hero stel je met --bg, --ink en --muted de achtergrond, kop- en introkleur in. --accent kleurt de kicker, de markering en de primaire knop. --speed is de duur van één regel, --stagger de vertraging tussen regels en --ease de curve. Een vierde regel voeg je toe met --i:3. De markering start automatisch na de laatste regel.

Toegankelijkheid en browsersupport

De kop is één echte heading, dus schermlezers lezen hem als een gewone zin. In de demo is dat een <h2>, omdat de pagina zelf al een <h1> heeft. Op je eigen homepage maak je er een <h1> van. De knoppen zijn echte links met :focus-visible-outlines. Off-white en acid lime op carbon hebben een hoog contrast. In het prefers-reduced-motion-blok staan alle animaties uit en is de markering direct zichtbaar. Container query units werken in alle actuele browsers. Oudere browsers vallen terug op vw.

Verder lezen

Wil je weten welke elementen een hero laten converteren? Lees hero-secties die converteren. Of ontdek hoe we typografie laten bewegen in interactief webdesign en animaties.