Beweging maakt een interface levend. Met transitions animeer je hover-effecten soepel. Met transform beweeg, schaal en roteer je elementen. Met @keyframes maak je herhalende animaties — allemaal zonder JavaScript.
transition — soepele overgangen
transition maakt dat een CSS-waardeverandering vloeiend verloopt in plaats van abrupt te springen.
/* property duur timing-function vertraging */
transition: background-color 0.3s ease;
transition: all 0.25s ease; /* animeer alle properties ⭐ */
transition: transform 0.3s ease, opacity 0.2s ease; /* meerdere */
/* Timing functions */
ease /* langzaam start, piek, langzaam einde (standaard) */
ease-in /* langzaam starten, snel eindigen */
ease-out /* snel starten, langzaam eindigen */
ease-in-out /* langzaam starten en eindigen */
linear /* constante snelheid */
cubic-bezier(0.68, -0.55, 0.27, 1.55) /* custom (bijv. bounce) */
Live demo — hover over de knop en kaart
/* Zo is de knop hierboven gemaakt */
.knop {
background: #2dd4bf;
transition: all 0.25s ease;
}
.knop:hover {
background: #0d9488;
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(45,212,191,0.4);
}
transform — bewegen, schalen, roteren
transform verplaatst, vergroot/verkleint of roteert een element — zonder de normale documentflow te beïnvloeden (andere elementen bewegen niet mee).
/* Verplaatsen */
transform: translateX(20px); /* 20px naar rechts */
transform: translateY(-10px); /* 10px omhoog */
transform: translate(20px, -10px); /* beide tegelijk */
/* Schalen */
transform: scale(1.1); /* 10% groter */
transform: scale(0.9); /* 10% kleiner */
transform: scaleX(2); /* alleen horizontaal verdubbeld */
/* Roteren */
transform: rotate(45deg); /* 45 graden met de klok mee */
transform: rotate(-90deg); /* 90 graden tegen de klok in */
/* Combineren (ruimte-gescheiden) */
transform: translateY(-4px) scale(1.02) rotate(1deg);
/* Scherpheidsoptimalisatie bij animaties */
will-change: transform; /* hint aan browser voor GPU-rendering */
translateY(-6px)
scale(1.3)
rotate(45deg)
@keyframes & animation
Met @keyframes definieer je een animatie-reeks. Met animation koppel je die aan een element.
/* Definieer de animatie */
@keyframes naam {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
/* Of met percentages voor meer controle */
@keyframes bounce {
0% { transform: translateY(0); }
40% { transform: translateY(-20px); }
60% { transform: translateY(-10px); }
80% { transform: translateY(-4px); }
100% { transform: translateY(0); }
}
/* Koppel aan element */
.element {
animation: naam 0.6s ease forwards;
/* naam duur timing fill-mode */
}
/* Alle animation-properties */
animation-name: naam;
animation-duration: 0.6s;
animation-timing-function: ease;
animation-delay: 0.2s;
animation-iteration-count: 1; /* of: infinite */
animation-direction: normal; /* of: reverse, alternate */
animation-fill-mode: forwards; /* blijf in eindstand ⭐ */
animation-play-state: running; /* of: paused */
pulse (infinite) · slide-in (eenmalig)
Veelgebruikte patronen & toegankelijkheid
Fade-in bij laden
@keyframes fade-in {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
}
.sectie { animation: fade-in 0.5s ease forwards; }
/* Gestaggerd (met vertraging per item) */
.item:nth-child(1) { animation-delay: 0.1s; }
.item:nth-child(2) { animation-delay: 0.2s; }
.item:nth-child(3) { animation-delay: 0.3s; }
Spinner
@keyframes spin {
to { transform: rotate(360deg); }
}
.spinner {
width: 32px; height: 32px;
border: 3px solid #374151;
border-top-color: #2dd4bf;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
♿ prefers-reduced-motion
Sommige gebruikers worden misselijk van beweging. Respecteer hun systeemvoorkeur:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
Performance: wat animeer je wel en niet?
Niet alle CSS-properties zijn even goedkoop om te animeren. De browser moet bij elke frame de pagina opnieuw renderen.
✅ Efficiënt (GPU)
transform(translate, scale, rotate)opacityfilter
Deze worden op de GPU afgehandeld — geen layout recalculation nodig.
⚠️ Duur (reflow)
width/heightmargin/paddingtop/leftfont-size
Gebruik transform: translate() in plaats van top/left.
transform en opacity. Je kunt vrijwel elk visueel effect hiermee bereiken, en ze zijn altijd soepel.
Oefening 1 – Knop met hover-animatie
Maak een knop met een soepele hover-transition:
• body: margin 0, padding 40px, background #0f172a, font-family sans-serif, display flex, gap 16px, flex-wrap wrap
• .knop: padding 12px 28px, background #2dd4bf, color #0f172a, font-weight 700, border none, border-radius 10px, cursor pointer, font-size 15px, transition all 0.25s ease
• .knop:hover: background #0d9488, color wit, transform translateY(-3px), box-shadow 0 8px 24px rgba(45,212,191,0.35)
• .knop:active: transform translateY(0), box-shadow none
HTML
<button class="knop">Begin nu</button>
<button class="knop">Meer info</button>
Live voorbeeld
Oefening 2 – Laadspinner & fade-in
Maak een laadspinner en een fade-in animatie:
• body: margin 0, padding 40px, background #0f172a, font-family sans-serif, display flex, flex-direction column, align-items center, gap 32px
• @keyframes spin: van transform rotate(0deg) naar rotate(360deg)
• .spinner: width 48px, height 48px, border 4px solid #1e293b, border-top-color #2dd4bf, border-radius 50%, animation spin 0.8s linear infinite
• @keyframes fade-up: from opacity 0 + translateY(24px) → to opacity 1 + translateY(0)
• .kaart: background #1e293b, color #e2e8f0, padding 24px 32px, border-radius 16px, animation fade-up 0.6s ease forwards, opacity 0
HTML
<div class="spinner"></div>
<div class="kaart">
<h3 style="margin:0 0 8px">
Geladen!
</h3>
<p style="margin:0;opacity:.7">
Deze kaart fadedt in.
</p>
</div>
Live voorbeeld
Quiz
Les 10 afgerond!
Transitions en animaties onder de knie! Nog twee lessen: variabelen & best practices, en het mini-project.