getComputedStyle est unique en son genre. Il fait quelques choses intéressantes en arrière-plan et a sa propre façon d'utiliser. Dans cet article, je partagerai mon expérience et mes réflexions sur cette API douce-amère.
Je m'attends à éditer ce post car j'interagis beaucoup avec cette fonction de nos jours. Je pense aussi qu’il peut y avoir de nombreux cas de niche dans ce domaine. D'ailleurs je mettrai quelques liens qui m'ont aidé dans mon parcours à la fin du post.
Directement depuis MDN :
La méthode Window.getComputedStyle() renvoie un objet contenant les valeurs de toutes les propriétés CSS d'un élément, après avoir appliqué des feuilles de style actives et résolu tout calcul de base que ces valeurs peuvent contenir.
Les valeurs de propriété CSS individuelles sont accessibles via les API fournies par l'objet ou par indexation avec les noms de propriété CSS.
Exemple d'utilisation en JavaScript simple :
const element = document.getElementById("#box"); // Get the computed styles of an element const styles = getComputedStyle(element);
En termes simples, il renvoie les styles pour l'élément donné. Un élément intéressant ici est la résolution des calculs. Supposons que vous ayez donné la propriété width en CSS avec calc() :
#box { width: calc(100px - 80px); }
Cela vous donnera 20px en conséquence. Cela signifie que vous pouvez réellement accéder aux résultats des calculs CSS à partir de JavaScript. Il calcule même la fenêtre d'affichage et les unités de pourcentage (100vh, 50% etc.) et donne le résultat en pixels. Génial !
GOTCHA : La valeur calculée dépend des propriétés et n'est pas statique. Cela signifie que vous ne pouvez pas vous attendre à ce qu'il calcule quelque chose comme ceci :
#box { --box-width: calc(100px - 80px); width: var(--box-width); }
// boxWidth variable will be set to string `calc(100px - 80px)` // Not `20px` const boxWidth = getComputedStyle(element)["--box-width"];
Cela est tout à fait logique puisqu'il serait impossible de calculer statiquement le résultat d'une variable CSS. Cela dépend de l'environnement et des aspects de la propriété (Pensez aux pourcentages par exemple).
Cependant, vous aurez 20 pixels si vous essayez d'accéder à la propriété width. Cela finirait par calculer la largeur de l'élément spécifique :
// 20px const { width } = getComputedStyle(element);
C'est cool et tout, mais quels sont les cas d'utilisation réels ?
Si vous lisez cet article après que calc-size() soit largement disponible sur les navigateurs modernes, arrêtez-vous et utilisez-le. Cela surpassera probablement notre solution ici. Si vous êtes coincé dans une réalité où nous ne pouvons pas passer à l'automobile, continuez !
Au cours de votre parcours de développement Web, vous avez peut-être rencontré plusieurs fois l'animation vers/depuis l'automobile. Une bibliothèque d'animations pourrait bien convenir ici, mais et si je vous disais que ce n'est pas du tout nécessaire ?
Disons qu'il y a une boîte que nous pouvons activer/désactiver et qui contient du texte. Le contenu du texte sera dynamique, nous ne pouvons donc pas lui donner une hauteur maximale au préalable. Oh, le concepteur veut aussi une animation là-bas, elle doit passer lentement de 0px à la hauteur automatique.
Ce qui suit sera notre HTML et CSS :
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> </head> <style> #box { position: relative; display: block; width: fit-content; height: 0px; overflow: hidden; background-color: rebeccapurple; color: whitesmoke; transition: 1s; } </style> <body> <button type="button" id="toggle">toggle</button> <div id="box"></div> <script type="module" src="/src/main.ts" defer></script> </body> </html>
Côté script, nous ne ferons pas grand chose pour le début. Il suffit de conserver un état simple pour mettre ou supprimer le contenu du texte. (Que vous utilisiez ou non TS dépend de vous) :
// get the wrapper div const box = document.getElementById("box") as HTMLDivElement; // get the trigger button const button = document.getElementById("toggle") as HTMLButtonElement; // state that keeps track let toggle = false; function changeBoxContent() { if (toggle) { box.innerText = `Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minima culpa ipsum quibusdam quia dolorum excepturi sequi non optio, ad eaque? Temporibus natus eveniet provident sit cum harum, praesentium et esse?`; } else { box.innerText = ""; } } button.addEventListener("click", () => { // flip the toggle toggle = !toggle; // update the content changeBoxContent(); // ... });
Le code ici définit simplement le texte intérieur de la boîte sur une chaîne pseudo ou le rétablit en une chaîne vide.
Si vous cliquez sur le bouton maintenant, vous verrez que rien n'a changé. C'est parce que nous définissons la hauteur de la boîte à 0 pixel et masquons son débordement.
Afin de savoir de combien d'espace nous avons besoin pour le texte, nous pouvons définir la hauteur de la boîte sur auto et appeler getComputedStyle sur notre boîte. L'idée ici est de laisser l'élément s'agrandir autant que nécessaire via auto et getComputedStyle ici nous récupérera cette taille en pixels.
button.addEventListener("click", () => { // flip the toggle toggle = !toggle; // update the content changeBoxContent(); // set the element's height to `auto`, this enlarges the element to fit it's content box.style.height = "auto"; // we got our desired height property! const height = getComputedStyle(box).height; console.log(height); });
Vous devriez voir que la boîte a autant de hauteur que nécessaire lorsque vous cliquez sur le bouton. On peut aussi voir la hauteur en pixels dans la console :
C'est cool mais nous ne sommes certainement pas en transition.
Puisque nous connaissons la hauteur dont nous avons besoin, nous pouvons peut-être remettre la hauteur de la boîte là où elle était. Lors d'un appel à requestAnimationFrame, nous pouvons le définir à la hauteur que nous avions depuis getComputedStyle. Essayons !
button.addEventListener("click", () => { // flip the toggle toggle = !toggle; // update the content changeBoxContent(); // set the element's height to `auto`, this enlarges the element to fit it's content box.style.height = "auto"; // we got our desired height property! const height = getComputedStyle(box).height; // set the height back to where it was (0px) box.style.height = ""; // set the final height in next animation frame requestAnimationFrame(() => { box.style.height = height; }); });
Puisque nous savons définir la hauteur sur 0px et la modifier dans la prochaine image d'animation, nous devrions la voir s'animer, n'est-ce pas ?
Eh bien, pas exactement. Si vous l'exécutez dans Chrome sur un PC haut de gamme, vous devriez observer l'animation de transition MAIS sur les PC bas de gamme ou dans certains navigateurs (comme Firefox), vous pouvez voir que rien n'a changé.
Comparaison de Firefox et Chrome sur mon ordinateur :
La raison pour laquelle cela se produit est que le calcul de la mise en page a lieu après les styles. Nous ne pouvons pas garantir que notre calcul de mise en page aura lieu avant le calcul de style. Il semble également que les navigateurs aient également différentes implémentations de requestAnimationFrame. (Vous pouvez en savoir plus ici)
Don't get into despair though! We have multiple solutions for this. We can:
Let's try forcing the browser to calculate styles first. Remember getComputedStyle? I'm sure you do. It'll come to our rescue here too!
Right after we set height back to 0px, we'll force to recalculate the layout:
button.addEventListener("click", () => { // flip the toggle toggle = !toggle; // update the content changeBoxContent(); // set the element's height to `auto`, this enlarges the element to fit it's content box.style.height = "auto"; // we got our desired height property! const height = getComputedStyle(box).height; // set the height back to where it was (reset) box.style.height = ""; // we're synchronously forcing the browser to recalculate the height of the element getComputedStyle(box).height; // set the final height in next animation frame requestAnimationFrame(() => { box.style.height = height; }); });
GOTCHA: You might be thinking why we're accessing height property but not assigning it to anything. Well that's because getComputedStyle computes a property on access. It's actually to make it more optimized, it'll only run layout calculations on access to top, left, bottom, right, width and height. Its not documented but good to keep in mind. Try changing it to getComputedStyle(box), you'll see nothing has changed.
So that was one way to solve it and honestly I like this way much better. It's good to know double rAF() trick too, though.
For that we simply need to wrap our requestAnimationFrame with another requestAnimationFrame:
button.addEventListener("click", () => { // flip the toggle toggle = !toggle; // update the content changeBoxContent(); // set the element's height to `auto`, this enlarges the element to fit it's content box.style.height = "auto"; // we got our desired height property! const height = getComputedStyle(box).height; // set the height back to where it was (reset) box.style.height = ""; // set the final height in next animation frame requestAnimationFrame(() => { requestAnimationFrame(() => { box.style.height = height; }); }); });
Think of it like in the next frame, we've queued an animation that'll run on the next frame. I know it sounds weird but that used to solve lots of problems since it has a bug in Chrome too.
That's the wrap! As you can see in a modern world where we have WAAPI, transitions and getComputedStyle still have their use! It's a bit nasty to understand at start but it has it's own way of doing things, what can I say!
Sources:
Transition to Height Auto With Vue.js by Markus Oberlehner
Need cheap paint? Use getComputedStyle().opacity by Webventures
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!