📚 Cours SCSS (Sass) 📍 Chapitre 8 / 21

Mixins SCSS

Les mixins sont l'un des outils SCSS les plus puissants pour éviter la duplication de code. Elles permettent de créer des blocs de styles réutilisables, avec ou sans paramètres, que tu peux appliquer à différents composants. Dans ce chapitre, tu vas apprendre à créer, appeler et structurer des mixins "propres" et professionnelles pour rationaliser ton code SCSS et gagner en productivité.

Objectifs du chapitre

  • Comprendre ce qu'est une mixin et à quoi elle sert concrètement.
  • Créer une mixin simple et l'utiliser avec @include.
  • Passer des paramètres et définir des valeurs par défaut.
  • Utiliser @content pour des mixins avec bloc de contenu.
  • Découvrir des cas d'usage professionnels : responsive, boutons, utilitaires.
  • Comprendre les limites et alternatives aux mixins.
À retenir

Une mixin sert à réutiliser des styles. Si tu te retrouves à copier-coller souvent le même bloc CSS, c'est un excellent candidat pour devenir une mixin. C'est l'un des piliers d'un code SCSS bien organisé.

Explications théoriques détaillées

Qu'est-ce qu'une mixin SCSS ?

Une mixin est une "recette de styles" que tu peux injecter dans plusieurs règles CSS. Elle est déclarée avec @mixin et utilisée avec @include.

SCSS
// Déclaration de la mixin
@mixin nom-de-la-mixin {
  /* styles réutilisables */
}

// Utilisation de la mixin
.selector {
  @include nom-de-la-mixin;
  /* autres styles spécifiques */
}

À la compilation, Sass remplace chaque @include par le contenu de la mixin.

Pourquoi utiliser des mixins ?

Les mixins résolvent plusieurs problèmes courants en CSS :

  • Éviter la duplication : Tu écris la logique une seule fois.
  • Centraliser les modifications : Tu peux corriger un comportement à un seul endroit.
  • Paramétrisation : Tu peux rendre la mixin configurable via des paramètres.
  • Consistance : Tous tes composants utilisent la même logique.
  • Abstraction : Tu masques la complexité derrière une API simple.
Conseil terrain

Une équipe qui utilise bien les mixins réduit fortement les incohérences visuelles (boutons, cartes, espacements). C'est un pas significatif vers la création d'un mini "design system" interne, même sur des projets modestes.

Limites importantes des mixins

Les mixins ont un inconvénient majeur : elles dupliquent le CSS. Chaque @include génère une nouvelle copie des styles dans le CSS final.

SCSS
@mixin box-shadow {
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.card-1 { @include box-shadow; }
.card-2 { @include box-shadow; }
.card-3 { @include box-shadow; }
.card-4 { @include box-shadow; }
CSS généré
.card-1 {
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.card-2 {
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.card-3 {
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.card-4 {
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
À retenir

Mixins = réutilisation pratique, mais elles peuvent augmenter significativement la taille du CSS généré. On les utilise avec bon sens, surtout pour les styles complexes ou paramétrables. Pour les styles simples répétés, on verra plus tard l'alternative avec @extend.

Exemples simples

Exemple 1 : Mixin simple - centrage flex

Une mixin très courante pour centrer des éléments avec flexbox.

SCSS
// Déclaration de la mixin
@mixin flex-center {
  display: flex;
  align-items: center;
  justify-content: center;
}

// Utilisation
.hero {
  @include flex-center;
  min-height: 200px;
  background: linear-gradient(135deg, #3b82f6, #8b5cf6);
}

.modal {
  @include flex-center;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
}
CSS généré
.hero {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 200px;
  background: linear-gradient(135deg, #3b82f6, #8b5cf6);
}

.modal {
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
}

Exemple 2 : Mixin avec paramètres simples

Tu peux rendre une mixin flexible en lui passant des valeurs en paramètres.

SCSS
// Mixin avec paramètres
@mixin box($padding, $radius) {
  padding: $padding;
  border-radius: $radius;
  border: 1px solid rgba(0, 0, 0, 0.1);
}

// Utilisation avec différentes valeurs
.card {
  @include box(16px, 12px);
  background: white;
}

.badge {
  @include box(6px 10px, 999px);
  background: #3b82f6;
  color: white;
  display: inline-block;
}

.alert {
  @include box(12px 16px, 8px);
  background: #fef3c7;
  border-color: #f59e0b;
}
CSS généré (extrait)
.card {
  padding: 16px;
  border-radius: 12px;
  border: 1px solid rgba(0, 0, 0, 0.1);
  background: white;
}

.badge {
  padding: 6px 10px;
  border-radius: 999px;
  border: 1px solid rgba(0, 0, 0, 0.1);
  background: #3b82f6;
  color: white;
  display: inline-block;
}

Exemple 3 : Paramètres avec valeurs par défaut

Les valeurs par défaut rendent les mixins plus faciles à utiliser.

SCSS
// Mixin avec valeurs par défaut
@mixin button($bg: #3b82f6, $color: white, $radius: 12px) {
  background: $bg;
  color: $color;
  padding: 10px 16px;
  border-radius: $radius;
  border: none;
  cursor: pointer;
  font-weight: 600;
  transition: background-color 0.2s ease;

  &:hover {
    background: darken($bg, 10%);
  }
}

// Utilisation avec différentes combinaisons
.btn {
  @include button(); // Utilise toutes les valeurs par défaut
}

.btn--danger {
  @include button(#ef4444); // Change seulement la couleur de fond
}

.btn--outline {
  @include button(transparent, #3b82f6, 8px);
  border: 2px solid #3b82f6;
  
  &:hover {
    background: rgba(59, 130, 246, 0.1);
  }
}
À retenir

Les valeurs par défaut rendent l'API de ta mixin plus simple à utiliser. Les développeurs peuvent n'écrire que les paramètres qu'ils veulent changer, rendant le code plus lisible et moins verbeux.

Exemples concrets et professionnels

Cas pro 1 : Mixin responsive avec @content

L'un des usages les plus puissants des mixins est la gestion des media queries. Avec @content, tu peux créer des mixins "conteneurs" qui englobent d'autres styles.

SCSS
// Mixin pour les breakpoints
@mixin mq($min-width) {
  @media (min-width: $min-width) {
    @content;
  }
}

// Mixin pour les breakpoints avec nom sémantique
$breakpoints: (
  'sm': 576px,
  'md': 768px,
  'lg': 992px,
  'xl': 1200px
);

@mixin breakpoint($name) {
  $width: map-get($breakpoints, $name);
  
  @if $width {
    @media (min-width: $width) {
      @content;
    }
  } @else {
    @error "Breakpoint '#{$name}' non trouvé dans $breakpoints";
  }
}

// Utilisation
.container {
  padding: 16px;

  @include mq(768px) {
    padding: 24px;
    max-width: 720px;
    margin: 0 auto;
  }

  @include breakpoint('lg') {
    padding: 32px;
    max-width: 960px;
  }

  @include breakpoint('xl') {
    max-width: 1140px;
  }
}

// Utilisation avec nesting
.navigation {
  display: flex;
  flex-direction: column;
  
  @include mq(768px) {
    flex-direction: row;
    
    .nav-item {
      margin-right: 20px;
      
      &:last-child {
        margin-right: 0;
      }
    }
  }
}
CSS généré
.container {
  padding: 16px;
}

@media (min-width: 768px) {
  .container {
    padding: 24px;
    max-width: 720px;
    margin: 0 auto;
  }
}

@media (min-width: 992px) {
  .container {
    padding: 32px;
    max-width: 960px;
  }
}

@media (min-width: 1200px) {
  .container {
    max-width: 1140px;
  }
}

.navigation {
  display: flex;
  flex-direction: column;
}

@media (min-width: 768px) {
  .navigation {
    flex-direction: row;
  }
  .navigation .nav-item {
    margin-right: 20px;
  }
  .navigation .nav-item:last-child {
    margin-right: 0;
  }
}
Explication importante

@content est une directive spéciale qui sert à "injecter" le contenu écrit entre les accolades du @include. C'est ce qui permet d'écrire des mixins "conteneurs" comme les media queries, les keyframes, ou les règles conditionnelles.

Cas pro 2 : Mixin pour un design system de boutons

Dans un projet professionnel, on veut des boutons cohérents : mêmes tailles, mêmes radius, mêmes états hover/focus. Une mixin centralise cette logique.

SCSS
// Mixin de base pour les boutons
@mixin button-core(
  $bg: #3b82f6,
  $text: white,
  $radius: 12px,
  $padding: 10px 16px
) {
  background: $bg;
  color: $text;
  padding: $padding;
  border-radius: $radius;
  border: 1px solid transparent;
  cursor: pointer;
  font-weight: 600;
  font-size: 14px;
  text-align: center;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: all 0.2s ease;
  text-decoration: none;
  user-select: none;

  // États
  &:hover {
    background: darken($bg, 10%);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  }

  &:active {
    transform: translateY(0);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  }

  &:focus-visible {
    outline: 3px solid rgba($bg, 0.4);
    outline-offset: 2px;
  }

  &:disabled {
    opacity: 0.6;
    cursor: not-allowed;
    pointer-events: none;
  }

  // Variante loading
  &.loading {
    position: relative;
    color: transparent;

    &::after {
      content: '';
      position: absolute;
      width: 16px;
      height: 16px;
      border: 2px solid rgba(255, 255, 255, 0.3);
      border-top-color: white;
      border-radius: 50%;
      animation: spin 0.8s linear infinite;
    }
  }
}

// Application
.btn {
  @include button-core();
}

.btn--danger {
  @include button-core($bg: #ef4444);
}

.btn--success {
  @include button-core($bg: #10b981);
}

.btn--outline {
  @include button-core($bg: transparent, $text: #3b82f6);
  border-color: rgba(59, 130, 246, 0.6);
  
  &:hover {
    background: rgba(59, 130, 246, 0.1);
  }
}

.btn--small {
  @include button-core($padding: 6px 12px, $radius: 8px);
  font-size: 13px;
}

.btn--large {
  @include button-core($padding: 14px 24px, $radius: 16px);
  font-size: 16px;
}
Conseil terrain

Mets les mixins de "design system" (boutons, cartes, typographie, formulaires) dans un dossier dédié (ex: abstracts/mixins/) et versionne-les comme des briques réutilisables. Documente-les avec des commentaires expliquant les paramètres et les cas d'usage.

Cas pro 3 : Mixins utilitaires pour le layout

Crée des mixins pour les patterns de layout récurrents.

SCSS
// Mixin pour le conteneur centré
@mixin container($max-width: 1200px, $padding: 16px) {
  max-width: $max-width;
  margin: 0 auto;
  padding: 0 $padding;
  width: 100%;
  box-sizing: border-box;
}

// Mixin pour la grille
@mixin grid($columns: 12, $gap: 24px) {
  display: grid;
  grid-template-columns: repeat($columns, 1fr);
  gap: $gap;
}

// Mixin pour les ombres (design system)
@mixin shadow($level: 'md') {
  @if $level == 'sm' {
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  } @else if $level == 'md' {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12);
  } @else if $level == 'lg' {
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  } @else if $level == 'xl' {
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.2);
  } @else {
    box-shadow: $level; // Permet une ombre personnalisée
  }
}

// Utilisation
.main-container {
  @include container(960px, 24px);
}

.card-grid {
  @include grid(3, 32px);
  
  @include mq(768px) {
    @include grid(6, 24px);
  }
  
  @include mq(1024px) {
    @include grid(12, 32px);
  }
}

.card {
  @include shadow('md');
  transition: box-shadow 0.3s ease;
  
  &:hover {
    @include shadow('lg');
  }
}

.modal {
  @include shadow('xl');
}

Bonnes pratiques

Règles d'or pour créer des mixins efficaces

  • Une responsabilité unique : Une mixin doit faire une chose et la faire bien.
  • Noms intentionnels : Nomme les mixins selon leur fonction, pas leur implémentation.
  • Paramètres clairs : Utilise des paramètres nommés et des valeurs par défaut.
  • Documentation minimale : Commente les paramètres et l'usage attendu.
  • Performance : Évite les mixins très lourdes utilisées des dizaines de fois.
  • Organisation : Regroupe les mixins liées dans des fichiers dédiés.
  • Éviter la sur-ingénierie : Pas besoin de mixin pour un style utilisé une seule fois.
  • Test avec différents paramètres : Vérifie que la mixin fonctionne dans tous les cas.
À retenir

Une bonne mixin ressemble à une API simple : elle fait une chose, bien, et elle est agréable à utiliser. Elle doit réduire la complexité, pas l'augmenter. Si une mixin est difficile à comprendre ou à utiliser, c'est qu'elle est probablement mal conçue.

Quand créer une mixin ? Quand s'en passer ?

DECISION
// BON CANDIDAT POUR UNE MIXIN
- Style utilisé 3+ fois dans le projet
- Style avec logique conditionnelle (@if, @else)
- Style qui évolue souvent (design system)
- Style avec plusieurs variantes (boutons, cartes)
- Style complexe à écrire (flexbox, grid, animations)

// PAS BESOIN DE MIXIN
- Style utilisé une seule fois
- Style très simple (margin: 10px)
- Style spécifique à un composant unique
- Style qui ne changera jamais

Erreurs courantes

Erreur 1 : Remplacer tout le CSS par des mixins

Les mixins ne sont pas une obligation. Si un style n'est pas réutilisé, une règle CSS simple est souvent meilleure. Un projet rempli de mixins micro-optimisées devient illisible.

Attention

N'utilise pas de mixin pour le simple plaisir d'utiliser une fonctionnalité SCSS. La question à se poser est : "Ce style sera-t-il réutilisé ailleurs ?" Si la réponse est non, une classe CSS standard suffit.

Erreur 2 : Mixins trop génériques et difficiles à comprendre

Une mixin comme @mixin style($a, $b, $c) sans intention claire devient un problème de maintenance. Préfère des noms explicites et une documentation minimale.

SCSS
// MAUVAIS - Trop générique
@mixin apply($prop, $value) {
  #{$prop}: $value;
}

// BON - Intention claire
@mixin text-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

Erreur 3 : Oublier l'impact sur le CSS généré

Chaque @include recopie les styles. Sur un design system avec des mixins complexes utilisées des dizaines de fois, la taille du CSS peut exploser.

Solution

Pour les styles simples mais répétés, considère @extend (voir chapitre 13) ou les classes utilitaires. Pour les styles complexes ou paramétrables, les mixins sont appropriées, mais sois conscient du trade-off.

Erreur 4 : Paramètres non typés et non validés

Sans validation, des paramètres incorrects peuvent générer du CSS invalide.

SCSS
// MAUVAIS - Pas de validation
@mixin spacing($value) {
  margin: $value;
  padding: $value;
}

// BON - Avec validation et valeurs par défaut
@mixin spacing($value: 0) {
  @if type-of($value) != 'number' {
    @error "Le paramètre $value doit être un nombre, reçu: #{$value}";
  }
  
  margin: $value;
  padding: $value;
}

Résumé du chapitre

Ce que vous avez appris
Les mixins permettent de réutiliser des blocs de styles via @mixin et @include.
Les paramètres et valeurs par défaut rendent les mixins flexibles et configurables.
@content permet de créer des mixins "conteneurs" comme les media queries.
Les mixins sont idéales pour les design systems, utilitaires et patterns récurrents.
Elles dupliquent le CSS à chaque inclusion, donc à utiliser avec discernement.

Prochain chapitre : Fonctions SCSS

Les mixins produisent des styles, mais parfois tu as besoin de calculer des valeurs plutôt que de générer du CSS. C'est là que les fonctions SCSS entrent en jeu. Dans le prochain chapitre, nous découvrirons comment créer des fonctions personnalisées pour manipuler des couleurs, calculer des tailles, et automatiser des transformations complexes.

  • Comprendre la différence entre mixins et fonctions
  • Créer des fonctions simples avec @function et @return
  • Utiliser les fonctions intégrées de Sass (couleurs, nombres, strings)
  • Créer des fonctions utilitaires pour ton projet
  • Bonnes pratiques et limitations des fonctions SCSS