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


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;

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

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 считает высоту элемента управления и его верхнюю и нижнюю отступы


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


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

    }

});

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

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, всегда есть способ получить доступ к тем же функциональным возможностям, которые у него есть, без его использования.


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

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

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");
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.