Formation Créer son Framework CSS | Les Classes Utilitaires

Créez des classes utilitaires pour appliquer simplement des styles CSS isolés (flex, color, margin...) sur vos éléments.

Icône de calendrier MAJ en
Débutant
6 chapitres

Qu’est-ce qu’une classe utilitaire ?

Les classes utilitaires (aussi appelées « utility classes » ) constituent une approche opposée à la création de composants CSS.

Au lieu de regrouper des styles dans des blocs spécifiques liés à des composants, elles se concentrent sur des responsabilités unitaires : une classe = une propriété.

Cette méthodologie, popularisée notamment par des frameworks comme Tailwind CSS, offre une flexibilité accrue aux développeurs, leur permettant de styliser directement dans leur HTML sans devoir modifier des fichiers CSS séparés.

Une approche de « CSS inline » qui m’a valu quelques réactions allergiques cutanées dans un premier temps… puis en m’y penchant de plus près, j’ai pu en découvrir les bénéfices.

Classes utilitaires pour notre framework

Dans notre framework, nous adopterons une approche hybride en utilisant des composants génériques pour des éléments d’interface réutilisable et des classes utilitaires pour des ajustements précis.

Flex

Commençons par créer des classes utilitaires dédiées à flexbox. Celles-ci sont fondamentales pour ajuster le placement d’éléments sur l’interface.

utilitites/_flex.css
copié !
.flex { display: flex; }
.flex-row { flex-direction: row; }
.flex-col { flex-direction: column; }
.flex-wrap { flex-wrap: wrap; }
.flex-nowrap { flex-wrap: nowrap; }
.justify-start { justify-content: flex-start; }
.justify-center { justify-content: center; }
.justify-end { justify-content: flex-end; }
.justify-space-between { justify-content: space-between; }
.justify-space-around { justify-content: space-around; }
.justify-space-evenly { justify-content: space-evenly; }
.items-start { align-items: flex-start; }
.items-center { align-items: center; }
.items-end { align-items: flex-end; }
.items-stretch { align-items: stretch; }
.items-baseline { align-items: baseline; }
.grow-0 { flex-grow: 0; }
.grow-1 { flex-grow: 1; }
.shrink-0 { flex-shrink: 0; }
.shrink-1 { flex-shrink: 1; }

Pour une utilisation plus poussée et permissive, il pourrait être intéressant, de créer des variantes pour chacun de nos breakpoints, à l’image de ce qui avait été fait lors de la création de notre grille responsive au chapitre précédent.

Il serait par exemple ainsi possible de modifier facilement l’axe de flexible de manière responsive :

copié !
<div class="flex-col md:flex-row">
	<div>Item 1</div>
	<div>Item 2</div>
</div>

Espacements

Si le rôle des classes utilitaire est de permettre d’appliquer des styles de manière précise, un de leurs usages de prédilection est alors de permettre d’injecter des espacements autour des éléments.

Et sur une interface web, on distingue 3 types d’espacements en CSS :

  1. Les marges internes (padding)
  2. Les marges externes (margin)
  3. Les espacements entre des éléments de grille et boîtes flexibles (gap)

Gap

Nous proposons dans notre framework 3 types de gaps pour gérer les espacements :

  • Gap global (propriété CSS gap) défini avec une classe .g
  • Gap entre les lignes (propriété CSS row-gap) défini avec une classe .g-row
  • Gap entre les colonnes (propriété CSS column-gap) défini avec une classe .g-col

L’espacement sera définis avec pour référentiel, la valeur de la variable --base-unit, afin d’assurer une cohérence globale au sein du framework.

utilities/_spacing.css
copié !
.g { gap: var(--base-unit); }
.g-row { row-gap: var(--base-unit); }
.g-col { column-gap: var(--base-unit); }

Pour une grande flexibilité à l’usage, ces gaps sont disponibles en 5 niveaux de taille.

Le coefficient agrandissement et de rétrécissement sera définie au sein d’une variable CSS --spacing-ratio, qui pourra par la suite être partagée avec les marges internes (padding) et externes (margin).

utilities/_spacing.css
copié !
:root {
	--spacing-ratio: 2;
}

.g { gap: var(--base-unit); }
.g-row { row-gap: var(--base-unit); }
.g-col { column-gap: var(--base-unit); }

Ces variantes de tailles seront définies avec les suffixes - et + :

  • - : Définit des gaps plus petits que la valeur de base
  • + : Définit des gaps plus grands que la valeur de base

Le fait de doubler le suffixe (-- ou ++) : Permet de multiplier la ratio d’espacement par 2, et ainsi descendre au minimum ou d’atteindre le maximum des tailles proposées.

utilities/_spacing.css
copié !
:root {
	--spacing-ratio: 2;
}

.g-- { gap: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.g- { gap: calc(var(--base-unit) / var(--spacing-ratio)); }
.g { gap: var(--base-unit); }
.g\+ { gap: calc(var(--base-unit) * var(--spacing-ratio)); }
.g\+\+ { gap: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.g-row-- { row-gap: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.g-row- { row-gap: calc(var(--base-unit) / var(--spacing-ratio)); }
.g-row { row-gap: var(--base-unit); }
.g-row\+ { row-gap: calc(var(--base-unit) * var(--spacing-ratio)); }
.g-row\+\+ { row-gap: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.g-col-- { column-gap: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.g-col- { column-gap: calc(var(--base-unit) / var(--spacing-ratio)); }
.g-col { column-gap: var(--base-unit); }
.g-col\+ { column-gap: calc(var(--base-unit) * var(--spacing-ratio)); }
.g-col\+\+ { column-gap: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

Voici par exemple comment ajouter simplement un grand gap entre des éléments flexibles :

copié !
<div class="flex g+">
	<div>Item 1</div>
	<div>Item 2</div>
</div>

Margin

Nous appliquerons aux marges externes (margin) la même méthodologie que celle appliquée aux gaps, à la seule différence que nous travaillerons ici non pas sur des espacements entre lignes et colonnes, mais bien avec les 4 directions : haut, bas, gauche et droite.

Nous travaillerons nos marges externes avec 7 familles de classes :

  • Marges globales (propriété CSS margin) défini avec une classe .m
  • Marges sur l’axe horizontal (gauche et droite) (propriété CSS margin avec 2 valeurs) défini avec une classe .mx
  • Marges sur l’axe vertical (haut et bas) (propriété CSS margin avec 2 valeurs) défini avec une classe .my
  • Marges en haut (propriété CSS margin-top) défini avec une classe .mt
  • Marges en bas (propriété CSS margin-bottom) défini avec une classe .mb
  • Marges à gauche (propriété CSS margin-left) défini avec une classe .ml
  • Marges à droite (propriété CSS margin-right) défini avec une classe .mr

L’espacement sera également définis avec pour référentiel, la valeur de la variable --base-unit.

utilities/_spacing.css
copié !
.m { margin: var(--base-unit); }
.mx {
	margin-left: var(--base-unit);
	margin-right: var(--base-unit);
}
.my {
	margin-top: var(--base-unit);
	margin-bottom: var(--base-unit);
}
.mt { margin-top: var(--base-unit); }
.mb { margin-bottom: var(--base-unit); }
.ml { margin-left: var(--base-unit); }
.mr { margin-right: var(--base-unit); }

Et voici nos déclinaisons de taille, en exploitant toujours la variable --spacing-ratio :

utilities/_spacing.css
copié !
.m-- { margin: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.m- { margin: calc(var(--base-unit) / var(--spacing-ratio)); }
.m { margin: var(--base-unit); }
.m\+ { margin: calc(var(--base-unit) * var(--spacing-ratio)); }
.m\+\+ { margin: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.mx-- { 
  margin-left: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
  margin-right: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
}
.mx- { 
  margin-left: calc(var(--base-unit) / var(--spacing-ratio)); 
  margin-right: calc(var(--base-unit) / var(--spacing-ratio)); 
}
.mx { 
  margin-left: var(--base-unit); 
  margin-right: var(--base-unit); 
}
.mx\+ { 
  margin-left: calc(var(--base-unit) * var(--spacing-ratio)); 
  margin-right: calc(var(--base-unit) * var(--spacing-ratio)); 
}
.mx\+\+ { 
  margin-left: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
  margin-right: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
}

.my-- { 
  margin-top: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
  margin-bottom: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
}
.my- { 
  margin-top: calc(var(--base-unit) / var(--spacing-ratio)); 
  margin-bottom: calc(var(--base-unit) / var(--spacing-ratio)); 
}
.my { 
  margin-top: var(--base-unit); 
  margin-bottom: var(--base-unit); 
}
.my\+ { 
  margin-top: calc(var(--base-unit) * var(--spacing-ratio)); 
  margin-bottom: calc(var(--base-unit) * var(--spacing-ratio)); 
}
.my\+\+ { 
  margin-top: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
  margin-bottom: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
}

.mt-- { margin-top: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.mt- { margin-top: calc(var(--base-unit) / var(--spacing-ratio)); }
.mt { margin-top: var(--base-unit); }
.mt\+ { margin-top: calc(var(--base-unit) * var(--spacing-ratio)); }
.mt\+\+ { margin-top: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.mb-- { margin-bottom: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.mb- { margin-bottom: calc(var(--base-unit) / var(--spacing-ratio)); }
.mb { margin-bottom: var(--base-unit); }
.mb\+ { margin-bottom: calc(var(--base-unit) * var(--spacing-ratio)); }
.mb\+\+ { margin-bottom: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.ml-- { margin-left: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.ml- { margin-left: calc(var(--base-unit) / var(--spacing-ratio)); }
.ml { margin-left: var(--base-unit); }
.ml\+ { margin-left: calc(var(--base-unit) * var(--spacing-ratio)); }
.ml\+\+ { margin-left: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.mr-- { margin-right: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.mr- { margin-right: calc(var(--base-unit) / var(--spacing-ratio)); }
.mr { margin-right: var(--base-unit); }
.mr\+ { margin-right: calc(var(--base-unit) * var(--spacing-ratio)); }
.mr\+\+ { margin-right: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

Padding

Nous appliquerons aux marges internes (padding) la même méthodologie que celle appliquée aux marges externes.

Nous travaillerons nos marges internes avec 7 familles de classes :

  • Marges globales (propriété CSS padding) défini avec une classe .p
  • Marges sur l’axe horizontal (gauche et droite) (propriété CSS padding avec 2 valeurs) défini avec une classe .px
  • Marges sur l’axe vertical (haut et bas) (propriété CSS padding avec 2 valeurs) défini avec une classe .py
  • Marges en haut (propriété CSS padding-top) défini avec une classe .pt
  • Marges en bas (propriété CSS padding-bottom) défini avec une classe .pb
  • Marges à gauche (propriété CSS padding-left) défini avec une classe .pl
  • Marges à droite (propriété CSS padding-right) défini avec une classe .pr

L’espacement sera également définis avec pour référentiel, la valeur de la variable --base-unit.

utilities/_spacing.css
copié !
.p { padding: var(--base-unit); }
.px {
	padding-left: var(--base-unit);
	padding-right: var(--base-unit);
}
.py {
	padding-top: var(--base-unit);
	padding-bottom: var(--base-unit);
}
.pt { padding-top: var(--base-unit); }
.pb { padding-bottom: var(--base-unit); }
.pl { padding-left: var(--base-unit); }
.pr { padding-right: var(--base-unit); }

Et voici nos déclinaisons de taille, en exploitant toujours la variable --spacing-ratio :

utilities/_spacing.css
copié !
.p-- { padding: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.p- { padding: calc(var(--base-unit) / var(--spacing-ratio)); }
.p { padding: var(--base-unit); }
.p\+ { padding: calc(var(--base-unit) * var(--spacing-ratio)); }
.p\+\+ { padding: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.px-- { 
  padding-left: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
  padding-right: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
}
.px- { 
  padding-left: calc(var(--base-unit) / var(--spacing-ratio)); 
  padding-right: calc(var(--base-unit) / var(--spacing-ratio)); 
}
.px { 
  padding-left: var(--base-unit); 
  padding-right: var(--base-unit); 
}
.px\+ { 
  padding-left: calc(var(--base-unit) * var(--spacing-ratio)); 
  padding-right: calc(var(--base-unit) * var(--spacing-ratio)); 
}
.px\+\+ { 
  padding-left: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
  padding-right: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
}

.py-- { 
  padding-top: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
  padding-bottom: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
}
.py- { 
  padding-top: calc(var(--base-unit) / var(--spacing-ratio)); 
  padding-bottom: calc(var(--base-unit) / var(--spacing-ratio)); 
}
.py { 
  padding-top: var(--base-unit); 
  padding-bottom: var(--base-unit); 
}
.py\+ { 
  padding-top: calc(var(--base-unit) * var(--spacing-ratio)); 
  padding-bottom: calc(var(--base-unit) * var(--spacing-ratio)); 
}
.py\+\+ { 
  padding-top: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
  padding-bottom: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
}

.pt-- { padding-top: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.pt- { padding-top: calc(var(--base-unit) / var(--spacing-ratio)); }
.pt { padding-top: var(--base-unit); }
.pt\+ { padding-top: calc(var(--base-unit) * var(--spacing-ratio)); }
.pt\+\+ { padding-top: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.pb-- { padding-bottom: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.pb- { padding-bottom: calc(var(--base-unit) / var(--spacing-ratio)); }
.pb { padding-bottom: var(--base-unit); }
.pb\+ { padding-bottom: calc(var(--base-unit) * var(--spacing-ratio)); }
.pb\+\+ { padding-bottom: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.pl-- { padding-left: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.pl- { padding-left: calc(var(--base-unit) / var(--spacing-ratio)); }
.pl { padding-left: var(--base-unit); }
.pl\+ { padding-left: calc(var(--base-unit) * var(--spacing-ratio)); }
.pl\+\+ { padding-left: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.pr-- { padding-right: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.pr- { padding-right: calc(var(--base-unit) / var(--spacing-ratio)); }
.pr { padding-right: var(--base-unit); }
.pr\+ { padding-right: calc(var(--base-unit) * var(--spacing-ratio)); }
.pr\+\+ { padding-right: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

Couleurs

Pouvoir appliquer les couleurs de notre design system à la demande peut s’avérer utile.

Couleurs de texte

Nous allons dans un premier temps créer des classes utilitaires permettant de modifier la couleur de texte d’un élément :

utilities/_color.css
copié !
.text-primary { color: var(--primary); }
.text-success { color: var(--success); }
.text-warning { color: var(--warning); }
.text-danger { color: var(--danger); }
copié !
<h1 class="text-primary">...</h1>

Couleurs de fond

Créons désormais des classes utilitaires permettant de modifier la couleur de fond d’un lément :

utilities/_color.css
copié !
/* COULEURS DE TEXTE ... */

.bg-primary { background-color: var(--primary); }
.bg-success { background-color: var(--success); }
.bg-warning { background-color: var(--warning); }
.bg-danger { background-color: var(--danger); }
copié !
<div class="bg-primary">...</div>

Images

Les images constituent un élément incontournable d’une page web. Prévoyons quelques classes utilitaires basiques pour les retravailler.

utilities/_image.css
copié !
.img-square { border-radius: 0px; }
.img-rounded { border-radius: calc(var(--base-unit) / 2); }
.img-circle { border-radius: 1000px; }

.img-full { width: 100%; }

.img-grayscale { filter: grayscale(100%); }
.img-sepia { filter: sepia(100%); }

Arrondis :

  • .img-square : Applique des bordures nettes, sans arrondis.
  • .img-rounded : Applique un arrondi correspondant à la moitié de la valeur de notre variable --base-unit.
  • .img-circle : Applique des arrondis maximaux (créant un rond si l’image a un ratio carré de 1/1).

Taille :

  • .img-full : Applique une largeur de 100%. Très utile lorsqu’il s’agit de placer une image dans une boîte, dans une colonne, etc.

Filtres :

  • .img-grayscale : Applique un filtre noir et blanc.
  • .img-sepia : Applique un filtre sépia.

Classes utilitaires et performances

Un des inconvénients des classes utilitaires, surtout lorsqu’elles sont utilisées en grande quantité, est qu’elles peuvent entraîner une surcharge inutile dans votre code CSS.

Si vous générez une quantité massive de classes pour couvrir tous les cas d’utilisation possibles, il y a de fortes chances que l’utilisateur de votre framework n’en utilise qu’une infime partie.

Cela a pour effet d’augmenter considérablement la taille du fichier CSS, ce qui ralentit le temps de chargement de la page.

La solution à cela est simple, passer en revu son code HTML côté serveur par un outil qui ne va builder dans un fichier .css que les classes utilisées. C’est notamment comme cela que le célèbre framework Tailwind CSS optimise le code pour la production.

Sans cela, charger Tailwind dans un projet reviendrait à charger des Mo de code CSS. 🤯

Vous l’aurez compris, sans processus d’optimisation avec des outils de build adaptés à la mise en production, les classes utilitaires de notre framework sont gourmandes !

Code complet

Voici le code complet des fichiers 📄 _flex.css, 📄 _spacing.css, 📄 _color.css et 📄 _image.css ainsi que du fichier global 📄 all.css :

css/components/_flex.css
copié !
.flex { display: flex; }
.flex-row { flex-direction: row; }
.flex-col { flex-direction: column; }
.flex-wrap { flex-wrap: wrap; }
.flex-nowrap { flex-wrap: nowrap; }
.justify-start { justify-content: flex-start; }
.justify-center { justify-content: center; }
.justify-end { justify-content: flex-end; }
.justify-space-between { justify-content: space-between; }
.justify-space-around { justify-content: space-around; }
.justify-space-evenly { justify-content: space-evenly; }
.items-start { align-items: flex-start; }
.items-center { align-items: center; }
.items-end { align-items: flex-end; }
.items-stretch { align-items: stretch; }
.items-baseline { align-items: baseline; }
.grow-0 { flex-grow: 0; }
.grow-1 { flex-grow: 1; }
.shrink-0 { flex-shrink: 0; }
.shrink-1 { flex-shrink: 1; }

@media (min-width: 576px) {
  .sm\:flex { display: flex; }
  .sm\:flex-row { flex-direction: row; }
  .sm\:flex-col { flex-direction: column; }
  .sm\:flex-wrap { flex-wrap: wrap; }
  .sm\:flex-nowrap { flex-wrap: nowrap; }
  .sm\:justify-start { justify-content: flex-start; }
  .sm\:justify-center { justify-content: center; }
  .sm\:justify-end { justify-content: flex-end; }
  .sm\:justify-space-between { justify-content: space-between; }
  .sm\:justify-space-around { justify-content: space-around; }
  .sm\:justify-space-evenly { justify-content: space-evenly; }
  .sm\:items-start { align-items: flex-start; }
  .sm\:items-center { align-items: center; }
  .sm\:items-end { align-items: flex-end; }
  .sm\:items-stretch { align-items: stretch; }
  .sm\:items-baseline { align-items: baseline; }
  .sm\:grow-0 { flex-grow: 0; }
  .sm\:grow-1 { flex-grow: 1; }
  .sm\:shrink-0 { flex-shrink: 0; }
  .sm\:shrink-1 { flex-shrink: 1; }
}

@media (min-width: 768px) {
  .md\:flex { display: flex; }
  .md\:flex-row { flex-direction: row; }
  .md\:flex-col { flex-direction: column; }
  .md\:flex-wrap { flex-wrap: wrap; }
  .md\:flex-nowrap { flex-wrap: nowrap; }
  .md\:justify-start { justify-content: flex-start; }
  .md\:justify-center { justify-content: center; }
  .md\:justify-end { justify-content: flex-end; }
  .md\:justify-space-between { justify-content: space-between; }
  .md\:justify-space-around { justify-content: space-around; }
  .md\:justify-space-evenly { justify-content: space-evenly; }
  .md\:items-start { align-items: flex-start; }
  .md\:items-center { align-items: center; }
  .md\:items-end { align-items: flex-end; }
  .md\:items-stretch { align-items: stretch; }
  .md\:items-baseline { align-items: baseline; }
  .md\:grow-0 { flex-grow: 0; }
  .md\:grow-1 { flex-grow: 1; }
  .md\:shrink-0 { flex-shrink: 0; }
  .md\:shrink-1 { flex-shrink: 1; }
}

@media (min-width: 992px) {
  .lg\:flex { display: flex; }
  .lg\:flex-row { flex-direction: row; }
  .lg\:flex-col { flex-direction: column; }
  .lg\:flex-wrap { flex-wrap: wrap; }
  .lg\:flex-nowrap { flex-wrap: nowrap; }
  .lg\:justify-start { justify-content: flex-start; }
  .lg\:justify-center { justify-content: center; }
  .lg\:justify-end { justify-content: flex-end; }
  .lg\:justify-space-between { justify-content: space-between; }
  .lg\:justify-space-around { justify-content: space-around; }
  .lg\:justify-space-evenly { justify-content: space-evenly; }
  .lg\:items-start { align-items: flex-start; }
  .lg\:items-center { align-items: center; }
  .lg\:items-end { align-items: flex-end; }
  .lg\:items-stretch { align-items: stretch; }
  .lg\:items-baseline { align-items: baseline; }
  .lg\:grow-0 { flex-grow: 0; }
  .lg\:grow-1 { flex-grow: 1; }
  .lg\:shrink-0 { flex-shrink: 0; }
  .lg\:shrink-1 { flex-shrink: 1; }
}

@media (min-width: 1200px) {
  .xl\:flex { display: flex; }
  .xl\:flex-row { flex-direction: row; }
  .xl\:flex-col { flex-direction: column; }
  .xl\:flex-wrap { flex-wrap: wrap; }
  .xl\:flex-nowrap { flex-wrap: nowrap; }
  .xl\:justify-start { justify-content: flex-start; }
  .xl\:justify-center { justify-content: center; }
  .xl\:justify-end { justify-content: flex-end; }
  .xl\:justify-space-between { justify-content: space-between; }
  .xl\:justify-space-around { justify-content: space-around; }
  .xl\:justify-space-evenly { justify-content: space-evenly; }
  .xl\:items-start { align-items: flex-start; }
  .xl\:items-center { align-items: center; }
  .xl\:items-end { align-items: flex-end; }
  .xl\:items-stretch { align-items: stretch; }
  .xl\:items-baseline { align-items: baseline; }
  .xl\:grow-0 { flex-grow: 0; }
  .xl\:grow-1 { flex-grow: 1; }
  .xl\:shrink-0 { flex-shrink: 0; }
  .xl\:shrink-1 { flex-shrink: 1; }
}
css/components/_spacing.css
copié !
/* GAPS */
:root {
	--spacing-ratio: 2;
}

.g-- { gap: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.g- { gap: calc(var(--base-unit) / var(--spacing-ratio)); }
.g { gap: var(--base-unit); }
.g\+ { gap: calc(var(--base-unit) * var(--spacing-ratio)); }
.g\+\+ { gap: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.g-row-- { row-gap: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.g-row- { row-gap: calc(var(--base-unit) / var(--spacing-ratio)); }
.g-row { row-gap: var(--base-unit); }
.g-row\+ { row-gap: calc(var(--base-unit) * var(--spacing-ratio)); }
.g-row\+\+ { row-gap: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.g-col-- { column-gap: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.g-col- { column-gap: calc(var(--base-unit) / var(--spacing-ratio)); }
.g-col { column-gap: var(--base-unit); }
.g-col\+ { column-gap: calc(var(--base-unit) * var(--spacing-ratio)); }
.g-col\+\+ { column-gap: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

/* MARGINS */
.m-- { margin: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.m- { margin: calc(var(--base-unit) / var(--spacing-ratio)); }
.m { margin: var(--base-unit); }
.m\+ { margin: calc(var(--base-unit) * var(--spacing-ratio)); }
.m\+\+ { margin: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.mx-- { 
  margin-left: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
  margin-right: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
}
.mx- { 
  margin-left: calc(var(--base-unit) / var(--spacing-ratio)); 
  margin-right: calc(var(--base-unit) / var(--spacing-ratio)); 
}
.mx { 
  margin-left: var(--base-unit); 
  margin-right: var(--base-unit); 
}
.mx\+ { 
  margin-left: calc(var(--base-unit) * var(--spacing-ratio)); 
  margin-right: calc(var(--base-unit) * var(--spacing-ratio)); 
}
.mx\+\+ { 
  margin-left: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
  margin-right: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
}

.my-- { 
  margin-top: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
  margin-bottom: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
}
.my- { 
  margin-top: calc(var(--base-unit) / var(--spacing-ratio)); 
  margin-bottom: calc(var(--base-unit) / var(--spacing-ratio)); 
}
.my { 
  margin-top: var(--base-unit); 
  margin-bottom: var(--base-unit); 
}
.my\+ { 
  margin-top: calc(var(--base-unit) * var(--spacing-ratio)); 
  margin-bottom: calc(var(--base-unit) * var(--spacing-ratio)); 
}
.my\+\+ { 
  margin-top: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
  margin-bottom: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
}

.mt-- { margin-top: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.mt- { margin-top: calc(var(--base-unit) / var(--spacing-ratio)); }
.mt { margin-top: var(--base-unit); }
.mt\+ { margin-top: calc(var(--base-unit) * var(--spacing-ratio)); }
.mt\+\+ { margin-top: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.mb-- { margin-bottom: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.mb- { margin-bottom: calc(var(--base-unit) / var(--spacing-ratio)); }
.mb { margin-bottom: var(--base-unit); }
.mb\+ { margin-bottom: calc(var(--base-unit) * var(--spacing-ratio)); }
.mb\+\+ { margin-bottom: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.ml-- { margin-left: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.ml- { margin-left: calc(var(--base-unit) / var(--spacing-ratio)); }
.ml { margin-left: var(--base-unit); }
.ml\+ { margin-left: calc(var(--base-unit) * var(--spacing-ratio)); }
.ml\+\+ { margin-left: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.mr-- { margin-right: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.mr- { margin-right: calc(var(--base-unit) / var(--spacing-ratio)); }
.mr { margin-right: var(--base-unit); }
.mr\+ { margin-right: calc(var(--base-unit) * var(--spacing-ratio)); }
.mr\+\+ { margin-right: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }


/* PADDINGS */
.p-- { padding: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.p- { padding: calc(var(--base-unit) / var(--spacing-ratio)); }
.p { padding: var(--base-unit); }
.p\+ { padding: calc(var(--base-unit) * var(--spacing-ratio)); }
.p\+\+ { padding: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.px-- { 
  padding-left: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
  padding-right: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
}
.px- { 
  padding-left: calc(var(--base-unit) / var(--spacing-ratio)); 
  padding-right: calc(var(--base-unit) / var(--spacing-ratio)); 
}
.px { 
  padding-left: var(--base-unit); 
  padding-right: var(--base-unit); 
}
.px\+ { 
  padding-left: calc(var(--base-unit) * var(--spacing-ratio)); 
  padding-right: calc(var(--base-unit) * var(--spacing-ratio)); 
}
.px\+\+ { 
  padding-left: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
  padding-right: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
}

.py-- { 
  padding-top: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
  padding-bottom: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); 
}
.py- { 
  padding-top: calc(var(--base-unit) / var(--spacing-ratio)); 
  padding-bottom: calc(var(--base-unit) / var(--spacing-ratio)); 
}
.py { 
  padding-top: var(--base-unit); 
  padding-bottom: var(--base-unit); 
}
.py\+ { 
  padding-top: calc(var(--base-unit) * var(--spacing-ratio)); 
  padding-bottom: calc(var(--base-unit) * var(--spacing-ratio)); 
}
.py\+\+ { 
  padding-top: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
  padding-bottom: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); 
}

.pt-- { padding-top: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.pt- { padding-top: calc(var(--base-unit) / var(--spacing-ratio)); }
.pt { padding-top: var(--base-unit); }
.pt\+ { padding-top: calc(var(--base-unit) * var(--spacing-ratio)); }
.pt\+\+ { padding-top: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.pb-- { padding-bottom: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.pb- { padding-bottom: calc(var(--base-unit) / var(--spacing-ratio)); }
.pb { padding-bottom: var(--base-unit); }
.pb\+ { padding-bottom: calc(var(--base-unit) * var(--spacing-ratio)); }
.pb\+\+ { padding-bottom: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.pl-- { padding-left: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.pl- { padding-left: calc(var(--base-unit) / var(--spacing-ratio)); }
.pl { padding-left: var(--base-unit); }
.pl\+ { padding-left: calc(var(--base-unit) * var(--spacing-ratio)); }
.pl\+\+ { padding-left: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }

.pr-- { padding-right: calc(var(--base-unit) / calc(var(--spacing-ratio) * 2)); }
.pr- { padding-right: calc(var(--base-unit) / var(--spacing-ratio)); }
.pr { padding-right: var(--base-unit); }
.pr\+ { padding-right: calc(var(--base-unit) * var(--spacing-ratio)); }
.pr\+\+ { padding-right: calc(var(--base-unit) * calc(var(--spacing-ratio) * 2)); }
css/components/_color.css
copié !
.text-primary { color: var(--primary); }
.text-success { color: var(--success); }
.text-warning { color: var(--warning); }
.text-danger { color: var(--danger); }

.bg-primary { background-color: var(--primary); }
.bg-success { background-color: var(--success); }
.bg-warning { background-color: var(--warning); }
.bg-danger { background-color: var(--danger); }
css/components/_image.css
copié !
.img-square { border-radius: 0px; }
.img-rounded { border-radius: calc(var(--base-unit) / 2); }
.img-circle { border-radius: 1000px; }

.img-full { width: 100%; }

.img-grayscale { filter: grayscale(100%); }
.img-sepia { filter: sepia(100%); }
css/utilities/all.css
copié !
@import '_flex.css';
@import '_spacing.css';
@import '_color.css';
@import '_image.css';

Les composants du framework sont importés dans 📄 app.css :

css/app.css
copié !
@import 'config.css';
@import 'base/all.css';
@import 'layout/all.css';
@import 'components/all.css';
@import 'utilities/all.css';