Skip to content

Tokens sémantiques

Les tokens sémantiques sont le cœur du système de design. Ils transforment des couleurs brutes en concepts significatifs, permettant une cohérence parfaite et une maintenance simplifiée.

Qu'est-ce qu'un token sémantique ?

Un token sémantique attribue un sens contextuel à une valeur technique.

Exemple

scss
// ❌ Valeur technique (couleur brute)
color: #111827;

// ✅ Token sémantique (intention claire)
color: var(--su-text-primary);

Avantages :

  • 🎯 Intention claire : "texte principal" vs "gris 900"
  • 🔄 Adaptabilité : Change automatiquement selon le thème
  • 🛠️ Maintenance : Un seul endroit à modifier
  • Accessibilité : Garanties de contraste intégrées

Architecture des tokens

Foundations (Palettes brutes)

Tokens sémantiques (Signification)

Variables CSS (Application)

Composants (Utilisation)

Catégories de tokens

1. Texte

Tokens pour tous les contenus textuels, avec contraste WCAG garanti.

--su-text-primary

Texte principal, contraste maximum (16.8:1 en mode light).

vue
<style scoped lang="scss">
.heading {
  color: var(--su-text-primary);
}
</style>

Usage : Titres, texte principal, contenu important.

--su-text-secondary

Texte secondaire, bon contraste (9.3:1 en mode light).

vue
<style scoped lang="scss">
.description {
  color: var(--su-text-secondary);
}
</style>

Usage : Descriptions, sous-titres, métadonnées.

--su-text-tertiary

Texte tertiaire, contraste minimum AA (4.7:1 en mode light).

vue
<style scoped lang="scss">
.caption {
  color: var(--su-text-tertiary);
}
</style>

Usage : Labels, timestamps, informations auxiliaires.

--su-text-disabled

Texte désactivé, indication visuelle d'indisponibilité.

vue
<style scoped lang="scss">
.input:disabled {
  color: var(--su-text-disabled);
}
</style>

Usage : Champs désactivés, actions indisponibles.

--su-text-inverse

Texte sur fond sombre (ou inversé selon le thème).

vue
<style scoped lang="scss">
.dark-banner {
  background-color: var(--su-primary-default);
  color: var(--su-text-inverse);
}
</style>

Usage : Texte sur boutons primaires, bannières colorées.

2. Liens

Tokens spécifiques pour les liens hypertexte.

Couleur par défaut des liens.

vue
<style scoped lang="scss">
a {
  color: var(--su-link-default);
  text-decoration: underline;
}
</style>

Couleur au survol.

vue
<style scoped lang="scss">
a:hover {
  color: var(--su-link-hover);
}
</style>

Liens déjà visités (améliore la navigation).

vue
<style scoped lang="scss">
a:visited {
  color: var(--su-link-visited);
}
</style>

Liens secondaires, moins proéminents.

vue
<style scoped lang="scss">
.footer-link {
  color: var(--su-link-muted);
}
</style>

3. Backgrounds

Tokens pour tous les arrière-plans.

--su-bg-canvas

Fond global de l'application.

vue
<style scoped lang="scss">
body {
  background-color: var(--su-bg-canvas);
}
</style>

Usage : Background de la page principale.

--su-bg-surface

Surface pour cartes, modales, panels.

vue
<style scoped lang="scss">
.card {
  background-color: var(--su-bg-surface);
}
</style>

Usage : Cartes, modales, menus déroulants.

--su-bg-surface-elevated

Surface surélevée (avec ombre).

vue
<style scoped lang="scss">
.modal {
  background-color: var(--su-bg-surface-elevated);
  box-shadow: var(--su-shadow-lg);
}
</style>

Usage : Modales, tooltips, éléments flottants.

--su-bg-overlay

Overlay semi-transparent pour backdrops.

vue
<style scoped lang="scss">
.modal-backdrop {
  background-color: var(--su-bg-overlay);
}
</style>

Usage : Fonds de modales, menus plein écran.

--su-bg-hover

Background au survol d'éléments interactifs.

vue
<style scoped lang="scss">
.list-item:hover {
  background-color: var(--su-bg-hover);
}
</style>

Usage : Items de liste, boutons secondaires.

--su-bg-active

Background en état actif/pressé.

vue
<style scoped lang="scss">
.list-item:active {
  background-color: var(--su-bg-active);
}
</style>

Usage : État cliqué, boutons pressés.

--su-bg-selected

Background pour éléments sélectionnés.

vue
<style scoped lang="scss">
.tab--active {
  background-color: var(--su-bg-selected);
}
</style>

Usage : Tabs actifs, items sélectionnés.

--su-bg-disabled

Background désactivé.

vue
<style scoped lang="scss">
.button:disabled {
  background-color: var(--su-bg-disabled);
}
</style>

Usage : Boutons, champs désactivés.

4. Bordures

Tokens pour toutes les bordures.

--su-border-default

Bordure standard.

vue
<style scoped lang="scss">
.card {
  border: 1px solid var(--su-border-default);
}
</style>

Usage : Cartes, séparateurs, outlines.

--su-border-subtle

Bordure très subtile.

vue
<style scoped lang="scss">
.divider {
  border-bottom: 1px solid var(--su-border-subtle);
}
</style>

Usage : Séparateurs légers, lignes de grille.

--su-border-strong

Bordure renforcée.

vue
<style scoped lang="scss">
.card:hover {
  border-color: var(--su-border-strong);
}
</style>

Usage : Hover states, éléments mis en avant.

--su-border-focus

Bordure de focus (accessibilité).

vue
<style scoped lang="scss">
.input:focus {
  border-color: var(--su-border-focus);
  outline: 2px solid var(--su-border-focus);
}
</style>

Usage : Focus visible, navigation au clavier.

--su-border-disabled

Bordure désactivée.

vue
<style scoped lang="scss">
.input:disabled {
  border-color: var(--su-border-disabled);
}
</style>

Usage : Champs désactivés.

5. États

Tokens pour les messages d'état et feedbacks.

Success (Succès)

vue
<style scoped lang="scss">
.alert-success {
  color: var(--su-state-success);
  background-color: var(--su-state-success-bg);
}
</style>

Usage : Validation, opération réussie, badges actifs.

Warning (Avertissement)

vue
<style scoped lang="scss">
.alert-warning {
  color: var(--su-state-warning);
  background-color: var(--su-state-warning-bg);
}
</style>

Usage : Avertissements, actions requérant attention.

Error (Erreur)

vue
<style scoped lang="scss">
.alert-error {
  color: var(--su-state-error);
  background-color: var(--su-state-error-bg);
}
</style>

Usage : Erreurs, échecs, actions destructives.

Info (Information)

vue
<style scoped lang="scss">
.alert-info {
  color: var(--su-state-info);
  background-color: var(--su-state-info-bg);
}
</style>

Usage : Informations neutres, aide contextuelle.

6. Actions primaires

Tokens pour les boutons et actions principales.

--su-primary-default

État par défaut du bouton primaire.

vue
<style scoped lang="scss">
.button-primary {
  background-color: var(--su-primary-default);
  color: var(--su-primary-text);
}
</style>

--su-primary-hover

État survol.

vue
<style scoped lang="scss">
.button-primary:hover {
  background-color: var(--su-primary-hover);
}
</style>

--su-primary-active

État actif/pressé.

vue
<style scoped lang="scss">
.button-primary:active {
  background-color: var(--su-primary-active);
}
</style>

--su-primary-disabled

État désactivé.

vue
<style scoped lang="scss">
.button-primary:disabled {
  background-color: var(--su-primary-disabled);
}
</style>

--su-primary-text

Texte sur bouton primaire.

vue
<style scoped lang="scss">
.button-primary {
  color: var(--su-primary-text);
}
</style>

7. Actions secondaires

Tokens pour les boutons secondaires.

vue
<style scoped lang="scss">
.button-secondary {
  background-color: var(--su-secondary-default);
  color: var(--su-secondary-text);
  
  &:hover {
    background-color: var(--su-secondary-hover);
  }
  
  &:active {
    background-color: var(--su-secondary-active);
  }
  
  &:disabled {
    background-color: var(--su-secondary-disabled);
  }
}
</style>

8. Ombres

Token pour la couleur des ombres (s'adapte au thème).

vue
<style scoped lang="scss">
.card {
  box-shadow: 0 4px 6px var(--su-shadow-color);
}
</style>

Tokens statiques

Ces tokens ne changent pas selon le thème.

Typographie

scss
.text {
  font-family: var(--su-font-family-base);
  font-size: var(--su-font-size-base);
  line-height: var(--su-line-height-normal);
}

Disponibles :

  • --su-font-family-base : Police principale
  • --su-font-family-mono : Police monospace
  • --su-font-size-xs à --su-font-size-3xl : Échelle de tailles
  • --su-line-height-tight|normal|relaxed : Interlignages

Espacement

scss
.component {
  padding: var(--su-spacing-4);
  margin-bottom: var(--su-spacing-6);
  gap: var(--su-spacing-2);
}

Disponibles :

  • --su-spacing-1 : 0.25rem (4px)
  • --su-spacing-2 : 0.5rem (8px)
  • --su-spacing-3 : 0.75rem (12px)
  • --su-spacing-4 : 1rem (16px)
  • --su-spacing-6 : 1.5rem (24px)
  • --su-spacing-8 : 2rem (32px)
  • --su-spacing-12 : 3rem (48px)

Border Radius

scss
.card {
  border-radius: var(--su-radius-lg);
}

.button {
  border-radius: var(--su-radius-md);
}

.avatar {
  border-radius: var(--su-radius-full);
}

Disponibles :

  • --su-radius-sm : 0.25rem (4px)
  • --su-radius-md : 0.375rem (6px)
  • --su-radius-lg : 0.5rem (8px)
  • --su-radius-xl : 0.75rem (12px)
  • --su-radius-full : 9999px (cercle)

Ombres

scss
.card {
  box-shadow: var(--su-shadow-sm);
}

.modal {
  box-shadow: var(--su-shadow-lg);
}

Disponibles :

  • --su-shadow-xs : Ombre très légère
  • --su-shadow-sm : Ombre légère
  • --su-shadow-md : Ombre moyenne
  • --su-shadow-lg : Ombre forte

Animations

scss
.button {
  transition-duration: var(--su-duration-normal);
  transition-timing-function: var(--su-ease-in-out);
}

Disponibles :

  • --su-duration-fast : 150ms (ou 0ms si reduced-motion)
  • --su-duration-normal : 200ms (ou 0ms si reduced-motion)
  • --su-duration-slow : 300ms (ou 0ms si reduced-motion)
  • --su-ease-in-out : cubic-bezier(0.4, 0, 0.2, 1)
  • --su-animation-scale : 1 (ou 0 si reduced-motion)

Focus

scss
.input:focus {
  outline: var(--su-focus-ring-width) solid var(--su-border-focus);
  outline-offset: var(--su-focus-ring-offset);
}

Disponibles :

  • --su-focus-ring-width : 2px
  • --su-focus-ring-offset : 2px

Exemples d'utilisation

Carte complète

vue
<template>
  <div class="card">
    <h3 class="card__title">Titre de la carte</h3>
    <p class="card__description">Description secondaire</p>
    <button class="card__action">Action</button>
  </div>
</template>

<style scoped lang="scss">
.card {
  background-color: var(--su-bg-surface);
  border: 1px solid var(--su-border-default);
  border-radius: var(--su-radius-lg);
  padding: var(--su-spacing-6);
  box-shadow: var(--su-shadow-sm);
  
  &:hover {
    border-color: var(--su-border-strong);
  }
}

.card__title {
  color: var(--su-text-primary);
  font-size: var(--su-font-size-xl);
  margin: 0 0 var(--su-spacing-2);
}

.card__description {
  color: var(--su-text-secondary);
  font-size: var(--su-font-size-base);
  margin: 0 0 var(--su-spacing-4);
}

.card__action {
  background-color: var(--su-primary-default);
  color: var(--su-primary-text);
  padding: var(--su-spacing-3) var(--su-spacing-4);
  border: none;
  border-radius: var(--su-radius-md);
  cursor: pointer;
  transition: background-color var(--su-duration-normal);
  
  &:hover {
    background-color: var(--su-primary-hover);
  }
  
  &:focus-visible {
    outline: var(--su-focus-ring-width) solid var(--su-border-focus);
    outline-offset: var(--su-focus-ring-offset);
  }
}
</style>

Alerte avec état

vue
<template>
  <div :class="['alert', `alert--${type}`]">
    <IconComponent :type="type" />
    <div class="alert__content">
      <strong class="alert__title">{{ title }}</strong>
      <p class="alert__message">{{ message }}</p>
    </div>
  </div>
</template>

<style scoped lang="scss">
.alert {
  display: flex;
  gap: var(--su-spacing-3);
  padding: var(--su-spacing-4);
  border-radius: var(--su-radius-md);
  border-left: 3px solid;
  
  &--success {
    color: var(--su-state-success);
    background-color: var(--su-state-success-bg);
    border-left-color: var(--su-state-success);
  }
  
  &--warning {
    color: var(--su-state-warning);
    background-color: var(--su-state-warning-bg);
    border-left-color: var(--su-state-warning);
  }
  
  &--error {
    color: var(--su-state-error);
    background-color: var(--su-state-error-bg);
    border-left-color: var(--su-state-error);
  }
  
  &--info {
    color: var(--su-state-info);
    background-color: var(--su-state-info-bg);
    border-left-color: var(--su-state-info);
  }
}

.alert__title {
  display: block;
  margin-bottom: var(--su-spacing-1);
  font-weight: 600;
}

.alert__message {
  margin: 0;
  opacity: 0.9;
}
</style>

Formulaire

vue
<template>
  <div class="form-field">
    <label class="form-field__label" :for="id">{{ label }}</label>
    <input 
      :id="id"
      class="form-field__input"
      :disabled="disabled"
      :class="{ 'form-field__input--error': hasError }"
    />
    <span v-if="hasError" class="form-field__error">{{ errorMessage }}</span>
  </div>
</template>

<style scoped lang="scss">
.form-field {
  display: flex;
  flex-direction: column;
  gap: var(--su-spacing-2);
}

.form-field__label {
  color: var(--su-text-primary);
  font-size: var(--su-font-size-sm);
  font-weight: 500;
}

.form-field__input {
  padding: var(--su-spacing-3) var(--su-spacing-4);
  font-size: var(--su-font-size-base);
  color: var(--su-text-primary);
  background-color: var(--su-bg-surface);
  border: 2px solid var(--su-border-default);
  border-radius: var(--su-radius-md);
  transition: border-color var(--su-duration-normal);
  
  &:hover:not(:disabled) {
    border-color: var(--su-border-strong);
  }
  
  &:focus {
    border-color: var(--su-border-focus);
    outline: none;
  }
  
  &:disabled {
    background-color: var(--su-bg-disabled);
    color: var(--su-text-disabled);
    border-color: var(--su-border-disabled);
    cursor: not-allowed;
  }
  
  &--error {
    border-color: var(--su-state-error);
  }
}

.form-field__error {
  color: var(--su-state-error);
  font-size: var(--su-font-size-sm);
}
</style>

Bonnes pratiques

✅ À faire

  1. Toujours utiliser les tokens plutôt que les valeurs brutes
  2. Choisir le token le plus sémantique pour le contexte
  3. Respecter la hiérarchie : primary > secondary > tertiary
  4. Tester tous les thèmes pour vérifier la cohérence
  5. Utiliser les mixins pour les patterns répétitifs

❌ À éviter

  1. Couleurs en dur : color: #111827
  2. Tokens non sémantiques : utiliser primary-600 au lieu de primary-default
  3. Mélanger les niveaux : utiliser des couleurs brutes avec des tokens ❌
  4. Ignorer les états : ne pas gérer hover, focus, disabled ❌
  5. Oublier l'accessibilité : contraste insuffisant ❌

Extension des tokens

Ajouter des tokens personnalisés

Si vous avez besoin de tokens spécifiques à votre application :

scss
// Dans votre thème personnalisé
$theme-custom: (
  // Tokens standard
  'text-primary': #1a202c,
  'bg-surface': #ffffff,
  
  // Tokens personnalisés
  'brand-highlight': #ff6b6b,
  'accent-secondary': #4ecdc4,
  'sidebar-bg': #f8f9fa,
);

Puis utilisez-les :

scss
.custom-component {
  background-color: var(--su-brand-highlight);
  border-left: 3px solid var(--su-accent-secondary);
}

Inspection des tokens

Via DevTools

javascript
// Console navigateur
const root = document.documentElement;
const styles = getComputedStyle(root);

// Voir tous les tokens
for (let i = 0; i < styles.length; i++) {
  const prop = styles[i];
  if (prop.startsWith('--su-')) {
    console.log(prop, ':', styles.getPropertyValue(prop));
  }
}

// Voir un token spécifique
console.log('Primary:', styles.getPropertyValue('--su-primary-default'));

Via Vue DevTools

vue
<script setup>
import { onMounted } from 'vue';

onMounted(() => {
  const primary = getComputedStyle(document.documentElement)
    .getPropertyValue('--su-primary-default');
  console.log('Couleur primaire:', primary);
});
</script>

Tableau récapitulatif complet

Tokens de couleur

TokenMode LightMode DarkUsage
--su-text-primary#111827 (16.8:1)#f9fafb (17.1:1)Texte principal
--su-text-secondary#374151 (9.3:1)#e5e7eb (12.6:1)Texte secondaire
--su-text-tertiary#6b7280 (4.7:1)#9ca3af (4.5:1)Texte tertiaire
--su-text-disabled#9ca3af#6b7280Texte désactivé
--su-text-inverse#f9fafb#111827Texte inversé
--su-link-default#2563eb#60a5faLien par défaut
--su-link-hover#1d4ed8#93c5fdLien survol
--su-link-visited#1e40af#a855f7Lien visité
--su-link-muted#6b7280#6b7280Lien secondaire
--su-bg-canvas#f9fafb#030712Fond global
--su-bg-surface#ffffff#111827Surface/carte
--su-bg-surface-elevated#ffffff#1f2937Surface surélevée
--su-bg-overlayrgba(0,0,0,0.5)rgba(0,0,0,0.7)Overlay modal
--su-bg-hover#f3f4f6#1f2937Fond survol
--su-bg-active#e5e7eb#374151Fond actif
--su-bg-selected#eff6ffrgba(59,130,246,0.2)Fond sélectionné
--su-bg-disabled#f3f4f6#1f2937Fond désactivé
--su-border-default#d1d5db#4b5563Bordure standard
--su-border-subtle#e5e7eb#374151Bordure subtile
--su-border-strong#9ca3af#6b7280Bordure forte
--su-border-focus#3b82f6#60a5faBordure focus
--su-border-disabled#e5e7eb#374151Bordure désactivée
--su-state-success#059669#4ade80État succès
--su-state-success-bg#ecfdf5rgba(74,222,128,0.15)Fond succès
--su-state-warning#d97706#facc15État warning
--su-state-warning-bg#fffbebrgba(250,204,21,0.15)Fond warning
--su-state-error#dc2626#f87171État erreur
--su-state-error-bg#fef2f2rgba(248,113,113,0.15)Fond erreur
--su-state-info#0891b2#38bdf8État info
--su-state-info-bg#ecfeffrgba(56,189,248,0.15)Fond info
--su-primary-default#2563eb#3b82f6Action primaire
--su-primary-hover#1d4ed8#60a5faPrimaire survol
--su-primary-active#1e40af#1e40afPrimaire actif
--su-primary-disabled#93c5fd#374151Primaire désactivé
--su-primary-text#ffffff#ffffffTexte sur primaire
--su-secondary-default#f3f4f6#1f2937Action secondaire
--su-secondary-hover#e5e7eb#374151Secondaire survol
--su-secondary-active#d1d5db#4b5563Secondaire actif
--su-secondary-disabled#f9fafb#111827Secondaire désactivé
--su-secondary-text#111827#f9fafbTexte sur secondaire
--su-shadow-colorrgba(0,0,0,0.1)rgba(0,0,0,0.5)Couleur ombres

Tokens statiques

TokenValeurDescription
Typographie
--su-font-family-baseSystem fontsPolice principale
--su-font-family-monoMonospacePolice code
--su-font-size-xs0.75rem (12px)Taille XS
--su-font-size-sm0.875rem (14px)Taille Small
--su-font-size-base1rem (16px)Taille base
--su-font-size-lg1.125rem (18px)Taille Large
--su-font-size-xl1.25rem (20px)Taille XL
--su-font-size-2xl1.5rem (24px)Taille 2XL
--su-font-size-3xl1.875rem (30px)Taille 3XL
--su-line-height-tight1.25Interligne serré
--su-line-height-normal1.5Interligne normal
--su-line-height-relaxed1.75Interligne aéré
Espacement
--su-spacing-10.25rem (4px)Espacement XS
--su-spacing-20.5rem (8px)Espacement S
--su-spacing-30.75rem (12px)Espacement M
--su-spacing-41rem (16px)Espacement base
--su-spacing-61.5rem (24px)Espacement L
--su-spacing-82rem (32px)Espacement XL
--su-spacing-123rem (48px)Espacement 2XL
Border Radius
--su-radius-sm0.25rem (4px)Rayon small
--su-radius-md0.375rem (6px)Rayon medium
--su-radius-lg0.5rem (8px)Rayon large
--su-radius-xl0.75rem (12px)Rayon XL
--su-radius-full9999pxRayon complet (cercle)
Ombres
--su-shadow-xs0 1px 2px rgba(...)Ombre très légère
--su-shadow-sm0 1px 3px rgba(...)Ombre légère
--su-shadow-md0 4px 6px rgba(...)Ombre moyenne
--su-shadow-lg0 10px 15px rgba(...)Ombre forte
Animations
--su-duration-fast150ms (ou 0ms)Durée rapide
--su-duration-normal200ms (ou 0ms)Durée normale
--su-duration-slow300ms (ou 0ms)Durée lente
--su-ease-in-outcubic-bezier(...)Easing par défaut
--su-animation-scale1 (ou 0)Multiplicateur animation
Focus
--su-focus-ring-width2pxÉpaisseur focus ring
--su-focus-ring-offset2pxDécalage focus ring

Patterns de composition

Pattern 1 : Composant interactif complet

vue
<style scoped lang="scss">
@use '@/styles/core/mixins' as *;

.interactive-component {
  // Base
  display: flex;
  align-items: center;
  gap: var(--su-spacing-3);
  padding: var(--su-spacing-4);
  
  // Apparence
  background-color: var(--su-bg-surface);
  border: 2px solid var(--su-border-default);
  border-radius: var(--su-radius-lg);
  color: var(--su-text-primary);
  
  // Typographie
  font-family: var(--su-font-family-base);
  font-size: var(--su-font-size-base);
  line-height: var(--su-line-height-normal);
  
  // Comportement
  cursor: pointer;
  @include transition(background-color, border-color, transform, box-shadow);
  
  // États
  &:hover:not(:disabled) {
    background-color: var(--su-bg-hover);
    border-color: var(--su-border-strong);
    box-shadow: var(--su-shadow-md);
    transform: translateY(calc(-2px * var(--su-animation-scale)));
  }
  
  &:active:not(:disabled) {
    background-color: var(--su-bg-active);
    transform: translateY(0);
  }
  
  &:focus-visible {
    @include focus-ring;
  }
  
  &:disabled {
    background-color: var(--su-bg-disabled);
    border-color: var(--su-border-disabled);
    color: var(--su-text-disabled);
    cursor: not-allowed;
    opacity: 0.6;
  }
}
</style>

Pattern 2 : Système de notification

vue
<style scoped lang="scss">
.notification {
  display: flex;
  align-items: flex-start;
  gap: var(--su-spacing-3);
  padding: var(--su-spacing-4);
  border-radius: var(--su-radius-md);
  border-left: 4px solid;
  box-shadow: var(--su-shadow-sm);
  
  // Variants basés sur les tokens d'état
  &--success {
    background-color: var(--su-state-success-bg);
    border-left-color: var(--su-state-success);
    
    .notification__icon {
      color: var(--su-state-success);
    }
    
    .notification__title {
      color: var(--su-state-success);
    }
  }
  
  &--warning {
    background-color: var(--su-state-warning-bg);
    border-left-color: var(--su-state-warning);
    
    .notification__icon {
      color: var(--su-state-warning);
    }
    
    .notification__title {
      color: var(--su-state-warning);
    }
  }
  
  &--error {
    background-color: var(--su-state-error-bg);
    border-left-color: var(--su-state-error);
    
    .notification__icon {
      color: var(--su-state-error);
    }
    
    .notification__title {
      color: var(--su-state-error);
    }
  }
  
  &--info {
    background-color: var(--su-state-info-bg);
    border-left-color: var(--su-state-info);
    
    .notification__icon {
      color: var(--su-state-info);
    }
    
    .notification__title {
      color: var(--su-state-info);
    }
  }
}

.notification__icon {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
}

.notification__content {
  flex: 1;
}

.notification__title {
  margin: 0 0 var(--su-spacing-1);
  font-size: var(--su-font-size-base);
  font-weight: 600;
}

.notification__message {
  margin: 0;
  font-size: var(--su-font-size-sm);
  color: var(--su-text-secondary);
}
</style>

Pattern 3 : Hierarchie typographique

vue
<style scoped lang="scss">
.content {
  color: var(--su-text-primary);
  font-family: var(--su-font-family-base);
  line-height: var(--su-line-height-normal);
  
  h1 {
    margin: 0 0 var(--su-spacing-4);
    font-size: var(--su-font-size-3xl);
    line-height: var(--su-line-height-tight);
    font-weight: 700;
  }
  
  h2 {
    margin: var(--su-spacing-8) 0 var(--su-spacing-3);
    font-size: var(--su-font-size-2xl);
    line-height: var(--su-line-height-tight);
    font-weight: 700;
  }
  
  h3 {
    margin: var(--su-spacing-6) 0 var(--su-spacing-2);
    font-size: var(--su-font-size-xl);
    line-height: var(--su-line-height-tight);
    font-weight: 600;
  }
  
  p {
    margin: 0 0 var(--su-spacing-4);
    font-size: var(--su-font-size-base);
    
    &:last-child {
      margin-bottom: 0;
    }
  }
  
  .lead {
    font-size: var(--su-font-size-lg);
    color: var(--su-text-secondary);
    line-height: var(--su-line-height-relaxed);
  }
  
  .caption {
    font-size: var(--su-font-size-sm);
    color: var(--su-text-tertiary);
  }
  
  a {
    color: var(--su-link-default);
    text-decoration: underline;
    @include transition(color);
    
    &:hover {
      color: var(--su-link-hover);
    }
    
    &:visited {
      color: var(--su-link-visited);
    }
  }
  
  code {
    padding: 2px 6px;
    font-family: var(--su-font-family-mono);
    font-size: var(--su-font-size-sm);
    background-color: var(--su-bg-canvas);
    border: 1px solid var(--su-border-default);
    border-radius: var(--su-radius-sm);
  }
}
</style>

Migration depuis d'autres systèmes

Depuis Tailwind CSS

scss
// Tailwind → Design System

// Colors
.text-gray-900 → color: var(--su-text-primary)
.text-gray-600 → color: var(--su-text-secondary)
.text-gray-400 → color: var(--su-text-tertiary)
.bg-white → background-color: var(--su-bg-surface)
.bg-gray-50 → background-color: var(--su-bg-canvas)
.border-gray-300 → border-color: var(--su-border-default)

// Spacing
.p-4 → padding: var(--su-spacing-4)
.m-6 → margin: var(--su-spacing-6)
.gap-2 → gap: var(--su-spacing-2)

// Radius
.rounded → border-radius: var(--su-radius-sm)
.rounded-md → border-radius: var(--su-radius-md)
.rounded-lg → border-radius: var(--su-radius-lg)
.rounded-full → border-radius: var(--su-radius-full)

// Typography
.text-sm → font-size: var(--su-font-size-sm)
.text-base → font-size: var(--su-font-size-base)
.text-xl → font-size: var(--su-font-size-xl)

Depuis Bootstrap

scss
// Bootstrap → Design System

// Colors
.text-primary → color: var(--su-primary-default)
.text-secondary → color: var(--su-text-secondary)
.text-muted → color: var(--su-text-tertiary)
.bg-light → background-color: var(--su-bg-canvas)
.bg-white → background-color: var(--su-bg-surface)

// Components
.btn-primary → background-color: var(--su-primary-default)
.btn-secondary → background-color: var(--su-secondary-default)
.alert-success → utiliser tokens --su-state-success
.alert-danger → utiliser tokens --su-state-error

// Spacing
.p-3 → padding: var(--su-spacing-3)
.mb-4 → margin-bottom: var(--su-spacing-4)

Ressources

Publié sous licence MIT.