Compruebe si el elemento HTML tiene barras de desplazamiento

113

¿Cuál es la forma más rápida de comprobar si un elemento tiene barras de desplazamiento?

Una cosa, por supuesto, es verificar si el elemento es más grande que su ventana gráfica, lo que se puede hacer fácilmente verificando estos dos valores:

el.scrollHeight > el.offsetHeight || el.scrollWidth > el.offsetWidth

pero eso no significa que también tenga barras de desplazamiento (por lo que los humanos pueden desplazarlo).

Pregunta

¿Cómo verifico las barras de desplazamiento en 1 navegador cruzado y 2 solo javascript (como sin jQuery )?

Solo Javascript, porque necesito la menor sobrecarga posible, porque me gustaría escribir un filtro selector de jQuery muy rápido

// check for specific scrollbars
$(":scrollable(x/y/both)")

// check for ANY scrollbar
$(":scrollable")

Supongo que tendría que verificar la overflowconfiguración de estilo, pero ¿cómo lo hago en un navegador cruzado?

Edición adicional

No solo overflowconfiguraciones de estilo. Comprobar si un elemento tiene barra de desplazamiento no es tan trivial como parece. La primera fórmula que escribí arriba funciona bien cuando el elemento no tiene un borde, pero cuando lo tiene (especialmente cuando el borde tiene un ancho considerable), la offsetdimensión puede ser mayor que la scrolldimensión, pero el elemento aún se puede desplazar. De hecho, tenemos que restar los bordes de la offsetdimensión para obtener la ventana gráfica desplazable real del elemento y compararla con la scrolldimensión.

Para futura referencia

:scrollableEl filtro selector de jQuery está incluido en mi .scrollintoview()complemento jQuery. El código completo se puede encontrar en la publicación de mi blog si alguien lo necesita. Aunque no proporcionó la solución real, el código de Soumya me ayudó considerablemente a resolver el problema. Me apuntó en la dirección correcta.

Robert Koritnik
fuente

Respuestas:

118

Encontré esto en algún lugar hace un par de semanas. Funcionó para mí.

var div = document.getElementById('container_div_id');

var hasHorizontalScrollbar = div.scrollWidth > div.clientWidth;
var hasVerticalScrollbar = div.scrollHeight > div.clientHeight;

/* you'll get true/false */
jzhinga
fuente
12
Obviamente, ha tenido un ejemplo simplificado. ¿Qué pasa si su contenedor se ha overflow:hiddenasentado? Habría contenido en exceso, pero aún no es desplazable. El problema no es tan simple como parece.
Robert Koritnik
7
Puede que esta no sea la solución aceptada, pero funcionó para mí. No estoy seguro de por qué lo desplazaría si está oculto.
vol7ron
Puede que esta no sea la solución aceptada, pero funcionó para mí. Robert, para esos casos, ¿no podría también obtener la propiedad de desbordamiento de css para probar esos casos (por ejemplo div.scrollHeight>div.clientHeight && !(div.style.overflow && div.style.overflow == 'hidden'))?
Vol7ron
7
Esto falla en muchos casos. Si su elemento tiene desbordamiento: visible; ancho: 200px; y tiene un elemento secundario con un ancho de 500px, su elemento no tiene barras de desplazamiento pero tiene un scrollWidth de 500px y un clientWidth de 200px.
Joseph Lennox
1
Si el desbordamiento es visible u oculto, generalmente no hay barras de desplazamiento.
Hubert Grzeskowiak
16

Tratar:

Para barra de desplazamiento vertical

el.scrollHeight> el.clientHeight

Para barra de desplazamiento horizontal

el.scrollWidth> el.clientWidth

Sé que esto funciona para IE8 y Firefox 3.6+ al menos.

Gary
fuente
2
Señalé esto, sí, que esto me dice que cierto elemento es más grande de lo que parece, pero eso no significa que muestre barras de desplazamiento. También puede haberlo hecho overflow:hiddeny ya no sería desplazable.
Robert Koritnik
1
Y comprobar con los valores de clientHeight / clientWidth no da buenos resultados, porque los elementos también pueden tener bordes, que no están incluidos en esta medida. Revisa mi fórmula. Funciona mejor que el tuyo.
Robert Koritnik
Eso es cierto acerca del uso de offsetHeight / offsetWidth para verificar las barras de desplazamiento en lugar de clientHeight / clientWidth. Gracias por señalar eso.
Gary
@RobertKoritnik: solo verifique si ese elemento específico tiene overflow:hidden... esta sigue siendo la respuesta correcta en mi opinión, ya que es la más simple.
vsync
14

Esto puede parecer (o ser) un poco complicado, pero puede probar las propiedades scrollTopy scrollLeft.

Si son mayores que 0, sabrá que hay barras de desplazamiento. Si son 0, configúrelos en 1 y pruébelos nuevamente para ver si obtiene un resultado de 1. Luego, vuelva a configurarlos en 0.

Ejemplo: http://jsfiddle.net/MxpR6/1/

function hasScroll(el, direction) {
    direction = (direction === 'vertical') ? 'scrollTop' : 'scrollLeft';
    var result = !! el[direction];

    if (!result) {
        el[direction] = 1;
        result = !!el[direction];
        el[direction] = 0;
    }
    return result;
}

alert('vertical? ' + hasScroll(document.body, 'vertical'));
alert('horizontal? ' + hasScroll(document.body, 'horizontal'));

Creo que hay una propiedad diferente para IE, así que lo actualizaré en un minuto.

EDITAR: Parece que IE puede admitir esta propiedad. (No puedo probar IE en este momento).

http://msdn.microsoft.com/en-us/library/ms534618(VS.85).aspx

usuario113716
fuente
Es mucho más fácil buscar barras de desplazamiento si compara offsetHeighty clientHeight. Este último es siempre menor por el tamaño de la barra de desplazamiento cuando la barra de desplazamiento está presente.
Robert Koritnik
@Robert: No estoy seguro de que sea más fácil, pero veo cómo funciona. Entonces supongo que si un elemento lo ha hecho overflow:scroll, desea que se informe como desplazable, ya sea que las barras de desplazamiento estén habilitadas o no. Por supuesto, mi solución podría tener problemas si hay un evento onscroll adjunto.
user113716
Realmente no. Si marca mi complemento jQuery , tengo que encontrar un ancestro desplazable real, de lo contrario, no puedo desplazar un elemento a la vista.
Robert Koritnik
8
@RobertKoritnik No es cierto; algunos navegadores pueden tener barras de desplazamiento que no reducen el ancho. En un OS X, por ejemplo. O dispositivos táctiles.
daniel.gindi
1
Siempre devuelve falso
Fatih Erol
14

Aquí hay otra solución:

Como señalaron algunas personas, simplemente comparar offsetHeight y scrollHeight no es suficiente ya que difieren en elementos con desbordamiento oculto, etc., que aún no tienen barras de desplazamiento. Entonces, aquí también estoy verificando si el desbordamiento es de desplazamiento o automático en los estilos calculados para el elemento:

var isScrollable = function(node) {
  var overflowY = window.getComputedStyle(node)['overflow-y'];
  var overflowX = window.getComputedStyle(node)['overflow-x'];
  return {
    vertical: (overflowY === 'scroll' || overflowY === 'auto') && node.scrollHeight > node.clientHeight,
    horizontal: (overflowX === 'scroll' || overflowX === 'auto') && node.scrollWidth > node.clientWidth,
  };
}
lotif
fuente
Si overflow*es scrollque siempre habrá una barra de desplazamiento, así que creo que quieres vertical: overflowY === 'scroll' || overflowY === 'auto' && node.scrollHeight > node.clientHeight, etc (es decir, eliminar los soportes de manera scroll*vs client*está comprobado solamente cuando overflow*es auto). De lo contrario, esta parece ser la solución más correcta.
Jake
@Jake Si scrollHeight <clientHeight en el desbordamiento de desplazamiento, las barras de desplazamiento estarán allí pero se deshabilitarán (es decir, el elemento no se puede desplazar). Entonces creo que depende de la aplicación. Su modificación es válida si simplemente desea verificar las barras de desplazamiento, sin importar el estado. Para mí, cuando se me ocurrió esto, estaba buscando implementar el desplazamiento automático para un componente, por lo que tener deshabilitadas las barras de desplazamiento es inútil en ese caso. Ese también parece ser el caso de esta pregunta (debe ser "desplazada por humanos")
lotif
6

Tal vez llegue un poco tarde a la fiesta, pero ...

Creo que puede detectar barras de desplazamiento con e.offsetWidth frente a e.clientWidth. El ancho de compensación incluye bordes y barras de desplazamiento, relleno y ancho. El ancho del cliente incluye relleno y ancho. Por favor mira:

https://developer.mozilla.org/en/DOM/element.offsetWidth (segunda imagen) https://developer.mozilla.org/en/DOM/element.clientWidth (segunda imagen)

Necesitas comprobar:

  1. Si el elemento tiene desbordamiento configurado en automático / desplazamiento (incluido overflowX / Y) usando el estilo calculado / en cascada / actual.
  2. Si el elemento tiene desbordamiento configurado en auto / scroll. Establezca offsetWidth y clientWidth.
  3. Si el clientWidth es menor que el offsetWidth - borde derecho (que se encuentra nuevamente a través del estilo calculado / en cascada / actual), entonces sabrá que tiene una barra de desplazamiento.

Haga lo mismo para la vertical (offset / clientHeight).

IE7 informa un clientHeight de 0 para algunos elementos (no he verificado por qué), por lo tanto, siempre necesita la primera verificación de desbordamiento.

¡Espero que esto ayude!


fuente
3

Hay varios problemas en caso de verificar la existencia de barras de desplazamiento, uno de los cuales es que en Mac no tiene ninguna barra de desplazamiento visible, por lo que las dos soluciones anteriores no le darían una respuesta precisa.

Entonces, debido a que la representación del navegador no es muy frecuente, puede verificar el desplazamiento con el cambio de desplazamiento y luego volver a configurarlo:

const hasScrollBar = (element) => {
  const {scrollTop} = element;

  if(scrollTop > 0) {
    return true;
  }

  element.scrollTop += 10;

  if(scrollTop === element.scrollTop) {
    return false;
  }

  // undoing the change
  element.scrollTop = scrollTop;
  return true;
};

hakobpogh
fuente
1

Simplemente jugando aquí ya que ninguna de las soluciones anteriores funcionó para mí (hasta ahora). He tenido cierto éxito al comparar la altura de desplazamiento de una div con su altura de desplazamiento.

var oh = $('#wrapDiv').get(0).offsetHeight;
var sh = $('#wrapDiv').get(0).scrollHeight;

Parece darme una comparación precisa ... hasta ahora. ¿Alguien sabe si esto es legítimo?

Miguel
fuente
2
Creo que quieres scrollHeight y clientHeight: stackoverflow.com/questions/4106538/…
rich remer
1

Para IE11 (Internet Explorer 11) tuve que cambiar la lógica a:

// Subtract 3 (a small arbitrary number) to allow for IE reporting a difference of 1 when no scrollbar is present
var hasVerticalScrollbar = div.scrollHeight - 3 > div.clientHeight;

Esto se debe a que IE informa scrollHeight como 1 más grande que clientHeight cuando no hay barra de desplazamiento, pero aproximadamente 9 más grande cuando hay una barra de desplazamiento.

danday74
fuente
0

Si necesita saber si hay una barra de desplazamiento presente para toda la página web y con soporte completo del navegador , puede usar esto:

const hasScrollbar = document.body.scrollHeight > window.innerHeight

Es importante usarlo en window.innerHeightlugar de document.body.clientHeightporque en algunos navegadores móviles clientHeight no obtendrá el tamaño de la barra de direcciones, pero scrollHeight sí, por lo que obtendrá cálculos incorrectos.

Sebastián Hernández
fuente
-5

ninguna de estas respuestas es correcta. tienes que usar esto:

var div = document.getElementById('container_div_id');

var hasHorizontalScrollbar = (div.offsetWidth > div.clientWidth);
var hasVerticalScrollbar = (div.offsetHeight > div.clientHeight);
Hamid
fuente
Se votó negativamente porque se copió / pegó de la respuesta aceptada de hace 6 años y no necesita paréntesis para convertir algo en un booleano.
moto
-6

Agrega un elemento 100% ancho en su interior. Luego, establezca el desbordamiento en oculto. Si cambia el estilo calculado del elemento (de jQ), el padre tenía una barra de desplazamiento.

EDITAR: Parece que desea un método de navegador cruzado como getComputedStyle . Tratar:

function getCSS(_elem, _style)
{
    var computedStyle;
    if (typeof _elem.currentStyle != 'undefined')
        computedStyle = _elem.currentStyle;
    else
        computedStyle = document.defaultView.getComputedStyle(_elem, null);
    return computedStyle[_style];
}
Soumya
fuente
1
Si ya usara jQuery para esto, preferiría hacerlo $(el).css("overflow/overflowX/overflowY")y ver si está configurado en automático o en desplazamiento . Pero me gustaría evitar usar jQuery.
Robert Koritnik
16
Los estilos CSS NO le dirán si un elemento tiene barras de desplazamiento o no . Solo si puede tener barras de desplazamiento o no . ¿Quizás encuentre un método de navegador cruzado para determinar el ancho del elemento interno?
Soumya
@ Soumya92: La comparación de tamaño entre el tamaño desplazable y el real es trivial y lo escribí arriba ... Todo lo que necesito verificar ahora es la configuración de desbordamiento actual en un elemento en particular.
Robert Koritnik
@ Soumya92: eso es exactamente lo que necesito. También se puede simplificar mucho usando coalescecomputedStyle = el.currentStyle || document.defaultView.getComputedStyle(el, null);
Robert Koritnik
Una cosa más: ¿Qué tan cruzado es este navegador? ¿Qué navegadores son compatibles con esto?
Robert Koritnik