alecxe
alecxe

Reputation: 473823

Finding all elements with a scroll

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

Answers (3)

Will Manley
Will Manley

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

Filipe
Filipe

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

Andrew Templeton
Andrew Templeton

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

Related Questions