Responsieve webdesigns maken met CSS (voor beginners)
Responsief webdesign betekent dat je website zich automatisch aanpast aan verschillende schermformaten: van een kleine telefoon tot een groot bureaubladscherm. In deze tutorial leer je stap voor stap hoe je dat met CSS opbouwt. Je krijgt niet alleen regels om te kopiëren, maar ook uitleg waarom je bepaalde keuzes maakt, welke valkuilen er zijn, en hoe je je ontwerp test.
Inhoud
- Wat is responsief webdesign?
- Basisprincipes: vloeibare layouts en flexibele media
- Een kleine projectstructuur opzetten
- Mobiel-eerst ontwerpen
- CSS-units die je echt moet kennen
- Media queries: de kern van responsiviteit
- Flexbox: responsieve rijen en kolommen
- CSS Grid: complete pagina-indelingen
- Responsieve typografie
- Responsieve afbeeldingen en video
- Navigatie responsief maken
- Veelgemaakte fouten en hoe je ze voorkomt
- Testen en debuggen
- Mini-project: een responsieve landingspagina
- Checklist voor je eigen projecten
Wat is responsief webdesign?
Een responsieve website:
- gebruikt vloeibare breedtes (bijvoorbeeld percentages in plaats van vaste pixels),
- schaalt afbeeldingen en media mee,
- verandert de layout met media queries (bijvoorbeeld 1 kolom op mobiel, 3 kolommen op desktop),
- zorgt dat tekst en knoppen leesbaar en klikbaar blijven.
Waarom is dit belangrijk?
- Mensen bezoeken websites op allerlei apparaten.
- Zoekmachines geven vaak de voorkeur aan mobielvriendelijke sites.
- Een responsieve site is meestal makkelijker te onderhouden dan aparte mobiele en desktopversies.
Basisprincipes: vloeibare layouts en flexibele media
Vloeibare layouts
Een vaste layout gebruikt bijvoorbeeld width: 960px;. Dat kan op een klein scherm problemen geven: je krijgt horizontaal scrollen of alles wordt te klein.
Een vloeibare layout gebruikt bijvoorbeeld:
max-widthin plaats vanwidth,- percentages (
%), - moderne units zoals
rem,vw,clamp().
Voorbeeld:
.container {
width: min(100% - 2rem, 1100px);
margin-inline: auto;
}
Uitleg:
100% - 2rembetekent: neem bijna de volledige breedte, maar laat links en rechts wat ruimte.1100pxis een bovengrens: op grote schermen wordt de tekstregel niet extreem breed.margin-inline: autocentreert de container.
Flexibele media
Afbeeldingen hebben vaak een vaste breedte in HTML of komen in een te grote resolutie binnen. Basisregel:
img, video {
max-width: 100%;
height: auto;
}
Dit voorkomt dat media buiten hun container “uitsteken”.
Een kleine projectstructuur opzetten
Maak een map voor je project, bijvoorbeeld responsief-beginner/ met deze bestanden:
index.htmlstyles.css
Je kunt dit aanmaken met echte terminalcommando’s.
Op Windows (PowerShell)
mkdir responsief-beginner
cd responsief-beginner
ni index.html
ni styles.css
Op macOS of Linux (Terminal)
mkdir responsief-beginner
cd responsief-beginner
touch index.html styles.css
Open de map in je editor. In index.html zetten we een basisstructuur.
Mobiel-eerst ontwerpen
Mobiel-eerst betekent:
- Je schrijft eerst CSS voor kleine schermen.
- Daarna voeg je uitbreidingen toe voor grotere schermen met media queries.
Waarom is dit slim?
- Je dwingt jezelf om te focussen op de kern.
- Je CSS blijft vaak eenvoudiger.
- Kleine schermen hebben vaak beperktere ruimte en soms minder rekenkracht.
Een mobiel-eerst media query ziet er zo uit:
/* Basis: mobiel */
.card-list {
display: grid;
gap: 1rem;
}
/* Vanaf 768px: tablet en groter */
@media (min-width: 768px) {
.card-list {
grid-template-columns: repeat(2, 1fr);
}
}
/* Vanaf 1024px: desktop */
@media (min-width: 1024px) {
.card-list {
grid-template-columns: repeat(3, 1fr);
}
}
CSS-units die je echt moet kennen
px (pixels)
Handig, maar niet altijd flexibel. Pixels zijn prima voor kleine details zoals borders, maar minder ideaal voor complete layouts.
% (percentages)
Relatief aan de breedte (of hoogte) van de oudercontainer.
.sidebar {
width: 30%;
}
rem en em
remis relatief aan de fontgrootte van het document (meestalhtml).emis relatief aan de fontgrootte van het element zelf (of zijn ouder).
Waarom rem vaak beter is: je kunt de schaal van je hele site aanpassen door de basisfontgrootte te wijzigen.
Voorbeeld:
html { font-size: 16px; }
h1 { font-size: 2rem; } /* 32px */
vw en vh
1vwis 1% van de viewportbreedte.1vhis 1% van de viewporthoogte.
Handig voor hero-secties, maar pas op: op mobiele browsers kan de zichtbare hoogte variëren door de adresbalk.
clamp()
Een moderne manier om een waarde responsief te maken binnen grenzen:
h1 {
font-size: clamp(1.8rem, 3vw + 1rem, 3rem);
}
Uitleg:
- minimum:
1.8rem - voorkeur:
3vw + 1rem(schaalt met viewport) - maximum:
3rem
Media queries: de kern van responsiviteit
Een media query past CSS toe op basis van eigenschappen van het apparaat, meestal de breedte.
Basisvorm
@media (min-width: 600px) {
/* CSS die geldt vanaf 600px breedte */
}
Veelgebruikte breekpunten
Er is geen “magische” set breekpunten, maar dit zijn vaak bruikbare richtlijnen:
- 480px: kleine telefoons
- 768px: tablets
- 1024px: kleine laptops
- 1280px+: grotere schermen
Belangrijk: kies breekpunten op basis van je ontwerp, niet op basis van specifieke apparaten. Je merkt vaak vanzelf wanneer een layout “breekt”.
Media queries slim organiseren
Zet je CSS in deze volgorde:
- Basis (mobiel)
@media (min-width: 600px)@media (min-width: 900px)@media (min-width: 1200px)
Zo voorkom je dat je later weer terug moet om regels te overschrijven.
Flexbox: responsieve rijen en kolommen
Flexbox is ideaal voor:
- navigatiebalken,
- knoppenrijen,
- kaarten die naast elkaar moeten staan,
- uitlijning in één dimensie (rij óf kolom).
Voorbeeld: kaarten die op mobiel onder elkaar staan
HTML:
<section class="features">
<article class="feature">Snel</article>
<article class="feature">Veilig</article>
<article class="feature">Schaalbaar</article>
</section>
CSS (mobiel-eerst):
.features {
display: flex;
flex-direction: column;
gap: 1rem;
}
.feature {
padding: 1rem;
border: 1px solid #ddd;
border-radius: 12px;
}
Vanaf tablet:
@media (min-width: 768px) {
.features {
flex-direction: row;
}
.feature {
flex: 1;
}
}
Uitleg:
flex-direction: columnstapelt items.- Op grotere schermen zetten we
row. flex: 1geeft elke kaart gelijke breedte.
Veelgebruikte flex-eigenschappen
justify-content: verdeling in de hoofdrichting (bijrowhorizontaal).align-items: uitlijning in de dwarsrichting.flex-wrap: laat items naar een nieuwe regel springen.
Voorbeeld met wrap:
.tags {
display: flex;
flex-wrap: wrap;
gap: .5rem;
}
CSS Grid: complete pagina-indelingen
Grid is ideaal voor tweedimensionale layouts: rijen én kolommen tegelijk.
Voorbeeld: een productoverzicht
HTML:
<section class="products">
<article class="product">Product 1</article>
<article class="product">Product 2</article>
<article class="product">Product 3</article>
<article class="product">Product 4</article>
</section>
CSS:
.products {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
}
.product {
border: 1px solid #e5e5e5;
border-radius: 12px;
padding: 1rem;
}
Vanaf 600px:
@media (min-width: 600px) {
.products {
grid-template-columns: repeat(2, 1fr);
}
}
Vanaf 1024px:
@media (min-width: 1024px) {
.products {
grid-template-columns: repeat(4, 1fr);
}
}
Automatisch kolommen laten ontstaan
Je kunt Grid ook “zelf” kolommen laten kiezen:
.products {
display: grid;
gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
Uitleg:
minmax(220px, 1fr)betekent: een kaart is minimaal 220px breed, maar mag groeien.auto-fitvult de rij met zoveel kolommen als passen.
Dit is vaak een van de krachtigste responsieve patronen, omdat je minder media queries nodig hebt.
Responsieve typografie
Tekst moet leesbaar blijven. Op mobiel wil je niet dat regels te lang zijn, en op desktop wil je niet dat alles te klein oogt.
Basisinstellingen
html {
font-size: 16px;
}
body {
font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
line-height: 1.6;
color: #1a1a1a;
}
Regellengte beperken
Een veelvoorkomend probleem op brede schermen is dat tekstregels te lang worden. Een prettige regellengte ligt vaak rond 60–80 tekens. Je kunt dit sturen met max-width:
.prose {
max-width: 65ch;
}
ch is een unit gebaseerd op de breedte van het teken “0”. Het is handig om tekstbreedte te sturen.
Koppen responsief maken met clamp()
h1 {
font-size: clamp(2rem, 4vw + 1rem, 3.5rem);
line-height: 1.1;
}
Hierdoor schaalt de kop mee, zonder extreem groot of klein te worden.
Responsieve afbeeldingen en video
Afbeeldingen die netjes schalen
Basisregel (herhaling, maar essentieel):
img {
max-width: 100%;
height: auto;
display: block;
}
display: block voorkomt kleine “witruimte” onder afbeeldingen die ontstaat door inline-uitlijning.
Afbeeldingen in een vaste verhouding
Soms wil je dat kaarten allemaal dezelfde beeldverhouding hebben. Gebruik aspect-ratio:
.card img {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
border-radius: 12px;
}
Uitleg:
object-fit: coversnijdt de afbeelding bij zodat de container gevuld wordt.aspect-ratiozorgt voor consistente hoogtes.
Video responsief insluiten
Voor een video in een container:
.video {
aspect-ratio: 16 / 9;
}
.video iframe {
width: 100%;
height: 100%;
border: 0;
}
Navigatie responsief maken
Een navigatie is vaak het eerste dat “breekt” op mobiel. Een eenvoudige aanpak:
- Op mobiel: items onder elkaar of een knop die een menu toont.
- Op desktop: items in één rij.
Hier doen we een simpele variant zonder ingewikkelde logica: op mobiel stapelen, op desktop in een rij.
HTML:
<header class="site-header">
<a class="logo" href="#">MijnSite</a>
<nav class="nav">
<a href="#features">Functies</a>
<a href="#prijzen">Prijzen</a>
<a href="#contact">Contact</a>
</nav>
</header>
CSS:
.site-header {
display: flex;
flex-direction: column;
gap: .75rem;
padding: 1rem;
border-bottom: 1px solid #eee;
}
.nav {
display: flex;
flex-direction: column;
gap: .5rem;
}
.nav a {
text-decoration: none;
color: inherit;
padding: .5rem .75rem;
border-radius: 10px;
}
.nav a:hover {
background: #f3f3f3;
}
Vanaf 768px:
@media (min-width: 768px) {
.site-header {
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.nav {
flex-direction: row;
align-items: center;
}
}
Uitleg:
- Op mobiel is het een kolom: logo boven, links eronder.
- Op desktop wordt het een rij met ruimte ertussen.
Veelgemaakte fouten en hoe je ze voorkomt
1) Vaste breedtes die niet kunnen krimpen
Fout:
.card { width: 500px; }
Oplossing:
.card { width: min(100%, 500px); }
2) Geen box-sizing: border-box
Zonder dit tellen padding en border op bij de breedte, wat onverwachte overflow kan geven.
Gebruik dit bijna altijd:
*,
*::before,
*::after {
box-sizing: border-box;
}
3) Horizontaal scrollen door overflow
Soms veroorzaakt een lang woord, een grote afbeelding of een element met width: 100vw horizontale scroll.
Tips:
- Vermijd
100vwvoor containers; gebruik liever100%. - Zet lange woorden om:
.prose {
overflow-wrap: anywhere;
}
4) Te veel breekpunten
Als je voor elk klein probleem een media query maakt, wordt je CSS onoverzichtelijk. Probeer eerst:
auto-fitmetminmax()in Grid,- flex-wrap,
clamp()voor typografie,min()enmax()voor breedtes.
5) Klikdoelen te klein op mobiel
Links en knoppen moeten makkelijk te raken zijn. Richtlijn: voldoende padding.
button, .btn, .nav a {
padding: .6rem .9rem;
}
Testen en debuggen
In je browser: responsieve modus
De meeste browsers hebben ontwikkelaarshulpmiddelen:
- open ontwikkelaarshulpmiddelen,
- zet de weergave op verschillende schermbreedtes,
- test ook draaien van portret naar landschap.
Test echte interactie
Let op:
- menu’s die goed werken met aanraking,
- formulieren die niet te klein zijn,
- tekst die niet tegen de randen plakt.
Snelle lokale server starten
Sommige dingen werken beter via een server (bijvoorbeeld bepaalde imports). Je kunt een simpele server starten.
Als je een omgeving hebt met Python:
python -m http.server 5173
Open daarna in je browser:
http://localhost:5173
Als je een omgeving hebt met Node.js en je wilt een snelle server via een pakket:
npm init -y
npm install --save-dev serve
npx serve .
Mini-project: een responsieve landingspagina
We bouwen een eenvoudige pagina met:
- header + navigatie
- hero-sectie
- kaarten (features)
- een grid met “prijzen”
- footer
Stap 1: HTML (index.html)
<!doctype html>
<html lang="nl">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Responsief beginner</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header class="site-header container">
<a class="logo" href="#">MijnSite</a>
<nav class="nav">
<a href="#features">Functies</a>
<a href="#prijzen">Prijzen</a>
<a href="#contact">Contact</a>
</nav>
</header>
<main>
<section class="hero container">
<div class="hero-text">
<h1>Maak een responsieve website met moderne CSS</h1>
<p class="lead">
Leer mobiel-eerst, Flexbox, Grid en media queries. Bouw layouts die er goed uitzien op elk scherm.
</p>
<div class="hero-actions">
<a class="btn primary" href="#features">Bekijk functies</a>
<a class="btn" href="#prijzen">Bekijk prijzen</a>
</div>
</div>
<div class="hero-media" aria-hidden="true">
<div class="mock"></div>
</div>
</section>
<section id="features" class="section container">
<h2>Functies</h2>
<div class="features">
<article class="card">
<h3>Mobiel-eerst</h3>
<p>Begin klein, schaal op. Zo blijft je CSS overzichtelijk en je site snel.</p>
</article>
<article class="card">
<h3>Flexbox</h3>
<p>Perfect voor rijen, navigatie en componenten die moeten meebewegen.</p>
</article>
<article class="card">
<h3>Grid</h3>
<p>Ideaal voor pagina-indelingen en kaartenoverzichten met automatische kolommen.</p>
</article>
</div>
</section>
<section id="prijzen" class="section container">
<h2>Prijzen</h2>
<div class="pricing">
<article class="price-card">
<h3>Start</h3>
<p class="price">€ 0</p>
<ul>
<li>1 project</li>
<li>Basis templates</li>
<li>Community support</li>
</ul>
<a class="btn primary" href="#contact">Kies Start</a>
</article>
<article class="price-card featured">
<h3>Pro</h3>
<p class="price">€ 9</p>
<ul>
<li>Onbeperkt</li>
<li>Extra componenten</li>
<li>Snellere feedback</li>
</ul>
<a class="btn primary" href="#contact">Kies Pro</a>
</article>
<article class="price-card">
<h3>Team</h3>
<p class="price">€ 29</p>
<ul>
<li>Team toegang</li>
<li>Design review</li>
<li>Prioriteit support</li>
</ul>
<a class="btn primary" href="#contact">Kies Team</a>
</article>
</div>
</section>
<section id="contact" class="section container">
<h2>Contact</h2>
<form class="contact">
<label>
Naam
<input type="text" name="naam" autocomplete="name" />
</label>
<label>
E-mail
<input type="email" name="email" autocomplete="email" />
</label>
<label>
Bericht
<textarea name="bericht" rows="5"></textarea>
</label>
<button class="btn primary" type="submit">Verstuur</button>
</form>
</section>
</main>
<footer class="footer container">
<p>© MijnSite</p>
</footer>
</body>
</html>
Belangrijk voor responsiviteit: deze regel in de <head>:
<meta name="viewport" content="width=device-width, initial-scale=1" />
Zonder deze meta-tag schalen mobiele browsers je pagina vaak alsof het een desktopsite is.
Stap 2: CSS (styles.css)
Plak dit als basis. Het is bewust mobiel-eerst opgebouwd.
/* 1) Basis reset en globale instellingen */
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-size: 16px;
}
body {
margin: 0;
font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
line-height: 1.6;
color: #161616;
background: #ffffff;
}
img, video {
max-width: 100%;
height: auto;
display: block;
}
/* 2) Herbruikbare layout-hulp: container */
.container {
width: min(100% - 2rem, 1100px);
margin-inline: auto;
}
/* 3) Typografie */
h1 {
font-size: clamp(2rem, 4vw + 1rem, 3.2rem);
line-height: 1.1;
margin: 0 0 1rem;
}
h2 {
font-size: clamp(1.4rem, 1.6vw + 1rem, 2rem);
margin: 0 0 1rem;
}
h3 {
margin: 0 0 .5rem;
}
.lead {
font-size: 1.05rem;
color: #333;
margin: 0 0 1.25rem;
max-width: 65ch;
}
/* 4) Knoppen */
.btn {
display: inline-block;
padding: .7rem 1rem;
border-radius: 12px;
border: 1px solid #d7d7d7;
text-decoration: none;
color: inherit;
background: #fff;
}
.btn.primary {
background: #111;
color: #fff;
border-color: #111;
}
.btn:hover {
filter: brightness(0.97);
}
/* 5) Header en navigatie */
.site-header {
display: flex;
flex-direction: column;
gap: .75rem;
padding-block: 1rem;
}
.logo {
font-weight: 700;
text-decoration: none;
color: inherit;
font-size: 1.1rem;
}
.nav {
display: flex;
flex-direction: column;
gap: .25rem;
}
.nav a {
padding: .55rem .75rem;
border-radius: 10px;
text-decoration: none;
color: inherit;
}
.nav a:hover {
background: #f3f3f3;
}
/* 6) Secties */
.section {
padding-block: 2.25rem;
}
/* 7) Hero */
.hero {
display: grid;
gap: 1.5rem;
padding-block: 2rem;
align-items: center;
}
.hero-actions {
display: flex;
flex-wrap: wrap;
gap: .75rem;
}
.hero-media .mock {
aspect-ratio: 16 / 10;
border-radius: 18px;
background:
linear-gradient(135deg, #111 0%, #444 45%, #888 100%);
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.15);
}
/* 8) Kaarten (features) */
.features {
display: grid;
gap: 1rem;
}
.card {
border: 1px solid #e7e7e7;
border-radius: 16px;
padding: 1rem;
background: #fff;
}
/* 9) Pricing grid */
.pricing {
display: grid;
gap: 1rem;
grid-template-columns: 1fr;
}
.price-card {
border: 1px solid #e7e7e7;
border-radius: 16px;
padding: 1rem;
background: #fff;
}
.price-card.featured {
border-color: #111;
}
.price {
font-size: 2rem;
margin: .25rem 0 1rem;
}
.price-card ul {
margin: 0 0 1rem;
padding-left: 1.1rem;
}
/* 10) Formulier */
.contact {
display: grid;
gap: .9rem;
max-width: 520px;
}
.contact label {
display: grid;
gap: .35rem;
font-weight: 600;
}
.contact input,
.contact textarea {
font: inherit;
padding: .7rem .85rem;
border-radius: 12px;
border: 1px solid #d7d7d7;
}
.contact input:focus,
.contact textarea:focus {
outline: 2px solid #111;
outline-offset: 2px;
}
/* 11) Footer */
.footer {
padding-block: 2rem;
border-top: 1px solid #eee;
color: #444;
}
/* 12) Media queries: vanaf tablet */
@media (min-width: 768px) {
.site-header {
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.nav {
flex-direction: row;
gap: .25rem;
}
.hero {
grid-template-columns: 1.2fr .8fr;
padding-block: 3rem;
}
.features {
grid-template-columns: repeat(3, 1fr);
}
.pricing {
grid-template-columns: repeat(3, 1fr);
}
}
/* 13) Media queries: vanaf desktop */
@media (min-width: 1024px) {
.section {
padding-block: 3rem;
}
.nav a {
padding: .55rem .9rem;
}
}
Wat gebeurt hier responsief?
- De header gaat van kolom (mobiel) naar rij (tablet).
- De hero gaat van één kolom naar twee kolommen.
- Features gaan van 1 kolom naar 3 kolommen.
- Pricing gaat van 1 kolom naar 3 kolommen.
- Typografie schaalt mee via
clamp().
Stap 3: Testen
-
Start een lokale server (bijvoorbeeld met Python):
python -m http.server 5173 -
Open
http://localhost:5173 -
Verklein en vergroot je browser.
-
Controleer of je nergens horizontaal hoeft te scrollen.
-
Controleer of knoppen en links prettig klikbaar blijven.
Checklist voor je eigen projecten
Gebruik deze lijst om te beoordelen of je ontwerp echt responsief is:
- Staat de viewport meta-tag in je HTML?
- Gebruik je
box-sizing: border-box? - Gebruik je containers met
max-widthin plaats van vaste breedtes? - Schalen afbeeldingen met
max-width: 100%? - Is je layout mobiel-eerst opgebouwd?
- Gebruik je Grid (
auto-fit+minmax) waar het media queries kan verminderen? - Is typografie leesbaar op klein én groot scherm (bij voorkeur met
clamp())? - Zijn klikdoelen groot genoeg (voldoende padding)?
- Heb je getest op meerdere breedtes en in portret/landschap?
- Heb je horizontale overflow gecontroleerd?
Volgende stappen
Als je deze basis beheerst, kun je verder met:
- responsieve navigatie met een menu-knop (met JavaScript),
- toegankelijkheid (focus-stijlen, toetsenbordnavigatie, contrast),
- moderne CSS-functies zoals
:has(), container queries ensubgrid, - optimalisatie van afbeeldingen met meerdere resoluties.
Als je wilt, kan ik op basis van jouw huidige HTML/CSS een concreet responsief plan maken met breekpunten, Grid/Flex-structuur en verbeterde typografie.