Des propriétés personnalisées très, très, très personnalisées
Retrouvez les slides en ligne sur
→ ffoodd.fr/paris-web.2020
et en version « commentée »
→ ffoodd.fr/paris-web.2020/verbose.
Les concepts-clés 🔑
À digérer avant de jouer avec les propriétés personnalisées :
- La cascade ;
- L’héritage ;
- Les stratégies de repli ;
- Les particularités.
Venez, on va bien rigoler !
Si, si, promis…
Cascade 🌈
Hop, galipette * !
La cascade est l’algorithme décidant quel style est finalement appliqué.
Amelia Wattenberger a rédigé un billet de blog interactif expliquant à merveille la cascade,
mais vous pouvez aussi lire la spécification du module Cascading and inheritance
du
W3C, si vous préférez !
Les propriétés personnalisées respectent la cascade, au même titre que les autres propriétés.
* Galipette réalisée par un professionnel, ne tentez pas ça chez vous.
L’héritage (Mitsouko) 💃
C’est comme ça-aaaaaa
L’héritage intervient quand la cascade n’aboutit à aucune valeur — une sombre histoire de succession, donc…
Mais toutes les propriétés ne sont pas héritées ! Ça concerne presque exclusivement les propriétés liées au texte
— cependant on peut influer sur ce comportement avec les valeurs inherit
, initial
, revert
ou unset
.
🛈 Cependant les propriétés personnalisées sont héritées, au cas où elles servent dans des propriétés liées au texte. Intéressant, non ?
Valeur de repli 🔙
Quand une valeur n’est pas supportée, elle est ignorée et la cascade puis l’héritage interviennent.
Cascade
main {
color: red;
color: color(display-p3 1 .5 0);
}
Héritage
html {
color: red;
}
main {
color: color(display-p3 1 .5 0);
}
Les particularités
Une sorte de définition
Les propriétés personnalisées :
- ne servent à rien si elles ne sont pas utilisées dans une valeur !
- peuvent avoir plusieurs valeurs au même moment, en fonction de l’élément qui s’en sert — cascade, héritage, repli… suivez, un peu !
- sont déclaratives, comme l’ensemble de CSS : si vous changez une valeur, elle changera pour tout l’arbre du document concerné — indépendamment de la position de la définition de la valeur dans vos CSS ;
- ne sont pas affectées par la propriéte
all
.
Rien à voir avec les variables Sass, donc 😈 !
Les capacités
Qu’est-ce qu’on va bien pouvoir faire de ça 😇 ?
Une palette de couleurs 🎨
Sara Soueidan
explique l’utilisation des propriétés personnalisées combinées à hsl()
pour gérer une palette de couleurs — et Una Kravets
pousse la réflexion encore plus loin.
J’ai implémenté une telle palette dans sseeeedd (sur GitHub) :
- en prenant comme couleur de départ
rebbecapurple
, - puis son analogue,
- en gérant les contrastes avec
calc()
, - puis les variantes claires et sombres, déterminées grâce au nombre d’or.
:root {
--hue: 240;
--lightness: 30%;
}
main {
color: hsl(var(--hue), 100%, var(--lightness));
}
@media screen and (min-width: 32em) {
:root {
--lightness: 40%;
}
}
@media screen and (prefers-color-scheme: dark) {
:root {
--lightness: 80%;
}
}
Vous pouvez ainsi changer la palette de couleurs en modifiant la seule propriété personnalisée --hue
ou basculer vers une palette complémentaire en modifiant --rotation
pour ajouter 180 au lieu de 30.
Vous pouvez aussi augmenter les contrastes et la luminosité en fonction du viewport ou gérer
prefers-color-scheme
en quelques lignes !
La même méthode peut-être utiliser pour les échelles typographiques : je vous conseille en la matière l’excellent Utopia, par James Gilyead & Trys Mudford, qui propose un générateur mais également des billets de blog extrêmement intéressants.
De la configuration globale ⚙
Je s’appelle :root
:root
Vous pouvez utiliser les propriétés personnalisées comme une API de surface avec vos styles :
Une cascade personnalisée
Hop, sans les mains 🤷
Miriam Suzanne a conceptualisé les cascades personnalisées, une sucession de propriétés personnalisées dans les valeurs de replis de propriétés personnalisées.
button {
background: var(--btn-bg--state,
var(--btn-bg,
var(--btn-bg--type,
var(--btn-bg--default)
)
)
);
}
[disabled] {
--btn-bg--state: darkgray;
}
.warn {
--btn-bg--type: maroon;
}
- Fini les interférences entre pseudo-classes — ou presque, la méthode LoVe Fuck HAte présentée par Romy Duhem-Verdière sera toujours utile,
- Facile de personnaliser en fonction du contexte,
- Permet de mitiger l’importance des styles en ligne !
Convertir un entier en chaîne 🔗
Ce n’est que du CSS
Cassie Evans
utilise les compteurs CSS pour afficher un entier dans la propiété content
,
ce qui n’est pas possible autrement.
.icon {
--number-var: 23;
}
.icon::before {
counter-reset: number var(--number-var);
content: counter(number);
}
Ce n’est que du CSS, mais y’a quand même des données typées. 😇
De la pseudo-logique 🤔
Ce n’est toujours que du CSS
Roman Komarov propose d’utiliser des propriétés personnalisées pseudo-booléennes pour qu’une propriété bascule d’une valeur calculée à une autre. Ana Tudor décortique des exemples concrets de ce qu’elle baptise DRY switching.
:root {
--is-big: 0;
}
.is-big {
--is-big: 1;
}
.block {
padding: calc(
25px * var(--is-big) +
10px * (1 - var(--is-big))
);
}
On peut par exemple basculer d’un point à un autre dans un tracé clip-path
.
Du responsive sans @media
Alias, ton univers impitoya-ableuh 🕵
James Atherton utilise une astuce qu’il nomme space toggler pour se passer des media queries dans son CSS — ou presque.
:root {
--media-lte-sm: initial;
}
div {
--small-borders: var(--media-lte-sm) 2px;
border: var(--small-borders, 15px) solid;
}
@media (min-width: 56.25em) {
:root {
--media-lte-sm: ;
}
}
Ce mécanisme vous intrigue ? La spécification du W3C explique très bien ce comportement, et le concept de « valeur invalide garantie » :jetez-y un œil !
En résumé :
- la valeur par défaut d’une propriété personnalisée est une valeur invalide garantie — quand vous appelez une propriété personnalisée non déclarée, c’est ce que vous obtenez ;
- si la propriété personnalisée est invalide, la propriété entière est invalide au moment du calcul — l;le navigateur ne savait pas qu’il échouerait à calculer, trop tard pour se référer à la cascade…
- quand une propriété personnalisée est vide, elle est valide : le navigateur continue comme si de rien n’était ;
- pour forcer une propriété personnalisée à être invalide, on utilise le mot-clé
initial
.
Autrement dit, le space toggler bascule d’une valeur inutile à une valeur invalide pour une propriété personnalisée :
quand la valeur est nulle, le navigateur affecte la valeur derrière var()
à la propriété personnalisée ;
quand elle est invalide, il ignore la propriété personnalisée (elle est donc indéfinie) et utilise la valeur de repli.
Si vous cherchez à vous passer de @media
, je vous conseille plutôt
la technique des Fab Four par Rémi Parmentier,
les modules Grid et Flexbox de CSS, des études de cas par
Heydon Pickering et Andy Bell sur every-layout.dev
ou encore un exemple détaillé de composant par Geoffrey Crofte (sur CSS-Tricks) notamment.
Styler votre shadow DOM 👥
Une variable pour les gouverner tous, et dans les ténèbres les lier…
Pousser des styles vers le shadow DOM est impossible… mais hériter des propriétés personnalisées fonctionne ! Sarah Dayan donne un exemple de symbôle SVG multicolore conçu pour appeler des propriétés personnalisées définies hors de l’hôte.
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
<symbol id="my-first-icon" viewBox="0 0 20 20">
<path fill="var(--color-1, red)" d="…"/>
<path fill="var(--color-2, blue)" d="…"/>
<path fill="var(--color-3, green)" d="…"/>
</symbol>
</svg>
<svg class="icon icon-colors">
<use xlink:href="#my-first-icon"/>
</svg>
.icon-colors {
--color-1: #c13127;
--color-2: #ef5b49;
--color-3: #cacaea;
}
Des styles réactifs 💥
Dans chaarts, je mets en place divers type de graphiques de données en CSS, qui dépendent de propriétés personnalisées déclarées côté HTML.
Autrement dit, ces graphiques réagissent à des changements de données en temps réels si vous mettez à jour
les propriétés personnalisées en JavaScript — de préférence à l’aide de la méthode .setProperty
.
<table class="chaarts radar"
style="--scale: 20; --step: 5; --items: 7;
--1: 14; --2: 11; --3: 13; --4: 16; --5: 10;
--6: 12; --7: 4; --8: var(--1);">
[…]
<td><span>14</span></td>
[…]
</table>
.chaarts[class*="radar"] td:nth-of-type(2) span {
--position: calc(100% - (var(--3) * 100% / (var(--scale) * var(--ratio))));
clip-path: polygon(
100% var(--position),
calc(100% - (var(--2) * 100% / var(--scale))) 100%,
100% 100%
);
}
Accessibilité | Référencement | Performance | Compatibilité | Sécurité | Qualité de code | Test |
---|---|---|---|---|---|---|
14 | 11 | 13 | 16 | 10 | 12 | 4 |
Factoriser votre code 📮
DRY
Certaines valeurs peuvent être très, très longues : les font-family
, les images (URL, dégradés, etc.),
ou encore les tracés complexes dans polygon()
.
Si la même valeur à rallonge est utilisée plusieurs fois, simplifiez-vous la vie : utilisez des propriétés personnalisées !
:root {
--stripes: url("data:image/svg+xml,%3Csvg width='6' height='6' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23ffffff99'%3E%3Cpath d='M5 0h1L0 6V5zM6 5v1H5z'/%3E%3C/g%3E%3C/svg%3E");
}
tr:nth-child(odd) {
background: white var(--stripes);
}
.hero {
background: rebeccapurple var(--stripes);
}
Conclusion
Les fausses bonnes idées 💡
Ça envoie du rêve, mais…
- Hors cascade, pas de repli possible — chez Jeremy Keith : vous pouvez obtenir une valeur invalide au moment du calcul car les variables ne peuvent pas « échouer tôt ». Le navigateur ne sait pas encore s’il supportera votre valeur, mais a déjà exclus les valeurs issues de la cascade ou de l’héritage !
- Le changement, c’est pas forcément maintenant — par Lisi Linhardt : changer à un seul endroit une valeur appliquée à des centaines d’endroits, super ? Non, c’est extrêmement coûteux en repaint et layout.
-
KISS : pour une seule valeur, aucun intérêt.
color: var(--color);
avec--color: #000;
, sérieusement ? - Si vous gagnez du temps mais prenez du poids, vous faites fausse route. Pensez à vos utilisateurs.
Merci
Et à bientôt ☺
Crédits
- Moteur de présentation : AccesSlide — par Access42 ;
- Pictogrammes : Rounded UI — par Marek Polakovic ;
- Typographie de titraille : Bello Pro — créée par Underware ;
- Typographie de labeur : Museo Slab — créée par Exljbris.