Vérifiez si l'élément HTML a des barres de défilement

113

Quel est le moyen le plus rapide de vérifier si un élément possède des barres de défilement?

Une chose bien sûr est de vérifier si l'élément est plus grand que sa fenêtre, ce qui peut facilement être fait en vérifiant ces deux valeurs:

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

mais cela ne veut pas dire qu'il a aussi des barres de défilement (donc il peut être fait défiler par les humains).

Question

Comment puis-je vérifier les barres de défilement dans un 1 navigateur croix et 2 javascript seulement (comme dans aucune jQuery ) façon?

Javascript uniquement, car j'ai besoin de la plus petite surcharge possible, car j'aimerais écrire un filtre de sélection jQuery très rapide

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

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

Je suppose que je devrais vérifier les overflowparamètres de style, mais comment puis-je faire cela dans un navigateur croisé?

Modification supplémentaire

Pas seulement les overflowparamètres de style. Vérifier si un élément a une barre de défilement n'est pas aussi simple qu'il n'y paraît. La première formule que j'ai écrite ci-dessus fonctionne bien lorsque l'élément n'a pas de bordure, mais quand c'est le cas (en particulier lorsque la bordure a une largeur considérable), la offsetdimension peut être plus grande que la scrolldimension, mais l'élément peut toujours faire défiler. Nous devons en fait soustraire les bordures de la offsetdimension pour obtenir la fenêtre déroulante réelle de l'élément et la comparer à la scrolldimension.

Pour référence future

:scrollableLe filtre de sélection jQuery est inclus dans mon .scrollintoview()plugin jQuery. Le code complet peut être trouvé dans mon article de blog si quelqu'un en a besoin. Même s'il n'a pas fourni la solution réelle, le code de Soumya m'a considérablement aidé à résoudre le problème. Cela m'a orienté dans la bonne direction.

Robert Koritnik
la source

Réponses:

118

J'ai trouvé ça quelque part il y a quelques semaines. Cela a fonctionné pour moi.

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
la source
12
Vous avez évidemment un exemple simplifié. Et si votre conteneur s'y est overflow:hiddenposé? Il y aurait un excès de contenu, mais ce n'est toujours pas défilable. Le problème n'est de loin pas aussi simple qu'il y paraît.
Robert Koritnik
7
Ce n'est peut-être pas la solution acceptée, mais cela a fonctionné pour moi. Je ne sais pas pourquoi vous le feriez défiler s'il est masqué.
vol7ron
Ce n'est peut-être pas la solution acceptée, mais cela a fonctionné pour moi. Robert, pour ces cas, ne pourriez-vous pas également récupérer la propriété de dépassement de capacité css pour tester ces cas (par exemple div.scrollHeight>div.clientHeight && !(div.style.overflow && div.style.overflow == 'hidden'))?
vol7ron le
7
Cela échoue dans de nombreux cas. Si votre élément a un débordement: visible; largeur: 200px; et a un enfant avec une largeur de 500px, votre élément n'a pas de barres de défilement mais a un scrollWidth de 500px et un clientWidth de 200px.
Joseph Lennox
1
Si le débordement est visible ou masqué, il n'y a généralement pas de barres de défilement.
Hubert Grzeskowiak
16

Essayer:

Pour la barre de défilement verticale

el.scrollHeight> el.clientHeight

Pour la barre de défilement horizontale

el.scrollWidth> el.clientWidth

Je sais que cela fonctionne au moins pour IE8 et Firefox 3.6+.

Gary
la source
2
J'ai fait remarquer que oui, cela me dit qu'un certain élément est plus grand qu'il n'y paraît, mais cela ne veut pas dire qu'il affiche des barres de défilement. Cela peut aussi bien l'être overflow:hiddenet il ne serait plus défilable.
Robert Koritnik le
1
Et vérifier avec les valeurs clientHeight / clientWidth ne donne pas de bons résultats, car les éléments peuvent également avoir des bordures, qui ne sont pas incluses dans cette mesure. Vérifiez ma formule. Cela fonctionne mieux que le vôtre.
Robert Koritnik le
C'est vrai à propos de l'utilisation de offsetHeight / offsetWidth pour vérifier les barres de défilement au lieu de clientHeight / clientWidth. Merci d'avoir fait remarquer cela.
Gary le
@RobertKoritnik - alors vérifiez simplement si cet élément spécifique contient overflow:hidden... c'est toujours la bonne réponse à mon avis, car c'est la plus simple.
vsync
14

Cela peut sembler (ou être) un peu hackish, mais vous pouvez tester lescrollTopscrollLeft propriétés et .

S'ils sont supérieurs à 0, vous savez qu'il existe des barres de défilement. S'ils sont 0, définissez-les sur 1 et testez-les à nouveau pour voir si vous obtenez un résultat de 1. Puis remettez-les à 0.

Exemple: 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'));

Je crois qu'il existe une propriété différente pour IE, donc je vais mettre à jour dans une minute avec cela.

EDIT: Apparaît comme si IE peut prendre en charge cette propriété. (Je ne peux pas tester IE pour le moment.)

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

utilisateur113716
la source
Il est beaucoup plus facile de vérifier les barres de défilement si vous comparez offsetHeightet clientHeight. Ce dernier est toujours plus petit par la taille de la barre de défilement lorsque la barre de défilement est présente.
Robert Koritnik le
@Robert: Je ne sais pas si c'est plus facile, mais je vois comment cela fonctionne. Ensuite, je suppose que si un élément a overflow:scroll, vous voulez qu'il soit signalé comme défilant, que les barres de défilement soient activées ou non. Bien sûr, ma solution pourrait avoir des problèmes s'il y a un événement onscroll attaché.
user113716
Pas vraiment. Si vous vérifiez mon plugin jQuery, je dois trouver l'ancêtre défilable, sinon je ne peux pas faire défiler un élément dans la vue.
Robert Koritnik
8
@RobertKoritnik Pas vrai; certains navigateurs peuvent avoir des barres de défilement qui ne réduisent pas la largeur. Sur un OS X par exemple. Ou touchez les appareils.
daniel.gindi
1
toujours retourner faux
Fatih Erol
14

Voici encore une autre solution:

Comme quelques personnes l'ont souligné, il ne suffit pas de comparer offsetHeight et scrollHeight car ils diffèrent sur les éléments avec le débordement caché, etc., qui n'ont toujours pas de barres de défilement. Donc, ici, je vérifie également si le débordement est scroll ou automatique sur les styles calculés pour l'élément:

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
la source
Si overflow*c'est le cas, scrollil y aura toujours une barre de défilement, donc je pense que vous voulez vertical: overflowY === 'scroll' || overflowY === 'auto' && node.scrollHeight > node.clientHeight, etc. (c'est-à-dire supprimer les crochets pour que scroll*vs client*ne soit testé que lorsque overflow*c'est le cas auto). Sinon, cela semble être la solution la plus correcte.
Jake
@Jake Si scrollHeight <clientHeight en cas de débordement de scroll, les barres de défilement vont être là mais elles vont être désactivées (c'est-à-dire que l'élément ne peut pas faire défiler). Donc je pense que cela dépend de l'application. Votre modification est valide si vous voulez simplement vérifier les barres de défilement, peu importe l'état. Pour moi, quand j'ai proposé cela, je cherchais à implémenter le défilement automatique pour un composant, donc avoir désactivé les barres de défilement est inutile dans ce cas. Cela semble également être le cas pour cette question (elle doit "être défilée par les humains")
lotif
6

Je suis peut-être un peu en retard à la fête, mais ...

Je crois que vous pouvez détecter les barres de défilement avec e.offsetWidth contre e.clientWidth. La largeur du décalage comprend les bordures et les barres de défilement, le remplissage et la largeur. La largeur du client comprend le rembourrage et la largeur. S'il te plait regarde:

https://developer.mozilla.org/en/DOM/element.offsetWidth (deuxième image) https://developer.mozilla.org/en/DOM/element.clientWidth (deuxième image)

Vous devez vérifier:

  1. Indique si l'élément a un débordement défini sur auto / scroll (y compris overflowX / Y) à l'aide du style calculé / en cascade / actuel.
  2. Si l'élément a un débordement défini sur auto / scroll. Définissez offsetWidth et clientWidth.
  3. Si clientWidth est inférieur à offsetWidth - bordure droite (retrouvée dans le style calculé / en cascade / actuel), vous savez que vous avez une barre de défilement.

Faites de même pour la verticale (offset / clientHeight).

IE7 signale un clientHeight de 0 pour certains éléments (je n'ai pas vérifié pourquoi), vous avez donc toujours besoin du premier contrôle de dépassement de capacité.

J'espère que cela t'aides!


la source
3

Il y a plusieurs problèmes en cas de vérification de l'existence de barres de défilement, dont l'un est que sous mac, vous n'avez pas de barre de défilement visible, donc toutes les solutions ci-dessus ne vous donneront pas une réponse précise.

Donc, comme le rendu du navigateur n'est pas très fréquent, vous pouvez vérifier le défilement avec changement de défilement, puis le remettre en place:

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
la source
1

Juste déconner ici car aucune des solutions ci-dessus n'a fonctionné pour moi (jusqu'à présent). J'ai trouvé un certain succès en comparant la hauteur de défilement d'une division à son décalage

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

Cela semble me donner une comparaison précise ... jusqu'à présent. Est-ce que quelqu'un sait si cela est légitime?

Michael
la source
2
Je pense que vous voulez scrollHeight et clientHeight: stackoverflow.com/questions/4106538/…
rappel riche
1

Pour IE11 (Internet Explorer 11), j'ai dû changer la logique pour:

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

C'est parce que IE signale scrollHeight comme 1 plus grand que clientHeight quand aucune barre de défilement n'est présente mais environ 9 plus grand quand une barre de défilement est présente

danday74
la source
0

Si vous avez besoin de savoir s'il existe une barre de défilement pour toute la page Web et avec une prise en charge complète du navigateur, vous pouvez utiliser ceci:

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

Il est important d'utiliser window.innerHeightau lieu de document.body.clientHeightcar dans certains navigateurs mobiles, clientHeight n'obtiendra pas la taille de la barre d'adresse, mais scrollHeight le fera, vous obtenez donc de faux calculs.

Sebastian Hernandez
la source
-5

aucune de ces réponses n'est correcte. vous devez utiliser ceci:

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

var hasHorizontalScrollbar = (div.offsetWidth > div.clientWidth);
var hasVerticalScrollbar = (div.offsetHeight > div.clientHeight);
hamid
la source
Cela a été critiqué car il a été copié / collé à partir de la réponse acceptée d'il y a 6 ans et vous n'avez pas besoin de parenthèses pour transformer quelque chose en booléen.
course
-6

Ajoutez un élément 100% large à l'intérieur. Définissez ensuite le débordement sur masqué. Si le style calculé de l'élément (à partir de jQ) change, le parent avait une barre de défilement.

EDIT: Il semble que vous vouliez une méthode multi-navigateurs comme getComputedStyle . Essayer:

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
la source
1
Si j'utilisais déjà jQuery pour cela, je préférerais simplement le faire $(el).css("overflow/overflowX/overflowY")et voir s'il est réglé sur automatique ou sur le défilement . Mais j'aimerais éviter d'utiliser jQuery.
Robert Koritnik le
16
Les styles CSS ne vous diront PAS si un élément a ou non des barres de défilement. Seulement si oui ou non il peut avoir des barres de défilement. Peut-être trouver une méthode de navigateur croisé pour déterminer la largeur de l'élément intérieur?
Soumya
@ Soumya92: La comparaison de taille entre la taille déroulante et la taille réelle est triviale et je l'ai écrite ci-dessus ... Tout ce que je dois vérifier maintenant, c'est le paramètre de débordement actuel sur un élément particulier.
Robert Koritnik le
@ Soumya92: c'est exactement ce dont j'ai besoin. Cela peut également être très simplifié en utilisant coalescecomputedStyle = el.currentStyle || document.defaultView.getComputedStyle(el, null);
Robert Koritnik
Une dernière chose: à quel point est-ce cross browser? Quels navigateurs sont pris en charge par cela?
Robert Koritnik le