Aanmelden

🎨CSS

Zelfstudie met uitleg, live voorbeelden en oefeningen: van je eerste kleurtje tot een volledig opgemaakte, responsieve pagina met Flexbox en Grid.

Je bekijkt deze pagina niet aangemeld — je kan de oefeningen, het opzoekwerk en de zelftest-quiz pas openen na het aanmelden.
Aanmelden

Overzicht

Werk de onderdelen hieronder in je eigen tempo af: lees de uitleg, doe het opzoekwerk en sluit af met een quizje. Klik een onderdeel open om te starten.

Van kale HTML naar een mooie pagina: hoe CSS werkt, hoe je een regel schrijft en op welke manieren je CSS aan je pagina koppelt.

Wat is CSS?
Het CSS3-logo
Het CSS3-logo

CSS staat voor Cascading Style Sheets. Waar HTML de inhoud en structuur van een pagina beschrijft, bepaalt CSS het uitzicht: kleuren, lettertypes, marges, de plaats van elementen en zelfs animaties.

Zonder CSS ziet elke pagina eruit zoals in 1995: zwarte tekst op een witte achtergrond. Met CSS krijgt ze karakter, en dat zonder je HTML aan te passen. Eén stylesheet kan het uitzicht van een héle website tegelijk bepalen.

Cascading?

“Cascading” betekent “trapsgewijs”. Meerdere regels kunnen op hetzelfde element van toepassing zijn, en CSS heeft vaste afspraken over welke regel wint. Dat leer je in het hoofdstuk over de cascade.

De opbouw van een CSS-regel

CSS bestaat uit regels. Elke regel zegt: kies deze elementen en geef ze deze eigenschappen.

stijl.cssh1 {
    color: blue;
    font-size: 32px;
}
OnderdeelIn het voorbeeldBetekenis
Selectorh1welke elementen je opmaakt
Declaratieblok{ … }alle opmaak tussen accolades
Eigenschap (property)colorwát je wijzigt
Waardebluehoe je het wijzigt

Eigenschap en waarde staan gescheiden door een dubbele punt. Elke declaratie eindigt met een puntkomma.

Vergeet de puntkomma niet

Een vergeten ; of } laat de browser de volgende regel negeren, zonder foutmelding. Krijg je een regel maar niet aan de praat? Zoek eerst naar een ontbrekende puntkomma of accolade in de regel erboven.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Drie manieren om CSS toe te voegen

1. Extern (in een apart bestand) ← zo doen wij het altijd. Je koppelt het bestand in de head met <link>:

index.html<head>
    <link rel="stylesheet" href="css/stijl.css">
</head>

2. Intern: in de pagina zelf, in een <style>-element in de head. Handig voor een snel proefje, of als je één pagina hebt.

<head>
    <style>
        h1 { color: blue; }
    </style>
</head>

3. Inline: rechtstreeks bij één element met het style-attribuut. Zonder selector en zonder accolades.

<p style="color: blue; font-size: 20px;">Deze alinea is blauw.</p>
ExternInternInline
Hergebruik op meerdere pagina’s✅❌❌
Eén plek om aan te passen✅❌❌
Snel testen➖✅✅
Aanbevolen voor projectenjaneebijna nooit
Scheid inhoud en opmaak

Zet CSS in een extern bestand: dan blijft je HTML kort en leesbaar, en verander je het uitzicht van de hele site op één plek. In de "Probeer zelf"-blokken hier gebruiken we een <style> omdat er maar één pagina is.

Commentaar en witruimte

Commentaar schrijf je tussen /* en */. De browser negeert het. Witruimte (spaties, enters) maakt voor CSS niet uit, dus zet elke declaratie op een eigen regel en spring in: dat is veel leesbaarder.

/* ---------- Titels ---------- */
h1 {
    color: navy;          /* donkerblauw */
    text-align: center;
}
Hoe werkt het samen met HTML?

CSS zoekt in je HTML de elementen die bij de selector passen en geeft ze de eigenschappen. Daarom zijn id en class uit de HTML-cursus zo belangrijk: dat zijn de haakjes waaraan je CSS zich vasthangt (zie volgend hoofdstuk).

Zo verwerkt de browser je paginaBrowser laadt index.html
   └─ leest <link rel="stylesheet" href="css/stijl.css">
        └─ laadt stijl.css
             └─ past elke regel toe op de passende elementen
Zo werk je in deze cursus

Bij de oefeningen typ je enkel CSS. De HTML is al voorzien en met ▶ Voorbeeld zie je meteen wat je CSS doet. Controleer kijkt na of je de gevraagde regels geschreven hebt.

🎯 Nu ben jij aan de beurt: Wat is CSS?

Verwerk wat je hierboven las met de onderdelen hieronder. Ze horen bij deze theorie.

Met een selector kies je precies welke elementen je opmaakt: op naam, klasse, id, positie of toestand.

Element-, klasse- en id-selectors

De drie basis-selectors kies je op basis van de HTML:

SelectorSchrijfwijzeKiest
Elementpalle <p>-elementen
Klasse.tipalle elementen met class="tip"
Id#hoofdtitelhet ene element met id="hoofdtitel"
p { color: gray; }                /* alle alinea's */
.tip { background: #fef9c3; }     /* alles met class="tip" */
#hoofdtitel { font-size: 40px; }  /* het element met id="hoofdtitel" */
Klasse of id?

Kies in CSS bij voorkeur klassen: je kan ze hergebruiken en ze zijn makkelijker te overschrijven. Bewaar id’s vooral voor JavaScript en ankers. Onthoud: een punt voor een klasse, een hekje voor een id.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Groeperen en combineren

Je kan selectors combineren om nauwkeuriger te kiezen:

SchrijfwijzeNaamKiest
h1, h2, h3groepalle h1, h2 én h3 (één regel voor meerdere selectors)
nav aafstammelingalle a die ergens binnen een nav staan
ul > likindenkel li die rechtstreeks in een ul staan
h1 + pbuurde p die meteen na een h1 komt
p.tipelement én klasseenkel p mét class="tip" (geen spatie!)
*universeelalle elementen
De spatie maakt het verschil

nav a (met spatie) = een a in een nav. p.tip (zonder spatie) = een p die zelf de klasse tip heeft.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Pseudo-klassen: toestanden

Een pseudo-klasse (met een dubbele punt) kiest een element in een bepaalde toestand of positie:

Pseudo-klasseBetekenis
a:hoverde muis staat erop
input:focushet veld is actief (cursor erin)
button:disabledde knop is uitgeschakeld
li:first-childde eerste li in zijn ouder
li:last-childde laatste li in zijn ouder
li:nth-child(2n)elke tweede li (2, 4, 6, …): handig voor zebrastrepen
input:checkedeen aangevinkte checkbox of radio
✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Attribuut-selectors en pseudo-elementen

Met attribuut-selectors kies je op basis van een attribuut in de HTML:

input[type="text"] { border: 2px solid gray; }       /* enkel tekstvelden */
a[href^="https"]   { color: green; }                  /* links die met https beginnen */
a[target="_blank"] { font-style: italic; }

Pseudo-elementen (met een dubbele dubbele punt) kiezen een deel van een element, of voegen zelf inhoud toe:

p::first-letter { font-size: 200%; }      /* de eerste letter */
p::first-line   { font-weight: bold; }
.nieuw::before  { content: "🆕 "; }        /* voegt tekst vóór het element toe */
.extern::after  { content: " ↗"; }
✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
🎯 Nu ben jij aan de beurt: Selectors: kies je elementen

Verwerk wat je hierboven las met de onderdelen hieronder. Ze horen bij deze theorie.

Kleurnamen, hex, rgb en hsl; achtergrondkleuren, afbeeldingen en kleurverlopen.

Tekstkleur en achtergrondkleur

Twee eigenschappen gebruik je voortdurend:

  • color: de kleur van de tekst (en van randen die geen eigen kleur hebben);
  • background-color: de kleur van de achtergrond.
body {
    background-color: #f8fafc;
    color: #1e293b;
}
Let op je contrast

Lichtgrijze tekst op een witte achtergrond is moeilijk leesbaar, zeker voor slechtzienden. Streef naar een contrastverhouding van minstens 4,5 : 1 (test op een contrastchecker).

Kleuren schrijven: vier notaties
NotatieVoorbeeldUitleg
Naamtomato±140 kleurnamen (red, navy, gold, lightblue, …)
Hex#3b82f6#RRGGBB in hexadecimaal; korte vorm #38f kan ook
rgb()rgb(59, 130, 246)rood, groen, blauw: elk 0 tot 255
rgba()rgba(0, 0, 0, 0.5)rgb + doorzichtigheid (0 = onzichtbaar, 1 = volledig)
hsl()hsl(217, 91%, 60%)tint (0–360°), verzadiging en helderheid: handig om varianten te maken

Ze geven allemaal dezelfde soort resultaat, dus kies de notatie die je het handigst vindt. In ontwerpen (Figma) krijg je meestal een hex-code: die kopieer je gewoon.

Hsl voor varianten

Met hsl() maak je makkelijk een lichtere of donkerdere versie van dezelfde kleur: verander enkel het laatste getal (helderheid): hsl(217, 91%, 30%) is donker, hsl(217, 91%, 90%) is heel licht.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Achtergrondafbeeldingen

Met background-image zet je een afbeelding achter een element. Met een paar extra eigenschappen bepaal je hoe:

.hero {
    background-image: url("../img/strand.jpg");
    background-size: cover;        /* vul het hele vlak, snij bij indien nodig */
    background-position: center;   /* waar de afbeelding staat */
    background-repeat: no-repeat;  /* niet herhalen */
    height: 300px;                 /* zonder hoogte is het element mogelijk leeg */
}
EigenschapWaarden
background-sizecover (vullen), contain (helemaal zichtbaar), of een afmeting
background-repeatrepeat (standaard), no-repeat, repeat-x
background-positioncenter, top, left bottom, …
Paden in CSS

Een pad in url() is relatief ten opzichte van het CSS-bestand, niet van de HTML-pagina. Staat je CSS in css/stijl.css en je foto in img/, dan schrijf je ../img/foto.jpg.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Kleurverlopen

Een verloop (gradient) is een achtergrond die van de ene kleur naar de andere overgaat, zonder afbeelding. Je zet het in background of background-image:

.banner {
    background: linear-gradient(to right, #3b82f6, #8b5cf6);
}
.cirkel {
    background: radial-gradient(circle, yellow, orange);
}

Bij linear-gradient geef je een richting (to right, to bottom, 45deg) en daarna twee of meer kleuren.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Doorzichtigheid: opacity

Met opacity (0 tot 1) maak je een heel element doorzichtig, inclusief tekst en kinderen. Wil je enkel de achtergrond doorzichtig maken en de tekst leesbaar houden, gebruik dan rgba() in background-color.

.vervaagd { opacity: 0.4; }                                  /* alles 40% zichtbaar */
.glas     { background-color: rgba(255, 255, 255, 0.6); }    /* enkel de achtergrond */
🎯 Nu ben jij aan de beurt: Kleuren en achtergronden

Verwerk wat je hierboven las met de onderdelen hieronder. Ze horen bij deze theorie.

Lettertypes kiezen, groottes en gewicht, regelafstand, uitlijning en het opmaken van links.

Het lettertype kiezen: font-family

Met font-family kies je het lettertype. Je geeft altijd een lijstje: de browser probeert ze van links naar rechts, en het laatste is een generieke familie als reserve.

body {
    font-family: "Segoe UI", Arial, sans-serif;
}
h1 {
    font-family: Georgia, "Times New Roman", serif;
}
code {
    font-family: Consolas, monospace;
}
Generieke familieKenmerk
serifmet staartjes (Times, Georgia): klassiek
sans-serifzonder staartjes (Arial, Helvetica): modern, goed leesbaar op scherm
monospaceelke letter even breed: voor code
Aanhalingstekens

Lettertypenamen met een spatie zet je tussen aanhalingstekens ("Times New Roman"), namen zonder spatie niet.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Eigen lettertypes met Google Fonts

Niet elke bezoeker heeft jouw lettertype geïnstalleerd. Met Google Fonts laad je een lettertype van het internet in. Kies er een op fonts.google.com, en kopieer de <link> naar je head:

in de <head> van je HTML<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap" rel="stylesheet">

Daarna gebruik je het gewoon in je CSS, met een reserve-lettertype:

body {
    font-family: "Poppins", sans-serif;
}
Beperk je keuze

Gebruik hoogstens twee lettertypes op een site (bv. één voor titels, één voor tekst) en laad enkel de gewichten die je nodig hebt (400 en 700). Zo blijft je pagina snel.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Grootte, gewicht en stijl
EigenschapVoorbeelden
font-size16px, 1.25rem, 120%
font-weightnormal, bold, of 100 tot 900 (400 = normaal, 700 = vet)
font-stylenormal, italic
fontverkorte schrijfwijze: font: italic 700 18px/1.5 Arial, sans-serif;

Koppen zijn standaard al groter en vet. Wil je ze anders, dan pas je ze aan met deze eigenschappen; maar kies nog altijd de juiste HTML-kop (h1, h2, …) voor de betekenis.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Uitlijning, regelafstand en versiering
EigenschapWaarden en uitleg
text-alignleft, center, right, justify
line-heightregelafstand: 1.6 (zonder eenheid = 1,6 × de lettergrootte); zorgt voor leesbare tekst
text-decorationnone, underline, line-through
text-transformuppercase, lowercase, capitalize
letter-spacingruimte tussen letters, bv. 2px
text-shadowschaduw: 2px 2px 4px gray (x, y, vervaging, kleur)
Regelafstand

Geef doorlopende tekst een line-height tussen 1.4 en 1.7: dat leest veel prettiger dan de standaardafstand. Gebruik geen eenheid, dan schaalt het mee met de lettergrootte.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Links opmaken

Een link heeft meerdere toestanden, elk met een eigen pseudo-klasse. Schrijf ze in deze volgorde (LoVe HAte): anders overschrijft een regel de andere.

a:link    { color: royalblue; }        /* nog niet bezocht */
a:visited { color: purple; }           /* al bezocht */
a:hover   { color: crimson; }          /* muis erop */
a:active  { color: red; }              /* ingedrukt */

In de praktijk schrijf je vaak gewoon a en a:hover. Wil je het onderstreepte weg (bijvoorbeeld in een menu), gebruik dan text-decoration: none.

a {
    color: royalblue;
    text-decoration: none;
}
a:hover {
    text-decoration: underline;
}
Lijsten opmaken

Met list-style verander je de opsommingstekens: list-style: none haalt ze weg (nodig voor een menu), square, circle en decimal kunnen ook. Bij menu’s haal je meestal ook de standaardruimte weg met padding: 0 en margin: 0.

nav ul {
    list-style: none;
    margin: 0;
    padding: 0;
}
🎯 Nu ben jij aan de beurt: Tekst en lettertypes

Verwerk wat je hierboven las met de onderdelen hieronder. Ze horen bij deze theorie.

Elk element is een doos: inhoud, binnenmarge, rand en buitenmarge. Wie het boxmodel begrijpt, begrijpt CSS-layout.

Elk element is een doos

Voor CSS is elk HTML-element een rechthoekige doos, opgebouwd uit vier lagen, van binnen naar buiten:

Het boxmodel┌──────────────────────── margin ─────────────────────────┐
│   ┌──────────────────── border ─────────────────────┐   │
│   │   ┌───────────────── padding ────────────────┐  │   │
│   │   │                                           │  │   │
│   │   │          content (tekst, afbeelding)      │  │   │
│   │   │                                           │  │   │
│   │   └───────────────────────────────────────────┘  │   │
│   └──────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘
LaagEigenschapUitleg
Contentwidth, heightde eigenlijke inhoud
Paddingpaddingbinnenmarge: ruimte tussen inhoud en rand (heeft de achtergrondkleur van het element)
Borderborderde rand rond de padding
Marginmarginbuitenmarge: ruimte tussen dit element en andere elementen (altijd doorzichtig)
Padding of margin?

Wil je ruimte binnen het vlak (tekst die niet tegen de rand plakt)? Padding. Wil je ruimte tussen twee vlakken? Margin.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Padding en margin schrijven

Je kan één waarde voor alle vier de zijden geven, of ze apart instellen. Bij meerdere waarden ga je met de wijzers van de klok: boven, rechts, onder, links.

padding: 10px;                 /* alle vier de zijden */
padding: 10px 20px;            /* boven en onder 10px, links en rechts 20px */
padding: 10px 20px 30px;       /* boven 10, links/rechts 20, onder 30 */
padding: 10px 20px 30px 40px;  /* boven, rechts, onder, links */

padding-top: 10px;             /* of één zijde apart */
margin-left: 50px;

Dezelfde schrijfwijze werkt voor margin. Bij margin kan je ook auto gebruiken: margin: 0 auto; centreert een blok horizontaal, mits het een vaste width heeft.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Randen en afgeronde hoeken

De verkorte eigenschap border bevat drie dingen: dikte, stijl en kleur.

border: 2px solid #1e40af;       /* dikte stijl kleur */
border-bottom: 1px dashed gray;  /* enkel de onderkant */
border-radius: 8px;              /* afgeronde hoeken */
border-radius: 50%;              /* een cirkel (bij een vierkant) */

Stijlen: solid (lijn), dashed (streepjes), dotted (puntjes), none (geen). Zonder stijl verschijnt er geen rand, ook al geef je een dikte en kleur.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
box-sizing: de grote valkuil

Geef je een element width: 200px en padding: 20px plus een rand van 5px, hoe breed is het dan? Standaard 430px (200 + 2×20 + 2×5): padding en rand komen bovenop de breedte! Dat rekent lastig.

Met box-sizing: border-box tellen padding en rand mee in de breedte: het element is dan echt 200px breed. Bijna elke ontwikkelaar zet daarom onderaan zijn stylesheet-begin:

bovenaan elk stylesheet*, *::before, *::after {
    box-sizing: border-box;
}
Onthoud dit

Zet box-sizing: border-box altijd op alle elementen. Zonder dit past een element met width: 100% en padding niet meer in zijn ouder en loopt de pagina horizontaal uit.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Schaduw en overloop

Een schaduw geeft diepte: box-shadow: x y vervaging kleur.

.kaart {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);   /* zacht, onderaan */
}

Wat als de inhoud groter is dan de doos? Met overflow bepaal je wat er gebeurt: visible (standaard, loopt eruit), hidden (afgesneden), scroll / auto (schuifbalk).

Maximale breedte

Met max-width laat je een element meegroeien maar niet breder dan een grens (bv. tekst die niet over de volledige breedte van een groot scherm loopt). Ook min-width, min-height en max-height bestaan.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
🎯 Nu ben jij aan de beurt: Het boxmodel

Verwerk wat je hierboven las met de onderdelen hieronder. Ze horen bij deze theorie.

px, %, em, rem, vw en vh: welke eenheid gebruik je waarvoor? Zo schaal je pagina’s mee met elk scherm.

Absolute en relatieve eenheden

Bij afmetingen (lettergrootte, breedte, marges, …) kies je een eenheid. Die zijn twee soorten:

  • Absoluut: altijd even groot. Enkel px (pixel) is daarvan nuttig op scherm.
  • Relatief: afhankelijk van iets anders (de ouder, de lettergrootte of het scherm). Die zorgen voor pagina’s die zich aanpassen.
EenheidRelatief aanGebruik voor
pxniets (vast)randen, schaduwen, kleine details
%de ouderbreedtes: width: 50%
emde lettergrootte van het element zelf (of zijn ouder)marges en padding die met de tekst meeschalen
remde lettergrootte van de root (html, standaard 16px)lettergroottes en algemene afstanden
vw / vh1% van de breedte / hoogte van het schermvolledige schermhoogte: height: 100vh
rem: de beste keuze voor tekst

Standaard is 1rem gelijk aan 16px. Schrijf je lettergroottes in rem, dan schalen ze mee als een bezoeker in zijn browser een grotere tekstgrootte kiest (belangrijk voor slechtzienden). Met pixels gebeurt dat niet.

body { font-size: 1rem; }        /* 16px */
h1   { font-size: 2.5rem; }      /* 40px */
h2   { font-size: 1.75rem; }     /* 28px */
small { font-size: 0.875rem; }   /* 14px */
Rekenen met 16

1rem = 16px, dus 24px = 1.5rem, 20px = 1.25rem, 12px = 0.75rem. Deel het aantal pixels door 16.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Procenten en meegroeiende blokken

Met % laat je een element meegroeien met zijn ouder. Combineer het met max-width voor een meegroeiende maar begrensde container: dat is de basis van een goede pagina.

.container {
    width: 90%;            /* op een klein scherm: 90% van de breedte */
    max-width: 1000px;     /* op een groot scherm: nooit breder dan 1000px */
    margin: 0 auto;        /* gecentreerd */
}
img {
    max-width: 100%;       /* een afbeelding wordt nooit breder dan haar ouder */
    height: auto;          /* behoud de verhoudingen */
}
Afbeeldingen responsief

De twee regels op img zorgen ervoor dat grote foto’s netjes krimpen op een gsm in plaats van uit het scherm te lopen. Zet ze in elk project!

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
vw, vh en calc()

vh en vw zijn percentages van het scherm (viewport): 100vh is de volledige schermhoogte, ideaal voor een hero-blok. Met calc() reken je met verschillende eenheden door elkaar:

.hero    { height: 100vh; }                     /* volledige schermhoogte */
.inhoud  { width: calc(100% - 250px); }         /* alles behalve een zijbalk van 250px */
h1       { font-size: clamp(1.5rem, 5vw, 3rem); }   /* meegroeiend, maar tussen 1.5rem en 3rem */
Spaties in calc()

Rond + en - in calc() moeten spaties staan: calc(100% - 250px). Zonder spaties werkt het niet.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
🎯 Nu ben jij aan de beurt: Eenheden en afmetingen

Verwerk wat je hierboven las met de onderdelen hieronder. Ze horen bij deze theorie.

Wat als twee regels elkaar tegenspreken? De cascade bepaalt wie wint: leer waarom je CSS soms “niet werkt” en hoe je dat oplost.

Het probleem: conflicterende regels

Meerdere regels kunnen op hetzelfde element van toepassing zijn en elkaar tegenspreken:

HTML<p id="intro" class="tip">Welke kleur ben ik?</p>
CSSp      { color: blue; }
.tip   { color: green; }
#intro { color: red; }

De tekst wordt rood. De browser lost het conflict op met drie criteria, in deze volgorde: 1. belangrijkheid (!important), 2. specificiteit en 3. volgorde in het bestand.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Specificiteit: hoe “gericht” is een selector?

Hoe specifieker een selector, hoe zwaarder hij weegt. De rangorde, van zwak naar sterk:

SoortVoorbeeldGewicht
Element (en pseudo-element)p, ::beforelaag (0,0,1)
Klasse, attribuut, pseudo-klasse.tip, [type="text"], :hovermiddel (0,1,0)
Id#introhoog (1,0,0)
Inline stylestyle="…"nog hoger
!importantcolor: red !important;wint bijna altijd

Je telt het aantal id’s, klassen en elementen in de selector. Eén id wint van duizend klassen, en één klasse wint van duizend elementen:

Specificiteit tellenp                → (0,0,1)
.tip             → (0,1,0)     wint van p
p.tip            → (0,1,1)     wint van .tip
nav ul li a      → (0,0,4)
.menu a:hover    → (0,2,1)
#intro           → (1,0,0)     wint van alle voorgaande
Bij gelijke specificiteit: de laatste wint

Hebben twee regels evenveel gewicht, dan wint de regel die het laatst in het stylesheet staat (of het laatst geladen wordt).

.knop { background: blue; }
.knop { background: red; }   /* deze wint: hij staat onderaan */
Zo organiseer je je CSS

Schrijf algemene regels bovenaan (element-selectors), daaronder specifiekere (klassen). Dan hoef je zelden tegen de specificiteit te vechten.

Overerving (inheritance)

Sommige eigenschappen worden doorgegeven van een ouder aan zijn kinderen, zodat je ze niet overal moet herhalen. Typisch tekst-eigenschappen: color, font-family, font-size, line-height, text-align.

body {
    font-family: Arial, sans-serif;   /* alle tekst op de pagina erft dit */
    color: #333;
}

Eigenschappen zoals border, margin, padding en background worden niet geërfd (logisch: als een doos een rand krijgt, wil je niet dat elk kind ook een rand krijgt).

Met de waarde inherit dwing je overerving af, met initial zet je terug naar de standaardwaarde. Bijvoorbeeld: knoppen en invoervelden erven het lettertype standaard niet:

button, input, textarea {
    font-family: inherit;   /* neem het lettertype van de pagina over */
}
a {
    color: inherit;         /* een link krijgt de tekstkleur van zijn ouder */
}
✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
!important: wees voorzichtig

Met !important achter een waarde win je van (bijna) alles. Het is verleidelijk, maar het maakt je CSS onbeheersbaar: het volgende probleem los je enkel op met nóg een !important.

Vuistregel

Gebruik !important zo goed als nooit. Is een regel niet van toepassing? Maak je selector specifieker (bv. .menu .knop in plaats van .knop) of verplaats de regel lager in het bestand.

Debuggen met DevTools

Werkt je CSS niet? Open de DevTools (F12), kies Elements, klik op het element en kijk naar het Styles-paneel:

  • Regels die het verliezen staan doorgestreept: dat is de winnende regel die eroverheen gaat;
  • Je ziet uit welk bestand en welke regel elke declaratie komt;
  • Vinkje weg = eigenschap tijdelijk uit: zo test je snel;
  • Een ⚠️ gele driehoek naast een eigenschap betekent dat de browser hem niet begrijpt (typfout?).
Live aanpassen

Je kan waarden rechtstreeks in DevTools aanpassen en meteen het resultaat zien. Dat verdwijnt bij het herladen; kopieer wat werkt naar je stylesheet.

🎯 Nu ben jij aan de beurt: De cascade en specificiteit

Verwerk wat je hierboven las met de onderdelen hieronder. Ze horen bij deze theorie.

Blok of inline? Verborgen? Vastgeplakt? Met display en position bepaal je hoe en waar een element in de pagina staat.

display: blok, inline en inline-block

De eigenschap display bepaalt hoe een element zich gedraagt in de stroom van de pagina:

WaardeGedrag
blockbegint op een nieuwe regel, neemt de volle breedte; breedte, hoogte en marges werken (div, p, h1, ul, …)
inlineloopt mee in de tekst; breedte en hoogte werken niet, verticale marges ook niet (span, a, strong, img)
inline-blockstaat naast elkaar zoals inline, maar breedte, hoogte en marges werken wél
nonehet element wordt volledig verborgen en neemt geen plaats meer in
flex / grideen moderne layout-container (volgende hoofdstukken)
display: none of visibility: hidden?

display: none haalt het element weg alsof het er nooit was. visibility: hidden maakt het onzichtbaar maar de plaats blijft leeg. Handig: met JavaScript zet je een klasse aan of uit om iets te tonen of te verbergen.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
position: elementen verplaatsen

Met position haal je een element uit de normale stroom of zet je het vast. Daarna schuif je het met top, right, bottom en left.

WaardeWerking
staticstandaard: normale stroom; top/left doen niets
relativeblijft op zijn plaats in de stroom, maar je kan hem schuiven vanaf zijn eigen plaats; dient vooral als referentiepunt voor absolute kinderen
absoluteuit de stroom; positioneert zich ten opzichte van de dichtstbijzijnde ouder die niet static is (bv. relative)
fixedvast ten opzichte van het scherm: blijft staan bij scrollen (bv. een chatknop)
stickygedraagt zich normaal, maar blijft plakken aan de rand van het scherm bij scrollen (bv. een menubalk)
Het klassieke patroon: relative + absolute

Zo plaats je een badge of sluitknop in de hoek van een kaart: de kaart is relative (referentiepunt), de badge is absolute en schuift vanuit die hoek.

.kaart {
    position: relative;      /* referentiepunt voor de badge */
}
.badge {
    position: absolute;      /* uit de stroom, tov .kaart */
    top: 8px;
    right: 8px;
}
Vergeet de ouder niet

Vergeet je position: relative op de ouder, dan positioneert de absolute badge zich ten opzichte van de hele pagina in plaats van van de kaart. Dat is de meest gemaakte fout bij position.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Vast en plakkend: fixed en sticky
header {
    position: sticky;     /* plakt bovenaan bij scrollen... */
    top: 0;               /* ...op 0px van de bovenrand */
    background: white;
    z-index: 10;          /* boven de rest van de inhoud */
}
.chat-knop {
    position: fixed;      /* altijd zichtbaar, ook bij scrollen */
    bottom: 20px;
    right: 20px;
}

Als elementen elkaar overlappen, bepaalt z-index wat bovenaan ligt: het element met het hoogste getal komt voor. Het werkt enkel bij elementen met een position anders dan static (en bij flex- en grid-kinderen).

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
🎯 Nu ben jij aan de beurt: Display en positie

Verwerk wat je hierboven las met de onderdelen hieronder. Ze horen bij deze theorie.

De moderne manier om elementen naast of onder elkaar te zetten, uit te lijnen en te centreren: rijen, menu’s en kaartjes worden kinderspel.

Wat is Flexbox?

Flexbox (flexible box) is een layoutsysteem voor één richting: een rij of een kolom. Je zet display: flex op de ouder (de flex-container); de directe kinderen (de flex-items) staan dan automatisch naast elkaar en je regelt hun uitlijning met een paar eigenschappen op de container.

.rij {
    display: flex;
}

Meer is er niet nodig om drie <div>s naast elkaar te krijgen!

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Twee assen: hoofdas en kruisas

Flexbox werkt met twee assen. Dit is de sleutel om het te begrijpen:

Assen in flexboxflex-direction: row  (standaard)          flex-direction: column

  hoofdas  ──────────────►                  kruisas  ──────────►
  ┌───┐ ┌───┐ ┌───┐         kruisas           ┌───┐   hoofdas
  │ 1 │ │ 2 │ │ 3 │            │              │ 1 │      │
  └───┘ └───┘ └───┘            ▼              ├───┤      │
                                              │ 2 │      ▼
                                              └───┘
  • De hoofdas is de richting waarin de items staan (bij row: horizontaal). Uitlijnen langs de hoofdas doe je met justify-content.
  • De kruisas staat er loodrecht op. Uitlijnen langs de kruisas doe je met align-items.
Uitlijnen: justify-content en align-items
EigenschapWaarden
flex-directionrow (standaard), column, row-reverse
justify-content
(hoofdas)
flex-start, center, flex-end, space-between (ruimte tússen), space-around, space-evenly
align-items
(kruisas)
stretch (standaard), center, flex-start, flex-end
gapruimte tussen de items, bv. 16px
flex-wrapnowrap (standaard), wrap (naar volgende regel als het niet past)
Gebruik gap

Met gap zet je ruimte tussen de items, zonder marges op de kinderen. Veel netter dan marges (want er komt geen extra ruimte aan de buitenkant).

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Perfect centreren

Iets horizontaal én verticaal centreren was vroeger een nachtmerrie. Met flexbox zijn het drie regels:

.scherm {
    display: flex;
    justify-content: center;   /* horizontaal (hoofdas) */
    align-items: center;       /* verticaal (kruisas) */
    height: 100vh;
}
✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
De items zelf: flex-grow, flex-shrink en flex-basis

Ook de kinderen kan je sturen. De verkorte eigenschap flex bepaalt hoe een item ruimte inneemt:

.item    { flex: 1; }              /* alle items delen de ruimte gelijk */
.groot   { flex: 2; }              /* dubbel zoveel ruimte als een item met flex: 1 */
.vast    { flex: 0 0 200px; }      /* niet groeien, niet krimpen, altijd 200px */
.kaart   { flex: 1 1 250px; }      /* groeien, krimpen, en begin op 250px */
Deel van flexBetekenis
flex-growhoeveel van de overblijvende ruimte het item mag opeisen
flex-shrinkmag het krimpen als er te weinig plaats is?
flex-basisde beginbreedte (voor het groeien en krimpen)

Met align-self lijn je één item anders uit dan de rest, en met order wijzig je de volgorde zonder je HTML aan te passen.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Praktijk: een menubalk en kaartjes

Menubalk: logo links, links rechts, alles verticaal gecentreerd.

nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px 24px;
}
nav ul {
    display: flex;         /* de lijst zelf is ook een flex-container */
    gap: 20px;
    list-style: none;
    margin: 0;
    padding: 0;
}

Kaartjes die naar een volgende regel gaan als er geen plaats meer is (zonder media-queries!):

.kaarten {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
}
.kaart {
    flex: 1 1 220px;       /* minstens 220px, groeit om de regel te vullen */
}
✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
🎯 Nu ben jij aan de beurt: Flexbox

Verwerk wat je hierboven las met de onderdelen hieronder. Ze horen bij deze theorie.

Flexbox werkt in één richting. Grid werkt in rijen én kolommen tegelijk: ideaal voor de indeling van een hele pagina of een galerij.

Wat is Grid?

CSS Grid verdeelt een container in een raster van rijen en kolommen. Net als bij flexbox zet je display: grid op de ouder; de directe kinderen vallen dan in de cellen van het raster.

FlexboxGrid
één richting (rij of kolom)twee richtingen (rijen én kolommen)
de inhoud bepaalt de layoutde layout bepaalt waar de inhoud komt
menu’s, rijen, uitlijnenpagina-indeling, galerijen, dashboards
Beide gebruiken

Flexbox en Grid zijn geen concurrenten. Vaak gebruik je Grid voor de grote indeling en Flexbox binnen de onderdelen (een menu, een kaart).

Kolommen maken met grid-template-columns

Met grid-template-columns geef je de breedte van elke kolom op. Handig is de eenheid fr (fractie): een deel van de beschikbare ruimte.

.raster {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;   /* drie gelijke kolommen */
    gap: 16px;                            /* ruimte tussen rijen en kolommen */
}

/* korter: */
grid-template-columns: repeat(3, 1fr);

/* zijbalk + inhoud: */
grid-template-columns: 250px 1fr;         /* 250px vast, de rest voor de inhoud */
grid-template-columns: 1fr 2fr;           /* tweede kolom is dubbel zo breed */

Rijen ontstaan vanzelf: elke keer als een rij vol zit, begint er een nieuwe. Wil je de hoogte van rijen sturen, dan gebruik je grid-auto-rows (bv. minmax(100px, auto)).

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Responsieve kaartjes zonder media queries

Met repeat(auto-fit, minmax(…, 1fr)) maak je een raster dat zelf beslist hoeveel kolommen er passen. Elke kolom is minstens 200px breed en de kolommen vullen samen de rij. Wordt het venster smaller, dan verdwijnen er kolommen.

.galerij {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 16px;
}
Dit is de meest gebruikte Grid-regel

Onthoud dit patroon: het is een responsieve galerij in drie regels, zonder één media query.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Elementen over meerdere cellen

Een kind kan meerdere kolommen of rijen innemen met grid-column en grid-row:

.breed { grid-column: span 2; }      /* neemt twee kolommen in */
.hoog  { grid-row: span 2; }         /* neemt twee rijen in */
.kop   { grid-column: 1 / -1; }      /* van de eerste tot de laatste kolomlijn: de volledige rij */
✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Een hele pagina met grid-template-areas

Met grid-template-areas teken je je pagina als ASCII-schets. Elk kind krijgt met grid-area een naam en gaat naar de juiste plek.

.pagina {
    display: grid;
    grid-template-columns: 200px 1fr;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
        "kop     kop"
        "zijbalk inhoud"
        "voet    voet";
    min-height: 100vh;
}
header { grid-area: kop; }
aside  { grid-area: zijbalk; }
main   { grid-area: inhoud; }
footer { grid-area: voet; }

Zo lees je meteen aan de CSS hoe de pagina eruitziet. Voor een gsm-versie wijzig je in een media query enkel de grid-template-areas (zie volgend hoofdstuk).

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Uitlijnen in het raster

Ook Grid kent uitlijn-eigenschappen, met dezelfde namen als bij flexbox: justify-items / align-items (cel-inhoud), justify-content / align-content (het hele raster). Met place-items: center centreer je in één regel alles in zijn cel.

🎯 Nu ben jij aan de beurt: CSS Grid

Verwerk wat je hierboven las met de onderdelen hieronder. Ze horen bij deze theorie.

Een website moet er goed uitzien op een gsm, een tablet en een groot scherm. Met media queries pas je de opmaak aan de schermbreedte aan.

Waarom responsive?

Meer dan de helft van het webverkeer komt van gsm’s. Een pagina die enkel op een groot scherm werkt, is voor die bezoekers onbruikbaar. Responsive design betekent: één website die zich aanpast aan het scherm van de bezoeker. Drie bouwstenen:

  1. De viewport-meta in je HTML;
  2. Flexibele maten (%, rem, max-width, flex/grid) in plaats van vaste pixels;
  3. Media queries om de layout te wijzigen op bepaalde breedtes.
De viewport-meta

Zonder deze regel in je head denkt een gsm dat je pagina 980px breed is en toont hij een uitgezoomde versie. Zet ze altijd:

in de <head> van elke pagina<meta name="viewport" content="width=device-width, initial-scale=1">

Ze zegt: “gebruik de echte breedte van het toestel en zoom niet uit”.

Media queries

Een media query past CSS-regels enkel toe als een voorwaarde klopt, meestal een schermbreedte:

/* enkel op schermen tot 600px breed (gsm) */
@media (max-width: 600px) {
    .rij {
        flex-direction: column;
    }
    h1 {
        font-size: 1.75rem;
    }
}

/* enkel op schermen vanaf 900px breed */
@media (min-width: 900px) {
    .container {
        width: 80%;
    }
}
  • max-width: 600px: geldt tot en met 600px breed;
  • min-width: 900px: geldt vanaf 900px breed;
  • Binnen de accolades van de query staan gewone CSS-regels, met hun eigen selectors.
✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Mobile first

De beste aanpak is mobile first: schrijf eerst de opmaak voor de kleinste schermen (zonder media query) en voeg met min-width verbeteringen toe voor grotere schermen.

/* basis: gsm — één kolom */
.kaarten {
    display: grid;
    gap: 16px;
    grid-template-columns: 1fr;
}

/* tablet: twee kolommen */
@media (min-width: 600px) {
    .kaarten { grid-template-columns: repeat(2, 1fr); }
}

/* desktop: vier kolommen */
@media (min-width: 1000px) {
    .kaarten { grid-template-columns: repeat(4, 1fr); }
}
Veelgebruikte breekpunten

Er zijn geen heilige getallen. Vaak zie je 600px (gsm → tablet), 900–1000px (tablet → laptop) en 1200px (groot scherm). Stel liever een breekpunt in waar je layout stuk gaat dan bij een bepaald toestel.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Handige extra’s

Menu verbergen op een gsm en een menu-knop tonen (met JavaScript eronder):

.menu-knop { display: none; }              /* op groot scherm niet nodig */

@media (max-width: 700px) {
    .menu-knop { display: block; }
    nav ul     { display: none; }          /* menu verborgen tot je op de knop klikt */
    nav ul.open { display: block; }        /* JavaScript zet de klasse 'open' aan */
}

Donkere modus: volg de voorkeur van de gebruiker:

@media (prefers-color-scheme: dark) {
    body {
        background: #0f172a;
        color: #e2e8f0;
    }
}

Ook afdrukken kan je aanpassen met @media print (bv. menu’s verbergen). Test altijd op een echt toestel of met de toestelmodus in de DevTools (F12 → icoon met gsm en tablet).

🎯 Nu ben jij aan de beurt: Responsive design

Verwerk wat je hierboven las met de onderdelen hieronder. Ze horen bij deze theorie.

Laat je pagina tot leven komen: zachte overgangen bij hover, verschuiven, draaien en zelfstandig bewegende animaties, allemaal zonder JavaScript.

Transities: zacht veranderen

Normaal springt een eigenschap meteen naar zijn nieuwe waarde (een knop wordt in één klap rood bij hover). Met een transitie gebeurt de verandering geleidelijk. Je zet de transitie op het element in zijn gewone toestand, de nieuwe waarde zet je in de hover-regel:

.knop {
    background-color: #2563eb;
    transition: background-color 0.3s ease;   /* wat, hoe lang, hoe */
}
.knop:hover {
    background-color: #1d4ed8;
}
OnderdeelBetekenis
transition-propertywelke eigenschap (bv. background-color, of all)
transition-durationhoe lang, bv. 0.3s of 300ms
transition-timing-functionhet tempo: ease (standaard), linear, ease-in-out
transition-delaywachttijd voor het begint
Zet de transitie op het basiselement

Zet transition in .knop en niet in .knop:hover. Dan animeert het ook terug als je de muis wegneemt.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Transform: verschuiven, schalen, draaien

Met transform verplaats je een element zonder de rest van de pagina te beïnvloeden:

FunctieEffect
translateX(20px) / translateY(-4px)verschuiven
scale(1.1)vergroten (1 = normaal, 0.5 = half)
rotate(15deg)draaien
translateY(-4px) scale(1.05)meerdere na elkaar

Combineer ze met een transitie voor de klassieke “kaart die opveert bij hover”:

.kaart {
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.kaart:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}
Waarom transform en niet margin?

Een transform verandert de layout niet: andere elementen blijven staan, en de browser animeert het heel vloeiend. Animeer daarom liever transform en opacity dan width of margin.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Animaties met @keyframes

Een transitie gaat van A naar B als er iets gebeurt (hover). Een animatie beweegt uit zichzelf en kan meerdere stappen hebben. In twee stappen:

1. Definieer de animatie met @keyframes en geef ze een naam:

@keyframes pulseer {
    0%   { transform: scale(1); }
    50%  { transform: scale(1.15); }
    100% { transform: scale(1); }
}

2. Pas ze toe met de eigenschap animation: naam, duur, tempo, aantal herhalingen.

.hartje {
    animation: pulseer 1s ease-in-out infinite;   /* naam duur tempo herhaling */
}

Met from en to (of percentages) beschrijf je de stappen. infinite herhaalt eindeloos; een getal (3) herhaalt zo vaak.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Een laadicoon
@keyframes draai {
    to { transform: rotate(360deg); }
}
.laden {
    width: 40px;
    height: 40px;
    border: 4px solid #cbd5e1;
    border-top-color: #2563eb;      /* één gekleurde kant */
    border-radius: 50%;
    animation: draai 0.8s linear infinite;
}
✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Met mate: toegankelijkheid en prestaties
  • Overdrijf niet. Animaties die de aandacht opeisen vermoeien en leiden af. Kort (0,2 tot 0,4 seconden) en subtiel werkt het best.
  • Sommige mensen worden onwel van bewegende beelden. Respecteer hun instelling:
@media (prefers-reduced-motion: reduce) {
    * {
        animation: none !important;
        transition: none !important;
    }
}

Dit is een van de zeldzame plaatsen waar !important verdedigbaar is.

🎯 Nu ben jij aan de beurt: Transities en animaties

Verwerk wat je hierboven las met de onderdelen hieronder. Ze horen bij deze theorie.

Schrijf onderhoudbare CSS: kleuren en maten één keer definiëren met variabelen, een reset gebruiken en je stylesheet netjes opbouwen.

Het probleem: herhaling

Stel: de hoofdkleur van je site is #2563eb en je gebruikt ze op 30 plaatsen. Wil je morgen een andere kleur, dan moet je 30 keer zoeken en vervangen. Ook lastig: welke blauwtint was het ook alweer?

De oplossing zijn CSS-variabelen (officieel custom properties): je definieert een waarde één keer en gebruikt ze overal.

Variabelen maken en gebruiken

Een variabele begint met twee streepjes. Je zet ze meestal in :root (het hoogste element, zodat ze overal beschikbaar zijn) en gebruikt ze met var():

:root {
    --kleur-primair: #2563eb;
    --kleur-tekst: #1e293b;
    --kleur-achtergrond: #f8fafc;
    --ruimte: 16px;
    --straal: 8px;
}

body {
    color: var(--kleur-tekst);
    background-color: var(--kleur-achtergrond);
}

.knop {
    background-color: var(--kleur-primair);
    padding: var(--ruimte);
    border-radius: var(--straal);
}
  • Namen zijn vrij te kiezen maar beginnen met --; kies een duidelijke naam (hoofdlettergevoelig).
  • var(--naam, reserve) laat je een reservewaarde opgeven voor als de variabele niet bestaat.
  • Variabelen kunnen ook binnen een selector staan en gelden dan enkel daar.
✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Thema’s: een donkere modus met variabelen

Omdat variabelen overschreven kunnen worden, zijn ze ideaal voor thema’s. Je gebruikt overal var(...) en wisselt enkel de waarden:

:root {
    --achtergrond: #ffffff;
    --tekst: #0f172a;
}

.donker {
    --achtergrond: #0f172a;
    --tekst: #e2e8f0;
}

body {
    background: var(--achtergrond);
    color: var(--tekst);
}

Zet je met JavaScript de klasse donker op de <body>, dan wisselen alle kleuren in één keer. Ook Bootstrap 5 werkt zo achter de schermen.

✏️ Probeer zelf — pas de code aan en klik op Uitvoeren
Een reset: gelijke startpunten

Elke browser heeft eigen standaardstijlen (marges op body, grootte van koppen, …). Veel ontwikkelaars beginnen hun stylesheet met een korte reset zodat alles overal hetzelfde start:

bovenaan stijl.css*, *::before, *::after {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: system-ui, sans-serif;
    line-height: 1.6;
}

img {
    max-width: 100%;
    height: auto;
    display: block;
}
Frameworks

Bootstrap bevat een eigen, uitgebreidere reset (Reboot). Gebruik je Bootstrap, dan hoef je dit niet zelf te schrijven.

Een stylesheet organiseren

Een stylesheet groeit snel. Geef het een vaste volgorde, van algemeen naar specifiek, en zet commentaarkoppen:

stijl.css/* 1. Variabelen */
:root { … }

/* 2. Reset en basis */
*, *::before, *::after { … }
body { … }
h1, h2, h3 { … }

/* 3. Layout */
.container { … }
.kop { … }
.voet { … }

/* 4. Componenten */
.knop { … }
.kaart { … }

/* 5. Hulpklassen */
.verborgen { display: none; }

/* 6. Media queries (onderaan, of bij hun component) */
@media (max-width: 600px) { … }
Goede gewoontes
  • Gebruik klassen, geen id’s, om op te maken: dat blijft flexibel en overschrijfbaar.
  • Beschrijvende namen die zeggen wat iets is, niet hoe het eruitziet: .waarschuwing in plaats van .rode-tekst.
  • Kies één naamconventie: kleine letters met streepjes (.product-kaart). Voor grotere projecten bestaat BEM: .kaart, .kaart__titel, .kaart--groot.
  • Herhaal je jezelf? Maak een variabele of een gedeelde klasse.
  • Verdeel grote projecten in meerdere bestanden (reset.css, layout.css, componenten.css) of gebruik een tool zoals Sass.
🎯 Nu ben jij aan de beurt: CSS-variabelen en organisatie

Verwerk wat je hierboven las met de onderdelen hieronder. Ze horen bij deze theorie.

Je hebt de HTML van een portfolio-pagina. Nu maak je ze mooi en responsief met alles wat je in deze cursus leerde.

De opdracht

Onderaan vind je de HTML van een portfolio: een menubalk, een introductieblok, een galerij projectkaarten en een voet. Jij schrijft de volledige CSS. Doel: een verzorgde, responsieve pagina.

Eisen:

  • Variabelen in :root voor je kleuren (--primair, --tekst, --achtergrond) en gebruik ze;
  • een reset met box-sizing: border-box en een leesbaar body (lettertype, regelafstand);
  • een menubalk met flexbox (logo links, links rechts, verticaal gecentreerd, plakkend bovenaan);
  • een hero met kleurverloop, gecentreerde witte tekst en een knop met hover-effect en transitie;
  • een kaartengalerij met grid dat automatisch het aantal kolommen kiest, kaarten met schaduw en een opveer-effect bij hover;
  • een media query die de menubalk op een gsm (max. 600px) onder elkaar zet.
Werkwijze
  1. Begin met de variabelen en de reset.
  2. Bouw dan van boven naar onder: menubalk → hero → kaarten → voet.
  3. Bekijk na elk onderdeel het ▶ Voorbeeld en klik op Controleer.
  4. Test op een smal venster of in de toestelmodus van de DevTools.
  5. Controleer of de contrast van je kleuren voldoende is.
Structuur van de HTML

De klassen zijn: .kop (menubalk), .logo, .hero, .knop, .projecten, .kaarten, .kaart en .voet. Gebruik in de oefening de Voorbeeld-knop om de HTML te zien werken met jouw CSS.

Mogelijke uitwerking

Probeer eerst zelf! Zit je vast, dan zie je hier één van de vele mogelijke oplossingen:

css/stijl.css/* ---------- Variabelen ---------- */
:root {
    --primair: #2563eb;
    --tekst: #1e293b;
    --achtergrond: #f8fafc;
    --straal: 10px;
}

/* ---------- Reset en basis ---------- */
*, *::before, *::after {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: system-ui, sans-serif;
    line-height: 1.6;
    color: var(--tekst);
    background-color: var(--achtergrond);
}

/* ---------- Menubalk ---------- */
.kop {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px 24px;
    background-color: white;
    position: sticky;
    top: 0;
    z-index: 10;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}

.kop nav ul {
    display: flex;
    gap: 20px;
    list-style: none;
    margin: 0;
    padding: 0;
}

.kop a {
    color: var(--tekst);
    text-decoration: none;
}

/* ---------- Hero ---------- */
.hero {
    background: linear-gradient(to right, var(--primair), #8b5cf6);
    color: white;
    text-align: center;
    padding: 60px 20px;
}

.knop {
    display: inline-block;
    background-color: white;
    color: var(--primair);
    padding: 12px 24px;
    border-radius: var(--straal);
    text-decoration: none;
    transition: transform 0.2s ease;
}

.knop:hover {
    transform: translateY(-2px);
}

/* ---------- Kaarten ---------- */
.kaarten {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 16px;
    padding: 24px;
}

.kaart {
    background-color: white;
    padding: 20px;
    border-radius: var(--straal);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
    transition: transform 0.2s ease;
}

.kaart:hover {
    transform: translateY(-4px);
}

/* ---------- Voet ---------- */
.voet {
    text-align: center;
    padding: 20px;
}

/* ---------- Gsm ---------- */
@media (max-width: 600px) {
    .kop {
        flex-direction: column;
        gap: 8px;
    }
}
Wat nu?

Gefeliciteerd: je kan nu een volledige website opmaken. Enkele mogelijke vervolgstappen:

  • Bootstrap: een kant-en-klaar raamwerk dat veel van dit werk voor je doet;
  • JavaScript en jQuery: je pagina reageert op klikken, zoals een uitklapbaar menu;
  • Sass en Tailwind CSS: hulpmiddelen voor grote projecten;
  • Oefenen: bouw na wat je op het web mooi vindt, bv. de homepage van een bekend merk.
🎯 Nu ben jij aan de beurt: Eindproject: de portfolio-site opmaken

Verwerk wat je hierboven las met de onderdelen hieronder. Ze horen bij deze theorie.