5
\$\begingroup\$

I have constructed a function that checks whether an element has a scrollbar or not, and can also check individual axes.

I don't know if this works in all major browsers and am unsure about the performance.

Is there any way to improve upon the code, did I miss anything?
How would a javascript equivalent look like?

Note: I first asked this question on Stack Overflow, but someone suggested I should post it here instead.


Code | Example

$.fn.hasScroll = function(axis){
    var sX = this.css("overflow-x"),
        sY = this.css("overflow-y");

    if(typeof axis == "undefined"){
        //Check both x and y declarations
        if(
            (sX == "hidden" && sY == "hidden") ||
            (sX == "visible" && sY == "visible")
        ){
            return false;
        }

        if(sX == "scroll" || sY == "scroll"){
            return true;
        }
    }else{
        //Check individual axis declarations
        switch(axis){
            case "x":
                if(sX == "hidden" || sX == "visible") return false;
                if(sX == "scroll") return true;
            break;
            case "y":
                if(sY == "hidden" || sY == "visible") return false;
                if(sY == "scroll") return true;
            break;
        }
    }

    //Compare client and scroll dimensions to see if a scrollbar is needed
    var bVertical = this[0].clientHeight < this[0].scrollHeight,
        bHorizontal = this[0].clientWidth < this[0].scrollWidth;

    return bVertical || bHorizontal;
};
\$\endgroup\$
8
\$\begingroup\$

I would write this as an extension to the Sizzle engine rather than a jQuery plugin; I've made a few other minor changes as well:

function hasScroll(el, index, match) {
    var $el = $(el),
        sX = $el.css('overflow-x'),
        sY = $el.css('overflow-y'),
        hidden = 'hidden', // minifiers would like this better
        visible = 'visible',
        scroll = 'scroll',
        axis = match[3]; // regex for filter -> 3 == args to selector

    if (!axis) { // better check than undefined
        //Check both x and y declarations
        if (sX === sY && (sY === hidden || sY === visible)) { //same check but shorter syntax
            return false;
        }
        if (sX === scroll || sY === scroll) { return true; }
    } else if (axis === 'x') { // don't mix ifs and switches on the same variable
        if (sX === hidden || sX === visible) { return false; }
        if (sX === scroll) { return true; }
    } else if (axis === 'y') {
        if (sY === hidden || sY === visible) { return false; }
        if (sY === scroll) { return true };
    }

    //Compare client and scroll dimensions to see if a scrollbar is needed

    return $el.innerHeight() < el.scrollHeight || //make use of potential short circuit
        $el.innerWidth() < el.scrollWidth; //innerHeight is the one you want
}
$.expr[':'].hasScroll = hasScroll;

You can then use this in any jQuery selector, such as:

$('div:hasScroll') //all divs that have scrollbars
$('div').filter(':hasScroll') //same but better
$(this).closest(':hasScroll(y)') //find the parent with the vert scrollbar
$list.is(':hasScroll(x)') //are there any horizontal scrollbars in the list?

If you must have an instance method to do this check then you could write this to keep your semantics:

$.fn.hasScroll = function(axis) {
    var el = this[0];
    if (!el) { return false; }
    return hasScroll(el, 0, [0, 0, 0, axis]);
};

Updated JsFiddle

\$\endgroup\$
  • 1
    \$\begingroup\$ Most impressive. I didn't consider having it as a selector function. Very nice. You wrote in the comments "don't mix ifs and switches on the same variable", "minifiers would like this better" and "better check than undefined". Could you explain these comments or point to some documentation that does? :) \$\endgroup\$ – ShadowScripter Jul 7 '12 at 9:17
8
\$\begingroup\$

=== everywhere

=== > == (Not that it really matters in this case, but it's still better.)

Also, IIRC clientHeight etc are not cross-browser, this is why jQuery provides .position(), .offset(), .scrollTop() and .height() (whichever one best suits your needs).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.