GuruYaya
GuruYaya

Reputation: 641

Javascript way to locate all elements with margin: auto

I'm looking for an easy way to locate elements on the page that have margin-left and margin-right set to auto.

I got this script, that helps me some of the time:

(function() {
  var elementsList = [];
  for (var i = 0; i < document.styleSheets.length; i++) {
    var styleSheet = document.styleSheets[i];
    if (styleSheet.rules) {
      for (var j = 0; j < styleSheet.rules.length; j++) {
        var rule = styleSheet.rules[j];
        if (rule && rule.style && rule.style.marginLeft == 'auto' && rule.style.marginRight == 'auto') {
          var smallList = document.querySelectorAll(rule.selectorText);
          if (smallList.length)
            elementsList = elementsList.concat(smallList);

        }

      }
    }
  }
  return elementsList
})();

While this function gets some of the job done, it doesn't catch most cases of margin: auto I've seen in websites.

Can you show me a better way?

Upvotes: 9

Views: 331

Answers (4)

Martin Ernst
Martin Ernst

Reputation: 3269

This problem is not trivial. Even in the days of window.getComputedStyle() it's hard to get a crossbrowser reliable answer for marginLeft/Right when margins are set to auto. So this is shurely not a complete answer but will try helping to find one.

margin-left and margin-right are also auto when the margin-shorthand is used:

#elem {margin: auto;} // or:
#elem {margin: 100px auto;} // or:
#elem {margin: 100px auto 30px;} // or:
#elem {margin: 100px auto 30px auto;}

You have to find those notations too when you are searching in the stylesheets. Include this function just before var elementsList=[]; in your code:

function expand(margin) {
    var parts = margin.split(' ');
    for (var i = 3; i; i--) parts[i] = parts[i] || parts[i - 2] || parts[0];
    return parts[1] == 'auto' && parts[3] == 'auto';
}

Then change your inner if-condition to:

if (rule && rule.style &&
    (rule.style.marginLeft == 'auto' && rule.style.marginRight == 'auto' || expand(rule.style.margin))
) {
    var smallList = document.querySelectorAll(rule.selectorText);
    if (smallList.length) elementsList = elementsList.concat(smallList);
}

Now you get also the rules where margin is used. But some problems stay with your code:

  • Same elements may be listed multiple times when they match more than one rule
  • It's not shure that all listet elements are really rendered with marginLeft/Right = auto. Maybe that css becomes overridden by another more specific rule.
  • As dfsq mentioned in his comment there can be inline-styles you can't find this way.

Upvotes: 0

GuruYaya
GuruYaya

Reputation: 641

I hate to say this, but this one has less success then my own version.

Upvotes: 0

Nicolas
Nicolas

Reputation: 1870

If you're OK to use JQuery

As said by Martin Ernst for yonatan's answer: 'This will select only elements with marginLeft/Right="auto".'

Besides, as described in the comments, elements must be hidden in order to work with FF and safari.

This should work using JQuery:

$(document).ready(function() {
    var visibleElements = $('body *:visible');
    $('body *').hide();
    var elements = $('body *').filter(function() {
        return $(this).css('margin-left') == 'auto' && $(this).css('margin-right') == 'auto';
    })
    // show only elements that were visible
    visibleElements.show();
});

Tip: if for some reason, you need to not load external scripts, just copy the content of the minified jquery script at the begining of yours.

Upvotes: 2

yonatan
yonatan

Reputation: 615

use jQuery:
$('*').filter(function(i, d){return d.style.marginLeft == "auto" && d.style.marginRight == 'auto';});

Upvotes: 0

Related Questions