Typed Object Model : Simplifiez vos Manipulations CSS en JavaScript
Dans cet article, nous allons explorer CSS Typed Object Model (Typed OM) et voir comment il nous permet de manipuler des styles CSS avec plus de clarté et de performances, en comparant chaque étape avec la méthode classique.
L’objectif est de montrer non seulement comment Typed OM simplifie la manipulation des styles, mais aussi pourquoi il est plus performant et maintenable à long terme. Nous commencerons par des exemples simples pour ensuite aborder des cas plus complexes, tout en expliquant les bénéfices pratiques à chaque étape.
Nous allons utiliser un exemple pratique où nous faisons suivre une boîte au mouvement de la souris, tout en modifiant et améliorant progressivement notre code au fil des sections. Cela vous permettra de bien saisir les avantages de Typed OM à chaque étape, sans vous sentir submergé par la syntaxe.
La manipulation des styles CSS en JavaScript peut rapidement devenir fastidieuse. Si vous avez déjà utilisé element.style
ou getComputedStyle()
, vous savez combien il peut être délicat de travailler avec des chaînes de caractères, surtout lorsque vous devez extraire et modifier des valeurs dynamiques. Typed OM, introduit dans le cadre de CSS Houdini, vise à corriger cela en nous permettant de manipuler les valeurs CSS comme des objets natifs JavaScript (voir notre précédent article CSS Houdini : Ouvrons la Boîte Noire du Navigateur Ensemble).
Pourquoi Typed OM ?
Avant de commencer avec Typed OM, rappelons comment nous modifions généralement les styles avec JavaScript. Pour chaque changement de style, nous utilisons des chaînes de caractères via element.style
. C’est simple, mais peut vite devenir difficile à maintenir lorsqu’on commence à manipuler des valeurs dynamiques ou des transformations complexes.
C’est ici que Typed OM entre en jeu. Au lieu de manipuler des chaînes de caractères fragiles, Typed OM permet de travailler avec des objets directement liés aux propriétés CSS, garantissant ainsi une manipulation plus sécurisée et une meilleure gestion des unités et des valeurs dynamiques.
Traditionnellement, lorsqu’on manipule une propriété CSS via JavaScript, on obtient souvent une chaîne de caractères, qui peut inclure à la fois une unité (comme px
, %
, etc.) et une valeur. Cela oblige à des conversions fastidieuses. Avec Typed OM, chaque valeur CSS est représentée par un objet fortement typé, ce qui évite les erreurs de conversion et rend le code plus clair.
Par exemple, lorsque nous voulons déplacer un élément en fonction de la position de la souris, la méthode traditionnelle consiste à utiliser element.style
et à concaténer les valeurs des transformations avec leurs unités dans une chaîne de caractères.
Ce processus oblige à recomposer manuellement les transformations chaque fois que la position change, ce qui devient rapidement fastidieux et sujet à des erreurs de syntaxe, en particulier dans les projets complexes.
element.style.transform = `translate(${x}px, ${y}px)`;
Ici, chaque fois que la position de la souris change, nous devons reconstruire cette chaîne de caractères, en combinant les coordonnées x
et y
avec l’unité px
. Cela fonctionne bien pour des cas simples, mais si nous souhaitons ajouter une autre transformation, comme une rotation ou un redimensionnement, la chaîne devient de plus en plus complexe. De plus, une petite erreur de syntaxe peut facilement provoquer des bugs difficiles à déboguer.
Typed OM propose une alternative. Au lieu de manipuler des chaînes, nous utilisons des objets pour chaque transformation. Cela permet non seulement de rendre le code plus lisible, mais aussi plus sûr. Par exemple, nous pouvons représenter translate()
avec deux objets CSSUnitValue
, qui stockent les coordonnées x
et y
et leurs unités respectives.
Avec Typed OM, chaque transformation est traitée comme un objet séparé, ce qui permet d’éviter la recomposition manuelle des chaînes. En plus de réduire les risques d’erreurs liées aux unités, cela facilite grandement la modification ou l’ajout de nouvelles transformations sans altérer la structure existante du code.
const translateX = new CSSUnitValue(0, 'px');
const translateY = new CSSUnitValue(0, 'px');
element.attributeStyleMap.set('transform', new CSSTransformValue([new CSSTranslate(translateX, translateY)]));
Avec cette approche, nous n’avons plus besoin de concaténer manuellement les valeurs et les unités. Nous travaillons directement avec des objets représentant les valeurs CSS. Cela rend les mises à jour des styles plus claires et moins sujettes aux erreurs, surtout dans des situations dynamiques.
Zoom sur les Objets Typed OM
Dans Typed OM, les propriétés CSS deviennent des objets natifs JavaScript. Chaque type de propriété a son propre objet, ce qui permet une manipulation fine et sécurisée des valeurs.
- CSSUnitValue : Gère une unité avec sa valeur (par exemple,
px
,em
,%
). - CSSKeywordValue : Pour les propriétés qui utilisent des mots-clés CSS (par exemple,
block
,none
). - CSSTransformValue : Pour gérer les transformations CSS comme
rotate()
ouscale()
.
Ces objets Typed OM garantissent que les valeurs sont toujours correctement formées et utilisables sans risque d’incompatibilité avec d’autres valeurs CSS. Vous pouvez ainsi manipuler des unités complexes comme calc()
sans avoir à convertir des chaînes de caractères en valeurs interprétables par JavaScript.
Pour illustrer ceci, prenons une transformation simple :
const rotateValue = new CSSUnitValue(90, 'deg');
const transform = new CSSTransformValue([new CSSRotate(rotateValue)]);
element.attributeStyleMap.set('transform', transform);
Plutôt que de concaténer des chaînes de caractères, nous travaillons avec des objets explicites, ce qui rend le code plus lisible et moins sujet aux erreurs.
Cela devient particulièrement utile lorsque nous avons besoin de combiner plusieurs transformations, car chaque transformation est traitée individuellement. Typed OM permet également une meilleure gestion des unités et des valeurs de transformation complexes, comme les angles en degrés, sans avoir à convertir manuellement ces valeurs.
Typed OM : Simplification des Transformations CSS
La principale force de Typed OM réside dans sa capacité à simplifier les manipulations CSS complexes. Prenons l’exemple où nous voulons ajouter une rotation à notre élément, en plus de la translation déjà existante. Dans une approche traditionnelle, nous serions obligés de continuer à concaténer les transformations dans une même chaîne, ce qui peut rapidement devenir lourd à gérer.
Voici un exemple classique où nous combinons translate()
et rotate()
dans une chaîne :
element.style.transform = `translate(${x}px, ${y}px) rotate(45deg)`;
Chaque fois que x
ou y
change, ou si nous voulons modifier l’angle de rotation, il nous faut réécrire la chaîne entière. Avec Typed OM, cette gestion devient beaucoup plus flexible. Chaque transformation est représentée par un objet distinct. Par exemple, rotate()
devient un objet CSSRotate
, et translate()
un objet CSSTranslate
. Nous pouvons les combiner de manière modulaire, sans avoir à gérer manuellement des chaînes de caractères.
Voici comment nous pouvons combiner translate()
et rotate()
avec Typed OM :
const translateX = new CSSUnitValue(100, 'px');
const translateY = new CSSUnitValue(150, 'px');
const rotation = new CSSUnitValue(45, 'deg');
const transform = new CSSTransformValue([
new CSSTranslate(translateX, translateY),
new CSSRotate(rotation)
]);
element.attributeStyleMap.set('transform', transform);
Dans cet exemple, chaque transformation est manipulée séparément et combinée dans un seul objet CSSTransformValue
. Si nous voulons modifier la rotation ou la translation, nous n’avons qu’à changer l’une des valeurs, sans avoir à réécrire toute la chaîne de transformation. Cela facilite la lecture et la maintenance du code.
Ajouter des Transformations Complexes : Flexibilité et Modularité
Typed OM devient particulièrement utile lorsque nous devons gérer plusieurs transformations complexes en même temps.
Dans des projets réels, il est fréquent de combiner différentes transformations comme la translation, la rotation et l’échelle (scale
). La méthode traditionnelle oblige à construire des chaînes complexes qui regroupent toutes ces transformations, ce qui devient difficile à maintenir lorsque les modifications sont fréquentes. Typed OM, en revanche, permet de gérer chaque transformation séparément, facilitant la modification de l’une sans affecter les autres.
Par exemple, si nous voulons ajouter une transformation supplémentaire comme scale()
pour redimensionner l’élément en plus de la translation et de la rotation, cela peut vite devenir fastidieux avec la méthode classique. Nous devons nous assurer que chaque transformation est correctement concaténée dans la chaîne transform
.
Voici à quoi cela ressemblerait avec l’approche traditionnelle, en ajoutant scale()
à notre chaîne :
element.style.transform = `translate(${x}px, ${y}px) rotate(45deg) scale(1.2)`;
Si nous voulons changer l’une de ces valeurs, nous devons reconstruire toute la chaîne, ce qui peut vite devenir fastidieux. Typed OM nous permet de manipuler chacune de ces transformations de façon indépendante, en utilisant des objets séparés pour chaque propriété.
Avec Typed OM, nous pouvons ajouter scale()
sans aucune complexité supplémentaire. Il suffit de créer un objet CSSScale
et de l’ajouter à notre groupe de transformations. Voici comment cela se fait :
const scaleValue = new CSSUnitValue(1.2, '');
const transform = new CSSTransformValue([
new CSSTranslate(translateX, translateY),
new CSSRotate(rotation),
new CSSScale(scaleValue)
]);
element.attributeStyleMap.set('transform', transform);
Chaque transformation (translate
, rotate
, scale
) est maintenant représentée par un objet distinct que nous pouvons modifier indépendamment.
Cette approche modulaire permet également de mieux organiser votre code. Au lieu de gérer une chaîne de caractères unique et complexe, vous pouvez travailler sur chaque transformation individuellement, ce qui réduit la probabilité d’erreurs et améliore la maintenabilité. Cela devient particulièrement important dans des applications complexes où les transformations évoluent fréquemment.
Interopérabilité et Combinaisons
L’un des grands avantages de Typed OM est sa capacité à s’intégrer parfaitement avec d’autres APIs modernes, comme la Web Animations API.
Cela signifie que vous pouvez non seulement utiliser Typed OM pour manipuler des styles CSS directement, mais aussi l’intégrer avec des systèmes d’animations JavaScript comme Web Animations ou d’autres outils d’animation JavaScript. Cette flexibilité vous permet de créer des animations plus fluides et plus performantes, tout en utilisant un code maintenable et optimisé.
En combinant Typed OM et cette API, vous pouvez créer des animations dynamiques de manière fluide et performante, tout en conservant la lisibilité et la modularité du code.
Dans un projet classique, créer des animations basées sur des transformations CSS implique souvent de manipuler des chaînes de caractères ou d’utiliser des frameworks JavaScript spécifiques. Cependant, avec Typed OM, il devient beaucoup plus simple de mettre à jour des objets CSS natifs, ce qui rend le code plus maintenable et performant, surtout pour des animations répétées.
Prenons un exemple simple où nous animons la rotation d’un élément en utilisant requestAnimationFrame() pour mettre à jour la transformation.
Au lieu de manipuler directement des chaînes de caractères dans les animations, Typed OM permet d’ajuster uniquement les valeurs nécessaires, en évitant la reconstruction complète des transformations. Cela permet de fluidifier les animations tout en réduisant la surcharge liée à la recomposition des styles.
const rotateValue = new CSSUnitValue(45, 'deg');
element.attributeStyleMap.set('transform', new CSSTransformValue([new CSSRotate(rotateValue)]));
function animate() {
rotateValue.value += 1;
element.attributeStyleMap.set('transform', new CSSTransformValue([new CSSRotate(rotateValue)]));
requestAnimationFrame(animate);
}
animate();
Dans cet exemple, requestAnimationFrame()
permet de rafraîchir l’animation à chaque image. Ici, nous mettons à jour uniquement la valeur de l’objet rotateValue
à chaque image, et non une chaîne de caractères, ce qui évite des opérations coûteuses de concaténation. Typed OM offre ainsi une approche plus optimisée pour la gestion des animations.
Cette intégration avec Web Animations API ou tout autre mécanisme d’animation JavaScript rend Typed OM idéal pour créer des animations fluides et performantes, tout en assurant une meilleure maintenabilité à long terme.
Performances et Optimisation : Réduire la Charge
Lorsque nous travaillons avec des styles dynamiques ou des animations, comme le déplacement d’un élément avec le mouvement de la souris, chaque mise à jour entraîne une reconstruction de la chaîne de transformation dans l’approche traditionnelle.
Cette recomposition constante des chaînes est non seulement source de bugs potentiels, mais elle peut aussi ralentir les performances, surtout lorsqu’il s’agit de mises à jour fréquentes. Typed OM simplifie cette gestion en permettant des mises à jour incrémentales sur les objets existants, évitant ainsi de recréer entièrement la chaîne de transformation à chaque interaction.
Par exemple, pour suivre la position de la souris, le code classique ressemblerait à ceci :
document.addEventListener('mousemove', (event) => {
const x = event.clientX;
const y = event.clientY;
element.style.transform = `translate(${x}px, ${y}px) rotate(45deg)`;
});
À chaque mouvement, nous recréons toute la chaîne de transformation, même si seule la position x
ou y
change. Avec Typed OM, nous pouvons optimiser cela en mettant à jour directement les valeurs des objets sans reconstruire toute la transformation. Voici comment nous le faisons :
document.addEventListener('mousemove', (event) => {
translateX.value = event.clientX;
translateY.value = event.clientY;
element.attributeStyleMap.set('transform', transform);
});
Dans cet exemple, seules les valeurs des objets translateX
et translateY
sont mises à jour, et la transformation est appliquée de manière efficace sans avoir à recréer toute la chaîne. Cela permet de réduire la charge de calcul sur le navigateur, particulièrement dans des contextes où les mises à jour sont fréquentes, comme les animations ou les interactions utilisateurs.
Compatibilité et Maintenabilité : Anticiper l’Avenir
Typed OM est largement supporté par les navigateurs modernes comme Chrome et Edge, mais certains navigateurs comme Firefox et Safari n’ont pas encore une compatibilité complète.
Pour garantir une expérience fluide pour tous les utilisateurs, il est important de vérifier la disponibilité de l’API Typed OM avant de l’utiliser dans votre projet, et de prévoir un mécanisme de fallback vers la méthode traditionnelle pour les navigateurs qui ne supportent pas encore pleinement cette API.
Avant d’utiliser attributeStyleMap
, il est recommandé de vérifier si cette API est disponible dans le navigateur :
if ('attributeStyleMap' in HTMLElement.prototype) {
element.attributeStyleMap.set('transform', transform);
} else {
element.style.transform = `translate(${x}px, ${y}px) rotate(45deg) scale(1.2)`;
}
Cette approche assure que votre code reste fonctionnel dans les environnements qui ne supportent pas encore Typed OM, tout en tirant parti de ses avantages dans les navigateurs compatibles.
Typed OM reste une solution à long terme pour la gestion des styles CSS, surtout dans des projets où la maintenabilité et la performance sont essentielles.
Pour ceux qui utilisent VS Code ou Sublime Text, il existe des extensions qui facilitent l’écriture de code Typed OM en vous suggérant des types natifs et en vérifiant la compatibilité du code CSS Peek, IntelliSense for CSS class names in HTML, ESLint, Prettier, JavaScript (ES6) code snippets. mais aussi SublimeLinter, Emmet, Sublime CodeIntel, CSS3
Conclusion : Pourquoi Adopter Typed OM ?
Typed OM révolutionne la manière dont nous manipulons les styles CSS avec JavaScript en transformant des chaînes de caractères complexes en objets natifs faciles à manipuler. Non seulement cela améliore la lisibilité et la maintenance du code, mais cela permet également d’optimiser les performances, particulièrement dans des scénarios interactifs ou dynamiques.
En adoptant cette approche modulaire et orientée objet, vous simplifiez la gestion des styles CSS, améliorez les performances de vos animations, et rendez votre code plus facile à maintenir, en particulier dans les projets complexes.
Que vous manipuliez des transformations simples ou complexes, Typed OM offre une solution plus robuste et modulaire pour gérer les styles CSS, tout en garantissant un code plus propre et plus maintenable à long terme.
Pour vous aider à démarrer avec Typed OM, voici quelques ressources utiles :
Nous vous encourageons à tester Typed OM directement dans votre éditeur de code. Si vous utilisez Visual Studio Code, installez des extensions telles que CSS Peek pour vous aider à naviguer dans vos feuilles de style tout en testant Typed OM.