Verifique se o elemento HTML possui barras de rolagem

113

Qual é a maneira mais rápida de verificar se um elemento possui barras de rolagem?

Uma coisa, claro, é verificar se o elemento é maior do que sua janela de visualização, o que pode ser feito facilmente verificando estes dois valores:

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

mas isso não significa que ele também tenha barras de rolagem (portanto, pode ser rolado por humanos).

Questão

Como faço para verificar se há barras de rolagem em um 1 cross browser e 2 única javascript (como em nenhum jQuery ) caminho?

Somente Javascript, porque preciso da menor sobrecarga possível, porque gostaria de escrever um filtro seletor jQuery muito rápido

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

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

Suponho que teria que verificar as overflowconfigurações de estilo, mas como faço isso em um navegador cruzado?

Edição adicional

Não apenas overflowconfigurações de estilo. Verificar se um elemento possui uma barra de rolagem não é tão trivial quanto parece. A primeira fórmula que escrevi acima funciona bem quando o elemento não tem uma borda, mas quando tem (especialmente quando a borda é de largura considerável), a offsetdimensão pode ser maior do que a scrolldimensão, mas o elemento ainda pode ser rolável. Na verdade, temos que subtrair as bordas da offsetdimensão para obter a janela de visualização rolável real do elemento e compará-la à scrolldimensão.

Para referência futura

:scrollableO filtro seletor jQuery está incluído no meu .scrollintoview()plugin jQuery. O código completo pode ser encontrado na postagem do meu blog se alguém precisar. Mesmo não fornecendo a solução real, o código de Soumya me ajudou consideravelmente a resolver o problema. Isso me apontou na direção certa.

Robert Koritnik
fonte

Respostas:

118

Eu encontrei isso em algum lugar algumas semanas atrás. Funcionou para mim

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
fonte
12
Você obviamente teve um exemplo simplificado. E se o seu contêiner estiver overflow:hiddeninstalado nele? Haveria conteúdo em excesso, mas ainda não é rolável. O problema não é tão simples quanto pode parecer.
Robert Koritnik
7
Essa pode não ser a solução aceita, mas funcionou para mim. Não tenho certeza por que você iria rolar se estiver oculto.
vol7ron de
Essa pode não ser a solução aceita, mas funcionou para mim. Robert, para esses casos, você não poderia também buscar a propriedade de estouro de css para testar nesses casos (por exemplo div.scrollHeight>div.clientHeight && !(div.style.overflow && div.style.overflow == 'hidden'))?
vol7ron de
7
Isso falha em muitos casos. Se o seu elemento tiver estouro: visível; largura: 200px; e tem um filho com largura de 500px, seu elemento não tem barras de rolagem, mas tem scrollWidth de 500px e clientWidth de 200px.
Joseph Lennox
1
Se o estouro estiver visível ou oculto, geralmente não há barras de rolagem.
Hubert Grzeskowiak
16

Experimentar:

Para barra de rolagem vertical

el.scrollHeight> el.clientHeight

Para barra de rolagem horizontal

el.scrollWidth> el.clientWidth

Eu sei que isso funciona para IE8 e Firefox 3.6+, pelo menos.

Gary
fonte
2
Eu indiquei isso sim, que isso me diz que um determinado elemento é maior do que parece, mas isso não significa que ele exibe barras de rolagem. Ele pode muito bem ter overflow:hiddene não seria mais rolável.
Robert Koritnik
1
E verificar os valores de clientHeight / clientWidth não dá bons resultados, porque os elementos também podem ter bordas, que não estão incluídas nesta medida. Verifique minha fórmula. Funciona melhor que o seu.
Robert Koritnik
Isso é verdade sobre o uso de offsetHeight / offsetWidth para verificar barras de rolagem em vez de clientHeight / clientWidth. Obrigado por apontar isso.
Gary
@RobertKoritnik - então é só verificar se aquele elemento específico contém overflow:hidden... esta ainda é a resposta correta na minha opinião, por ser a mais simples.
vsync
14

Isso pode parecer (ou ser) um pouco hackeado, mas você pode testar as propriedades scrollTope scrollLeft.

Se eles forem maiores que 0, você sabe que existem barras de rolagem. Se forem 0, defina-os como 1 e teste-os novamente para ver se obtém um resultado de 1. Em seguida, defina-os de volta para 0.

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

Acredito que haja uma propriedade diferente para o IE, então vou atualizar em um minuto com isso.

EDIT: Parece que o IE pode oferecer suporte a esta propriedade. (Não consigo testar o IE agora.)

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

user113716
fonte
É muito mais fácil verificar as barras de rolagem se você comparar offsetHeighte clientHeight. O último é sempre menor pelo tamanho da barra de rolagem quando a barra de rolagem está presente.
Robert Koritnik
@Robert: Não tenho certeza se é mais fácil, mas vejo como funciona. Então, suponho que se um elemento foi overflow:scroll, você deseja que seja relatado como rolável, estejam as barras de rolagem habilitadas ou não. Claro que minha solução pode ter problemas se houver um evento onscroll anexado.
user113716
Na verdade não. Se você verificar meu plugin jQuery , terei que encontrar o ancestral rolável real, caso contrário, não consigo rolar um elemento para a visualização.
Robert Koritnik
8
@RobertKoritnik Não é verdade; alguns navegadores podem ter barras de rolagem que não reduzem a largura. Em um OS X, por exemplo. Ou dispositivos de toque.
daniel.gindi
1
sempre retorna falso
Fatih Erol
14

Aqui está outra solução:

Como algumas pessoas apontaram, simplesmente comparar offsetHeight e scrollHeight não é suficiente, pois eles diferem em elementos com overflow oculto, etc., que ainda não possuem barras de rolagem. Portanto, aqui também estou verificando se o estouro é scroll ou auto nos estilos calculados para o elemento:

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
fonte
Se overflow*estiver scroll, sempre haverá uma barra de rolagem, então acho que você quer vertical: overflowY === 'scroll' || overflowY === 'auto' && node.scrollHeight > node.clientHeight, etc. (ou seja, remova os colchetes para que o scroll*vs client*seja testado apenas quando overflow*for auto). Caso contrário, esta parece ser a solução mais correta.
Jake
@Jake Se scrollHeight <clientHeight no overflow de rolagem, as barras de rolagem estarão lá, mas serão desabilitadas (ou seja, o elemento não é rolável). Então acho que depende do aplicativo. Sua modificação é válida se você apenas deseja verificar as barras de rolagem, não importa o estado. Para mim, quando pensei nisso, estava procurando implementar o autoscroll para um componente, portanto, desativar as barras de rolagem é inútil nesse caso. Esse também parece ser o caso para esta pergunta (ela precisa "ser rolada por humanos")
lotif
6

Estou um pouco atrasado para a festa, mas ...

Eu acredito que você pode detectar barras de rolagem com e.offsetWidth vs. e.clientWidth. A largura do deslocamento inclui bordas e barras de rolagem, preenchimento e largura. A largura do cliente inclui preenchimento e largura. Por favor, veja:

https://developer.mozilla.org/en/DOM/element.offsetWidth (segunda imagem) https://developer.mozilla.org/en/DOM/element.clientWidth (segunda imagem)

Você precisa verificar:

  1. Se o elemento tem ou não overflow definido como auto / scroll (incluindo overflowX / Y) usando o estilo computado / em cascata / atual.
  2. Se o elemento tiver overflow definido como auto / scroll. Estabeleça o offsetWidth e clientWidth.
  3. Se clientWidth for menor que offsetWidth - borda direita (encontrada novamente por meio do estilo computado / em cascata / atual), você sabe que tem uma barra de rolagem.

Faça o mesmo para a vertical (offset / clientHeight).

O IE7 relata um clientHeight de 0 para alguns elementos (não verifiquei o porquê), portanto, você sempre precisa da primeira verificação de estouro.

Espero que isto ajude!


fonte
3

Existem vários problemas no caso de verificar a existência de barras de rolagem, um dos quais é que no mac você não tem nenhuma barra de rolagem visível, então ambas as soluções acima não lhe dariam uma resposta precisa.

Portanto, como a renderização do navegador não é muito frequente, você pode verificar a rolagem alterando a rolagem e configurando-a novamente:

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
fonte
1

Só estou brincando aqui, pois nenhuma das soluções acima funcionou para mim (até agora). Eu encontrei algum sucesso comparando a altura de rolagem de um Div com seu offsetHeight

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

Parece me dar uma comparação precisa ... até agora. Alguém sabe se isso é legítimo?

Michael
fonte
2
Acho que você quer scrollHeight e clientHeight: stackoverflow.com/questions/4106538/…
rich remer
1

Para o IE11 (Internet Explorer 11), tive que alterar a lógica para:

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

Isso ocorre porque o IE relata scrollHeight como 1 maior do que clientHeight quando nenhuma barra de rolagem está presente, mas aproximadamente 9 maior quando uma barra de rolagem está presente

danday74
fonte
0

Se você precisa saber se existe uma barra de rolagem presente em toda a página da web e com suporte completo ao navegador, você pode usar isto:

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

É importante usar em window.innerHeightvez de document.body.clientHeightporque em alguns navegadores móveis clientHeight não obterá o tamanho da barra de endereço, mas scrollHeight sim, então você obtém cálculos errados.

Sebastian Hernandez
fonte
-5

nenhuma dessas respostas está correta. você tem que usar isto:

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

var hasHorizontalScrollbar = (div.offsetWidth > div.clientWidth);
var hasVerticalScrollbar = (div.offsetHeight > div.clientHeight);
Hamid
fonte
Isso foi rejeitado porque foi copiado / colado da resposta aceita de 6 anos atrás e você não precisa de parênteses para transformar algo em um booleano.
moto
-6

Adicione um elemento 100% largo dentro dele. Em seguida, defina o estouro como oculto. Se o estilo calculado do elemento (de jQ) muda, o pai tinha uma barra de rolagem.

EDIT: Parece que você quer um método de navegador cruzado como getComputedStyle . Experimentar:

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
fonte
1
Se eu já usasse jQuery para isso, prefiro apenas fazer $(el).css("overflow/overflowX/overflowY")e ver se está definido como automático ou rolar . Mas eu gostaria de evitar o uso de jQuery.
Robert Koritnik
16
Os estilos CSS NÃO informarão se um elemento tem ou não barras de rolagem. Só se é ou não podem ter barras de rolagem. Talvez encontre um método de navegador cruzado para determinar a largura do elemento interno?
Soumya
@ Soumya92: A comparação de tamanho entre o tamanho rolável e o tamanho real é trivial e eu escrevi acima ... Tudo o que preciso verificar agora é a configuração de estouro atual em um elemento específico.
Robert Koritnik
@ Soumya92: é exatamente disso que preciso. Também pode ser muito simplificado usando coalescecomputedStyle = el.currentStyle || document.defaultView.getComputedStyle(el, null);
Robert Koritnik
Mais uma coisa: Como cross browser é esse? Quais navegadores são compatíveis com isso?
Robert Koritnik