Comprendre offsetWidth, clientWidth, scrollWidth et -Height, respectivement

385

Il y a plusieurs questions sur StackOverflow concernant offsetWidth / clientWidth / scrollWidth (et -Height, respectivement), mais aucune ne donne une explication complète de ces valeurs.

En outre, il existe plusieurs sources sur le Web qui donnent des informations confuses ou incorrectes.

Pouvez-vous donner une explication complète, y compris quelques conseils visuels? De plus, comment ces valeurs peuvent-elles être utilisées pour calculer les largeurs des barres de défilement?

user123444555621
la source

Réponses:

869

Le modèle de boîte CSS est plutôt compliqué, en particulier en ce qui concerne le défilement du contenu. Alors que le navigateur utilise les valeurs de votre CSS pour dessiner des boîtes, déterminer toutes les dimensions à l'aide de JS n'est pas simple si vous ne disposez que du CSS.

C'est la raison pour laquelle chaque élément a six propriétés DOM pour votre confort: offsetWidth, offsetHeight, clientWidth, clientHeight, scrollWidthet scrollHeight. Il s'agit d'attributs en lecture seule représentant la disposition visuelle actuelle, et tous sont des entiers (pouvant donc être sujets à des erreurs d'arrondi).

Voyons-les en détail:

  • offsetWidth, offsetHeight: La taille de la boîte visuelle comprenant toutes les bordures. Peut être calculé en ajoutant width/ heightet des rembourrages et des bordures, si l'élément adisplay: block
  • clientWidth, clientHeight: La partie visuelle du contenu de la boîte, à l'exclusion des bordures ou des barres de défilement, mais comprend le remplissage. Ne peut pas être calculé directement à partir de CSS, dépend de la taille de la barre de défilement du système.
  • scrollWidth, scrollHeight: La taille de tout le contenu de la boîte, y compris les parties actuellement masquées en dehors de la zone de défilement. Ne peut pas être calculé directement à partir de CSS, dépend du contenu.

Modèle de boîte CSS2

Essayez-le: jsFiddle


Étant donné que offsetWidthprend en compte la largeur de la barre de défilement, nous pouvons l'utiliser pour calculer la largeur de la barre de défilement via la formule

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

Malheureusement, nous obtenons des erreurs d' arrondi, car offsetWidthet clientWidthsont toujours des entiers, alors que la taille réelle peut être fractionné avec des niveaux de zoom autres que 1.

Notez que ceci

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

ne fonctionne pas de manière fiable dans Chrome, car Chrome revient widthavec la barre de défilement déjà soustraite. (De plus, Chrome rend paddingBottom au bas du contenu du défilement, contrairement aux autres navigateurs)

user123444555621
la source
27
Pour ceux qui recherchent une granularité plus fine que les entiers, utilisez element.getBoundingClientRect()(voir la note sur developer.mozilla.org/en-US/docs/Web/API/Element.clientWidth )
Anson Kao
1
Notez que selon votre disposition, scrollWidth et scrollHeight peuvent être très utiles pour obtenir la taille de vos pseudo-éléments :: avant et :: après.
David
En outre, il serait utile d'expliquer comment ces éléments sont liés à naturalWidthetnaturalHeight
YakovL
pourquoi scrollHeightinclut padding-bottommais scrollWidthn'inclut paspadding-right
JunGor
clientWidthpour document.documentElement.clientWidthest différent car il semble inclure le padding, bordersetmargin
Drenai
50

J'ai créé une version plus complète et plus propre que certaines personnes pourraient trouver utile pour se souvenir de quel nom correspond à quelle valeur. J'ai utilisé le code couleur de Chrome Dev Tool et les étiquettes sont organisées symétriquement pour détecter plus rapidement les analogies:

entrez la description de l'image ici

  • Remarque 1: clientLeftinclut également la largeur de la barre de défilement verticale si la direction du texte est définie de droite à gauche (car la barre est affichée à gauche dans ce cas)

  • Remarque 2: la ligne la plus à l'extérieur représente le parent le plus proche positionné (un élément dont la positionpropriété est définie sur une valeur différente de staticou initial). Ainsi, si le conteneur direct n'est pas un élément positionné , la ligne ne représente pas le premier conteneur de la hiérarchie mais un autre élément plus haut dans la hiérarchie. Si aucun parent positionné n'est trouvé, le navigateur prendra l' élément htmlou bodycomme référence


J'espère que quelqu'un le trouvera utile, juste mes 2 cents;)

Lual
la source
30

Si vous souhaitez utiliser scrollWidth pour obtenir la LARGEUR / LA HAUTEUR DE CONTENU "RÉEL" (car le contenu peut être PLUS GRAND que la largeur / hauteur définie par CSS), la scrollWidth / Height est très ILLICITE car certains navigateurs semblent "DÉPLACER" le paddingRIGHT & paddingBOTTOM si le contenu est trop volumineux. Ils placent ensuite les rembourrages à DROITE / BAS du "contenu trop large / élevé" (voir photo ci-dessous).

==> Par conséquent, pour obtenir la LARGEUR DE CONTENU RÉEL dans certains navigateurs, vous devez soustraire les DEUX rembourrages de la largeur de défilement et dans certains navigateurs, vous n'avez qu'à soustraire le remplissage GAUCHE.

J'ai trouvé une solution pour cela et je voulais l'ajouter en tant que commentaire, mais ce n'était pas autorisé. J'ai donc pris la photo et l'ai rendue un peu plus claire en ce qui concerne les "rembourrages déplacés" et le "scrollWidth peu fiable". Dans la ZONE BLEUE, vous trouverez ma solution pour obtenir la LARGEUR DE CONTENU "RÉELLE"!

J'espère que cela aide à rendre les choses encore plus claires!

entrez la description de l'image ici

Manny_user3297459
la source
13

Il y a un bon article sur MDN qui explique la théorie derrière ces concepts: https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements

Il explique également les différences conceptuelles importantes entre la largeur / hauteur de boundingClientRect et offsetWidth / offsetHeight.

Ensuite, pour prouver que la théorie est bonne ou mauvaise, vous avez besoin de tests. C'est ce que j'ai fait ici: https://github.com/lingtalfi/dimensions-cheatsheet

Il teste chrome53, ff49, safari9, edge13 et ie11.

Les résultats des tests prouvent que la théorie est généralement correcte. Pour les tests, j'ai créé 3 divs contenant 10 paragraphes lorem ipsum chacun. Certains CSS leur ont été appliqués:

.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);
}

Et voici les résultats:

  • div1

    • offsetWidth: 530 (chrome53, ff49, safari9, edge13, ie11)
    • offsetHeight: 330 (chrome53, ff49, safari9, edge13, ie11)
    • largeur bcr: 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)
    • largeur bcr: 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 (chrome53, ff49, safari9, edge13, ie11)
    • largeur bcr: 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)

Ainsi, en dehors de la valeur de hauteur du boundingClientRect (299.9999694824219 au lieu de 300 attendu) dans edge13 et ie11, les résultats confirment que la théorie derrière cela fonctionne.

De là, voici ma définition de ces concepts:

  • offsetWidth / offsetHeight: dimensions de la zone de bordure de présentation
  • boundingClientRect: dimensions de la zone de bordure de rendu
  • clientWidth / clientHeight: dimensions de la partie visible de la zone de remplissage de la mise en page (à l'exclusion des barres de défilement)
  • scrollWidth / scrollHeight: dimensions de la zone de remplissage de la mise en page si elle n'était pas contrainte par des barres de défilement

Remarque: la largeur de la barre de défilement verticale par défaut est de 12px en bord13, 15px en chrome53, ff49 et safari9, et 17px en ie11 (effectuées par des mesures dans Photoshop à partir de captures d'écran, et prouvées par les résultats des tests).

Cependant, dans certains cas, votre application n'utilise peut-être pas la largeur de la barre de défilement verticale par défaut.

Donc, étant donné les définitions de ces concepts, la largeur de la barre de défilement verticale doit être égale à (en pseudo code):

  • dimension de présentation: offsetWidth - clientWidth - (borderLeftWidth + borderRightWidth)

  • dimension de rendu: boundingClientRect.width - clientWidth - (borderLeftWidth + borderRightWidth)

Remarque, si vous ne comprenez pas la mise en page et le rendu, veuillez lire l'article mdn.

De plus, si vous avez un autre navigateur (ou si vous voulez voir les résultats des tests par vous-même), vous pouvez voir ma page de test ici: http://codepen.io/lingtalfi/pen/BLdBdL

lingue
la source