Stephen R
Stephen R

Reputation: 3927

Detect if scrollbar is visible (e.g. on a mobile device)

I've seen lots of questions/answers regarding detecting if an HTML element is scrollable (e.g. Detect scrollbar dynamically ). I need something similar, but not quite the same.

I have a div set to overflow-y: scroll;. On a desktop browser it shows the vertical scrollbar; that's fine. On an iPad, there is no vertical scrollbar; but you can scroll it by touch. The problem I'm having is that it's not always visually obvious on an iPad that the div can be scrolled. The Div simply contains a list; and sometimes my users think they're seeing the entire list and don't realize there's more if they scroll.

I'm thinking that if I can somehow detect if there is a visible scrollbar -- not simply if it's scrollable or not -- I can add a background image or similar visual cue for the mobile users who don't have the scrollbar. But I don't want a redundant cue if there's already a scrollbar.

I'm open either to JavaScript/PHP solutions to detect the scrollbar, or other ways (CSS?) to "cue" the fact that a section can be scrolled. Any ideas?

Upvotes: 4

Views: 6838

Answers (2)

Stephen R
Stephen R

Reputation: 3927

Based on Doug's hint about comparing offsetWidths, here's a working solution I came up with. Elements with the vscroll class are styled overflow-y: scroll;.

$(document).ready(function () {
    var scrollables = document.getElementsByClassName('vscroll');
    if( scrollables.length && 0 === scrollables[0].offsetWidth - scrollables[0].clientWidth ) {
        for ( const scrollable of scrollables ) {
            scrollable.style.background = 'url("/images/updnarrows_75.png") no-repeat 60% 50%';
        }
    }
});

The image is a set of faded up/down arrows that appear centered in the background of the div.

Upvotes: 0

Doug
Doug

Reputation: 1515

JS solution: Compare the height (offsetHeight or clientHeight) of the element wrapping the content and the list itself -- then execute code accordingly.

If you want to detect a scrollbar, this stackoverflow answer may help: Hide scroll bar, but while still being able to scroll

Where you can do Element.offsetWidth - Element.clientWidth to get a scrollbar's width (it should return 0 if there is no scrollbar).

This Stack Overflow answer goes into detail about offset vs. client: What is offsetHeight, clientHeight, scrollHeight?

const listWrapper = document.getElementById('list-wrapper'),
      container   = document.getElementById('container'),
      list        = document.getElementById('list');

// compare the height of the target element ( listWrapper or list )
// against the element containing the element ( container )
if( list.offsetHeight > container.offsetHeight ){
  // if the list is longer, add a class to the containing element
  container.className = 'overflowed';
}

console.log( container.offsetHeight - container.clientHeight );
console.log( listWrapper.offsetHeight - listWrapper.clientHeight );
#container{ height: 150px; width: 150px; overflow-y: scroll; border: solid 1px red; }
#container.overflowed{
  background: linear-gradient(transparent 85%, rgba(0,0,0,0.25) );
}
<div id="container">
  <div id="list-wrapper">
    <ul id="list">
      <li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li><li>abcde</li>
    </ul>
  </div>
</div>

Upvotes: 3

Related Questions