9

We have a situation in our project when resizing a container. It seems to be impossible to keep the "auto" value for our elements margin.

For example when trying to get the margin value with javascript or jquery, the value always returns 0. We really need to keep "auto" when resizing, so is there a way to determine which elements have margin: auto;

Even if it's possible using raw javascript?

----------------- Possible solution but needs Extending -----------------

I have found this useful. Which in fact solves part of the problem!

Retrieve element margin if it's 'auto' (Answer 3)

if($(this).position().left*2 == ($(this).parent().innerWidth() - $(this).outerWidth())) {
  console.info($(this).attr('id'));
}

However this matches far to many elements, so need to somehow be more specific. hopefully someone knows how to improve this code?

Community
  • 1
  • 1
user828941
  • 145
  • 1
  • 9
  • I'm not very good at this. Have you tried to set margin:auto after resizing? If so, what happend? – Pikaurd Dec 02 '11 at 12:44
  • This sounds like a small issue which is part of a bigger problem. What exactly should happen when you resize the container? – Rory McCrossan Dec 02 '11 at 12:51
  • Pikaurd: To have a automatic resize I don't want to manually set auto. But will consider this suggestion if this problem can not be solved – user828941 Dec 02 '11 at 13:00
  • Rory: When I resize the main container the entire site resizes, but unfortunately certain divs are not centered because they are set to 0 instead of auto :( – user828941 Dec 02 '11 at 13:03
  • As for the `css('margin') == 'auto'` answers: "Shorthand CSS properties (e.g. margin, background, border) are not supported. For example, if you want to retrieve the rendered margin, use: $(elem).css('marginTop') and $(elem).css('marginRight'), and so on." http://api.jquery.com/css/ – Viruzzo Dec 02 '11 at 14:17

4 Answers4

5

EDIT: I've only tested the following solution in Chrome. It isn't currently working in IE or Firefox. I'll provide an update when I get it working.

EDIT 2: Firefox solution: http://jsfiddle.net/E9eW6/8/ . The problem is that each browser handles their CSSStyleDeclaration object differently. While Firefox's was managable, IE is out in la-la land somewhere with their CSSRuleStyleDeclaration equivalent. I apologize, but I am not knowledgeable nor patient enough to learn Microsoft's poor implementation that will likely change in the future.

after a bit of research of this intriguing question, I found a solution

jsFiddle: http://jsfiddle.net/S5Sbf/3/

The answer was actually in another question here on Stackoverflow: Can jQuery get all CSS styles associated with an element? (see 2nd answer)

Basically the function will iterate through document.Stylesheets looking for the element that matches yours, and returns all of its CSS in a nice scrumptious object.

This is a very beautiful function, use it with pride!

function css(a){
    var sheets = document.styleSheets, o = {};
    for(var i in sheets) {
        var rules = sheets[i].rules || sheets[i].cssRules;
        for(var r in rules) {
            if(a.is(rules[r].selectorText)) {
                o = $.extend(o, css2obj(rules[r].style), css2obj(a.attr('style')));
            }
        }
    }
    return o;
}

function css2obj(css){
        var s = {};
        if(!css) return s;
        if(css instanceof CSSStyleDeclaration) {
            for(var i in css) {
                if((css[i]).toLowerCase) {
                    s[(css[i]).toLowerCase()] = (css[css[i]]);
                }
            }
        } else if(typeof css == "string") {
            css = css.split("; ");          
            for (var i in css) {
                var l = css[i].split(": ");
                s[l[0].toLowerCase()] = (l[1]);
            };
        }
        return s;
    }

(Usage details in 2nd answer: Can jQuery get all CSS styles associated with an element?)

Using the css function above:

$("*").each(function(index, element){
    cssObj = css($(element));
    $(element).after("margin-left is " + cssObj['margin-left'] + '<br/>');
    $(element).after("margin-right is " + cssObj['margin-right'] + '<br/>');
    $(element).after("margin-top is " + cssObj['margin-top'] + '<br/>');
    $(element).after("margin-bottom is " + cssObj['margin-bottom'] + '<br/>');
});
Community
  • 1
  • 1
Vigrond
  • 8,148
  • 4
  • 28
  • 46
  • This is a very impressive answer. Unfortunately after testing this method the margins are still undefined in Firefox. However your method is very interesting. I have found it is possible to return cssText from the CSS Rule object which now allows me to output the entire content for each CSS rule. Which includes margin auto. So all I need to do is loop through these properties and create a global CSS object! So I am certainly much closer to a solution thanks to your post :) I will hopefully post the complete solution later on this evening. – user828941 Dec 04 '11 at 15:33
  • 1
    I think an alternate solution may be the best thing for you. While you can get this concept to work in Firefox/Webkit, IE is a totally different monster. Perhaps you can more thoroughly describe your website structure and what needs to happen with it using jsfiddle? – Vigrond Dec 04 '11 at 19:23
1

Thanks to Vigrond previous answer above. I was able to research further into the CSS Rule Object.

Finally I have come up with my own solution to return the actual CSS rules direct from the style-sheet! This not only solves my problem with margin auto, it also allows me to return all other css values which are not returned by the jquery CSS object.

Although the code could be optimized further. I am very happy with the result, also I added a white list as in my case it is not necessary to loop through all style-sheets.

Here is the code I ended up with!

var cssObj  = {};
function getStyle(element) {    
  var extractStyles = function(cssText) {
    var css = {};
    regEx   = /\.*\{[^\}](.*)}/im;
    styles  = cssText.match(regEx)[1].split(';');
    $.each(styles, function(k, style) {
      $key = style.split(':')[0].trim();
      $val = style.split(':')[1];
      if($key != '')
        css[$key] = $val.trim();
    });
    return css;
  };
  var sheets    = document.styleSheets;
  var whiteList = [
    cssPath+'product.css',
    cssPath+'style.css'
  ];
  $.each(sheets, function(key, sheet) {
    if($.inArray(sheet.href, whiteList) >=0) {
      $rules = sheet.rules || sheet.cssRules;
      $.each($rules, function(key, rule) {
        if(element.is(rule.selectorText)) {
          if(typeof(rule.cssText) != 'undefined' && rule.cssText) {
            cssObj[rule.selectorText] = extractStyles(rule.cssText);
          } else {
            cssObj[rule.selectorText] = (typeof(rule.cssText) != 'undefined' ? extractStyles(rule.style.cssText) : '');
          }
        }
     });
    }
 });
}
user828941
  • 145
  • 1
  • 9
0

well yo could something like this?

$('.container').each(function(){
      if($(this).css('margin') == 'auto'){
             console.log($(this).attr('id')+' has margin auto');
      }
});

but if you post some code or link will be easier to help

Toni Michel Caubet
  • 19,333
  • 56
  • 202
  • 378
0

you can do this for every element in a page with the $("*") search in jQuery

 $("*").each(function(){
      if($(this).css('margin') == 'auto'){
           console.log($(this).attr('id')+' has margin auto');
      }
 });
Amadeus
  • 189
  • 8
  • 1
    Thanks for your answer. I have tried this, but again have the same problem the condition still returns false. But in firebug I know several elements are set to auto. – user828941 Dec 02 '11 at 14:03