Disons que nous développons une bibliothèque de composants.
Disons que nous utilisons React.
Disons qu’il a un composant de bouton.
Classiquement, cela ressemblera à ceci:
} » data-lang= »text/javascript »>
// CustomButton.js
import './CustomButton.css'
const CustomButton = ({ children, className="" }) => {
const customClass="CustomButton" + className;
return <button className={customClass}>{children}</button>
}
Et les styles ressembleront à ceci :
/* CustomButton.css */
.CustomButton {
background: aquamarine;
padding: 4px 12px;
border: none;
}
Ici, les développeurs viennent nous voir et nous disent : « Le bouton est super, mais il nous faut un lien sous forme de bouton ! Aucun problème! Ajoutons une propriété :
} » data-lang= »text/javascript »>
// CustomButton.js
import './CustomButton.css'
const CustomButton = ({ children, Component="button", className="" }) => {
const customClass="CustomButton" + className;
return <Component className={customClass}>{children}</Component>
}
Exemple d’utilisation :
const linkCustomButton = (
<CustomButton Component="a" href="https://google.com">
Google.com
</CustomButton>
);
Oups, « a » est un élément en ligne. Quel est le problème, demandez-vous? Le bouton ressemble à ce qu’il était. Pas exactement! Imaginez que les utilisateurs souhaitent ajouter de l’espace au-dessus du bouton :
// App.js
<CustomButton className="myCustomButton">Click it!</CustomButton>
/* App.css */
.myCustomButton {
margin-top: 10px;
}
L’élément en ligne ignorera cette marge.
C’est bon! Nous avons été dans des embouteillages pires que cela. Changeons le style du bouton :
/* CustomButton.css */
.CustomButton {
background: aquamarine;
padding: 4px 12px;
border: none;
display: inline-block;
}
Non, il y a un autre problème, bien plus vil et insoluble. Attention aux mains ! Imaginez la façon suivante d’utiliser un bouton dans un projet. Disons qu’il y a une sorte d’état de chargement, et si c’est vrai, le bouton doit être caché :
// App.js
<CustomButton className={loading ? 'hidden' : ''} />
Le problème est que .hidden
et .CustomButton
ont le même poids, et ils revendiquent tous deux le display
propriété. Cela signifie que l’analyseur CSS devra déterminer le gagnant tout en étant guidé par la commande. La commande est le dernier niveau de la cascade. Lorsque vos fichiers CSS sont divisés en modules, vous ne pouvez pas vous fier à leur ordre d’apparition spécifique dans le groupe final. En conséquence, cela conduira à des situations dans lesquelles l’un ou l’autre sélectionneur gagne. Donc que fais-tu?
Couche à la rescousse
La couche cascade est située exactement avant la spécificité et l’ordre :
- Importance
- Contexte
- Couche (salut)
- Spécificité
- Commande
La couche vous permet de définir de manière flexible différents niveaux de vos feuilles de style. Dans notre exemple, il peut y avoir trois niveaux (ou peut-être plus) :
- Une feuille de style réinitialisée
- Une feuille de style bibliothèque
- Une feuille de style d’application
Fixons ces niveaux.
@layer reset, library;
/* CustomButton.css */
@layer reset {
.CustomButton {
display: inline-block;
}
}
@layer library {
.CustomButton {
background: aquamarine;
padding: 4px 12px;
border: none;
}
}
Mais attendez : nous voulions définir trois niveaux, mais nous n’en avons défini que deux. Ceci est spécifique à la cascade de couches. Tout ce qui est défini en dehors de tout niveau devient automatiquement la priorité la plus élevée. Nous n’avons pas besoin library
aussi, mais je l’ai utilisé pour plus de clarté.
C’est cool que tous les styles sans niveau gagnent parce que les utilisateurs n’ont pas à envelopper leurs styles prioritaires dans certains @layer app
.
Autrement dit, ce style finira par remplacer celui de @layer reset
.
/* App.css */
.hidden {
display: none;
}
Est-ce pratique ? Je pense que c’est tout simplement fantastique, en grande partie parce que les navigateurs n’ont toujours pas cette cascade 🙁
Encore.