Comprendre offsetWidth, clientWidth, scrollWidth et -Height, respectivement

Il existe 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 donnant des informations confuses ou incorrectes.

Pouvez-vous donner une explication complète, y compris des indications visuelles? En outre, comment ces valeurs peuvent-elles être utilisées pour calculer les largeurs des barres de défilement?

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

C’est pourquoi chaque élément possède six propriétés DOM pour votre commodité: offsetWidth , offsetHeight , clientWidth , clientHeight , scrollWidth et scrollHeight . Ce sont des atsortingbuts en lecture seule représentant la disposition visuelle en cours, et tous sont des entiers (pouvant donc être soumis à des erreurs d’arrondi).

Voyons-les en détail:

  • offsetWidth , offsetHeight : taille de la boîte visuelle incluant toutes les bordures. Peut être calculé en ajoutant width / height et paddings and borders, si l’élément est display: block
  • clientWidth , clientHeight : la partie visuelle du contenu de la boîte, à l’ clientHeight bordures ou des barres de défilement, mais inclut le remplissage. Ne peut être calculé directement à partir de CSS, en fonction de la taille de la barre de défilement du système.
  • scrollWidth , scrollHeight : 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 être calculé directement à partir de CSS, dépend du contenu.

Modèle de boîte CSS2

Essayez-le: jsFiddle


Comme offsetWidth prend 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 pouvons obtenir des erreurs d’arrondi, car offsetWidth et clientWidth sont toujours des entiers, alors que les tailles réelles peuvent être fractionnées 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, puisque Chrome renvoie la width avec la barre de défilement déjà soustraite. (En outre, Chrome rend paddingBottom au bas du contenu de défilement, contrairement aux autres navigateurs)

Si vous voulez utiliser scrollWidth pour obtenir la LARGEUR / HAUTEUR DE CONTENU “REAL” (car le contenu peut être PLUS GRAND que la largeur / hauteur-boîte définie par CSS), le scrollWidth / Height est très INRELIABLE car certains navigateurs semblent “DÉPLACER” & paddingBOTTOM si le contenu est trop gros. Ils placent ensuite les rembourrages à DROITE / BAS du “contenu trop large / élevé” (voir image ci-dessous).

==> Par conséquent, pour obtenir la LARGEUR DE CONTENU REEL dans certains navigateurs, vous devez soustraire les deux éléments de la largeur de défilement et, dans certains navigateurs, il suffit de soustraire le remplissage LEFT.

J’ai trouvé une solution pour cela et je voulais append ceci comme un 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 “paddings déplacés” et la “scrollWidth non fiable”. Dans la zone bleue, vous trouverez ma solution pour obtenir la LARGEUR DE CONTENU “REAL”!

J’espère que cela aidera à rendre les choses encore plus claires!

entrer la description de l'image ici

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

entrer la description de l'image ici

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

  • Remarque 2: la ligne la plus extérieure représente le parent le plus proche (un élément dont la propriété de position est définie sur une valeur différente de la valeur static ou 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 prend comme référence l’élément html ou body


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

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

Elle explique également les différences conceptuelles importantes entre width / height et offsetWidth / offsetHeight de boundingClientRect.

Ensuite, pour prouver la théorie correcte ou non, 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 div contenant 10 paragraphes de 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)
    • 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 (chrome53, 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)

Ainsi, hormis la valeur de hauteur de boundingClientRect (299.9999694824219 au lieu de 300 attendue) dans edge13 et ie11, les résultats confirment que la théorie sous-jacente fonctionne.

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

  • offsetWidth / offsetHeight: dimensions de la zone de bordure de la disposition
  • boundingClientRect: dimensions de la zone de bordure de rendu
  • clientWidth / clientHeight: dimensions de la partie visible de la boîte de remplissage d’agencement (sauf les barres de défilement)
  • scrollWidth / scrollHeight: dimensions de la zone de remplissage de la mise en page si elles ne sont pas contraintes par les barres de défilement

Note: la largeur de la barre de défilement verticale par défaut est 12px dans edge13, 15px dans chrome53, ff49 et safari9, et 17px dans ie11 (effectuée par des mesures dans photoshop à partir de captures d’écran et prouvée 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 la mise en page: offsetWidth – clientWidth – (borderLeftWidth + borderRightWidth)

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

Notez que si vous ne comprenez pas la mise en page et le rendu, lisez l’article mdn.

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