getComputedStyle ist einzigartig. Es führt einige interessante Dinge im Hintergrund aus und verfügt über eine ganz eigene Verwendungsweise. In diesem Beitrag teile ich meine Erfahrungen und Gedanken zu dieser bittersüßen API.
Ich erwarte, dass ich diesen Beitrag bearbeite, da ich heutzutage viel mit dieser Funktion interagiere. Ich denke auch, dass es dafür auch viele Nischenfälle geben kann. Übrigens werde ich am Ende des Beitrags einige Links einfügen, die mir auf meiner Reise geholfen haben.
Direkt von MDN:
Die Methode Window.getComputedStyle() gibt ein Objekt zurück, das die Werte aller CSS-Eigenschaften eines Elements enthält, nachdem aktive Stylesheets angewendet und alle grundlegenden Berechnungen aufgelöst wurden, die diese Werte möglicherweise enthalten.
Auf einzelne CSS-Eigenschaftswerte wird über vom Objekt bereitgestellte APIs oder durch Indizierung mit CSS-Eigenschaftsnamen zugegriffen.
Verwendungsbeispiel in einfachem JavaScript:
const element = document.getElementById("#box"); // Get the computed styles of an element const styles = getComputedStyle(element);
Einfach ausgedrückt gibt es Stile für das angegebene Element zurück. Interessant ist hier das Auflösen von Berechnungen. Angenommen, Sie haben in CSS mit calc():
die Eigenschaft width angegeben
#box { width: calc(100px - 80px); }
Als Ergebnis erhalten Sie 20px. Das bedeutet, dass Sie tatsächlich über JavaScript auf Ergebnisse von CSS-Berechnungen zugreifen können. Es berechnet sogar Ansichtsfenster- und Prozenteinheiten (100 vh, 50 % usw.) und gibt das Ergebnis in Pixeln aus. Großartig!
GOTCHA: Der berechnete Wert hängt von den Eigenschaften ab und ist nicht statisch. Das heißt, Sie können nicht erwarten, dass es so etwas berechnet:
#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"];
Das macht absolut Sinn, da es unmöglich wäre, das Ergebnis einer CSS-Variablen statisch zu berechnen. Es hängt von der Umgebung und den Eigentumsaspekten ab (denken Sie zum Beispiel an Prozentsätze).
Sie erhalten jedoch 20 Pixel, wenn Sie versuchen, auf die Breiteneigenschaft zuzugreifen. Am Ende würde die Breite für das spezifische Element berechnet:
// 20px const { width } = getComputedStyle(element);
Das ist cool und alles andere als was sind die tatsächlichen Anwendungsfälle?
Wenn Sie diesen Beitrag lesen, nachdem calc-size() in modernen Browsern weit verbreitet ist, hören Sie auf, ihn zu verwenden. Es wird wahrscheinlich unsere Lösung hier übertreffen. Wenn Sie in einer Realität feststecken, in der wir nicht auf das Auto umsteigen können, machen Sie weiter!
Auf Ihrer Reise in die Webentwicklung sind Sie vielleicht schon ein paar Mal auf die Animation von/zu Auto gestoßen. Eine Animationsbibliothek könnte hier gut passen, aber was ist, wenn ich Ihnen sage, dass überhaupt kein Bedarf dafür besteht?
Nehmen wir an, es gibt ein Feld, das wir ein-/ausschalten können und das Textinhalt enthält. Der Textinhalt wird dynamisch sein, daher können wir ihm nicht im Voraus eine maximale Höhe zuweisen. Oh, der Designer möchte dort auch eine Animation, sie muss langsam von 0 Pixel auf die automatische Höhe übergehen.
Das Folgende wird unser HTML und CSS sein:
<!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>
Auf der Skriptseite werden wir zunächst nicht viel tun. Wir müssen lediglich einen einfachen Zustand beibehalten, um den Textinhalt einzufügen oder zu entfernen. (Ob Sie TS verwenden oder nicht, bleibt Ihnen überlassen):
// 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(); // ... });
Der Code hier setzt einfach den inneren Text der Box auf eine Pseudozeichenfolge oder setzt ihn wieder in eine leere Zeichenfolge zurück.
Wenn Sie jetzt auf die Schaltfläche klicken, werden Sie feststellen, dass sich nichts geändert hat. Das liegt daran, dass wir die Höhe der Box auf 0 Pixel setzen und den Überlauf ausblenden.
Um zu wissen, wie viel Platz wir für den Text benötigen, können wir die Höhe der Box auf „Auto“ setzen und getComputedStyle für unsere Box aufrufen. Die Idee hier ist, das Element automatisch so weit vergrößern zu lassen, wie es benötigt, und getComputedStyle hier ruft uns diese Größe in Pixel ab.
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); });
Wenn Sie auf die Schaltfläche klicken, sollten Sie sehen, dass das Feld die erforderliche Höhe hat. Wir können die Höhe auch in Pixeln in der Konsole sehen:
Das ist cool, aber wir werden mit Sicherheit nicht umstellen.
Da wir die Höhe kennen, die wir benötigen, können wir die Höhe der Box vielleicht wieder auf den ursprünglichen Wert zurücksetzen. Innerhalb eines Aufrufs von requestAnimationFrame können wir es auf die Höhe setzen, die wir von getComputedStyle erhalten haben. Probieren wir es aus!
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; }); });
Da wir wissen, dass wir die Höhe auf 0 Pixel setzen und sie im nächsten Animationsframe ändern, sollten wir eine Animation sehen, oder?
Naja, nicht ganz. Wenn Sie dies in Chrome auf einem High-End-PC ausführen, sollten Sie die Übergangsanimation beobachten, ABER auf Low-End-PCs oder in einigen Browsern (wie Firefox) können Sie sehen, dass sich nichts geändert hat.
Vergleich von Firefox und Chrome auf meinem Computer:
Der Grund dafür ist, dass die Berechnung des Layouts nach den Stilen erfolgt. Wir können nicht garantieren, dass unsere Layoutberechnung vor der Stilberechnung erfolgt. Anscheinend haben auch Browser unterschiedliche Implementierungen von requestAnimationFrame. (Mehr darüber erfahren Sie hier)
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
Das obige ist der detaillierte Inhalt vongetComputedStyle: Die guten, die schlechten und die hässlichen Teile. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!