Determine exactly whether an item scrolls

I am working on a custom knockout snap that determines whether a particular item scrolls and updates the border observed with the top of the item relative to the viewport. The binding seems to work right now, but I have some concerns about whether there are circumstances where this will not be.

HTML:

Scroll position: <span data-bind="text: scrollPosition"></span> <div class="longdiv"> <p data-bind="scroll: scrollPosition">This is some text.</p> <div class="shim"></div> </div> 

CSS:

 .longdiv { width: 200px; height: 200px; overflow: scroll; border: 1px solid black; } 

JS:

 ko.bindingHandlers.scroll = { init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { var firstScrollableContainer = null; var binding = allBindings.get('scroll'); $(element).parents().each(function (i, parent) { if ($(parent).css('overflow')=='scroll') { firstScrollableContainer = parent; return false; } }); firstScrollableContainer = firstScrollableContainer || window; binding(element.getBoundingClientRect().top); $(firstScrollableContainer).scroll(function() { binding(element.getBoundingClientRect().top); }); } }; var ViewModel = function() { var self = this; self.scrollPosition = ko.observable(0); }; ko.applyBindings(new ViewModel()); 

Jsfiddle

The binding takes an element and uses jQuery to go through the parent chain and see if the parent element has overflow: scroll set. If it finds a div with overflow: scroll, it associates an event handler with this element's scroll event. If it does not find the parent with overflow: scroll, it binds to the window scroll event.

So what I'm looking for, given a document structured like this:

 body > div > div > div > p 

is the closest element to p that can be scrolled so that I can attach an event handler to it.

My question is: looks at overflow: scroll enough test to see if parent element can scroll? If not, what should I look at?

EDIT: Based on your helpful comments and answers, here is the solution I came up with:

 function scrollable(element) { var vertically_scrollable, horizontally_scrollable; var e = $(element); if ( e.css('overflow') == 'scroll' || e.css('overflow') == 'auto' || e.css('overflowY') == 'scroll' || e.css('overflowY') == 'auto' || e.css('height') != 'none' || e.css('max-height') != 'none' ) { return true; } else { return false; } } 
+12
source share
3 answers

Do you want to know if an item can be scrolled or is it currently scrolling?

Is it possible to scroll an element?

An element can scroll if it has a fixed height (or max-height ) and overflow-y scroll or auto . But since it is not easy to indicate if the height of an element is fixed or not , it is probably enough to simply check overflow-y :

 e.css('overflow-y') == 'scroll' || e.css('overflow-y') == 'auto' 

Can an item scroll right now?

An element can scroll right now if its scrollHeight larger than its clientHeight , and if it has a scroll bar that can be determined by comparing clientWidth and offsetWidth (taking into account fields and borders) or if overflow-y is scroll or auto .

+10
source

This is probably the safest solution (jQuery required, for simple JavaScript see below):

 $.fn.isHScrollable = function () { return this[0].scrollWidth > this[0].clientWidth; }; $.fn.isVScrollable = function () { return this[0].scrollHeight > this[0].clientHeight; }; $.fn.isScrollable = function () { return this[0].scrollWidth > this[0].clientWidth || this[0].scrollHeight > this[0].clientHeight; }; 

Then you can check if the element can be scrolled as follows:

 $(parent).isScrollable(); 

For use without jQuery, you can implement such functions:

 function isScrollable(element) { return element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight; }; var myParent = document.getElementById('myParent') isScrollable(myParent) 
+10
source

By combining the two answers together and adding something of my own , I use this to check for vertical scrolling. It can be easily converted for other occasions. (H & VH)

 function isScrollable(e){ if( e.scrollTopMax !== undefined ) return e.scrollTopMax > 0; //All Hail Firefox and it superior technology! if( e == document.scrollingElement ) //If what you're checking is BODY (or HTML depending on your css styles) return e.scrollHeight > e.clientHeight; //This is a special case. return e.scrollHeight > e.clientHeight && ["scroll", "auto"].indexOf(getComputedStyle(e).overflowY) >= 0 } 

I tested this on Firefox and Chromium. Both are Linux. You can still check them out yourself.

0
source

All Articles