Как я могу проверить, видна ли полоса прокрутки?

277

Можно ли проверить overflow:autodiv?

Например:

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

});

Иногда содержимое короткое (без полосы прокрутки), а иногда длинное (видимая полоса прокрутки).

Питер
источник

Ответы:

376

маленький плагин для этого.

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

используйте это так,

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

протестировал работу на Firefox, Chrome, IE6,7,8

но не работает должным образом на bodyселекторе тегов

демонстрация


редактировать

Я обнаружил, что если у вас есть горизонтальная полоса прокрутки, которая вызывает вертикальную полосу прокрутки, эта функция не работает ....

Я нашел другое решение ... использовать clientHeight

return this.get(0).scrollHeight > this.get(0).clientHeight;
Reigel
источник
22
Если у вас есть отступы, вам нужно использовать > this.innerHeight(); jsfiddle.net/p3FFL/210
jcubic
2
Есть проблема с этим, если горизонтальная полоса прокрутки также существует, то она вернет false, даже если вертикальная полоса прокрутки существует до тех пор, пока высота не будет уменьшена на высоту горизонтальной полосы прокрутки.
Союзник
почему вы определили одну и ту же функцию два раза? @jcubic
Нитин Савант
9
Обратите внимание, что на компьютерах Mac полоса прокрутки перемещается поверх содержимого и исчезает, когда она не используется. В Windows это всегда видно и занимает горизонтальное пространство. Поэтому только то, что контент можно прокручивать (который обнаруживает эта функция), не означает, что полоса прокрутки обязательно присутствует.
Андрей
2
(function ($) {$ .fn.hasScrollBar = function () {return this.get (0) .scrollWidth> this.width); }}) (jQuery); это работает для горизонтального переполнения. Хорошо подходит для проверки мобильности на веб-сайтах в фреймах.
Александр Николай Попа
57

Может быть, более простое решение.

if ($(document).height() > $(window).height()) {
    // scrollbar
}
Шон Чжэн
источник
Этот ответ сработал для меня после проверки, готов ли DOM с использованием JQuery.ready()
Simple Sandman,
4
Это предполагает, что полоса прокрутки находится в окне, а не элемент div. Предложите изменить ссылку, чтобы предложить: «Если вам нужно только проверить полосу прокрутки в главном окне, вы можете попробовать:»
justdan23
43

Вы можете сделать это , используя комбинацию из Element.scrollHeightи Element.clientHeightатрибутов.

Согласно MDN:

Element.scrollHeight только для чтения атрибута является измерением высоты содержимого элемента, в том числе содержания не видно на экране из - за переполнение. Значение scrollHeight равно минимальному значению clientHeight, которое потребуется элементу для размещения всего содержимого в точке обзора без использования вертикальной полосы прокрутки. Включает заполнение элемента, но не его поле.

И:

Свойство Element.clientHeight только для чтения возвращает внутреннюю высоту элемента в пикселях, включая отступ, но не высоту горизонтальной полосы прокрутки, границу или поле.

clientHeight может быть рассчитан как высота CSS + CSS padding - высота горизонтальной полосы прокрутки (если есть).

Следовательно, элемент будет отображать полосу прокрутки, если высота прокрутки больше высоты клиента, поэтому ответ на ваш вопрос:

function scrollbarVisible(element) {
  return element.scrollHeight > element.clientHeight;
}
Ajedi32
источник
2
пример: github.com/twbs/bootstrap/blob/master/js/modal.js#L242 и +1 для цитаты и объяснения MDN!
lowtechsun
хромом , если содержание имеет границы , чем он не включен в scrollHeight
AT
1
Проголосовал за то, что не отказался от использования фреймворка / библиотеки.
Джон
Осторожно - это вызывает оплавление, что приводит к снижению производительности. gist.github.com/paulirish/5d52fb081b3570c81e3a
Тодд Шоландер
43

Я должен немного изменить то, что сказал Рейгель:

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

innerHeight считает высоту элемента управления и его верхнюю и нижнюю отступы

kpull1
источник
return (this.get (0))? this.get (0) .scrollHeight> this.innerHeight (): false;
commonpike
3
Я думаю, что это должно быть назначено как правильный ответ. Это работало на FF35, IE11 и Chrome39.
LucasBr
Он не проверяет значение «переполнения», чтобы убедиться, что полосы прокрутки появятся при выполнении этого условия scrollHeight.
BT
1
@BT Но если у меня в css установлен переполнение на auto, то мне не нужна эта дополнительная проверка? Он сравнивает размеры и этого достаточно ...?
Андрей
Ответ, который работает только для вас, не является ответом ... откуда вы знаете, что есть у других людей в их CSS? Ваш ответ не упоминает это ограничение. Если кто-то не может оставить ваш ответ и заставить его работать, это не очень хороший ответ.
BT
27

Это расширяет ответ @ Рейгеля. Он вернет ответ для горизонтальной или вертикальной полосы прокрутки.

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

Пример:

element.hasScrollBar()             // Returns { vertical: true/false, horizontal: true/false }
element.hasScrollBar().vertical    // Returns true/false
element.hasScrollBar().horizontal  // Returns true/false
the4tress
источник
8

Я создал новый пользовательский псевдо-селектор для jQuery, чтобы проверить, имеет ли элемент одно из следующих свойств CSS:

  1. переполнение: [прокрутка | авто]
  2. overflow-x: [прокрутка | авто]
  3. переполнение-у: [прокрутка | авто]

Я хотел найти ближайшего прокручиваемого родителя другого элемента, поэтому я также написал еще один маленький плагин jQuery, чтобы найти ближайшего родителя с переполнением.

Это решение, вероятно, не работает лучше, но, похоже, работает. Я использовал его вместе с плагином $ .scrollTo. Иногда мне нужно знать, находится ли элемент внутри другого прокручиваемого контейнера. В этом случае я хочу прокрутить родительский прокручиваемый элемент против окна.

Я, вероятно, должен был обернуть это в один плагин и добавить селектор psuedo как часть плагина, а также выставить «ближайший» метод для поиска ближайшего (родительского) прокручиваемого контейнера.

Во всяком случае .... вот оно.

$ .isScrollable jQuery плагин:

$.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') псевдо-селектор jQuery:

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

Плагин $ .scrollableparent () jQuery:

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

Реализация довольно проста

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

ОБНОВЛЕНИЕ: Я обнаружил, что Роберт Коритник уже придумал гораздо более мощный: прокручиваемый псевдоселектор, который будет определять прокручиваемые оси и высоту прокручиваемых контейнеров, как часть его плагина $ .scrollintoview () jQuery. scrollintoview плагин

Вот его причудливый псевдо-селектор (реквизит):

    $.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
источник
6

Первое решение выше работает только в IE Второе решение выше работает только в FF

Эта комбинация обеих функций работает в обоих браузерах:

//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");
}​
  • Завернуть в документ готов
  • monitorWidth1: div, где переполнение установлено на auto
  • mtc: контейнерный блок внутри monitorWidth1
  • AdjustOverflowWidth: класс css, применяемый к элементу #mtc, когда полоса прокрутки активна. * Используйте предупреждение, чтобы протестировать кросс-браузер, а затем закомментировать окончательный производственный код.

НТН

Аарон Хопкинс
источник
6

(scrollWidth / Height - clientWidth / Height) является хорошим индикатором наличия полосы прокрутки, но во многих случаях дает ложный положительный ответ. если вам нужно быть точным, я бы предложил использовать следующую функцию. вместо того, чтобы пытаться угадать, является ли элемент прокручиваемым - вы можете прокрутить его ...

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>

Яир Леви
источник
В каких случаях это даст ложный положительный результат?
GaloisGirl
5

Тьфу все ответы здесь неполны, и давайте прекратим использовать jquery в SO ответах, пожалуйста. Проверьте документацию jquery, если хотите получить информацию о jquery.

Вот обобщенная функция чистого javascript для проверки наличия или отсутствия у элемента ползун прокрутки:

// 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
источник
4
Почему бы не использовать jquery для вопроса, помеченного как jquery? Пожалуйста, добавьте ссылки на ту часть документации jquery, которую вы упомянули.
kpull1
6
@ kpull1 Слишком много людей помечают jQuery на каждый свой вопрос по javascript. Этот вопрос имеет 0 отношение к jQuery. Там нет ни одна части документации JQuery , который имеет ответ, потому что JQuery не делать этого, и не должна.
BT
4

Я собираюсь рассказать об этом еще дальше тем беднягам, которые, как и я, используют одну из современных сред js, а не JQuery и были полностью заброшены людьми из этой ветки:

это было написано на Angular 6, но если вы напишите React 16, Vue 2, Polymer, Ionic, React-Native, вы будете знать, что нужно сделать, чтобы адаптировать его. И это весь компонент, так что должно быть легко.

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

в html будет div с классом "elem-list", который стилизован в css или scss, чтобы иметь значение a heightи overflowзначение, которого нет hidden. (так autoили sroll)

Я запускаю это eval при событии прокрутки, потому что моей конечной целью было иметь «автоматическую прокрутку фокуса», которая решает, прокручивают ли они весь набор компонентов по горизонтали, если у указанных компонентов нет вертикальной прокрутки, а в противном случае прокручивает только внутренности одного из компоненты по вертикали.

но вы можете поместить eval в другом месте, чтобы он был вызван чем-то другим.

Здесь важно помнить, что вы никогда не будете вынуждены использовать JQuery, всегда есть способ получить доступ к тем же функциональным возможностям, которые у него есть, без его использования.

Tatsu
источник
1
Любопытно, почему вы слушаете события колеса, чтобы проверить, есть ли полоса прокрутки или нет.
mix3d
3
Кроме того, поскольку вы используете функции стрелок, thisсохраняет родительскую область видимости; th = this;не нужно
mix3d
1
@ mix3d Я лично использую этот код для автоматического переключения между горизонтальной и вертикальной прокруткой, в зависимости от того, какое направление прокрутки у заданного остроконечного элемента является динамическим
tatsu
1
Re: это; это в основном синтаксический сахар (плюс хорошая стенография) дляfunction(){}.bind(this)
mix3d
1

Вот улучшенная версия ответа Эвана, которая, кажется, правильно учитывает логику переполнения.

            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
источник
1

Решения, представленные выше, будут работать в большинстве случаев, но проверки scrollHeight и переполнения иногда недостаточно и может произойти сбой для элементов body и html, как показано здесь: https://codepen.io/anon/pen/EvzXZw

1. Решение - Проверьте, прокручивается ли элемент:

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

Примечание: элементы с overflow: hiddenтакже рассматриваются как прокручиваемые ( больше информации ), так что вы можете добавить условие к этому тоже при необходимости:

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

Насколько я знаю, этот метод не работает, только если элемент имеет scroll-behavior: smooth.

Объяснение: хитрость в том, что попытка прокрутки вниз и возврата назад не будет отображаться браузером. Самая верхняя функция также может быть написана следующим образом:

2. Решение - выполните все необходимые проверки:

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;
}
Robbendebiene
источник
0

Вот мое улучшение: добавлен parseInt. по какой-то странной причине это не сработало без него.

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

Работает на Chrome , Edge , Firefox и Opera , по крайней мере, в новых версиях.

Используя JQuery ...

Настройте эту функцию, чтобы исправить нижний колонтитул:

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

Возвращает функцию. Сделано таким образом, чтобы один раз установить тело и нижний колонтитул.

А затем установите это, когда документ будет готов.

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

Добавьте это к своему нижнему колонтитулу CSS:

footer {
    bottom: 0;
}
Матеус Пирес
источник
0

Большинство представленных ответов приблизили меня к тому месту, где я должен был быть, но не совсем там.

Мы в основном хотели оценить, будут ли полосы прокрутки видимыми в нормальной ситуации, по этому определению, означающему, что размер элемента тела больше, чем порт представления. Это не было представлено решение, поэтому я представляю его.

Надеюсь, это кому-нибудь поможет!

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

По сути, у нас есть hasScrollbarфункция, но возвращаемая, если запрошенный элемент больше, чем порт просмотра. Для просмотра размера порта мы просто использовали $(window).height(). Быстрое сравнение этого с размером элемента, дает правильные результаты и желаемое поведение.

Барри Чепмен
источник
0

Найдите родителя текущего элемента с вертикальной прокруткой или телом.

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

Может использоваться для автоматической прокрутки до текущего элемента через:

var $scrollable = $elem.scrollableParent();
$scrollable.scrollTop($elem.position().top);
Дмитрий Синцов
источник
0

Подход JavaScript без фреймворка, проверяет как вертикальное, так и горизонтальное

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

Используйте это так

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

        if(document.getElementsByTagName("body")[0].hasScrollBars().horizontal){
            alert("horizontal");
}
Дэвид Кльюс
источник