Drie opties voor CSS
In een Vue-app heb je drie manieren om dingen te stijlen:
- Scoped CSS in een component →
<style scoped>in een.vuebestand - Class binding → dynamisch een class aan/uit zetten op basis van state
- Globale CSS → één CSS-bestand voor je hele app (reset, basis, kleuren-variabelen)
Voor wie Tailwind wil: dat is een aparte aanpak met utility-classes. Zie de Tailwind pagina.
<style scoped> — de Vue manier
Het derde blok in een .vue bestand is voor CSS. Met scoped gelden de stijlen alleen voor dit component.
<!-- src/components/Card.vue -->
<template>
<div class="card">
<h2 class="title">Mijn titel</h2>
<p>Inhoud</p>
</div>
</template>
<style scoped>
.card {
padding: 16px;
border: 1px solid #ccc;
border-radius: 8px;
}
.title {
color: #42b883;
margin-bottom: 8px;
}
</style>
Wat is "scoped"? Vue voegt automatisch een uniek data-attribute toe aan elke tag in dit component. De CSS-selectors gelden alleen voor elementen met dat attribute. Een .title in dit component botst niet met een .title in een ander component.
Met of zonder scoped?
- Met
scoped→ bijna altijd. Voorkomt CSS-conflicten. - Zonder
scoped→ inApp.vuevoor globale stijlen, of als je expliciet child-components wilt stijlen.
Dynamische class binding
De grote kracht van Vue: classes op basis van state. Drie manieren:
1. Object — voorwaardelijk een class
<script setup>
import { ref } from 'vue'
const isActive = ref(true)
const hasError = ref(false)
</script>
<template>
<div :class="{ active: isActive, error: hasError }">
Hallo
</div>
</template>
Resultaat (omdat isActive true, hasError false):
<div class="active">Hallo</div>
2. Array — meerdere classes combineren
<script setup>
const baseClass = 'btn'
const variantClass = 'btn-primary'
</script>
<template>
<button :class="[baseClass, variantClass]">Klik</button>
</template>
3. Statisch + dynamisch mixen
<script setup>
import { ref } from 'vue'
const isLoading = ref(true)
</script>
<template>
<button class="btn" :class="{ loading: isLoading }">
Verzenden
</button>
</template>
Resultaat als isLoading true: <button class="btn loading">. De statische class="btn" en de dynamische :class="{...}" worden samengevoegd.
Vue vs React: In React schrijf je className={isActive ? 'card active' : 'card'}. In Vue is dat :class="['card', { active: isActive }]" — duidelijker en korter.
Inline style binding
Voor stijlen die je niet vooraf weet (kleuren uit een database, dynamische dimensies):
<script setup>
import { ref } from 'vue'
const color = ref('red')
const fontSize = ref(20)
</script>
<template>
<p :style="{ color: color, fontSize: fontSize + 'px' }">
Gekleurde tekst
</p>
</template>
Gebruik dit spaarzaam. Inline styles zijn moeilijker te overschrijven en maken je templates rommelig. Voor "deze tekst is rood" of "verberg dit element": gebruik een class binding. Inline style is alleen écht nodig bij truly dynamische waardes.
Let op CSS-property namen
In JavaScript schrijf je fontSize (camelCase), niet font-size (kebab-case):
:style="{ fontSize: '20px' }" // ✅
:style="{ 'font-size': '20px' }" // ✅ ook (met quotes)
:style="{ font-size: '20px' }" // ❌ syntax error
Globale CSS
Voor stijlen die overal moeten gelden (reset, fonts, kleur-variabelen): gebruik een CSS-bestand dat je in main.js importeert.
1. Maak src/assets/main.css
/* Reset */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* CSS variabelen */
:root {
--primary: #42b883;
--text: #333;
--bg: #fff;
}
body {
font-family: system-ui, sans-serif;
color: var(--text);
background: var(--bg);
}
2. Importeer in main.js
import { createApp } from 'vue'
import App from './App.vue'
import './assets/main.css' // ← globale CSS
createApp(App).mount('#app')
3. Gebruik de variabelen in elk component
<style scoped>
.button {
background: var(--primary);
color: white;
}
</style>
Aanpak die altijd werkt: globale CSS voor resets en variabelen, scoped CSS voor component-specifieke stijlen. Geen conflicten, makkelijk te onderhouden.
Belangrijke Regels
- Default:
<style scoped>per component - Dynamische classes →
:class="{ active: isActive }" - Globale CSS → één bestand in
src/assets/, geïmporteerd inmain.js - CSS-variabelen op
:rootvoor app-brede kleuren/spacing - Inline style → alleen voor écht dynamische waardes
Veelgemaakte Fouten
Fout — :class als statische string:
<div :class="card active">...</div>
<!-- ❌ "card" en "active" worden als JS-variabelen behandeld -->
Goed:
<div class="card active">...</div> <!-- statisch -->
<div :class="['card', 'active']">...</div> <!-- dynamisch (array) -->
Fout — CSS-properties in kebab-case zonder quotes:
<div :style="{ background-color: 'red' }">
<!-- ❌ syntax error -->
Goed:
<div :style="{ backgroundColor: 'red' }"> <!-- ✅ -->
<div :style="{ 'background-color': 'red' }"> <!-- ✅ ook -->
Fout — geen scoped → CSS lekt:
<!-- Card.vue -->
<style>
.title { color: red; } /* ❌ raakt ALLE .title in je hele app */
</style>
Goed:
<style scoped>
.title { color: red; } /* ✅ alleen voor dit component */
</style>