Een geweldige gebruikerservaring (User Experience of UX) zit hem vaak in de kleinste details. Wanneer je op een knop klikt, met je muis over een kaartje beweegt of een formulier invult, verwacht je als gebruiker direct feedback. Zonder enige beweging voelt een website stijf en statisch aan; verandert iets te plotseling, dan werkt dat storend.
Hier komen micro-interacties en CSS Transities in beeld. Met een transitie laat je een CSS-eigenschap niet 'in één klap' veranderen van waarde A naar waarde B, maar laat je die verandering vloeiend en geleidelijk verlopen over een bepaalde tijdsduur.
In deze les leer je hoe je met transities subtiele, professionele micro-interacties ontwerpt die jouw websites tot leven brengen!
Een micro-interactie is een klein, functioneel animatiemoment in een gebruikersinterface dat ontworpen is voor één specifieke taak.
GEBRUIKER DOET IETS SSTEEM GEEFT FEEDBACK GEVOEL
[ Hover over knop ] ──► [ Knop kleurt zacht om ] ──► "Aha, hier kan ik op klikken!"
[ Vinkje aanklikken ] ──► [ Groen vinkje plopt op ] ──► "Mijn actie is gelukt!"
Om een transitie in te stellen op een element, gebruikt CSS vier losse eigenschappen:
transition-property: Welke CSS-eigenschap moet veranderen? (bijv. background-color, transform, opacity).transition-duration: Hoe lang duurt de overgang? (in seconden s of milliseconden ms).transition-timing-function: Hoe verloopt de snelheid van de beweging? (snel starten, traag eindigen, etc.).transition-delay: Hoe lang moet de browser wachten voordat de transitie begint?.knop {
background-color: #2563eb;
/* 1. Welke eigenschap? */
transition-property: background-color;
/* 2. Hoe lang duurt het? */
transition-duration: 0.3s; /* 0.3 seconden (of 300ms) */
/* 3. Snelheidsverloop? */
transition-timing-function: ease-out;
/* 4. Vertraging? */
transition-delay: 0s;
}
/* De 'Hover' toestand waarin de eigenschap verandert */
.knop:hover {
background-color: #1d4ed8;
}
Belangrijke regel:
Plaats detransition-eigenschap op het basiselement (.knop), en NIET enkel op de:hover-status! Als je het op:hoverzet, verloopt het weggaan van de muis namelijk weer abrupt en schokkerig.
In de praktijk schrijven we zelden alle vier de eigenschappen los uit. We gebruiken vrijwel altijd de verkorte notatie: transition.
selector {
transition: [property] [duration] [timing-function] [delay];
}
/* Transfereer alle veranderende eigenschappen in 0.3 seconden met 'ease' */
.kaart {
transition: all 0.3s ease;
}
/* Bepaalde eigenschap gericht animeren (AANBEVOLEN!) */
.kaart-foto {
transition: transform 0.4s ease-out;
}
/* Meerdere eigenschappen met een eigen tijdsduur combineren (gescheiden door komma) */
.badge {
transition: background-color 0.2s ease, transform 0.4s ease-in-out;
}
De transition-timing-function bepaalt de 'sfeer' en het 'gewicht' van de beweging. Een object in de echte wereld stopt immers ook zelden abrupt; het versnelt en vertraagt.
Linear: [====================] (Constante snelheid - voelt mechanisch/robotachtig aan)
Ease-In: [ ===============] (Traag starten, snel eindigen)
Ease-Out: [=============== ] (Snel starten, traag uitbollen - VEELGEBRUIKT VOOR UI!)
Ease-In-Out: [ ───────────── ] (Traag starten, versnellen, traag eindigen)
linear: Gelijke snelheid van begin tot eind. (Matig geschikt voor UI, leuk voor draaiende loaders).ease: (Standaard) Begint rustig, versnelt, en eindigt weer traag.ease-in: Begint langzaam en versnelt.ease-out: Schiet direct in beweging en remt af op het einde. Ideaal voor knoppen en pop-ups!ease-in-out: Begint en eindigt rustig, versnelt in het midden.cubic-bezier()Wil je een unieke beweging ontwerpen (zoals een lichte 'bounce' of 'veereffect')? Dan kun je gebruikmaken van een Cubic Bezier-curve:
.pop-up {
/* Creëert een elastisch "bounce" effect bij de overgang */
transition: transform 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
Tip: Gebruik de website cubic-bezier.com om visueel je eigen custom timing curves te bouwen en te kopiëren!
Niet alle CSS-eigenschappen zijn even geschikt om te animeren. Als je eigenschappen animeert die de lay-out van de pagina herberekenen, kan de browser gaan haperen (lag).
Deze eigenschappen kosten de browser nauwelijks rekenkracht. Gebruik deze voor $90\%$ van je micro-interacties!
opacity: Transparantie aanpassen (faden).transform: Verschuiven (translate), schalen (scale), roteren (rotate).Probeer animaties van deze eigenschappen te vermijden bij complexe pagina's:
width, heightmargin, paddingtop, left, bottom, right/* ❌ SLECHT VOOR PERFORMANCE (verplaatst andere elementen op de pagina) */
.knop:hover {
width: 200px;
margin-top: -10px;
}
/* 🟢 PERFECTE PERFORMANCE (zweeft boven de lay-out via GPU) */
.knop:hover {
transform: translateY(-5px) scale(1.02);
}
In dit praktijkvoorbeeld bouwen we een interactieve kaart. Wanneer de gebruiker eroverheen beweegt, gebeuren er drie subtiele dingen tegelijk:
transform: translateY).box-shadow).index.html)<article class="card">
<div class="card__image-wrapper">
<img src="[https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=600](https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=600)" alt="Sneaker" class="card__image">
<span class="card__badge">Nieuw</span>
</div>
<div class="card__content">
<h3 class="card__title">Nike Air Max Red</h3>
<p class="card__price">€ 149,99</p>
<button class="card__btn">In Winkelmand</button>
</div>
</article>
style.css)/* Reset & Basis */
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', system-ui, sans-serif;
background-color: #f1f5f9;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* CARD COMPONENT (BEM) */
.card {
width: 320px;
background-color: #ffffff;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
/* TRANSITIE op de kaart zelf voor het oplicht-effect */
transition: transform 0.3s ease-out, box-shadow 0.3s ease-out;
cursor: pointer;
}
/* Micro-interactie 1: Kaart optillen bij hover */
.card:hover {
transform: translateY(-8px);
box-shadow: 0 20px 30px rgba(0, 0, 0, 0.12);
}
/* Afbeelding Wrapper met overflow: hidden voor het inzoom-effect */
.card__image-wrapper {
position: relative;
width: 100%;
height: 220px;
overflow: hidden;
}
.card__image {
width: 100%;
height: 100%;
object-fit: cover;
/* TRANSITIE op de afbeelding voor een vloeiende zoom */
transition: transform 0.5s ease-out;
}
/* Micro-interactie 2: Afbeelding licht inzoomen bij hover over kaart */
.card:hover .card__image {
transform: scale(1.08);
}
.card__badge {
position: absolute;
top: 12px;
left: 12px;
background-color: #ef4444;
color: white;
font-size: 0.75rem;
font-weight: bold;
padding: 4px 10px;
border-radius: 20px;
}
.card__content {
padding: 20px;
}
.card__title {
font-size: 1.2rem;
color: #0f172a;
margin-bottom: 6px;
}
.card__price {
font-size: 1.1rem;
font-weight: bold;
color: #2563eb;
margin-bottom: 16px;
}
/* KNOP STYLING MET HOVER EN ACTIVE STATE */
.card__btn {
width: 100%;
padding: 12px;
background-color: #0f172a;
color: #ffffff;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
/* TRANSITIE op de knop voor kleur & indruk-effect */
transition: background-color 0.2s ease, transform 0.1s ease;
}
/* Micro-interactie 3: Knopkleur verandert bij hover */
.card__btn:hover {
background-color: #2563eb;
}
/* Micro-interactie 4: Knop veert licht in bij daadwerkelijk klikken (:active) */
.card__btn:active {
transform: scale(0.97);
}
transition shorthand-eigenschap: transition: [property] [duration] [timing-function] [delay];.transition-regel altijd op het hoofdelement, zodat de beweging heen én terug vloeiend verloopt.ease-out is de meest gebruikte timing function voor UI-elementen (snel starten, zacht afremmen).transform en opacity te animeren.:active-state toe aan interactieve elementen (zoals knoppen) voor dat extra 'indruk-gevoel' bij een muisklik!