Comprender offsetWidth, clientWidth, scrollWidth y -Height, respectivamente

385

Hay varias preguntas sobre StackOverflow con respecto a offsetWidth / clientWidth / scrollWidth (y -Height, respectivamente), pero ninguna da una explicación exhaustiva de cuáles son esos valores.

Además, hay varias fuentes en la web que brindan información confusa o incorrecta.

¿Puedes dar una explicación completa que incluya algunos consejos visuales? Además, ¿cómo se pueden usar esos valores para calcular los anchos de la barra de desplazamiento?

usuario123444555621
fuente

Respuestas:

869

El modelo de cuadro CSS es bastante complicado, especialmente cuando se trata de desplazar contenido. Si bien el navegador usa los valores de su CSS para dibujar cuadros, determinar todas las dimensiones usando JS no es sencillo si solo tiene el CSS.

Es por eso que cada elemento tiene seis propiedades DOM para su conveniencia: offsetWidth, offsetHeight, clientWidth, clientHeight, scrollWidthy scrollHeight. Estos son atributos de solo lectura que representan el diseño visual actual, y todos ellos son enteros (posiblemente sujetos a errores de redondeo).

Veamos en detalle:

  • offsetWidth, offsetHeight: El tamaño del cuadro visual que incluye todos los bordes. Se puede calcular agregando width/ heighty rellenos y bordes, si el elemento tienedisplay: block
  • clientWidth, clientHeight: La porción visual del contenido del cuadro, sin incluir bordes ni barras de desplazamiento, pero incluye relleno. No se puede calcular directamente desde CSS, depende del tamaño de la barra de desplazamiento del sistema.
  • scrollWidth, scrollHeight: El tamaño de todo el contenido del cuadro, incluidas las partes que actualmente están ocultas fuera del área de desplazamiento. No se puede calcular directamente desde CSS, depende del contenido.

Modelo de caja CSS2

Pruébelo: jsFiddle


Dado que offsetWidthtiene en cuenta el ancho de la barra de desplazamiento, podemos usarlo para calcular el ancho de la barra de desplazamiento mediante la fórmula

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

Desafortunadamente, puede obtener errores de redondeo, puesto offsetWidthy clientWidthsiempre son números enteros, mientras que los tamaños reales pueden ser fraccionada con niveles de zoom distintos a 1.

Tenga en cuenta que esto

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

no no funcionar de forma fiable en Chrome, ya que Chrome vuelve widthcon barra de desplazamiento ya se restan. (Además, Chrome muestra el relleno de la parte inferior a la parte inferior del contenido de desplazamiento, mientras que otros navegadores no)

usuario123444555621
fuente
27
Para aquellos que buscan una granularidad más fina que los enteros, use element.getBoundingClientRect()(vea la nota en developer.mozilla.org/en-US/docs/Web/API/Element.clientWidth )
Anson Kao
1
Tenga en cuenta que dependiendo de su diseño, scrollWidth y scrollHeight pueden ser realmente útiles para obtener el tamaño de sus pseudo elementos :: before y :: after.
David
Además, sería útil explicar cómo se relacionan naturalWidthynaturalHeight
YakovL
por qué scrollHeightincluye padding-bottompero scrollWidthno incluyepadding-right
JunGor
clientWidthpara document.documentElement.clientWidthes diferente, ya que parece incluir el padding, bordersymargin
Drenai
50

Creé una versión más completa y limpia que algunas personas pueden encontrar útil para recordar qué nombre corresponde a qué valor. Utilicé el código de color de Chrome Dev Tool y las etiquetas están organizadas simétricamente para captar analogías más rápido:

ingrese la descripción de la imagen aquí

  • Nota 1: clientLefttambién incluye el ancho de la barra de desplazamiento vertical si la dirección del texto se establece de derecha a izquierda (ya que la barra se muestra a la izquierda en ese caso)

  • Nota 2: la línea más externa representa el más cercano posicionado padre (un elemento cuya positionpropiedad está ajustado a un valor diferente de statico initial). Por lo tanto, si el contenedor directo no es un elemento posicionado , entonces la línea no representa el primer contenedor en la jerarquía sino otro elemento más alto en la jerarquía. Si no se encuentra ningún padre posicionado , el navegador tomará el elemento htmlo bodycomo referencia


Espero que alguien lo encuentre útil, solo mis 2 centavos;)

Lual
fuente
30

Si desea usar scrollWidth para obtener el ANCHO / ALTURA DE CONTENIDO "REAL" (ya que el contenido puede ser MÁS GRANDE que el ancho / alto-cuadro definido por css), el ancho / alto de desplazamiento es muy poco confiable ya que algunos navegadores parecen "MOVER" el relleno DERECHO & paddingBOTTOM si el contenido es demasiado grande. Luego colocan los rellenos a la DERECHA / ABAJO del "contenido demasiado amplio / alto" (vea la imagen a continuación).

==> Por lo tanto, para obtener el ANCHO DE CONTENIDO REAL en algunos navegadores, debe restar AMBOS rellenos del ancho de desplazamiento y en algunos navegadores solo debe restar el Relleno IZQUIERDO.

Encontré una solución para esto y quería agregar esto como un comentario, pero no estaba permitido. Así que tomé la foto y la hice un poco más clara con respecto a los "rellenos movidos" y el "ancho de desplazamiento poco confiable". ¡En el ÁREA AZUL encontrará mi solución sobre cómo obtener el ANCHO DE CONTENIDO "REAL"!

¡Espero que esto ayude a aclarar las cosas!

ingrese la descripción de la imagen aquí

Manny_user3297459
fuente
13

Hay un buen artículo sobre MDN que explica la teoría detrás de esos conceptos: https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements

También explica las importantes diferencias conceptuales entre el ancho / alto del límite de ClientRect frente a offsetWidth / offsetHeight.

Luego, para demostrar que la teoría es correcta o incorrecta, necesita algunas pruebas. Eso es lo que hice aquí: https://github.com/lingtalfi/dimensions-cheatsheet

Está probando chrome53, ff49, safari9, edge13 e ie11.

Los resultados de las pruebas demuestran que la teoría es generalmente correcta. Para las pruebas, creé 3 divs que contienen 10 párrafos lorem ipsum cada uno. Se les aplicó algo de CSS:

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

Y aquí están los resultados:

  • div1

    • offsetWidth: 530 (chrome53, ff49, safari9, edge13, ie11)
    • offsetHeight: 330 (chrome53, ff49, safari9, edge13, ie11)
    • ancho bcr: 530 (chrome53, ff49, safari9, edge13, ie11)
    • bcr. altura: 330 (chrome53, ff49, safari9, edge13, ie11)

    • ancho del cliente: 505 (chrome53, ff49, safari9)

    • Ancho del cliente: 508 (edge13)
    • Ancho del cliente: 503 (es decir, 11)
    • 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. altura: 300 (chrome53, ff49, safari9)
    • bcr. altura: 299.9999694824219 (edge13, ie11)
    • ancho del cliente: 475 (chrome53, ff49, safari9)
    • Ancho del cliente: 478 (edge13)
    • Ancho del cliente: 473 (es decir, 11)
    • 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)
    • ancho bcr: 265 (chrome53, ff49, safari9, edge13, ie11)
    • bcr. altura: 165 (chrome53, ff49, safari9, edge13, ie11)
    • ancho del cliente: 505 (chrome53, ff49, safari9)
    • Ancho del cliente: 508 (edge13)
    • Ancho del cliente: 503 (es decir, 11)
    • 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)

Por lo tanto, aparte del valor de altura del límite de ClientRect (299.9999694824219 en lugar del esperado 300) en edge13 e ie11, los resultados confirman que la teoría detrás de esto funciona.

A partir de ahí, aquí está mi definición de esos conceptos:

  • offsetWidth / offsetHeight: dimensiones del cuadro de borde de diseño
  • boundingClientRect: dimensiones del cuadro de borde de representación
  • clientWidth / clientHeight: dimensiones de la parte visible del cuadro de relleno de diseño (excluyendo las barras de desplazamiento)
  • scrollWidth / scrollHeight: dimensiones del cuadro de relleno de diseño si no estaba limitado por las barras de desplazamiento

Nota: el ancho predeterminado de la barra de desplazamiento vertical es 12px en edge13, 15px en chrome53, ff49 y safari9, y 17px en ie11 (hecho por mediciones en photoshop a partir de capturas de pantalla, y demostrado por los resultados de las pruebas).

Sin embargo, en algunos casos, tal vez su aplicación no esté utilizando el ancho predeterminado de la barra de desplazamiento vertical.

Entonces, dadas las definiciones de esos conceptos, el ancho de la barra de desplazamiento vertical debe ser igual a (en pseudocódigo):

  • dimensión de diseño: offsetWidth - clientWidth - (borderLeftWidth + borderRightWidth)

  • dimensión de representación: boundingClientRect.width - clientWidth - (borderLeftWidth + borderRightWidth)

Tenga en cuenta que si no comprende el diseño frente a la representación, lea el artículo de mdn.

Además, si tiene otro navegador (o si desea ver los resultados de las pruebas por sí mismo), puede ver mi página de prueba aquí: http://codepen.io/lingtalfi/pen/BLdBdL

abadejo
fuente