Проверьте, есть ли у HTML-элемента полосы прокрутки

113

Какой самый быстрый способ проверить, есть ли у элемента полосы прокрутки?

Одна вещь, конечно же, - это проверить, больше ли элемент, чем его область просмотра, что можно легко сделать, проверив эти два значения:

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

но это не значит, что у него также есть полосы прокрутки (так что люди могут его прокручивать).

Вопрос

Как я могу проверить для скроллинга в 1 кросс - браузер и 2 Javascript только (как не JQuery ) способом?

Только Javascript, потому что мне нужно как можно меньше накладных расходов, потому что я хотел бы написать очень быстрый фильтр селектора jQuery

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

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

Полагаю, мне придется проверить overflowнастройки стиля, но как мне это сделать в кросс-браузере?

Дополнительное редактирование

Не только overflowнастройки стиля. Проверить, есть ли у элемента полоса прокрутки, не так тривиально, как кажется. Первая формула, которую я написал выше, отлично работает, когда элемент не имеет границы, но когда она есть (особенно когда граница имеет значительную ширину), offsetразмер может быть больше scrollразмера, но элемент все еще можно прокручивать. На самом деле нам нужно вычесть границы из offsetизмерения, чтобы получить фактическое прокручиваемое окно просмотра элемента и сравнить его с scrollразмером.

Для дальнейшего использования

:scrollableФильтр селектора jQuery включен в мой .scrollintoview()плагин jQuery. Полный код можно найти в моем блоге, если он кому-нибудь понадобится. Несмотря на то, что он не предлагал фактического решения, код Soumya значительно помог мне решить проблему. Это указывало мне в правильном направлении.

Роберт Коритник
источник

Ответы:

118

Я нашел это где-то пару недель назад. У меня это сработало.

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

var hasHorizontalScrollbar = div.scrollWidth > div.clientWidth;
var hasVerticalScrollbar = div.scrollHeight > div.clientHeight;

/* you'll get true/false */
джжинга
источник
12
Очевидно, у вас был упрощенный пример. Что, если ваш контейнер overflow:hiddenна нем установился? Был бы лишний контент, но он все равно не прокручивается. Проблема далеко не так проста, как может показаться.
Роберт Коритник
8
Возможно, это неприемлемое решение, но оно сработало для меня. Я не уверен, зачем вам прокручивать его, если он скрыт.
vol7ron
Возможно, это неприемлемое решение, но оно сработало для меня. Роберт, для этих случаев не могли бы вы также получить свойство переполнения css для проверки этих случаев (например div.scrollHeight>div.clientHeight && !(div.style.overflow && div.style.overflow == 'hidden'))?
vol7ron
7
Во многих случаях это не удается. Если у вашего элемента есть переполнение: visible; ширина: 200 пикселей; и имеет дочерний элемент шириной 500 пикселей, ваш элемент не имеет полос прокрутки, но имеет scrollWidth 500 пикселей и clientWidth 200 пикселей.
Джозеф Леннокс,
1
Если переполнение видно или скрыто, полос прокрутки обычно нет.
Hubert Grzeskowiak
16

Пытаться:

Для вертикальной полосы прокрутки

el.scrollHeight> el.clientHeight

Для горизонтальной полосы прокрутки

el.scrollWidth> el.clientWidth

Я знаю, что это работает как минимум для IE8 и Firefox 3.6+.

Gary
источник
2
Я указал на это, да, это говорит мне, что определенный элемент больше, чем кажется, но это не значит, что он отображает полосы прокрутки. Он тоже может быть, overflow:hiddenи его больше нельзя будет прокручивать.
Роберт Коритник 02
1
И проверка с использованием значений clientHeight / clientWidth не дает хороших результатов, потому что элементы также могут иметь границы, которые не включены в этот показатель. Проверьте мою формулу. Он работает лучше, чем ваш.
Роберт Коритник 02
Это верно в отношении использования offsetHeight / offsetWidth для проверки полос прокрутки вместо clientHeight / clientWidth. Спасибо что подметил это.
Гэри
@RobertKoritnik - так что просто проверьте, есть ли overflow:hiddenна нем этот конкретный элемент ... это все еще правильный ответ, на мой взгляд, поскольку он самый простой.
vsync
14

Это может показаться (или быть) немного хака, но вы можете протестировать scrollTopи scrollLeftсвойство.

Если они больше 0, вы знаете, что есть полосы прокрутки. Если они равны 0, установите их в 1 и проверьте их снова, чтобы увидеть, получите ли вы результат 1. Затем установите их обратно в 0.

Пример: 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'));

Я считаю, что для IE есть другое свойство, поэтому я обновлю его через минуту.

EDIT: похоже, что IE может поддерживать это свойство. (Я не могу сейчас протестировать IE.)

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

user113716
источник
Гораздо проще проверить полосы прокрутки, если сравнить offsetHeightи clientHeight. Последний всегда меньше на размер полосы прокрутки, когда полоса прокрутки присутствует.
Роберт Коритник
@ Роберт: Не уверен, что проще, но я вижу, как это работает. Затем я предполагаю, что если у элемента есть overflow:scroll, вы хотите, чтобы он отображался как прокручиваемый, независимо от того, включены ли полосы прокрутки. Конечно, у моего решения могут быть проблемы, если к нему прикреплено событие onscroll.
user113716 04
На самом деле, нет. Если вы проверите мой плагин jQuery, мне нужно найти фактического прокручиваемого предка, иначе я не смогу прокрутить элемент в поле зрения.
Роберт Коритник
8
@RobertKoritnik Неправда; в некоторых браузерах могут быть полосы прокрутки, не уменьшающие ширину. Например, в OS X. Или сенсорные устройства.
daniel.gindi
1
всегда возвращает ложь
Фатих Эрол
14

Вот еще одно решение:

Как отметили некоторые люди, простого сравнения offsetHeight и scrollHeight недостаточно, поскольку они различаются по элементам со скрытым переполнением и т. Д., У которых все еще нет полос прокрутки. Итак, здесь я также проверяю, является ли переполнение прокручиваемым или автоматическим для вычисленных стилей для элемента:

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,
  };
}
лотиф
источник
Если overflow*это scrollвсегда будет полоса прокрутки, так что я думаю , что вы хотите vertical: overflowY === 'scroll' || overflowY === 'auto' && node.scrollHeight > node.clientHeight, и т.д. (т.е. снять скобки так scroll*против client*проверяется только когда overflow*есть auto). В противном случае это кажется наиболее правильным решением.
Джейк
@Jake Если scrollHeight <clientHeight при переполнении прокрутки, полосы прокрутки будут там, но они будут отключены (т.е. элемент не прокручивается). Думаю, это зависит от приложения. Ваша модификация действительна, если вы просто хотите проверить наличие полос прокрутки, независимо от состояния. Когда я придумал это, я хотел реализовать автопрокрутку для компонента, поэтому отключение полос прокрутки в этом случае бесполезно. Похоже, то же самое относится и к этому вопросу (он должен «прокручиваться людьми»)
lotif
6

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

Я считаю, что вы можете обнаружить полосы прокрутки с помощью e.offsetWidth против e.clientWidth. Ширина смещения включает границы и полосы прокрутки, отступы и ширину. Ширина клиента включает отступы и ширину. Посмотри пожалуйста:

https://developer.mozilla.org/en/DOM/element.offsetWidth (второе изображение) https://developer.mozilla.org/en/DOM/element.clientWidth (второе изображение)

Вам необходимо проверить:

  1. Установлено ли для элемента переполнение автоматически / прокрутка (включая переполнение X / Y) с использованием вычисленного / каскадного / текущего стиля.
  2. Если для элемента задано автоматическое переполнение / прокрутка. Установите offsetWidth и clientWidth.
  3. Если clientWidth меньше, чем offsetWidth - правая граница (снова найденная с помощью вычисляемого / каскадного / текущего стиля), то вы знаете, что у вас есть полоса прокрутки.

Сделайте то же самое для вертикали (offset / clientHeight).

IE7 сообщает, что clientHeight равен 0 для некоторых элементов (я не проверял почему), поэтому вам всегда нужна первая проверка переполнения.

Надеюсь это поможет!


источник
3

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

Так как рендеринг браузера происходит не очень часто, вы можете проверить наличие прокрутки с изменением прокрутки, а затем вернуть ее:

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

Хакобпог
источник
1

Просто возиться здесь, поскольку ни одно из вышеперечисленных решений для меня не сработало (пока). Я нашел некоторый успех при сравнении высоты прокрутки Div с его offsetHeight

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

Кажется, это дает мне точное сравнение ... пока что. Кто-нибудь знает, законно ли это?

Майкл
источник
2
Думаю, вам нужны scrollHeight и clientHeight: stackoverflow.com/questions/4106538/…
rich remer
1

Для IE11 (Internet Explorer 11) мне пришлось изменить логику на:

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

Это связано с тем, что IE сообщает scrollHeight на 1 больше, чем clientHeight, когда полоса прокрутки отсутствует, но примерно на 9 больше, когда полоса прокрутки присутствует.

danday74
источник
0

Если вам нужно знать, присутствует ли полоса прокрутки для всей веб-страницы и с полной поддержкой браузера, вы можете использовать это:

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

Это важно использовать window.innerHeightвместо, document.body.clientHeightпотому что в некоторых мобильных браузерах clientHeight не получает размер адресной строки, а scrollHeight будет, поэтому вы получите неправильные вычисления.

Себастьян Эрнандес
источник
-5

ни один из этих ответов не является правильным. вы должны использовать это:

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

var hasHorizontalScrollbar = (div.offsetWidth > div.clientWidth);
var hasVerticalScrollbar = (div.offsetHeight > div.clientHeight);
Гамид
источник
Это было отклонено, потому что он был скопирован / вставлен из принятого ответа от 6 лет назад, и вам не нужны круглые скобки, чтобы превратить что-то в логическое.
мото
-6

Добавьте внутрь элемент шириной 100%. Затем установите значение переполнения как скрытое. Если вычисленный стиль элемента (из jQ) изменяется, у родительского элемента была полоса прокрутки.

РЕДАКТИРОВАТЬ: Кажется, вам нужен кроссбраузерный метод, например getComputedStyle . Пытаться:

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
источник
1
Если бы я уже использовал для этого jQuery, я бы просто сделал это $(el).css("overflow/overflowX/overflowY")и посмотрел, установлен ли он на автоматический или прокручиваемый . Но я бы не хотел использовать jQuery.
Роберт Коритник 02
16
Стили CSS не будут вам сказать , является ли или нет элемента имеет скроллбар. Только то, могут ли у него полосы прокрутки или нет . Может быть, найти кроссбраузерный метод определения ширины внутреннего элемента?
Soumya
@ Soumya92: Сравнение размеров прокручиваемого и фактического размера тривиально, и я написал это выше ... Все, что мне нужно сейчас проверить, это текущая настройка переполнения для конкретного элемента.
Роберт Коритник 02
@ Soumya92: это именно то, что мне нужно. Его также можно значительно упростить, используя coalescecomputedStyle = el.currentStyle || document.defaultView.getComputedStyle(el, null);
Роберт Коритник
Еще один вопрос: насколько это кроссбраузерность? Какие браузеры это поддерживает?
Роберт Коритник 02