Comment puis-je vérifier si une barre de défilement est visible?


277

Est-il possible de vérifier le overflow:autod'un div?

Par exemple:

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'):
         }
    }

});

Parfois, le contenu est court (pas de barre de défilement) et parfois long (barre de défilement visible).

Réponses:


376

un petit plugin pour ça.

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

l'utiliser comme ça,

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

testé fonctionnant sur Firefox, Chrome, IE6,7,8

mais ne fonctionne pas correctement sur le bodysélecteur de balises

démo


Éditer

J'ai découvert que lorsque vous avez une barre de défilement horizontale qui fait apparaître la barre de défilement verticale, cette fonction ne fonctionne pas ....

J'ai trouvé une autre solution ... utiliser clientHeight

return this.get(0).scrollHeight > this.get(0).clientHeight;

22
Si vous avez du rembourrage, vous devez utiliser > this.innerHeight(); jsfiddle.net/p3FFL/210
jcubic

2
Il y a un problème avec cela, si une barre de défilement horizontale existe également, alors cela retournera faux même si une barre de défilement verticale existe jusqu'à ce que la hauteur ait été réduite par la hauteur de la barre de défilement horizontale.
Ally

pourquoi avez-vous défini deux fois la même fonction? @jcubic
Nitin Sawant

9
Notez que sur Mac, la barre de défilement flotte sur le contenu et disparaît lorsqu'elle n'est pas utilisée. Sous Windows, il est toujours visible et occupe un espace horizontal. Par conséquent, ce n'est pas parce qu'une barre de défilement est nécessairement présente que le contenu peut être défilé (ce que cette fonction détecte).
Andrew

2
(function ($) {$ .fn.hasScrollBar = function () {retourne this.get (0) .scrollWidth> this.width); }}) (jQuery); cela fonctionne pour le sur-flux horizontal. Bon pour vérifier la réactivité mobile sur les sites Web dans les iframes.
Alexander Nicholas Popa

57

Peut-être une solution plus simple.

if ($(document).height() > $(window).height()) {
    // scrollbar
}

Cette réponse a fonctionné pour moi après avoir vérifié si le DOM est prêt à l'aide de JQuery.ready()
Simple Sandman

4
Cela suppose que la barre de défilement est sur la fenêtre et non un élément div. Proposer de changer la référence pour suggérer: "Si vous avez seulement besoin de tester la barre de défilement sur la fenêtre principale, vous pouvez essayer:"
justdan23

43

Vous pouvez le faire en utilisant une combinaison des attributs Element.scrollHeightet Element.clientHeight.

Selon MDN:

L' attribut en lecture seule Element.scrollHeight est une mesure de la hauteur du contenu d'un élément, y compris le contenu non visible à l'écran en raison d'un débordement. La valeur scrollHeight est égale à la valeur minimale clientHeight dont l'élément aurait besoin pour tenir tout le contenu du point de vue sans utiliser une barre de défilement verticale. Il inclut le remplissage de l'élément mais pas sa marge.

Et:

La propriété en lecture seule Element.clientHeight renvoie la hauteur intérieure d'un élément en pixels, y compris le remplissage, mais pas la hauteur, la bordure ou la marge de la barre de défilement horizontale.

clientHeight peut être calculé comme hauteur CSS + remplissage CSS - hauteur de la barre de défilement horizontale (si présente).

Par conséquent, l'élément affichera une barre de défilement si la hauteur de défilement est supérieure à la hauteur du client, donc la réponse à votre question est:

function scrollbarVisible(element) {
  return element.scrollHeight > element.clientHeight;
}

2
exemple: github.com/twbs/bootstrap/blob/master/js/modal.js#L242 et +1 pour le devis et l'explication MDN!
lowtechsun

en chrome si le contenu a une bordure alors qu'il n'est pas inclus dans scrollHeight
AT

1
Voté pour ne pas avoir lâché et utilisé un framework / bibliothèque.
John

Attention - cela provoque une refusion, qui est un drain de performance. gist.github.com/paulirish/5d52fb081b3570c81e3a
Todd Sjolander

43

Je devrais changer un peu ce que Reigel a dit:

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

innerHeight compte la hauteur du contrôle et ses rembourrages supérieur et inférieur


return (this.get (0))? this.get (0) .scrollHeight> this.innerHeight (): false;
commonpike

3
Je pense que cela devrait être attribué comme la bonne réponse. Cela a fonctionné sur FF35, IE11 et Chrome39.
LucasBr

Il ne vérifie pas la valeur de «débordement» pour s'assurer que les barres de défilement apparaîtront lorsque cette condition scrollHeight est remplie.
BT

1
@BT Mais si j'ai un débordement réglé sur auto dans mon CSS, alors je n'ai pas besoin de cette vérification supplémentaire? Il compare les tailles et ça suffit ...?
Andrew

Une réponse qui ne fonctionne que pour vous n'est pas une réponse .. comment savez-vous ce que les autres ont dans leur CSS? Votre réponse ne mentionne pas cette limitation. Si quelqu'un ne peut pas déposer votre réponse et la faire fonctionner, ce n'est pas une bonne réponse.
BT

27

Cela élargit la réponse de @ Reigel. Il renverra une réponse pour les barres de défilement horizontales ou verticales.

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

Exemple:

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


8

J'ai fait un nouveau sélecteur personnalisé: pseudo pour jQuery pour tester si un élément a l'une des propriétés css suivantes:

  1. débordement: [défilement | auto]
  2. overflow-x: [défilement | auto]
  3. débordement-y: [défilement | auto]

Je voulais trouver le parent déroulant le plus proche d'un autre élément, j'ai donc également écrit un autre petit plugin jQuery pour trouver le parent le plus proche avec débordement.

Cette solution ne fonctionne probablement pas le mieux, mais elle semble fonctionner. Je l'ai utilisé conjointement avec le plugin $ .scrollTo. Parfois, j'ai besoin de savoir si un élément se trouve dans un autre conteneur déroulant. Dans ce cas, je veux faire défiler l'élément déroulant parent par rapport à la fenêtre.

J'aurais probablement dû emballer cela dans un seul plugin et ajouter le sélecteur psuedo en tant que partie du plugin, ainsi qu'exposer une méthode `` la plus proche '' pour trouver le conteneur déroulant (parent) le plus proche.

Anywho .... le voici.

Plugin jQuery $ .isScrollable:

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

$ (': scrollable') pseudo sélecteur 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 mise en œuvre est assez 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();

MISE À JOUR: J'ai trouvé que Robert Koritnik avait déjà proposé un pseudo-sélecteur beaucoup plus puissant: un pseudo sélecteur défilable qui identifiera les axes de défilement et la hauteur des conteneurs défilables, dans le cadre de son plugin jQuery $ .scrollintoview (). plugin scrollintoview

Voici son pseudo sélecteur de fantaisie (accessoires):

    $.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();

    }

});

6

La première solution ci-dessus ne fonctionne que dans IE La deuxième solution ci-dessus ne fonctionne que dans FF

Cette combinaison des deux fonctions fonctionne dans les deux navigateurs:

//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");
}​
  • Envelopper dans un document prêt
  • monitorWidth1: le div où le débordement est réglé sur auto
  • mtc: un conteneur div à l'intérieur de monitorWidth1
  • AdjustOverflowWidth: une classe css appliquée à la div #mtc lorsque la barre de défilement est active * Utilisez l'alerte pour tester le navigateur croisé, puis commentez pour le code de production final.

HTH


6

(scrollWidth / Height - clientWidth / Height) est un bon indicateur de la présence d'une barre de défilement, mais il vous donnera une réponse "faux positif" à plusieurs reprises. si vous avez besoin d'être précis, je suggère d'utiliser la fonction suivante. au lieu d'essayer de deviner si l'élément peut défiler - vous pouvez le faire défiler ...

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>


À quelles occasions donnera-t-il un faux positif?
GaloisGirl

5

Les réponses de tout le monde ici sont incomplètes, et permet déjà d'arrêter d'utiliser jquery dans les réponses SO. Consultez la documentation de jquery si vous voulez des informations sur jquery.

Voici une fonction javascript pur généralisée pour tester si un élément a ou non des barres de défilement de manière complète:

// 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"
}

4
Pourquoi éviter d'utiliser jquery sur une question mise en forme comme jquery? Veuillez ajouter des liens vers la partie de la documentation jquery que vous mentionnez.
kpull1

6
@ kpull1 Trop de gens marquent jQuery sur chaque question javascript qu'ils ont. Cette question a 0 relation avec jQuery. Il n'y a aucune partie de la documentation jQuery qui a la réponse, car jQuery ne fait pas cela, ni ne devrait le faire.
BT

4

Je vais m'étendre encore plus sur ces pauvres âmes qui, comme moi, utilisent l'un des frameworks js modernes et non JQuery et ont été complètement abandonnées par les gens de ce fil:

cela a été écrit dans Angular 6 mais si vous écrivez React 16, Vue 2, Polymer, Ionic, React-Native, vous saurez quoi faire pour l'adapter. Et c'est tout le composant, donc ça devrait être facile.

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

dans le html, il y aurait un div avec la classe "elem-list" qui est stylisé dans le css ou le scss pour avoir un heightet une overflowvaleur qui ne l'est pas hidden. (alors autoousroll )

Je déclenche cet eval sur un événement de défilement parce que mon objectif final était d'avoir des "défilages de mise au point automatique" qui décident s'ils font défiler l'ensemble des composants horizontalement si lesdits composants n'ont pas de défilement vertical disponible et sinon ne font défiler que les entrailles de l'un des verticalement.

mais vous pouvez placer l'eval ailleurs pour qu'il soit déclenché par autre chose.

la chose importante à retenir ici, c'est que vous n'êtes jamais forcé à utiliser JQuery, il y a toujours un moyen d'accéder aux mêmes fonctionnalités qu'il a sans l'utiliser.


1
Curieux de savoir pourquoi vous écoutez les événements de la roue pour vérifier s'il y a une barre de défilement ou non.
mix3d

3
De plus, puisque vous utilisez des fonctions fléchées, thisconserve la portée parent; th = this;est inutile.
mix3d

1
@ mix3d J'utilise personnellement ce code pour basculer automatiquement entre le défilement horizontal et vertical en fonction de la direction de défilement à l'élément pointé donné qui est dynamique
tatsu

1
Re: ceci; c'est essentiellement du sucre syntaxique (plus une belle sténographie) pourfunction(){}.bind(this)
mix3d

1

Voici une version améliorée de la réponse d'Evan qui semble prendre correctement en compte la logique de débordement.

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

1

Les solutions fournies ci-dessus fonctionneront dans la plupart des cas, mais la vérification de scrollHeight et du débordement n'est parfois pas suffisante et peut échouer pour les éléments body et html comme indiqué ici: https://codepen.io/anon/pen/EvzXZw

1. Solution - Vérifiez si l'élément peut défiler:

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

Remarque: les éléments avec overflow: hiddensont également traités comme défilants ( plus d'informations ), vous pouvez donc également ajouter une condition contre cela si nécessaire:

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

Pour autant que je sache, cette méthode échoue uniquement si l'élément a scroll-behavior: smooth .

Explication: L'astuce est que la tentative de défilement vers le bas et de retour ne sera pas rendue par le navigateur. La fonction la plus haute peut également être écrite comme suit:

2. Solution - Faites toutes les vérifications nécessaires:

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

0

Voici mon amélioration: ajout de parseInt. pour une raison étrange, cela ne fonctionnait pas sans lui.

// 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);

0

Fonctionne sur Chrome , Edge , Firefox et Opera , au moins dans les versions les plus récentes.

Utilisation de JQuery ...

Configurez cette fonction pour corriger le pied de page:

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

Il renvoie une fonction. Fabriqué de cette façon juste pour régler le corps et le pied de page une fois.

Et puis, définissez-le lorsque le document est prêt.

$(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);
});

Ajoutez ceci à votre footer css:

footer {
    bottom: 0;
}

0

La plupart des réponses présentées m'ont rapproché de l'endroit où je devais être, mais pas tout à fait là.

Nous voulions essentiellement évaluer si les barres de défilement - seraient - visibles dans une situation normale, par cette définition signifiant que la taille de l'élément de corps est plus grande que le port de vue. Ce n'était pas une solution présentée, c'est pourquoi je la soumets.

Espérons que cela aide quelqu'un!

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

Essentiellement, nous avons la hasScrollbarfonction, mais en retournant si l'élément demandé est plus grand que le port de vue. Pour voir la taille du port, nous venons de l'utiliser $(window).height(). Une comparaison rapide de cela par rapport à la taille de l'élément, donne les résultats corrects et le comportement souhaitable.


0

Trouvez un parent de l'élément actuel qui a un défilement vertical ou un corps.

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

Il peut être utilisé pour faire défiler automatiquement vers l'élément actuel via:

var $scrollable = $elem.scrollableParent();
$scrollable.scrollTop($elem.position().top);

0

Une approche JavaScript sans cadre, vérifie à la fois verticale et horizontale

 /*
 * 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};
}

Utilisez-le comme ça

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

        if(document.getElementsByTagName("body")[0].hasScrollBars().horizontal){
            alert("horizontal");
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.