Come posso verificare se una barra di scorrimento è visibile?


277

È possibile verificare la presenza overflow:autodi un div?

Per esempio:

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 volte il contenuto è breve (nessuna barra di scorrimento) e talvolta lungo (barra di scorrimento visibile).

Risposte:


376

un piccolo plugin per questo.

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

usalo così,

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

testato su Firefox, Chrome, IE6,7,8

ma non funziona correttamente sul bodyselettore di tag

dimostrazione


modificare

Ho scoperto che quando hai una barra di scorrimento orizzontale che fa apparire la barra di scorrimento verticale, questa funzione non funziona ....

Ho scoperto un'altra soluzione ... usare clientHeight

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

22
Se hai il padding devi usare > this.innerHeight(); jsfiddle.net/p3FFL/210
jcubic

2
C'è un problema con questo, se esiste anche una barra di scorrimento orizzontale, questo restituirà falso anche se esiste una barra di scorrimento verticale fino a quando l'altezza non è stata ridotta dall'altezza della barra di scorrimento orizzontale.
Ally,

perché hai definito la stessa funzione due volte? @jcubic
Nitin Sawant

9
Si noti che sui Mac la barra di scorrimento si sposta sul contenuto e scompare quando non viene utilizzata. Su Windows è sempre visibile e occupa spazio orizzontale. Pertanto, solo perché il contenuto può essere fatto scorrere (che questa funzione rileva) non significa che sia necessariamente presente una barra di scorrimento.
Andrew

2
(function ($) {$ .fn.hasScrollBar = function () {return this.get (0) .scrollWidth> this.width); }}) (jQuery); questo funziona per il overfolow orizzontale. Buono per controllare la reattività mobile sui siti Web negli iframe.
Alexander Nicholas Popa,

57

Forse una soluzione più semplice.

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

Questa risposta ha funzionato per me dopo aver verificato se il DOM è pronto utilizzando JQuery.ready()
Simple Sandman il

4
Ciò presuppone che la barra di scorrimento sia sulla finestra e non un elemento div. Proponi di modificare il riferimento per suggerire: "Se hai solo bisogno di testare la barra di scorrimento nella finestra principale, potresti provare:"
justdan23

43

Puoi farlo usando una combinazione di Element.scrollHeighteElement.clientHeight attributi .

Secondo MDN:

L' attributo Element.scrollHeight di sola lettura è una misurazione dell'altezza del contenuto di un elemento, incluso il contenuto non visibile sullo schermo a causa dell'overflow. Il valore scrollHeight è uguale al clientHeight minimo richiesto dall'elemento per adattare tutto il contenuto nel punto di vista senza utilizzare una barra di scorrimento verticale. Include il padding dell'elemento ma non il suo margine.

E:

The Element.clientHeight di sola lettura restituisce l'altezza interna in un elemento in pixel, incluso il riempimento ma non l'altezza, il bordo o il margine della barra di scorrimento orizzontale.

clientHeight può essere calcolato come altezza CSS + riempimento CSS - altezza della barra di scorrimento orizzontale (se presente).

Pertanto, l'elemento visualizzerà una barra di scorrimento se l'altezza di scorrimento è maggiore dell'altezza del client, quindi la risposta alla tua domanda è:

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

2
esempio: github.com/twbs/bootstrap/blob/master/js/modal.js#L242 e +1 per la citazione e la spiegazione MDN!
lowtechsun,

in chrome se il contenuto ha un bordo di quanto non sia incluso in scrollHeight
AT

1
Votato per non aver abbandonato e utilizzato un framework / libreria.
John,

Attenzione: questo provoca un riflusso, che è un drenaggio delle prestazioni. gist.github.com/paulirish/5d52fb081b3570c81e3a
Todd Sjolander

43

Dovrei cambiare una piccola cosa di ciò che Reigel ha detto:

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

innerHeight conta l'altezza del controllo e le sue imbottiture superiore e inferiore


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

3
Penso che questo dovrebbe essere assegnato come la risposta giusta. Questo ha funzionato su FF35, IE11 e Chrome39.
LucasBr,

Non controlla il valore di "overflow" per assicurarsi che le barre di scorrimento vengano visualizzate quando viene soddisfatta quella condizione scrollHeight.
BT,

1
@BT Ma se ho overflow impostato su auto nel mio CSS, non ho bisogno di questo controllo extra? Confronta le dimensioni ed è abbastanza ...?
Andrew,

Una risposta che funziona solo per te non è una risposta .. come fai a sapere cosa hanno gli altri nel loro css? La tua risposta non menziona questa limitazione. Se qualcuno non riesce a inserire la tua risposta e farlo funzionare, non è una buona risposta.
BT,

27

Questo si espande sulla risposta di @ Reigel. Restituirà una risposta per le barre di scorrimento orizzontali o verticali.

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

Esempio:

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


8

Ho creato una nuova personalizzazione: pseudo-selettore per jQuery per verificare se un articolo ha una delle seguenti proprietà css:

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

Volevo trovare il genitore scorrevole più vicino di un altro elemento, quindi ho anche scritto un altro piccolo plugin jQuery per trovare il genitore più vicino con overflow.

Questa soluzione probabilmente non funziona al meglio, ma sembra funzionare. L'ho usato insieme al plugin $ .scrollTo. A volte ho bisogno di sapere se un elemento si trova all'interno di un altro contenitore scorrevole. In tal caso, voglio scorrere l'elemento scorrevole genitore rispetto alla finestra.

Probabilmente avrei dovuto racchiuderlo in un singolo plug-in e aggiungere il selettore psuedo come parte del plug-in, oltre a esporre un metodo "più vicino" per trovare il contenitore scorrevole più vicino (genitore).

Comunque ... eccolo qui.

$ .is Plugin jQuery scorrevole:

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

L'implementazione è piuttosto semplice

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

AGGIORNAMENTO: Ho scoperto che Robert Koritnik ha già creato uno pseudo-selettore molto più potente: scorrevole che identificherà gli assi scorrevoli e l'altezza dei contenitori scorrevoli, come parte del suo plugin $ .scrollintoview () jQuery. plugin scrollintoview

Ecco il suo fantastico pseudo-selettore (oggetti di scena):

    $.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 prima soluzione sopra funziona solo in IE La seconda soluzione sopra funziona solo in FF

Questa combinazione di entrambe le funzioni funziona in entrambi i browser:

//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");
}​
  • Avvolgi un documento pronto
  • monitorWidth1: il div in cui l'overflow è impostato su auto
  • mtc: un contenitore div all'interno di monitorWidth1
  • AdjustOverflowWidth: una classe css applicata al div #mtc quando la barra di scorrimento è attiva * Utilizzare l'avviso per testare il browser incrociato, quindi commentare il codice di produzione finale.

HTH


6

(scrollWidth / Height - clientWidth / Height) è un buon indicatore della presenza di una barra di scorrimento, ma ti darà una risposta "falsa positiva" in molte occasioni. se devi essere preciso suggerirei di utilizzare la seguente funzione. invece di provare a indovinare se l'elemento è scorrevole, puoi scorrere ...

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>


In quali occasioni darà un falso positivo?
GaloisGirl,

5

Le risposte di tutti qui sono incomplete e smettiamo di usare jquery nelle risposte SO già per favore. Controlla la documentazione di jquery se desideri informazioni su jquery.

Ecco una funzione general-javascript generalizzata per verificare se un elemento ha barre di scorrimento in modo completo:

// 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
Perché evitare di usare jquery su una domanda come jquery? Si prega di aggiungere collegamenti alla parte della documentazione jquery citata.
kpull1,

6
@ kpull1 Troppe persone taggano jQuery su ogni singola domanda javascript che hanno. Questa domanda ha 0 relazione con jQuery. Non v'è alcuna parte della documentazione di jQuery che ha la risposta, perché jQuery non lo fa, né dovrebbe.
BT

4

Ho intenzione di estenderlo ancora di più per quelle povere anime che, come me, usano uno dei moderni framework js e non JQuery e sono state completamente abbandonate dalla gente di questo thread:

questo è stato scritto in Angular 6 ma se scrivi React 16, Vue 2, Polymer, Ionic, React-Native, saprai cosa fare per adattarlo. Ed è l'intero componente, quindi dovrebbe essere 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!
    }
  });
}
}

nell'html ci sarebbe un div con classe "elem-list" che è stilizzata nel CSS o SCSS per avere un heighte un overflowvalore che non lo è hidden. (così autoosroll )

Attivo questa valutazione su un evento di scorrimento perché il mio obiettivo finale era avere "scroll di messa a fuoco automatici" che decidono se stanno scorrendo l'intero insieme di componenti in orizzontale se detti componenti non hanno uno scorrimento verticale disponibile e altrimenti fanno scorrere solo le viscere di uno dei componenti in verticale.

ma puoi posizionare l'eval altrove per farlo innescare da qualcos'altro.

la cosa importante da ricordare qui, è che non sei mai costretto a tornare a usare JQuery, c'è sempre un modo per accedere alle stesse funzionalità che ha senza usarlo.


1
Curioso perché stai ascoltando gli eventi della ruota per verificare se c'è una barra di scorrimento o meno.
mix3d

3
Inoltre, poiché si utilizzano le funzioni freccia, thismantiene l'ambito padre; th = this;non è necessario.
mix3d

1
@ mix3d Personalmente uso questo codice per passare automaticamente dallo scorrimento orizzontale a quello verticale in base al quale ha la direzione di scorrimento in corrispondenza di un determinato elemento appuntito che è dinamico
tatsu

1
Ri: questo; è fondamentalmente zucchero sintattico (più una bella scorciatoia) perfunction(){}.bind(this)
mix3d

1

Ecco una versione migliorata della risposta di Evan che sembra spiegare correttamente la logica di overflow.

            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

Le soluzioni fornite sopra funzioneranno nella maggior parte dei casi, ma il controllo di scrollHeight e overflow a volte non è sufficiente e può non riuscire per gli elementi body e html come mostrato qui: https://codepen.io/anon/pen/EvzXZw

1. Soluzione: verificare se l'elemento è scorrevole:

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

Nota: gli elementi con overflow: hiddenvengono anche trattati come scorrevoli ( maggiori informazioni ), quindi potresti aggiungere una condizione anche a questo, se necessario:

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

Per quanto ne so questo metodo fallisce solo se l'elemento ha scroll-behavior: smooth.

Spiegazione: Il trucco è che il tentativo di scorrere verso il basso e ripristinarlo non verrà eseguito dal browser. La funzione più in alto può anche essere scritta come la seguente:

2. Soluzione: eseguire tutti i controlli necessari:

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

0

Ecco il mio miglioramento: aggiunto parseInt. per qualche strana ragione non funzionava senza di essa.

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

Funziona su Chrome , Edge , Firefox e Opera , almeno nelle versioni più recenti.

Utilizzo di JQuery ...

Imposta questa funzione per correggere il piè di pagina:

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

Restituisce una funzione. Fatto in questo modo solo per impostare il corpo e il piè di pagina una volta.

E quindi, impostalo quando il documento è pronto.

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

Aggiungi questo al tuo piè di pagina css:

footer {
    bottom: 0;
}

0

La maggior parte delle risposte presentate mi ha avvicinato a dove dovevo essere, ma non proprio lì.

In pratica volevamo valutare se le barre di scorrimento sarebbero state visibili in una situazione normale, con quella definizione che significa che la dimensione dell'elemento body è più grande della porta della vista. Questa non era una soluzione presentata, motivo per cui la sto inviando.

Spero che aiuti qualcuno!

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

In sostanza, abbiamo la hasScrollbarfunzione, ma restituendo se l'elemento richiesto è più grande della porta di visualizzazione. Per visualizzare le dimensioni della porta, abbiamo appena usato $(window).height(). Un rapido confronto di quello con la dimensione dell'elemento, produce i risultati corretti e il comportamento desiderabile.


0

Trova un genitore dell'elemento corrente con scorrimento verticale o corpo.

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

Può essere usato per scorrere automaticamente verso l'elemento corrente tramite:

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

0

Un approccio JavaScript No Framework, controlla sia verticale che orizzontale

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

Usalo in questo modo

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

        if(document.getElementsByTagName("body")[0].hasScrollBars().horizontal){
            alert("horizontal");
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.