Waar je met transities enkel een vloeiende overgang maakt tussen twee toestanden (zoals een :hover), laten CSS Transforms en CSS Animaties je de wetten van de fysica op het web herschrijven.
Met transform kun je elementen vervormen, verplaatsen, vergroten en zelfs in 3D-ruimte laten ronddraaien. In combinatie met @keyframes en de animation-eigenschappen kun je ingewikkelde, meerstaps animaties bouwen die automatisch afspelen, oneindig herhalen of reageren op gebruikersinteractie.
In deze geavanceerde les leer je hoe je statische ontwerpen omzet in dynamische, bewegende ervaringen!
transform)De eigenschap transform past de visuele weergave van een HTML-element aan zonder de normale lay-out van de pagina (de HTML-stroom) te verstoren.
De vier belangrijkste 2D-functies zijn:
.box {
/* 1. Verplaatsen (X-as, Y-as) */
transform: translate(20px, -10px);
/* 2. Schalen (vergroten/verkleinen) */
transform: scale(1.2); /* 120% van de originele grootte */
/* 3. Roteren (draaien in graden) */
transform: rotate(45deg);
/* 4. Schuintrekken (vervormen) */
transform: skew(10deg, 5deg);
}
translate(x, y)Met translate() schuif je een element over de horizontale ($X$) en verticale ($Y$) as.
translateX(50px): Verschuift $50\text{px}$ naar rechts.translateY(-20px): Verschuift $20\text{px}$ naar boven.translate(-50%, -50%): Veelgebruikte techniek om een element exact in het midden van zijn ouder te centreren!scale(x, y)Met scale() vergroot of verklein je een element.
scale(1.5): Vergroot het element gelijkmatig met $150\%$.scale(0.8): Verkleint het element naar $80\%$.scaleX(2): Maakt het element dubbel zo breed, maar behoudt de hoogte.rotate(deg)Draait een element met de klok mee (positieve waarde) of tegen de klok in (negatieve waarde).
rotate(90deg): Draait het element een kwartslag met de klok mee.rotate(-180deg): Draait het element ondersteboven.skew(x-deg, y-deg)Vervormt een element door de zijkanten schuin te trekken, wat een dynamisch 'snelheidseffect' of een parallellogram kan creëren.
.actie-banner {
/* Trekt het element 15 graden schuin over de X-as */
transform: skewX(-15deg);
}
Standaard vindt elke transformatie plaats vanuit het exacte middelpunt van het element (transform-origin: center center; of 50% 50%). Je kunt dit scharnierpunt verplaatsen!
.deur {
/* Draait het element vanuit de linker bovenhoek, als een scharnier */
transform-origin: top left;
transform: rotate(30deg);
}
Wil je diepte creëren op een plat scherm? Dan stappen we over naar 3D Transforms. In 3D werken we niet alleen met de $X$-as (breedte) en $Y$-as (hoogte), maar ook met de $Z$-as (diepte, naar de bezoeker toe of van de bezoeker af).
Y (Verticale as)
│
│ Z (Diepte - naar je toe)
│ /
│ /
───────┼─────── X (Horizontale as)
/│
/ │
perspectiveOm 3D-effecten echt te laten overkomen, moet de ouder-container weten hoe ver de virtuele 'camera' van het scherm staat. Dit stellen we in met perspective.
/* Het hoofdelement dient als de '3D-ruimte' */
.card-container {
perspective: 1000px; /* Kleinere waarde = heftiger 3D-effect; grotere waarde = subtieler */
}
/* Het kind-element roteert in 3D */
.card-3d {
transform: rotateY(45deg) rotateX(10px);
transition: transform 0.5s ease;
}
.card-container:hover .card-3d {
transform: rotateY(180deg); /* Kaart omdraaien! */
}
💡 Praktijktip: backface-visibility
Wanneer je een element 180 graden draait in 3D, zie je normaal gesproken de achterkant in spiegelbeeld. Wil je dat de achterkant onzichtbaar wordt bij het omdraaien (bijvoorbeeld bij een memorykaart-spel)?
Gebruik dan: backface-visibility: hidden;.
@keyframes)Met transition animeer je van status A naar status B. Met Keyframes kun je een animatie opbouwen uit tientallen tussenstappen!
Je definieert de animatie eerst met een naam via @keyframes. Daarna koppel je die naam aan een HTML-element.
from / to)@keyframes binnen-zweven {
from {
opacity: 0;
transform: translateY(50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
%)Met procenten geef je exact aan wat er moet gebeuren op $0\%$ (start), $50\%$ (halverwege) en $100\%$ (einde) van de totale tijdsduur.
@keyframes stuitermagie {
0% {
transform: translateY(0) scale(1);
}
30% {
transform: translateY(-30px) scale(1.1);
}
50% {
transform: translateY(0) scale(0.95); /* Vlakt licht af bij impact */
}
100% {
transform: translateY(-100px) scale(1);
opacity: 0;
}
}
animation EigenschappenZodra een @keyframes animatie is aangemaakt, koppel je deze aan een element via de animation-eigenschappen.
.loader {
/* 1. Welke keyframe animatie gebruiken we? */
animation-name: draaiSpinner;
/* 2. Hoe lang duurt één cyclus? */
animation-duration: 1.5s;
/* 3. Snelheidsverloop (linear, ease, ease-in-out, etc.) */
animation-timing-function: linear;
/* 4. Hoe vaak herhalen? (bijv. 3, of infinite) */
animation-iteration-count: infinite;
/* 5. Richting (normal, reverse, alternate, alternate-reverse) */
animation-direction: alternate;
/* 6. Wat gebeurt er VOOR of NA de animatie? */
animation-fill-mode: forwards;
/* 7. Vertraging voor de start */
animation-delay: 0.5s;
}
animation-fill-mode?Dit is een van de meest gemaakte fouten bij beginners! Zodra een animatie stopt, springt het element normaal direct terug naar zijn oorspronkelijke CSS-staat.
none (Standaard): Element keert na afloop terug naar de beginstatus.forwards: Het element behoudt de CSS-stijl van het LAATSTE keyframe ($100\%$) nadat de animatie is afgelopen!backwards: Het element neemt direct de waarden aan van het $0\%$ keyframe tijdens de animation-delay.both: Combineert forwards en backwards.Net als bij transities gebruiken we meestal de shorthand:
/* Shorthand: [name] [duration] [timing-function] [delay] [iteration-count] [direction] [fill-mode] */
.puls-knop {
animation: pulseren 2s ease-in-out infinite alternate;
}
Animaties moeten supersoepel draaien ($60\text{ fps}$ ofwel frames per seconde). Als een animatie hapert, schrikt dat bezoekers af.
Gouden Regel voor Animaties:
Aanbranden van de processor voorkomen? Animeer uitsluitend de eigenschappentransformenopacity.
De browser kan deze eigenschappen rechtstreeks verwerken via de videokaart (GPU-acceleratie), waardoor ze vloeiend lopen zonder de lay-out te herberekenen!
In dit praktijkvoorbeeld bouwen we twee veelgebruikte elementen: een 3D Flip-Card die omdraait bij hover, en een Pulse Loader die oneindig geanimeerd wordt.
index.html)<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Transforms & Animaties</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class="demo-container">
<!-- 1. 3D FLIP CARD -->
<div class="card-scene">
<div class="card">
<div class="card__face card__face--front">
<h3>Pas Muis Over Mij!</h3>
<p>3D Rotate Showcase</p>
</div>
<div class="card__face card__face--back">
<h3>Achterkant!</h3>
<p>Gebouwd met CSS 3D Transforms</p>
</div>
</div>
</div>
<!-- 2. INFINITE PULSE LOADER -->
<div class="loader-container">
<div class="pulse-ring"></div>
<div class="pulse-core"></div>
</div>
</section>
</body>
</html>
style.css)/* Reset & Algemene Lay-out */
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', system-ui, sans-serif;
background-color: #0f172a;
color: #ffffff;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.demo-container {
display: flex;
flex-wrap: wrap;
gap: 60px;
align-items: center;
justify-content: center;
}
/* ====================================================== */
/* 1. 3D FLIP CARD STYLING */
/* ====================================================== */
/* De '3D Ruimte' (Perspective instellen) */
.card-scene {
width: 260px;
height: 340px;
perspective: 1000px; /* Creëert diepte */
}
.card {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d; /* Zorgt dat kinderen hun 3D-positie behouden */
transition: transform 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275);
cursor: pointer;
}
/* Bij hover op de scèneruimte draait de kaart 180 graden */
.card-scene:hover .card {
transform: rotateY(180deg);
}
.card__face {
position: absolute;
width: 100%;
height: 100%;
border-radius: 16px;
padding: 24px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
/* Verberg de achterkant wanneer hij weggedraaid is! */
backface-visibility: hidden;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
}
/* Voorkant styling */
.card__face--front {
background: linear-gradient(135deg, #2563eb, #1d4ed8);
color: #ffffff;
}
/* Achterkant styling */
.card__face--back {
background: linear-gradient(135deg, #059669, #047857);
color: #ffffff;
/* De achterkant staat van zichzelf al 180 graden gedraaid */
transform: rotateY(180deg);
}
/* ====================================================== */
/* 2. INFINITE PULSE LOADER (@keyframes) */
/* ====================================================== */
.loader-container {
position: relative;
width: 80px;
height: 80px;
display: flex;
justify-content: center;
align-items: center;
}
.pulse-core {
width: 24px;
height: 24px;
background-color: #38bdf8;
border-radius: 50%;
}
.pulse-ring {
position: absolute;
width: 100%;
height: 100%;
border: 4px solid #38bdf8;
border-radius: 50%;
/* Koppel de geavanceerde keyframe animatie */
animation: pulseren 1.6s ease-out infinite;
}
/* DEFINEER DE KEYFRAMES */
@keyframes pulseren {
0% {
transform: scale(0.3);
opacity: 1;
}
80%, 100% {
transform: scale(1.5);
opacity: 0; /* Vervliegt geleidelijk */
}
}
transform: Vervormt een element zonder de omliggende lay-out te verstoren.translate(x, y): Verplaatsen.scale(x, y): Schalen.rotate(deg): Roteren.skew(x, y): Schuintrekken.perspective: Onmisbaar op de ouder-container om 3D-effecten (rotateY, rotateX) diepte te geven.backface-visibility: hidden: Verbergt de achterzijde van een gedraaid element in 3D.@keyframes: Bepaalt het verloop van een animatie van $0\%$ tot $100\%$.animation-fill-mode: forwards: Zorgt dat een geanimeerd element de eindtoestand ($100\%$) vasthoudt na afloop.transform en opacity.