Avantages de l'utilisation des propriétés personnalisées dans les systèmes de conception et les bibliothèques de composants
Je m'appelle Dave et je suis développeur front-end senior chez Nordhealth. Je travaille sur la conception et le développement de notre système de conception Nord, ce qui implique la création de composants Web pour notre bibliothèque de composants. J'aimerais vous expliquer comment nous avons résolu les problèmes liés au style des composants Web à l'aide des propriétés CSS personnalisées, et vous présenter certains des autres avantages liés à l'utilisation de propriétés personnalisées dans les systèmes de conception et les bibliothèques de composants.
Comment nous créons des composants Web
Pour créer nos composants Web, nous utilisons Lit, une bibliothèque qui fournit une grande quantité de code récurrent comme l'état, les styles à champ d'application, les modèles, etc. Lit est non seulement léger, mais il est également basé sur des API JavaScript natives, ce qui signifie que nous pouvons fournir un bundle de code léger qui exploite les fonctionnalités déjà présentes dans le navigateur.
Mais le plus intéressant à propos des composants Web est qu'ils fonctionnent avec presque tous les frameworks JavaScript existants, voire avec aucun framework du tout. Une fois que le package JavaScript principal est référencé dans la page, l'utilisation d'un composant Web est très semblable à l'utilisation d'un élément HTML natif. Le seul signe indiquant qu'il ne s'agit pas d'un élément HTML natif est le trait d'union cohérent dans les balises. Il s'agit d'une norme indiquant au navigateur qu'il s'agit d'un composant Web.
Encapsulation du style Shadow DOM
Tout comme les éléments HTML natifs, les composants Web utilisent un Shadow DOM. Le Shadow DOM est une arborescence cachée de nœuds au sein d'un élément. Pour visualiser cela, ouvrez votre Web Inspector et activez l'option "Show Shadow DOM tree" (Afficher l'arborescence Shadow DOM). Une fois cette opération effectuée, essayez d'examiner un élément d'entrée natif dans l'inspecteur. Vous avez maintenant la possibilité d'ouvrir cette entrée et d'afficher tous les éléments qu'elle contient. Vous pouvez même essayer avec l'un de nos composants Web : inspectez notre composant d'entrée personnalisé pour voir son Shadow DOM.
L'un des avantages (ou des inconvénients, selon votre vision) de Shadow DOM est l'encapsulation de style. Si vous écrivez du code CSS dans votre composant Web, ces styles ne peuvent pas fuir ni affecter la page principale ou les autres éléments. Ils sont entièrement contenus dans le composant. De plus, les codes CSS écrits pour la page principale ou un composant Web parent ne peuvent pas être divulgués dans votre composant Web.
Cette encapsulation de styles est un avantage de notre bibliothèque de composants. Cela nous donne plus de certitudes quant au fait que lorsqu'un utilisateur utilise l'un de nos composants, il s'affichera comme prévu, quels que soient les styles appliqués à la page parente. Pour plus de sécurité, nous ajoutons all: unset;
à la racine (ou "hôte") de tous nos composants Web.
Cependant, que se passe-t-il si un utilisateur de votre composant Web a une raison légitime de modifier certains styles ? Peut-être une ligne de texte a-t-elle besoin de plus de contraste en raison de son contexte ou une bordure doit être plus épaisse ? Si aucun style ne peut être intégré à votre composant, comment pouvez-vous déverrouiller ces options de style ?
C'est là qu'interviennent les propriétés CSS personnalisées.
Propriétés CSS personnalisées
Les propriétés personnalisées sont nommées de manière très appropriée. Ce sont des propriétés CSS que vous pouvez vous-même nommer vous-même et appliquer la valeur nécessaire. La seule condition requise est que vous les prépariez avec deux traits d'union. Une fois que vous avez déclaré votre propriété personnalisée, la valeur peut être utilisée dans votre CSS à l'aide de la fonction var()
.
En ce qui concerne l'héritage, toutes les propriétés personnalisées sont héritées, ce qui suit le comportement typique des propriétés et des valeurs CSS standards. Toute propriété personnalisée appliquée à un élément parent, ou à l'élément lui-même, peut être utilisée en tant que valeur dans d'autres propriétés. Nous faisons un usage intensif des propriétés personnalisées pour nos jetons de conception en les appliquant à l'élément racine via notre framework CSS. Cela signifie que tous les éléments de la page peuvent utiliser ces valeurs de jeton, qu'il s'agisse d'un composant Web, d'une classe d'assistance CSS ou d'un développeur souhaitant extraire une valeur de notre liste de jetons.
Cette possibilité d'hériter des propriétés personnalisées, grâce à la fonction var()
, nous permet de percer le Shadow DOM de nos composants Web et de donner aux développeurs un contrôle plus précis sur la stylisation de nos composants.
Propriétés personnalisées dans un composant Web Nord
Lorsque nous développons un composant pour notre système de conception, nous adoptons une approche réfléchie de son code CSS : nous cherchons à obtenir un code simple, mais facile à gérer. Les jetons de conception sont définis comme des propriétés personnalisées dans notre framework CSS principal sur l'élément racine.
Ces valeurs de jeton sont ensuite référencées dans nos composants. Dans certains cas, nous appliquerons la valeur directement à la propriété CSS, mais dans d'autres, nous définirons une nouvelle propriété personnalisée contextuelle et lui appliquerons la valeur.
Nous allons également extraire des valeurs spécifiques au composant, mais qui ne figurent pas dans nos jetons, et les transformer en propriété personnalisée contextuelle. Les propriétés personnalisées qui sont contextuelles par rapport au composant nous offrent deux avantages principaux. Tout d'abord, cela signifie que notre code CSS peut être plus "semi", car cette valeur peut être appliquée à plusieurs propriétés à l'intérieur du composant.
D'autre part, cela permet d'effectuer des changements d'état et de variation très nets des composants : seule la propriété personnalisée doit être modifiée pour mettre à jour toutes ces propriétés lorsque, par exemple, vous définissez le style d'un pointage, d'un état actif ou, dans ce cas, d'une variante.
Mais le plus important est que lorsque nous définissons ces propriétés personnalisées contextuelles sur un composant, nous créons une sorte d'API CSS personnalisée pour chacun de nos composants, dont l'utilisateur peut se servir.
L'exemple précédent montre l'un de nos composants Web avec une propriété personnalisée contextuelle modifiée via un sélecteur. Grâce à cette approche globale, un composant offre une flexibilité de style suffisante à l'utilisateur tout en contrôlant la plupart des styles réels. En outre, en tant que développeurs de composants, nous avons la possibilité d'intercepter les styles appliqués par l'utilisateur. Si nous souhaitons ajuster ou étendre l'une de ces propriétés, nous pouvons le faire sans que l'utilisateur ait besoin de modifier son code.
Nous trouvons cette approche extrêmement efficace, non seulement pour nous en tant que créateurs de nos composants de système de conception, mais aussi pour notre équipe de développement lorsqu'elle les utilise dans nos produits.
Aller plus loin avec les propriétés personnalisées
Au moment de la rédaction de ce document, nous ne dévoilons pas réellement ces propriétés personnalisées contextuelles dans notre documentation. Toutefois, nous prévoyons de le faire afin que notre équipe de développement au sens large puisse comprendre et exploiter ces propriétés. Nos composants sont empaquetés sur npm avec un fichier manifeste contenant toutes les informations à leur sujet. Nous utilisons ensuite le fichier manifeste en tant que données lors du déploiement de notre site de documentation, à l'aide d'Eleventy et de sa fonctionnalité Global Data. Nous prévoyons d'inclure ces propriétés personnalisées contextuelles dans ce fichier de données manifeste.
Nous souhaitons également améliorer la manière dont ces propriétés personnalisées contextuelles héritent des valeurs. À l'heure actuelle, par exemple, si vous souhaitez ajuster la couleur de deux composants de séparation, vous devez cibler ces deux composants spécifiquement avec des sélecteurs, ou appliquer la propriété personnalisée directement à l'élément à l'aide de l'attribut de style. Cela peut sembler acceptable, mais il serait plus utile que le développeur puisse définir ces styles sur un élément conteneur ou même au niveau racine.
Vous devez définir la valeur de la propriété personnalisée directement au niveau du composant, car elle est définie sur le même élément via le sélecteur d'hôte du composant. Les jetons de conception globaux que nous utilisons directement dans le composant sont transmis directement, ne sont pas concernés par ce problème et peuvent même être interceptés sur des éléments parents. Comment tirer le meilleur des deux mondes ?
Propriétés personnalisées privées et publiques
Les propriétés personnalisées privées ont été mises en place par Lea Verou. Il s'agit d'une propriété personnalisée contextuelle "privée" sur le composant lui-même, mais définie sur une propriété personnalisée "publique" avec remplacement.
Définir nos propriétés personnalisées contextuelles de cette manière signifie que nous pouvons toujours faire tout ce que nous faisions auparavant, comme hériter des valeurs de jeton globales et réutiliser les valeurs dans le code de notre composant. Toutefois, le composant héritera harmonieusement des nouvelles définitions de cette propriété sur lui-même ou sur tout élément parent.
Bien qu'on puisse affirmer que cette méthode n'est pas vraiment "privée", nous continuons à penser qu'il s'agit d'une solution plutôt élégante à un problème qui nous inquiète. Lorsque nous en saurons l'occasion, nous nous attaquerons à ce problème dans nos composants. Ainsi, notre équipe de développement pourra mieux contrôler leur utilisation tout en bénéficiant des garde-fous que nous avons mis en place.
J'espère que ces informations sur la façon dont nous utilisons les composants Web avec des propriétés CSS personnalisées vous seront utiles. N'hésitez pas à nous donner votre avis. Si vous décidez d'utiliser l'une de ces méthodes dans votre travail, vous pouvez me retrouver sur Twitter (@DavidDarnes). Vous pouvez également retrouver Nordhealth @NordhealthHQ sur Twitter, ainsi que sur le reste de mon équipe, qui a travaillé dur pour intégrer ce système de conception et exécuter les fonctionnalités mentionnées dans cet article: @Viljamis, @WickyNilliams et @eric_habich.
Image principale de Dan Cristian Pădureț