March 16, 2012

Find all block elements

Question by Ilya Volodin

I need to find all block elements in a given node. Block elements are not just elements that have display:block in the CSS, but also default block elements like div and p.

I know I can just get computed style of the element and check for the display property, however, my code will execute in a long loop and getting computed styles flushes reflow stack every time, so it will be very expansive.

I’m looking for some trick to do this without getComputedStyle.

Edit

Here’s my current code that I would like to improve:

var isBlockOrLineBreak = function(node)
{
    if (!node) {
        return false;
    }
    var nodeType = node.nodeType;
    return nodeType == 1 && (!inlineDisplayRegex.test(getComputedStyleProperty(node, "display")) || node.tagName === "BR")
        || nodeType == 9 || nodeType == 11;
};

Another edit

jQuery’s .css calls getComputedStyle under the hood. So that’s not what I’m looking for.

My solution

Thanks everyone for suggestions. Unfortunately, none of them matched what I was looking for. After a lot of digging through documentation I realized that there’s no real way to do this without getComputedStyle. However, I came up with the code that should avoid getComputedStyle as much as humanly possible. Here’s the code:

$.extend($.expr[':'], {
    block: function(a) {
        var tagNames = {
            "ADDRESS": true,"BLOCKQUOTE": true,"CENTER": true,"DIR": true,"DIV": true,
            "DL": true,"FIELDSET": true,"FORM": true,"H1": true,"H2": true,"H3": true,
            "H4": true,"H5": true,"H6": true,"HR": true,"ISINDEX": true,"MENU": true,
            "NOFRAMES": true,"NOSCRIPT": true,"OL": true,"P": true,"PRE": true,"TABLE": true,
            "UL": true,"DD": true,"DT": true,"FRAMESET": true,"LI": true,"TBODY": true,
            "TD": true,"TFOOT": true,"TH": true,"THEAD": true,"TR": true
        };
        return $(a).is(function() {
            if (tagNames[this.tagName.toUpperCase()]) {
                if (this.style.display === "block")
                {
                    return true;
                }
                if (this.style.display !== "" || this.style.float !== "")
                {
                    return false;
                }
                else {
                    return $(this).css("display") === "block";
                }
            }
            else {
                if (this.style.display === "block") {
                    return
                }
                else {
                    return $(this).css("display") === "block";
                }
            }
        });
    }
});

Usage of this code is very simple just do $(“:block”) or $(“form :block”). This will avoid using .css property in a lot of cases, and only fallback to it as a last resort.

Starx’s answer was what gave me the idea to do this, so I’m going to mark his message as an answer.

Answer by Starx

The best way I see is to

  • assign a common class to all the not-native block element and
  • using jQuery’s mulitple-selector.

Then we can do it as simple as this this

CSS:

.block { display: block; }

jQuery:

var blockelements = $("div, p, table, ..., .block"); 
                                   // ^ represents other block tags

If you want to include all the block elements. Here is a link

Author: Nabin Nepal (Starx)

Hello, I am Nabin Nepal and you can call me Starx. This is my blog where write about my life and my involvements. I am a Software Developer, A Cyclist and a Realist. I hope you will find my blog interesting. Follow me on Google+

...

Please fill the form - I will response as fast as I can!