Reputation: 473823
What is the most reliable and efficient way to find all elements having a scroll on a page?
Currently, I'm thinking about using element.all()
with filter()
comparing the height
and scrollHeight
attribute values:
element.all(by.xpath("//*")).filter(function (elm) {
return protractor.promise.all([
elm.getAttribute("height"),
elm.getAttribute("scrollHeight")
]).then(function (heights) {
return heights[1] > heights[0];
});
});
But I'm not sure about the correctness and performance of this approach.
Upvotes: 19
Views: 3150
Reputation: 2484
@Andrew Templeton's answer rewritten in straightforward style:
/** @param {Element} elem */
function hasScroller(elem) {
const x_overflowing = elem.offsetWidth < elem.scrollWidth;
const y_overflowing = elem.offsetHeight < elem.scrollHeight;
if (!x_overflowing && !y_overflowing) {
return false;
}
const css = document.defaultView.getComputedStyle(elem, null);
return (
(x_overflowing && (css['overflow-x'] == 'scroll' || css['overflow-x'] == 'auto')) ||
(y_overflowing && (css['overflow-y'] == 'scroll' || css['overflow-y'] == 'auto'))
);
}
var elementsWithScrolls = Array.from(document.querySelectorAll('*').filter(hasScroller));
Upvotes: 2
Reputation: 1798
It will select the elements with overflowed and non-overflowed scrolls inside body tag:
$('body *').filter(function() {
return ($(this).scrollTop() != 0 || $(this).css('overflow') == 'scroll');
});
Upvotes: 2
Reputation: 1696
This works with both horizontal and vertical scrollbars. The trick is detecting BOTH the too-wide/too-short AND if the computed CSS is going to allow you to display a scrollbar.
var ElementsWithScrolls = (function() {
var getComputedStyle = document.body && document.body.currentStyle ? function(elem) {
return elem.currentStyle;
} : function(elem) {
return document.defaultView.getComputedStyle(elem, null);
};
function getActualCss(elem, style) {
return getComputedStyle(elem)[style];
}
function isXScrollable(elem) {
return elem.offsetWidth < elem.scrollWidth &&
autoOrScroll(getActualCss(elem, 'overflow-x'));
}
function isYScrollable(elem) {
return elem.offsetHeight < elem.scrollHeight &&
autoOrScroll(getActualCss(elem, 'overflow-y'));
}
function autoOrScroll(text) {
return text == 'scroll' || text == 'auto';
}
function hasScroller(elem) {
return isYScrollable(elem) || isXScrollable(elem);
}
return function ElemenetsWithScrolls() {
return [].filter.call(document.querySelectorAll('*'), hasScroller);
};
})();
ElementsWithScrolls();
Upvotes: 8