Grundlegendes zu offsetWidth, clientWidth, scrollWidth und -Height


385

Es gibt mehrere Fragen zu StackOverflow in Bezug auf offsetWidth / clientWidth / scrollWidth (bzw. -Height), aber keine geben eine umfassende Erklärung für diese Werte.

Es gibt auch mehrere Quellen im Web, die verwirrende oder falsche Informationen enthalten.

Können Sie eine vollständige Erklärung mit einigen visuellen Hinweisen geben? Wie können diese Werte auch zur Berechnung der Breite der Bildlaufleisten verwendet werden?

Antworten:


869

Das CSS-Box-Modell ist ziemlich kompliziert, insbesondere wenn es um das Scrollen von Inhalten geht. Während der Browser die Werte aus Ihrem CSS zum Zeichnen von Feldern verwendet, ist das Bestimmen aller Dimensionen mit JS nicht einfach, wenn Sie nur über das CSS verfügen.

Das ist , warum jedes Element sechs DOM - Eigenschaften für Ihre Bequemlichkeit hat: offsetWidth, offsetHeight, clientWidth, clientHeight, scrollWidthund scrollHeight. Dies sind schreibgeschützte Attribute, die das aktuelle visuelle Layout darstellen, und alle sind Ganzzahlen (daher können Rundungsfehler auftreten).

Lassen Sie uns sie im Detail durchgehen:

  • offsetWidth, offsetHeight: Die Größe der visuellen Box mit allen Rändern. Kann durch Hinzufügen von width/ heightund Auffüllungen und Rahmen berechnet werden , wenn das Element hatdisplay: block
  • clientWidth, clientHeight: Der visuelle Teil des Boxinhalts, ohne Rahmen oder Bildlaufleisten, aber mit Auffüllung. Kann nicht direkt aus CSS berechnet werden, hängt von der Größe der Bildlaufleiste des Systems ab.
  • scrollWidth, scrollHeight: Die Größe des gesamten Inhalts der Box, einschließlich der Teile, die derzeit außerhalb des Bildlaufbereichs verborgen sind. Kann nicht direkt aus CSS berechnet werden, hängt vom Inhalt ab.

CSS2-Box-Modell

Probieren Sie es aus: jsFiddle


Da offsetWidthdie Breite der Bildlaufleiste berücksichtigt wird, können wir damit die Breite der Bildlaufleiste über die Formel berechnen

scrollbarWidth = offsetWidth - clientWidth - getComputedStyle().borderLeftWidth - getComputedStyle().borderRightWidth

Leider können Rundungsfehler auftreten, da offsetWidthund clientWidthimmer ganze Zahlen sind, während die tatsächlichen Größen mit anderen Zoomstufen als 1 gebrochen sein können.

Beachten Sie, dass dies

scrollbarWidth = getComputedStyle().width + getComputedStyle().paddingLeft + getComputedStyle().paddingRight - clientWidth

funktioniert in Chrome nicht zuverlässig, da Chrome widthmit bereits abgezogener Bildlaufleiste zurückkehrt. (Außerdem rendert Chrome paddingBottom am unteren Rand des Bildlaufinhalts, während andere Browser dies nicht tun.)


27
Für diejenigen, die eine feinere Granularität als Ganzzahlen suchen, verwenden Sie element.getBoundingClientRect()(siehe Hinweis unter developer.mozilla.org/en-US/docs/Web/API/Element.clientWidth )
Anson Kao

1
Beachten Sie, dass scrollWidth und scrollHeight je nach Layout sehr nützlich sein können, um die Größe Ihrer Pseudoelemente :: before und :: after zu ermitteln.
David

Es wäre auch nützlich zu erklären, wie sich diese auf naturalWidthund beziehennaturalHeight
YakovL

warum scrollHeightenthält padding-bottom, scrollWidthaber nicht enthaltenpadding-right
JunGor

clientWidthfür document.documentElement.clientWidthanders als es die gehören scheint padding, bordersundmargin
Drenai

50

Ich habe eine umfassendere und übersichtlichere Version erstellt, die einige Leute möglicherweise nützlich finden, um sich daran zu erinnern, welcher Name welchem ​​Wert entspricht. Ich habe den Farbcode von Chrome Dev Tool verwendet und die Beschriftungen sind symmetrisch angeordnet, um Analogien schneller zu erkennen:

Geben Sie hier die Bildbeschreibung ein

  • Hinweis 1: clientLeftEnthält auch die Breite der vertikalen Bildlaufleiste, wenn die Richtung des Texts von rechts nach links eingestellt ist (da die Leiste in diesem Fall links angezeigt wird).

  • Hinweis 2: Die äußerste Linie repräsentiert das am nächsten positionierte übergeordnete Element (ein Element, dessen positionEigenschaft auf einen anderen Wert als staticoder festgelegt ist initial). Wenn der direkte Container kein positioniertes Element ist, repräsentiert die Linie nicht den ersten Container in der Hierarchie, sondern ein anderes Element höher in der Hierarchie. Wenn kein positioniertes übergeordnetes Element gefunden wird, verwendet der Browser das Element htmloder bodyals Referenz


Hoffe jemand findet es nützlich, nur meine 2 Cent;)


30

Wenn Sie scrollWidth verwenden möchten, um die "REAL" CONTENT WIDTH / HEIGHT (da der Inhalt größer sein kann als die CSS-definierte Breite / Höhe-Box) zu erhalten, ist die scrollWidth / Height sehr unzuverlässig, da einige Browser das PaddingRIGHT zu "bewegen" scheinen & paddingBOTTOM, wenn der Inhalt zu groß ist. Dann platzieren sie die Polster rechts / UNTEN des "zu breiten / hohen Inhalts" (siehe Bild unten).

==> Um in einigen Browsern die REAL CONTENT WIDTH zu erhalten, müssen Sie BEIDE Auffüllungen von der Bildlaufbreite abziehen, und in einigen Browsern müssen Sie nur die LEFT Padding abziehen.

Ich habe eine Lösung dafür gefunden und wollte diese als Kommentar hinzufügen, war aber nicht erlaubt. Also habe ich das Bild gemacht und es in Bezug auf die "bewegten Polster" und die "unzuverlässige Scrollbreite" etwas klarer gemacht. Im BLAUEN BEREICH finden Sie meine Lösung, wie Sie die "ECHTE" INHALTSBREITE erhalten!

Hoffe, das hilft, die Dinge noch klarer zu machen!

Geben Sie hier die Bildbeschreibung ein


13

Es gibt einen guten Artikel über MDN, der die Theorie hinter diesen Konzepten erklärt: https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements

Außerdem werden die wichtigen konzeptionellen Unterschiede zwischen der Breite / Höhe von boundingClientRect und der OffsetWidth / OffsetHeight erläutert.

Um die Theorie richtig oder falsch zu beweisen, benötigen Sie einige Tests. Das habe ich hier gemacht: https://github.com/lingtalfi/dimensions-cheatsheet

Es wird auf Chrome53, ff49, Safari9, Edge13 und IE11 getestet.

Die Ergebnisse der Tests beweisen, dass die Theorie im Allgemeinen richtig ist. Für die Tests habe ich 3 Divs erstellt, die jeweils 10 Lorem-Ipsum-Absätze enthalten. Einige CSS wurde auf sie angewendet:

.div1{
    width: 500px;
    height: 300px;
    padding: 10px;
    border: 5px solid black;
    overflow: auto;
}
.div2{
    width: 500px;
    height: 300px;
    padding: 10px;
    border: 5px solid black;
    box-sizing: border-box;
    overflow: auto;
}

.div3{
    width: 500px;
    height: 300px;
    padding: 10px;
    border: 5px solid black;
    overflow: auto;
    transform: scale(0.5);
}

Und hier sind die Ergebnisse:

  • div1

    • offsetWidth: 530 (chrome53, ff49, safari9, edge13, ie11)
    • offsetHeight: 330 (chrom53, ff49, safari9, edge13, ie11)
    • bcr.width: 530 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.height: 330 (chrome53, ff49, safari9, edge13, ie11)

    • clientWidth: 505 (chrome53, ff49, safari9)

    • clientWidth: 508 (edge13)
    • clientWidth: 503 (ie11)
    • clientHeight: 320 (chrome53, ff49, safari9, edge13, ie11)

    • scrollWidth: 505 (chrome53, safari9, ff49)

    • scrollWidth: 508 (edge13)
    • scrollWidth: 503 (ie11)
    • scrollHeight: 916 (chrome53, safari9)
    • scrollHeight: 954 (ff49)
    • scrollHeight: 922 (edge13, ie11)
  • div2

    • offsetWidth: 500 (chrome53, ff49, safari9, edge13, ie11)
    • offsetHeight: 300 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.width: 500 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.height: 300 (chrome53, ff49, safari9)
    • bcr.height: 299.9999694824219 (edge13, ie11)
    • clientWidth: 475 (chrome53, ff49, safari9)
    • clientWidth: 478 (edge13)
    • clientWidth: 473 (ie11)
    • clientHeight: 290 (chrome53, ff49, safari9, edge13, ie11)

    • scrollWidth: 475 (chrome53, safari9, ff49)

    • scrollWidth: 478 (edge13)
    • scrollWidth: 473 (ie11)
    • scrollHeight: 916 (chrome53, safari9)
    • scrollHeight: 954 (ff49)
    • scrollHeight: 922 (edge13, ie11)
  • div3

    • offsetWidth: 530 (chrome53, ff49, safari9, edge13, ie11)
    • offsetHeight: 330 (chrom53, ff49, safari9, edge13, ie11)
    • bcr.width: 265 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.height: 165 (chrome53, ff49, safari9, edge13, ie11)
    • clientWidth: 505 (chrome53, ff49, safari9)
    • clientWidth: 508 (edge13)
    • clientWidth: 503 (ie11)
    • clientHeight: 320 (chrome53, ff49, safari9, edge13, ie11)

    • scrollWidth: 505 (chrome53, safari9, ff49)

    • scrollWidth: 508 (edge13)
    • scrollWidth: 503 (ie11)
    • scrollHeight: 916 (chrome53, safari9)
    • scrollHeight: 954 (ff49)
    • scrollHeight: 922 (edge13, ie11)

Abgesehen von dem Höhenwert von boundingClientRect (299.9999694824219 anstelle von erwarteten 300) in edge13 und ie11 bestätigen die Ergebnisse, dass die dahinter stehende Theorie funktioniert.

Von dort aus ist hier meine Definition dieser Konzepte:

  • offsetWidth / offsetHeight: Abmessungen des Layoutrahmenrahmens
  • boundingClientRect: Abmessungen des Rendering-Rahmenfelds
  • clientWidth / clientHeight: Abmessungen des sichtbaren Teils des Layout-Auffüllfelds (ohne Bildlaufleisten)
  • scrollWidth / scrollHeight: Abmessungen des Layout-Auffüllfelds, wenn es nicht durch Bildlaufleisten eingeschränkt wurde

Hinweis: Die Standardbreite der vertikalen Bildlaufleiste beträgt 12px in edge13, 15px in chrome53, ff49 und safari9 und 17px in ie11 (durchgeführt durch Messungen in Photoshop anhand von Screenshots und durch die Testergebnisse bestätigt).

In einigen Fällen verwendet Ihre App jedoch möglicherweise nicht die Standardbreite der vertikalen Bildlaufleiste.

Angesichts der Definitionen dieser Konzepte sollte die Breite der vertikalen Bildlaufleiste also gleich sein (im Pseudocode):

  • Layoutdimension: offsetWidth - clientWidth - (borderLeftWidth + borderRightWidth)

  • Rendering-Dimension: boundingClientRect.width - clientWidth - (borderLeftWidth + borderRightWidth)

Hinweis: Wenn Sie Layout und Rendering nicht verstehen, lesen Sie bitte den MDN-Artikel.

Wenn Sie einen anderen Browser haben (oder die Ergebnisse der Tests selbst sehen möchten), können Sie meine Testseite hier sehen: http://codepen.io/lingtalfi/pen/BLdBdL

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.