Opent in een nieuw tabblad

CSS-lab · Tekst-effecten

Typewriter met knipperende cursor

Een terminalvenster waarin een regel letter voor letter wordt getypt, even blijft staan en weer wordt gewist, met een knipperende acid cursor. Pure CSS met steps() en ch.

  • Gemiddeld
  • Pure CSS
  • MIT-licentie
  • steps()
  • ch-eenheid
  • @keyframes
  • border-right cursor
  • calc() met custom properties
HTML
<div class="twt-term">
  <div class="twt-bar" aria-hidden="true">
    <span></span><span></span><span></span>
    <em>manifest — zsh</em>
  </div>
  <p class="twt-row">
    <span class="twt-prompt" aria-hidden="true">~ $</span>
    <span class="twt-line">Ontwerp. Code. Lancering.</span>
  </p>
</div>
CSS
/* Typewriter: steps() + ch-eenheden + border-cursor */
.twt-term {
  --bg: #141416;
  --ink: #F9F8F6;
  --accent: #C6FF3D;
  --chars: 25;
  --speed: 6s;
  width: min(100%, 640px);
  overflow: hidden;
  border: 1px solid #2A2A2F;
  border-radius: 14px;
  background: var(--bg);
  box-shadow: 0 30px 60px -24px rgba(0, 0, 0, .7);
  font-family: ui-monospace, Menlo, Consolas, monospace;
}

/* Titelbalk met drie lampjes */
.twt-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border-bottom: 1px solid #2A2A2F;
}

.twt-bar span {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #FF5C5C;
}

.twt-bar span:nth-child(2) { background: #FFC83D; }
.twt-bar span:nth-child(3) { background: var(--accent); }

.twt-bar em {
  margin-left: auto;
  font-size: 12px;
  font-style: normal;
  color: #8E8E96;
}

.twt-row {
  display: flex;
  align-items: baseline;
  gap: .6em;
  margin: 0;
  padding: clamp(20px, 4vw, 36px) clamp(16px, 3vw, 28px);
  font-size: clamp(16px, 3.2vw, 30px);
  color: var(--ink);
}

.twt-prompt {
  flex-shrink: 0;
  color: var(--accent);
}

/* Breedte groeit per heel teken: 1ch per stap */
.twt-line {
  display: inline-block;
  box-sizing: content-box;
  width: 0;
  overflow: hidden;
  white-space: nowrap;
  letter-spacing: 0;
  border-right: .12em solid var(--accent);
  animation:
    twt-type var(--speed) steps(var(--chars), end) infinite,
    twt-blink .75s step-end infinite;
}

/* Typen, even laten staan, weer wissen */
@keyframes twt-type {
  0% { width: 0; }
  45%, 80% { width: calc(var(--chars) * 1ch); }
  95%, 100% { width: 0; }
}

@keyframes twt-blink {
  50% { border-color: transparent; }
}

@media (prefers-reduced-motion: reduce) {
  .twt-line {
    width: auto;
    animation: none;
  }
}

Wat het is en waar je het gebruikt

Het typmachine-effect is een klassieker, maar meestal wordt het met JavaScript gebouwd. Deze versie is pure CSS. In een strak terminalvenster verschijnt de regel letter voor letter, blijft hij even staan, wordt hij teruggewist en begint alles opnieuw. Een acid-lime blokcursor knippert er de hele tijd achter.

Gebruik het in de hero van een developer-tool, op een pagina over techniek, in een portfolio van een ontwikkelaar of als speelse slogan. Het effect werkt het best met één korte regel van ongeveer 15 tot 35 tekens.

Zo werkt het

  • Monospace en ch: in een monospace-font is elk teken even breed, en 1ch is precies één teken. De regel .twt-line krijgt daarom als eindbreedte calc(var(--chars) * 1ch).
  • Typen in stappen: de breedte animeert van 0 naar die eindwaarde met steps(var(--chars), end). Elke stap onthult precies één letter, zonder halve tekens. overflow: hidden en white-space: nowrap houden de rest verborgen.
  • Typen, wachten, wissen: de keyframes twt-type gaan van 0 naar vol (tot 45%), blijven vol tot 80% en gaan dan terug naar 0. Omdat de steps-timing per keyframe-segment geldt, wordt ook het wissen letter voor letter gedaan.
  • Cursor: de cursor is gewoon border-right. De keyframes twt-blink maken de randkleur halverwege transparent met step-end, dus hij knippert hard aan en uit.
  • Box-sizing: de regel krijgt box-sizing: content-box. Anders telt de cursorrand mee in de breedte en valt de laatste letter weg.

Aanpassen

De variabelen staan op .twt-term:

  • --chars: het aantal tekens van je regel, inclusief spaties en leestekens. Pas dit altijd aan als je de tekst verandert.
  • --speed: de duur van één hele cyclus van typen, wachten en wissen.
  • --accent: de kleur van de cursor, de prompt en het groene lampje.
  • --bg en --ink: de kleuren van het venster en de tekst.

Wil je dat de tekst na het typen blijft staan? Laat dan de laatste twee keyframes weg, gebruik forwards en verwijder infinite uit de eerste animatie.

Toegankelijkheid en browsersupport

De volledige zin staat altijd in de HTML. Screenreaders lezen hem dus in één keer voor, ongeacht hoe ver de animatie is. De nep-knoppen in de titelbalk en de prompt hebben aria-hidden="true". Met prefers-reduced-motion: reduce staat de hele regel direct in beeld en knippert de cursor niet meer. var() binnen steps() en de ch-eenheid werken in alle actuele browsers. Let op: het effect is gemaakt voor één regel. Voor meerdere regels heb je per regel een eigen element en vertraging nodig.

Verder lezen

Wil je het typen pas laten starten als de regel in beeld scrolt? Lees dan ons artikel over scroll-driven animations in CSS. En voor complete sites waarin beweging en techniek samenkomen, kijk je bij interactief webdesign en animaties.