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