¿Cómo puedo verificar si hay una barra de desplazamiento visible?

277

¿Es posible verificar el overflow:autode un div?

Por ejemplo:

HTML

<div id="my_div" style="width: 100px; height:100px; overflow:auto;" class="my_class"> 
  * content
</div>

JQUERY

$('.my_class').live('hover', function (event)
{
    if (event.type == 'mouseenter')
    {
         if( ...  if scrollbar visible ? ... )
         {
            alert('true'):
         }
         else
         {
            alert('false'):
         }
    }

});

A veces el contenido es corto (sin barra de desplazamiento) y a veces largo (barra de desplazamiento visible).

Peter
fuente

Respuestas:

376

un pequeño plugin para ello

(function($) {
    $.fn.hasScrollBar = function() {
        return this.get(0).scrollHeight > this.height();
    }
})(jQuery);

úsalo así,

$('#my_div1').hasScrollBar(); // returns true if there's a `vertical` scrollbar, false otherwise..

probado trabajando en Firefox, Chrome, IE6,7,8

pero no funciona correctamente en el bodyselector de etiquetas

manifestación


Editar

Descubrí que cuando tienes una barra de desplazamiento horizontal que hace que aparezca la barra de desplazamiento vertical, esta función no funciona ...

Encontré otra solución ... uso clientHeight

return this.get(0).scrollHeight > this.get(0).clientHeight;
Reigel
fuente
22
Si tiene relleno necesita usar > this.innerHeight(); jsfiddle.net/p3FFL/210
jcubic
2
Hay un problema con esto, si también existe una barra de desplazamiento horizontal, esto devolverá falso incluso si existe una barra de desplazamiento vertical hasta que la altura se haya reducido por la altura de la barra de desplazamiento horizontal.
Ally
¿Por qué has definido la misma función dos veces? @jcubic
Nitin Sawant
9
Tenga en cuenta que en Mac, la barra de desplazamiento flota sobre el contenido y desaparece cuando no está en uso. En Windows siempre es visible y ocupa espacio horizontal. Por lo tanto, el hecho de que el contenido se pueda desplazar (que esta función detecta) no significa que una barra de desplazamiento esté necesariamente presente.
Andrew
2
(function ($) {$ .fn.hasScrollBar = function () {return this.get (0) .scrollWidth> this.width); }}) (jQuery); Esto funciona para el overfolow horizontal. Bueno para verificar la capacidad de respuesta móvil en sitios web en iframes.
Alexander Nicholas Popa
57

Quizás una solución más simple.

if ($(document).height() > $(window).height()) {
    // scrollbar
}
Sean Zheng
fuente
Esta respuesta funcionó para mí después de verificar si el DOM está listo usando JQuery.ready()
Simple Sandman
44
Esto supone que la barra de desplazamiento está en la ventana y no un elemento div. Proponga cambiar la referencia para sugerir: "Si solo necesita probar la barra de desplazamiento en la ventana principal, puede intentar:"
justdan23
43

Puede hacerlo utilizando una combinación de los atributos Element.scrollHeighty Element.clientHeight.

De acuerdo con MDN:

El atributo Element.scrollHeight de solo lectura es una medida de la altura del contenido de un elemento, incluido el contenido no visible en la pantalla debido al desbordamiento. El valor scrollHeight es igual al valor mínimo clientHeight que requeriría el elemento para ajustar todo el contenido en el punto de vista sin usar una barra de desplazamiento vertical. Incluye el relleno del elemento pero no su margen.

Y:

La propiedad de solo lectura Element.clientHeight devuelve la altura interna de un elemento en píxeles, incluido el relleno, pero no la altura, borde o margen de la barra de desplazamiento horizontal.

clientHeight se puede calcular como altura de CSS + relleno de CSS: altura de la barra de desplazamiento horizontal (si está presente).

Por lo tanto, el elemento mostrará una barra de desplazamiento si la altura de desplazamiento es mayor que la altura del cliente, por lo que la respuesta a su pregunta es:

function scrollbarVisible(element) {
  return element.scrollHeight > element.clientHeight;
}
Ajedi32
fuente
2
ejemplo: github.com/twbs/bootstrap/blob/master/js/modal.js#L242 y +1 para la cotización y explicación de MDN.
lowtechsun
en cromo si el contenido tiene un borde que no está incluido en scrollHeight
AL
1
Votaron a favor de no faltar y usar un marco / biblioteca.
John
Cuidado: esto provoca un reflujo, que es un drenaje de rendimiento. gist.github.com/paulirish/5d52fb081b3570c81e3a
Todd Sjolander
43

Debería cambiar algo de lo que dijo Reigel:

(function($) {
    $.fn.hasScrollBar = function() {
        return this[0] ? this[0].scrollHeight > this.innerHeight() : false;
    }
})(jQuery);

innerHeight cuenta la altura del control y sus acolchados superior e inferior

kpull1
fuente
return (this.get (0))? this.get (0) .scrollHeight> this.innerHeight (): falso;
commonpike
3
Creo que esto debería asignarse como la respuesta correcta. Esto funcionó en FF35, IE11 y Chrome39.
LucasBr
No comprueba el valor de 'desbordamiento' para asegurarse de que aparecerán barras de desplazamiento cuando se cumpla esa condición de desplazamiento de altura.
BT
1
@BT Pero si tengo el desbordamiento configurado en automático en mi CSS, ¿entonces no necesito esta verificación adicional? Compara tamaños y eso es suficiente ...?
Andrew
Una respuesta que solo funciona para ti no es una respuesta ... ¿cómo sabes lo que otras personas tienen en su CSS? Su respuesta no menciona esa limitación. Si alguien no puede dejar caer su respuesta y hacer que funcione, no es una buena respuesta.
BT
27

Esto se expande en la respuesta de @ Reigel. Devolverá una respuesta para las barras de desplazamiento horizontal o vertical.

(function($) {
    $.fn.hasScrollBar = function() {
        var e = this.get(0);
        return {
            vertical: e.scrollHeight > e.clientHeight,
            horizontal: e.scrollWidth > e.clientWidth
        };
    }
})(jQuery);

Ejemplo:

element.hasScrollBar()             // Returns { vertical: true/false, horizontal: true/false }
element.hasScrollBar().vertical    // Returns true/false
element.hasScrollBar().horizontal  // Returns true/false
the4tress
fuente
8

Hice una nueva costumbre: pseudo selector para jQuery para probar si un elemento tiene una de las siguientes propiedades css:

  1. desbordamiento: [scroll | auto]
  2. overflow-x: [scroll | auto]
  3. overflow-y: [scroll | auto]

Quería encontrar el padre desplazable más cercano de otro elemento, así que también escribí otro pequeño complemento jQuery para encontrar el padre más cercano con desbordamiento.

Es probable que esta solución no funcione mejor, pero parece funcionar. Lo usé junto con el complemento $ .scrollTo. A veces necesito saber si un elemento está dentro de otro contenedor desplazable. En ese caso, quiero desplazar el elemento desplazable principal frente a la ventana.

Probablemente debería haber envuelto esto en un solo complemento y agregar el selector psuedo como parte del complemento, así como exponer un método 'más cercano' para encontrar el contenedor desplazable más cercano (principal).

De todos modos ... aquí está.

$ .is Plugin jQuery desplazable:

$.fn.isScrollable = function(){
    var elem = $(this);
    return (
    elem.css('overflow') == 'scroll'
        || elem.css('overflow') == 'auto'
        || elem.css('overflow-x') == 'scroll'
        || elem.css('overflow-x') == 'auto'
        || elem.css('overflow-y') == 'scroll'
        || elem.css('overflow-y') == 'auto'
    );
};

$ (': desplazable') pseudo selector de jQuery:

$.expr[":"].scrollable = function(a) {
    var elem = $(a);
    return elem.isScrollable();
};

$ .scrollableparent () plugin jQuery:

$.fn.scrollableparent = function(){
    return $(this).closest(':scrollable') || $(window); //default to $('html') instead?
};

La implementación es bastante simple

//does a specific element have overflow scroll?
var somedivIsScrollable = $(this).isScrollable();
//use :scrollable psuedo selector to find a collection of child scrollable elements
var scrollableChildren = $(this).find(':scrollable');
//use $.scrollableparent to find closest scrollable container
var scrollableparent = $(this).scrollableparent();

ACTUALIZAR: descubrí que Robert Koritnik ya ideó un pseudo selector desplazable mucho más poderoso que identificará los ejes desplazables y la altura de los contenedores desplazables, como parte de su complemento jQuery $ .scrollintoview (). plugin scrollintoview

Aquí está su elegante pseudo selector (accesorios):

    $.extend($.expr[":"], {

    scrollable: function (element, index, meta, stack) {

        var direction = converter[typeof (meta[3]) === "string" && meta[3].toLowerCase()] || converter.both;

        var styles = (document.defaultView && document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(element, null) : element.currentStyle);

        var overflow = {

            x: scrollValue[styles.overflowX.toLowerCase()] || false,

            y: scrollValue[styles.overflowY.toLowerCase()] || false,

            isRoot: rootrx.test(element.nodeName)

        };



        // check if completely unscrollable (exclude HTML element because it's special)

        if (!overflow.x && !overflow.y && !overflow.isRoot)

        {

            return false;

        }



        var size = {

            height: {

                scroll: element.scrollHeight,

                client: element.clientHeight

            },

            width: {

                scroll: element.scrollWidth,

                client: element.clientWidth

            },

            // check overflow.x/y because iPad (and possibly other tablets) don't dislay scrollbars

            scrollableX: function () {

                return (overflow.x || overflow.isRoot) && this.width.scroll > this.width.client;

            },

            scrollableY: function () {

                return (overflow.y || overflow.isRoot) && this.height.scroll > this.height.client;

            }

        };

        return direction.y && size.scrollableY() || direction.x && size.scrollableX();

    }

});
thegrandoverseer
fuente
6

La primera solución anterior solo funciona en IE La segunda solución anterior solo funciona en FF

Esta combinación de ambas funciones funciona en ambos navegadores:

//Firefox Only!!
if ($(document).height() > $(window).height()) {
    // has scrollbar
    $("#mtc").addClass("AdjustOverflowWidth");
    alert('scrollbar present - Firefox');
} else {
    $("#mtc").removeClass("AdjustOverflowWidth");
}

//Internet Explorer Only!!
(function($) {
    $.fn.hasScrollBar = function() {
        return this.get(0).scrollHeight > this.innerHeight();
    }
})(jQuery);
if ($('#monitorWidth1').hasScrollBar()) {
    // has scrollbar
    $("#mtc").addClass("AdjustOverflowWidth");
    alert('scrollbar present - Internet Exploder');
} else {
    $("#mtc").removeClass("AdjustOverflowWidth");
}​
  • Envuelva en un documento listo
  • monitorWidth1: el div donde el desbordamiento se establece en automático
  • mtc: un contenedor div dentro de monitorWidth1
  • AdjustOverflowWidth: una clase css aplicada al div #mtc cuando la barra de desplazamiento está activa * Use la alerta para probar el navegador cruzado y luego comente el código de producción final.

HTH

Aaron Hopkins
fuente
6

(scrollWidth / Height - clientWidth / Height) es un buen indicador de la presencia de una barra de desplazamiento, pero le dará una respuesta "falsa positiva" en muchas ocasiones. Si necesita ser preciso, le sugiero que utilice la siguiente función. en lugar de tratar de adivinar si el elemento es desplazable, puede desplazarlo ...

function isScrollable( el ){
  var y1 = el.scrollTop;
  el.scrollTop  += 1;
  var y2 = el.scrollTop;
  el.scrollTop  -= 1;
  var y3 = el.scrollTop;
  el.scrollTop   = y1;
  var x1 = el.scrollLeft;
  el.scrollLeft += 1;
  var x2 = el.scrollLeft;
  el.scrollLeft -= 1;
  var x3 = el.scrollLeft;
  el.scrollLeft  = x1;
  return {
    horizontallyScrollable: x1 !== x2 || x2 !== x3,
    verticallyScrollable: y1 !== y2 || y2 !== y3
  }
}
function check( id ){
  alert( JSON.stringify( isScrollable( document.getElementById( id ))));
}
#outer1, #outer2, #outer3 {
  background-color: pink;
  overflow: auto;
  float: left;
}
#inner {
  width:  150px;
  height: 150px;
}
button {  margin: 2em 0 0 1em; }
<div id="outer1" style="width: 100px; height: 100px;">
  <div id="inner">
    <button onclick="check('outer1')">check if<br>scrollable</button>
  </div>
</div>
<div id="outer2" style="width: 200px; height: 100px;">
  <div id="inner">
    <button onclick="check('outer2')">check if<br>scrollable</button>
  </div>
</div>
<div id="outer3" style="width: 100px; height: 180px;">
  <div id="inner">
    <button onclick="check('outer3')">check if<br>scrollable</button>
  </div>
</div>

Yair Levy
fuente
¿En qué ocasiones dará un falso positivo?
GaloisGirl
5

Ugh, las respuestas de todos aquí están incompletas, y dejemos de usar jquery en las respuestas SO, por favor. Consulte la documentación de jquery si desea información sobre jquery.

Aquí hay una función generalizada de javascript puro para probar si un elemento tiene barras de desplazamiento de forma completa:

// dimension - Either 'y' or 'x'
// computedStyles - (Optional) Pass in the domNodes computed styles if you already have it (since I hear its somewhat expensive)
function hasScrollBars(domNode, dimension, computedStyles) {
    dimension = dimension.toUpperCase()
    if(dimension === 'Y') {
        var length = 'Height'
    } else {
        var length = 'Width'
    }

    var scrollLength = 'scroll'+length
    var clientLength = 'client'+length
    var overflowDimension = 'overflow'+dimension

    var hasVScroll = domNode[scrollLength] > domNode[clientLength]


    // Check the overflow and overflowY properties for "auto" and "visible" values
    var cStyle = computedStyles || getComputedStyle(domNode)
    return hasVScroll && (cStyle[overflowDimension] == "visible"
                         || cStyle[overflowDimension] == "auto"
                         )
          || cStyle[overflowDimension] == "scroll"
}
BT
fuente
44
¿Por qué evitar usar jquery en una pregunta marcada como jquery? Agregue enlaces a la parte de la documentación de jquery que menciona.
kpull1
66
@ kpull1 Demasiadas personas etiquetan jQuery en cada pregunta de JavaScript que tienen. Esta pregunta tiene 0 relación con jQuery. No es ninguna parte de la documentación de jQuery que tiene la respuesta, porque jQuery no lo hace, ni debe.
BT
4

Voy a ampliar esto aún más para aquellas pobres almas que, como yo, usan uno de los modernos frameworks js y no JQuery y han sido totalmente abandonados por la gente de este hilo:

esto se escribió en Angular 6 pero si escribe React 16, Vue 2, Polymer, Ionic, React-Native, sabrá qué hacer para adaptarlo. Y es todo el componente, por lo que debería ser fácil.

import {ElementRef, AfterViewInit} from '@angular/core';

@Component({
  selector: 'app',
  templateUrl: './app.html',
  styleUrls: ['./app.scss']
})
export class App implements AfterViewInit {
scrollAmount;

constructor(
  private fb: FormBuilder,
  private element: ElementRef 
) {}

ngAfterViewInit(){
  this.scrollAmount = this.element.nativeElement.querySelector('.elem-list');
  this.scrollAmount.addEventListener('wheel', e => { //you can put () instead of e
  // but e is usefull if you require the deltaY amount.
    if(this.scrollAmount.scrollHeight > this.scrollAmount.offsetHeight){
       // there is a scroll bar, do something!
    }else{
       // there is NO scroll bar, do something!
    }
  });
}
}

en el html habría un div con la clase "elem-list" que está estilizada en css o scss para tener un heighty un overflowvalor que no lo es hidden. (tan autoosroll )

Disparo esta evaluación en un evento de desplazamiento porque mi objetivo final era tener "desplazamientos de enfoque automático" que deciden si están desplazando el conjunto completo de componentes horizontalmente si dichos componentes no tienen desplazamiento vertical disponible y, de lo contrario, solo desplazan las entrañas de uno de los componentes verticalmente.

pero puede colocar la evaluación en otro lugar para que otra cosa la active.

Lo importante a recordar aquí es que nunca se te obliga a volver a usar JQuery, siempre hay una manera de acceder a las mismas funcionalidades que tiene sin usarlo.

tatsu
fuente
1
Curioso por qué estás escuchando eventos de rueda para verificar si hay una barra de desplazamiento o no.
mix3d
3
Además, dado que está utilizando funciones de flecha, thismantiene el ámbito primario; th = this;es innecesario
mix3d
1
@ mix3d Yo personalmente uso este código para cambiar automáticamente entre desplazamiento horizontal y vertical en función de cuál tiene la dirección de desplazamiento en el elemento puntiagudo dado que es dinámico
tatsu
1
Re: esto; es básicamente azúcar sintáctico (más taquigrafía) parafunction(){}.bind(this)
mix3d
1

Aquí hay una versión mejorada de la respuesta de Evan que parece explicar adecuadamente la lógica de desbordamiento.

            function element_scrollbars(node) {
                var element = $(node);
                var overflow_x = element.css("overflow-x");
                var overflow_y = element.css("overflow-y");
                var overflow = element.css("overflow");
                if (overflow_x == "undefined") overflow_x == "";
                if (overflow_y == "undefined") overflow_y == "";
                if (overflow == "undefined") overflow == "";
                if (overflow_x == "") overflow_x = overflow;
                if (overflow_y == "") overflow_y = overflow;
                var scrollbar_vertical = (
                    (overflow_y == "scroll")
                    || (
                        (
                            (overflow_y == "hidden")
                            || (overflow_y == "visible")
                        )
                        && (
                            (node.scrollHeight > node.clientHeight)
                        )
                    )
                );
                var scrollbar_horizontal = (
                    (overflow_x == "scroll")
                    || (
                        (
                            (overflow_x == "hidden")
                            || (overflow_x == "visible")
                        )
                        && (
                            (node.scrollWidth > node.clientWidth)
                        )
                    )
                );
                return {
                    vertical: scrollbar_vertical,
                    horizontal: scrollbar_horizontal
                };
            }
JBlitzen
fuente
1

Las soluciones proporcionadas anteriormente funcionarán en la mayoría de los casos, pero verificar el scrollHeight y el desbordamiento a veces no es suficiente y puede fallar para los elementos body y html como se ve aquí: https://codepen.io/anon/pen/EvzXZw

1. Solución: compruebe si el elemento es desplazable:

function isScrollableY (element) {
  return !!(element.scrollTop || (++element.scrollTop && element.scrollTop--));
}

Nota: los elementos con overflow: hiddentambién se tratan como desplazables ( más información ), por lo que también puede agregar una condición contra eso si es necesario:

function isScrollableY (element) {
    let style = window.getComputedStyle(element);
    return !!(element.scrollTop || (++element.scrollTop && element.scrollTop--)) 
           && style["overflow"] !== "hidden" && style["overflow-y"] !== "hidden";
}

Hasta donde sé, este método solo falla si el elemento tiene scroll-behavior: smooth .

Explicación: El truco es que el navegador no procesará el intento de desplazarse hacia abajo y revertirlo. La función superior también se puede escribir de la siguiente manera:

2. Solución: realice todas las comprobaciones necesarias:

function isScrollableY (element) {
  const style = window.getComputedStyle(element);
  
  if (element.scrollHeight > element.clientHeight &&
      style["overflow"] !== "hidden" && style["overflow-y"] !== "hidden" &&
      style["overflow"] !== "clip" && style["overflow-y"] !== "clip"
  ) {
    if (element === document.documentElement) return true;
    else if (style["overflow"] !== "visible" && style["overflow-y"] !== "visible") {
      // special check for body element (https://drafts.csswg.org/cssom-view/#potentially-scrollable)
      if (element === document.body) {
        const parentStyle = window.getComputedStyle(element.parentElement);
        if (parentStyle["overflow"] !== "visible" && parentStyle["overflow-y"] !== "visible" &&
            parentStyle["overflow"] !== "clip" && parentStyle["overflow-y"] !== "clip"
        ) {
          return true;
        }
      }
      else return true;
    }
  }
  
  return false;
}
Robbendebiene
fuente
0

Aquí está mi mejora: agregado parseInt. por alguna extraña razón no funcionó sin él.

// usage: jQuery('#my_div1').hasVerticalScrollBar();
// Credit: http://stackoverflow.com/questions/4814398/how-can-i-check-if-a-scrollbar-is-visible
(function($) {
    $.fn.hasVerticalScrollBar = function() {
        return this.get(0) ? parseInt( this.get(0).scrollHeight ) > parseInt( this.innerHeight() ) : false;
    };
})(jQuery);
Svetoslav Marinov
fuente
0

Funciona en Chrome , Edge , Firefox y Opera , al menos en las versiones más recientes.

Usando JQuery ...

Configure esta función para corregir el pie de página:

function fixFooterCaller()
{
    const body = $('body');
    const footer = $('body footer');

    return function ()
    {
        // If the scroll bar is visible
        if ($(document).height() > $(window).height())
        {
            // Reset
            footer.css('position', 'inherit');
            // Erase the padding added in the above code
            body.css('padding-bottom', '0');
        }
        // If the scrollbar is NOT visible
        else
        {
            // Make it fixed at the bottom
            footer.css('position', 'fixed');
            // And put a padding to the body as the size of the footer
            // This makes the footer do not cover the content and when
            // it does, this event fix it
            body.css('padding-bottom', footer.outerHeight());
        }
    }
}

Devuelve una función. Hecho de esta manera solo para configurar el cuerpo y el pie de página una vez.

Y luego, configúrelo cuando el documento esté listo.

$(document).ready(function ()
{
    const fixFooter = fixFooterCaller();

    // Put in a timeout call instead of just call the fixFooter function
    // to prevent the page elements needed don't be ready at this time
    setTimeout(fixFooter, 0);
    // The function must be called every time the window is resized
    $(window).resize(fixFooter);
});

Agregue esto a su pie de página css:

footer {
    bottom: 0;
}
Mateus Pires
fuente
0

La mayoría de las respuestas presentadas me acercaron a donde necesitaba estar, pero no del todo.

Básicamente queríamos evaluar si las barras de desplazamiento serían visibles en una situación normal, por esa definición, lo que significa que el tamaño del elemento del cuerpo es más grande que el puerto de vista. Esta no fue una solución presentada, por eso la estoy enviando.

¡Ojalá ayude a alguien!

(function($) {
    $.fn.hasScrollBar = function() {
        return this.get(0).scrollHeight > $(window).height();
    }
})(jQuery);

Esencialmente, tenemos la hasScrollbarfunción, pero regresamos si el elemento solicitado es más grande que el puerto de vista. Para ver el tamaño del puerto, acabamos de usar $(window).height(). Una comparación rápida de eso con el tamaño del elemento, produce los resultados correctos y el comportamiento deseable.

Barry Chapman
fuente
0

Encuentre un elemento primario del elemento actual que tenga desplazamiento vertical o cuerpo.

$.fn.scrollableParent = function() {
    var $parents = this.parents();

    var $scrollable = $parents.filter(function(idx) {
        return this.scrollHeight > this.offsetHeight && this.offsetWidth !== this.clientWidth;
    }).first();

    if ($scrollable.length === 0) {
        $scrollable = $('html, body');
    }
    return $scrollable;
};

Se puede usar para desplazarse automáticamente al elemento actual a través de:

var $scrollable = $elem.scrollableParent();
$scrollable.scrollTop($elem.position().top);
Dmitriy Sintsov
fuente
0

Un enfoque JavaScript sin marco, verifica tanto vertical como horizontal

 /*
 * hasScrollBars
 * 
 * Checks to see if an element has scrollbars
 * 
 * @returns {object}
 */
Element.prototype.hasScrollBars = function() {
    return {"vertical": this.scrollHeight > this.style.height, "horizontal": this.scrollWidth > this.style.width};
}

Úselo así

if(document.getElementsByTagName("body")[0].hasScrollBars().vertical){
            alert("vertical");
}

        if(document.getElementsByTagName("body")[0].hasScrollBars().horizontal){
            alert("horizontal");
}
David Clews
fuente