JavaScript und CSS/CSS-Eigenschaften auslesen
Oft wird gefragt, wie man Abmessungen von Elementen mit JavaScript ermitteln kann. Häufig liegt hier bereits der Denkfehler - modernes CSS überlässt solche Berechnungen dem Browser.
Meist ist es nicht nötig, diese Werte zu ermitteln, da sich ein responsives Layout unabhängig von genauen Pixelangaben an den Viewport anpasst.
ermöglichen es, dass der Browser Seitenelemente automatisch ohne weiteres Zutun des Entwicklers passend positioniert.
Und trotzdem kann es sinnvoll sein, mit JavaScript CSS-Eigenschaften, bzw. die Abmessungen von HTMLElement-Objekten auszulesen, um diese Informationen anderswo zu verarbeiten. Dieses Kapitel stellt die verschiedenen Möglichkeiten, Anwendungsfälle und Best practices vor.
Inhaltsverzeichnis
CSS-Eigenschaften auslesen
Das style-Objekt wird immer wieder missverstanden: Man kann damit lediglich Inline-Styles setzen und die bereits gesetzten auslesen, aber nicht den berechneten Wert einer CSS-Eigenschaft ermitteln.
Die besagten Objekteigenschaften (.style.cssEigenschaft
) sind allesamt leer, wenn sie nicht im betreffenden HTML-Element über ein style-Attribut oder wie beschrieben mit JavaScript gesetzt wurden:
<p id="ohne-inline-styles">Element ohne Inline-Styles</p>
<p id="mit-inline-styles" style="color: red">Element mit Inline-Styles</p>
// Gibt einen leeren String aus:
console.log(
document.getElementById('ohne-inline-styles').style.backgroundColor
);
// Gibt »red« aus, weil Inline-Style gesetzt wurde:
console.log(
document.getElementById('mit-inline-styles').style.backgroundColor
);
getComputedStyle
Das Auslesen des gegenwärtigen Werts von CSS-Eigenschaften eines Elements gestaltet sich als schwierig. Wenn man in Erfahrung bringen will, welche tatsächliche Textfarbe oder welche Pixel-Breite ein Element hat, dann ist nach den sogenannten berechneten Werten (englisch: computed values) gefragt, wie sie in der CSS-Fachsprache genannt werden.
Im Allgemeinen besteht der aktuelle CSS-Eigenschaftswert eines Elements aus einer Kombination von …
- Standardformatierungen des Browsers
- (oft mehreren) im CSS festgelegten Regelsätzen, die über Selektoren ausgewählt werden und dann nach den Regeln der Kaskade kombiniert und überschrieben werden.
Die Methode Window.getComputedStyle() enthält für jede CSS-Eigenschaft eine entsprechende Objekteigenschaft mit dem aktuellen berechneten Wert.
page.addEventListener('mouseover',getCSSValues);
function getCSSValues(event) {
const element = event.target;
const compStyles = window.getComputedStyle(element);
let textsize = compStyles.getPropertyValue('font-size');
let textcolor = compStyles.getPropertyValue('color');
document.getElementById('textsize').textContent = textsize;
document.getElementById('textcolor').textContent = textcolor;
}
Im Beispiel wird ein addEventListener gesetzt, der beim Überfahren mit der Maus die Funktion getCSSValues()
aufruft. Diese ermittelt mit getComputedStyle() die berechneten Werte. Wie man in der Konsole sehen kann, werden alle Werte (Stand Februar 2024: 367!) angezeigt.
Um das Beispiel übersichtlich zu halten, werden mit getPropertyValue() nur die Werte für font-size und color ausgelesen.
Die berechneten Werte (computed values), die getComputedStyle
zurückgibt, werden letztlich in Pixelwerte umgerechnet, sodass getComputedStyle
Werte mit der Einheit px zurückgibt. Gerade bei der verschachtelten ul sieht man, dass der Standardschriftwert in jeder Ebene mit 0.8 multipliziert und so immer kleiner wird.
Auch beispielsweise bei Farbwerten ist das ähnlich:
Bei Farbangaben wie beispielsweise color: red,
oder #ff0000
liefert getComputedStyle
für color
den Wert "rgb(255 0 0)"
. Dies ist derselbe Wert in einer alternativen Schreibweise, wie das Farbfeld zeigt.
Spoiler: Die Linkfarbe ändert sich, da die Pseudoklasse :visited aktiviert wird.
Allerdings gibt getComputedStyle die Farbe weiter wie bei :unvisited-Links an, damit man nicht per JS herausfinden kann, welche Seiten besucht wurden.[1]
Elementbox-Größen auslesen
Um die aktuelle Höhe und Breite einer Element-Box zu ermitteln, müssen wir erst einmal überlegen, welche Werte wir dafür benötigen. Neben den Eigenschaften width und height bestimmen ja auch noch Rahmen und Innen- und Außenabstände die Dimensionen von Element-Boxen. So gibt es mehrere Möglichkeiten, die Größe zu ermitteln:
- clientWidth und clientHeight: liefern Breite bzw. Höhe der Innenabstand-Box des Elements. Das bedeutet, dass
padding
inbegriffen ist, währendborder
undmargin
nicht eingerechnet werden. Ebenso wird die Größe einer möglicherweise angezeigte Bildlaufleiste (Scrollbar) nicht einberechnet. - offsetWidth und offsetHeight: liefern die Breite bzw. Höhe der Rahmen-Box des Elements. Das bedeutet, dass der Innenabstand (
padding
) und der Rahmen (border
) inbegriffen sind, der Außenrahmen hingegen (margin
) nicht. - scrollWidth und scrollHeight: geben die tatsächlich angezeigte Breite bzw. Höhe des Inhalts wieder. Wenn das Element kleiner ist, als der Inhalt es erfordert, also Bildlaufleisten angezeigt werden, so geben diese Eigenschaften die Größe des aktuell sichtbaren Ausschnittes wieder.[2]
In den meisten Fällen benötigt man die äußere Größe eines Elements, also offsetWidth
und offsetHeight
.
var element = document.getElementById('beispielID');
console.log('Breite: ' + element.offsetWidth + '\nHöhe: ' + element.offsetHeight);
Im Gegensatz zu getComputedStyle
geben sie keine String-Werte samt Einheiten zurück, sondern direkt JavaScript-Zahlen (Number-Werte) in der Einheit Pixel.
Falls du die innere Größe benötigst, so kannst du zunächst die aktuellen Werte der jeweiligen padding
-Eigenschaften auslesen. Das sind padding-left
und padding-right
für die Breite bzw. padding-top
und padding-bottom
für die Höhe.
let Innenbreite = offsetWidth - (padding-left + padding-right); let Innenhoehe = offsetHeight - (padding-top + padding-bottom);
getBoundingClientRect
Die Element.getBoundingClientRect()-Methode gibt die Größe und Position eines Elements relativ zur Größe des Viewports zurück.
Syntax
rectObject = element.getBoundingClientRect(node);
-
rectObject
: Rückgabewert ist einDOMRect
-Objekt, das left, top, right, bottom, x, y, width, height-Eigenschaften besitzt, die ausgelesen werden können.- Alle Eigenschaften außer
width
andheight
sind relativ zur oberen linken Ecke (top-left) des Viewports. -
width
undheight
geben die tatsächliche Breite, bzw. Höhe des Elements zurück, alsoHöhe + padding + border-width
, nicht nur die Größe der content-box.
- Alle Eigenschaften außer
Mit der getBoundingClientRect-Methode kannst du einen einfachen Seiteninspektor erstellen:
function getCSSValues(event) {
const element = event.target;
const name = element.nodeName;
const rect = element.getBoundingClientRect();
let result = `
Elementname: ${name} \n
x₁, y₁ : ${rect.left}px, ${rect.top}px (links oben) \n
x₂, y₂: ${rect.right}px, ${rect.bottom}px (rechts unten) \n
Höhe: ${rect.height}px \n
Breite: ${rect.width}px
`;
console.log(result);
result = result.replaceAll("\n", "<br>");
document.getElementById('info').innerHTML = result;
}
An das body-Element werden mit addEventListener zwei Eventhandler angefügt, sodass beim Überfahren oder beim Klick mit der Maus die Funktion getCSSValues()
aufgerufen wird.
Diese Funktion ermittelt mit event.target das Element, durch das das Ereignis ausgelöst wurde. Von diesem Element werden jetzt mit getBoundingClientRect()
die einzelnen Eigenschaften abgefragt, in einer Variaben result
zusammengefügt und anschließend in der Konsole ausgegeben.
Die Variable result
enthält mehrere line breaks \n
. Da der string auch im HTML sichtbar gemacht werden soll, werden mit String.replaceAll alle Vorkommen mit einem br ersetzt und es anschließend im output-Element ausgegeben.
getBoundingClientRect()
aber in px ermittelt werden.Es wäre schöner, wenn die ausgegebenen Werte mit toFixed nur 2 oder 3 Nachkommastellen erhielten; es sollte in diesem Beispiel aber die Genauigkeit demonstriert werden.
Siehe auch
- Infobox/Akkordeon mit details
Um das Auf- und Zuklappen eines details-Elements zu animieren, wird zuerst mit getBoundingClientRect() die Höhe der Box einmal im geöffneten und einmal im geschlossenen Zustand ermittelt.
computedStyleMap
Die computedStyleMap()-Methode der Element-Schnittstelle gibt ein StylePropertyMapReadOnly
-Objekt zurück.
Dieses Objekt ist mit dem CSSStyleDeclaration
-Objekt vergleichbar, das du in der style
-Eigenschaft des Elements findest. Es enthält die Eigenschaftswerte jedoch in Form eines CSSStyleValue-Objekts, das einen einfacheren Zugriff auf Werte und Einheiten bietet. (Im MDN gibt es ein sehenswertes Beispiel, dass alle Eigenschaften des StylePropertyMapReadOnly auflistet.)
In der StylePropertyMapReadOnly
gibt es auch keinen direkten Zugriff auf CSS-Eigenschaften über den Eigenschaftsnamen. Du musst für den Zugriff auf einen Eigenschaftswert die get
-Methode verwenden, oder mit entries()
einen Iterator für die Einträge erhalten (den du dann zum Beispiel mit einer for...of Schleife durchlaufen kannst).
function getCSSValues(event) {
const element = event.target;
const compStyles = element.computedStyleMap();
console.log(compStyles);
let name = element.nodeName;
let value = element.computedStyleMap().get('font-size').value;
let unit = element.computedStyleMap().get('font-size').unit;
let result = `
Elementname: ${name} \n
Schriftgröße: \n
- Wert: ${value} \n
- Einheit: ${unit} \n
`;
console.log(result);
}
Jedes mit der Maus oder Klick gewählte Element wird analysiert.
-
computedStyleMap()
erzeugt dasStylePropertyMapReadOnly
-Objekt , das (Stand: März 2024) in Chrome 380 Einträge hat. -
element.computedStyleMap().get('font-size').value;
liest mit derget
-Methode den Wert der font-size-Eigenschaft aus. anders als in den oben vorgestellten Methoden ist dies kein String sondern eine number - so könnte man den erhaltenen Wert einfach berechnen. -
element.computedStyleMap().get('font-size').unit;
gibt die dazugehörige Einheit aus. Anders als im CSS notiert, wird der berechnete Wert in px angezeigt.
Hauptartikel: CSS Typed OM
auf Veränderungen reagieren
resizes mit resizeObserver
Oft möchte man mit Javascript die Größe von Fenstern und Boxen überprüfen. Der typische Weg ist die Verwendung eines Event-Listeners auf das resize-Event des Fensters:[3]
el.addEventListener('resize', () => {
if (document.body.clientWidth >= 750) {
// do something
}
});
Allerdings wird das Event jedes Mal gefeuert, wenn das Fenster in der Größe verändert wird, und zwar bei jeder Pixelvergrößerung/-verkleinerung! Dies kann zu enormen Leistungsproblemen führen, wenn die Funktion des Ereignis-Listeners zu langsam ist.
Und eigentlich wollten wir doch nur wissen, ob die Größe des Bildes noch in das Layout passt.
In folgendem Beispiel soll der Platzbedarf für einen Sticky Header ermittelt und freigehalten werden. Auf großen Viewports passt die Navigation in eine Zeile, bei schmalen Viewports nimmt sie mehr Platz ein.[4]
const resizeObserver = new ResizeObserver(entries => {
document.documentElement.style.setProperty(
'--header-height', `${entries[0].target.offsetHeight}px`
);
});
resizeObserver.observe(document.querySelector('nav'));
Der resizeObserver ermittelt die offsetHeight des nav-Elements und weist sie der custom property --header-height
zu.
Dieser Wert wird nun dem html-Element als oberer Scroll-Innenabstand zugewiesen:
html {
scroll-padding-top: var(--header-height);
}
Weitere Observer
Es gibt noch weitere Observer, z.B. ...
- Der Intersection Observer überwacht, ob ein Element gerade sichtbar ist.
- Der MutationObserver achtet darauf, ob irgendwo im DOM etwas verändert wird.
Siehe auch
- SELF-Blog: Wir erzwingen Ihre Einstimmung! vom 18.03.2024
Cookie-Terror-Banner mit dem Mutation Observer ausblenden
Medienabfragen mit matchMedia
Ist der verfügbare Platz noch ausreichend für das Element? Oft gibt es in solchen Fällen eine bessere Alternative, nämlich die Verwendung von media queries. Im Stylesheet wird ein Regelsatz in einer Medienabfrage notiert und der Browser entscheidet selbstständig, ob die Bedingung zutrifft. Dafür benötigt man kein JavaScript.
Und doch gibt es Spezialfälle, bei denen man Berechnungen in JavaScript anstellen muss, wenn man …
- eben nicht genau weiß, wie lang oder breit ein Element ist. Eine Navigation soll die Links horizontal anordnen. Abhängig von Schriftgröße und verwendetem Font ->ich messe bei meinem Navigationsmenü, ob es noch einzeilig auf die Seite passt, oder ob ich das Hamburgericon zeige.
Deshalb kann man die Medienabfrage mit Window.matchMedia() durch JavaScript durchführen lassen:
const mediaQueryList = window.matchMedia('(min-width: 35em)');
mediaQueryList.addEventListener('change', event => {
console.log(window.innerWidth);
if (event.matches) {
console.log('The window is now 35em or under');
} else {
console.log('The window is now over 35em');
}
})
Bildern im Quer- oder sogar landscape-Format bieten ein Panorama. Je kleiner der Bildschirm wird, desto winziger wird die Grafik. Während man bei der Art Direction mit mehreren Bildern arbeitet, kann man bei SVG die viewBox und damit Seitenverhältnis und sichtbare Ausschnitte ändern. Da es sich bei viewBox aber (noch) nicht um ein Präsentationsattribut handelt, lässt sich das nicht mit CSS @media-Abfragen lösen. Mit JavaScript und matchMedia geht es:
const landscape = document.querySelector('#landscape'),
mql = window.matchMedia("(max-width:50em)");
changeViewBox(mql);
mql.addEventListener('change', changeViewBox);
function changeViewBox(mql) {
if (mql.matches) {
landscape.setAttribute('viewBox','100 66 120 100');
console.log ('Kleines Browserfenster: max-width: 50em');
} else {
landscape.setAttribute('viewBox','0 66 250 100');
console.log ('Großes Browserfenster max-width:50em ist false');
}
}
Das SVG-viewBox-Attribut legt den sichtbaren Ausschnitt einer Grafik fest und kann nicht durch CSS angesprochen werden. changeViewBox(mql)
ändert das viewBox-Attribut, wenn die Media query erfüllt ist, um das Bild auf kleinen Monitoren als Ausschnitt und auf großen Monitoren in voller Breite zu zeigen.
Siehe auch
- Hintergrundvideo
Nutzer, die keine Animation und Bewegung mögen, erhalten mitwindow.matchMedia('(prefers-reduced-motion: reduce)')
nur ein Standbild - Fullscreen
window.matchMedia('(display-mode: fullscreen)')
überprüft, ob die Webseite im Fullscreen-Modus ist und fügt dann einen Schließen-Button hinzu, da es auf Tablets kein ESC gibt - Dark Mode
kombinierte Abfrage von prefers-color-scheme und Nutzerauswahl
Wie man sehen kann, wird mit matchMedia() viel mehr als nur Längen ermittelt!
Weblinks
- ↑ :visited links have limited styling and getComputedStyle lies about their style(css-tricks.com)
- ↑ MDN: Determining the dimensions of elements
- ↑ Why you should use window.matchMedia when checking for window resizes in Javascript October 3, 2020 (webdevetc.com)
- ↑ sticky header, scroll-padding-top, ResizeObserver CodePen von Gunnar Bittersmann