Maison  >  Article  >  interface Web  >  getComputedStyle : les bons, les mauvais et les mauvais côtés

getComputedStyle : les bons, les mauvais et les mauvais côtés

WBOY
WBOYoriginal
2024-07-28 10:42:23750parcourir

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.

Qu’est-ce que getComputedStyle ?

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 ?

Transition d'un élément de 0px à auto

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 :

Result A1

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 :

getComputedStyle: The good, the bad and the ugly parts

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:

  • Force the browser to run layout calculations immediately before styles
  • Use intertwined requestAnimationFrames to make sure the animation will be run on the next tick (also known as double rAF())

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn