Thomas: getComputedStyle und margin:auto im Firefox

Hallo zusammen!

Ich möchte per JavaScript herausfinden, welchen margin-left (-right) ein bestimmtes Element besitzt. Normalerweise ist das kein Problem:

window.getComputedStyle(element, false).marginLeft

Das klappt aber leider bei manchen Block-Elementen nicht, wenn diese "margin: auto" besitzen; dann liefert getComputedStyle nämlich 0.

Testcase:

<head>  
    <title>Test</title>  
    <style type="text/css">  
        p { background: yellow; margin: auto; width: 300px;}  
    </style>  
</head>  
  
<body>  
    <p id="p"></p>  
    <script type="text/javascript">  
        var p = document.getElementById('p');  
        p.appendChild(document.createTextNode(  
            'margin-left: '  
            + window.getComputedStyle(p, false).marginLeft  
        ));  
    </script>  
</body>

Erst mal habe ich so meine Zweifel, ob das korrekt ist, denn:

http://www.w3.org/TR/CSS2/visudet.html#q6

If 'left' or 'right' are given as 'auto', their computed value is 0.
The following constraints must hold between the other properties:

'margin-left' + 'border-left-width' + 'padding-left' + 'width'
+ 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block
[...]
If both 'margin-left' and 'margin-right' are 'auto', their computed values are equal.

Im Testcase sind die borders und paddings 0. Somit müsste 'margin-left'  = 'margin-right' = (Breite von Body - width)/2 sein. Gerendert wird es ja richtig, aber getComputedStyle liefert 0. Bug im Firefox?

Da das nun mal nicht funktioniert, gibt es irgendeine andere Möglichkeit?

Vielen Dank schon mal!

  1. Gerendert wird es ja richtig, aber getComputedStyle liefert 0. Bug im Firefox?

    Ich sehe gerade, Opera 9/10(Lin/Win) versagt ebenfalls. Safari 3.2.2(Win) macht es hingegen so, wie ich mir das vorstelle.

  2. Im Testcase sind die borders und paddings 0. Somit müsste 'margin-left'  = 'margin-right' = (Breite von Body - width)/2 sein.

    was hindert dich dran, das dann auch so zu berechnen?

    1. was hindert dich dran, das dann auch so zu berechnen?

      Diese Formel gilt ja nur bei "margin: auto". Das Skript soll auf mehreren Seiten einsetzbar sein, und ich weiß a priori nicht, ob das Element "margin: auto" oder "margin: 0px" hat. Das Problem ist ja eben gerade, das herauszufinden.

      Aber vielleicht geht es anders:
      Wann gilt denn
      marginLeft == offsetLeft - offsetParent.paddingLeft
      ?

      Das sollte ja bei nicht-gefloateten Boxen mit "position:static" hinhauen, oder?

      Und bei "position:relative" so:
      marginLeft == offsetLeft - offsetParent.paddingLeft - left

      (Man verzeihe mir den nicht-funktionierenden Pseudo-Code. Ihr wisst hoffentlich, was gemeint ist.)

      1. Tja, das ist ja wohl wirklich nicht ganz einfach. Der einzige Anhaltspunkt ist offsetLeft, und mir fällt zur Berechnung keine bessere Methode ein als diese:

        function getMarginLeftUsedValue(element) {  
            var elementComputedStyle = window.getComputedStyle(element, null);  
            var computedMarginLeft = elementComputedStyle.marginLeft;  
            if (parseFloat(computedMarginLeft) != 0)  
                return computedMarginLeft;  
            if (!/^(relative|static)$/.test(elementComputedStyle.position))  
                return computedMarginLeft;  
            var offsetParent = element.offsetParent;  
            var containingBlock = element.parentNode;  
            var containingBlockComputedStyle = window.getComputedStyle(containingBlock, null);  
            while(!/^((inline-)?block|list-item|run-in|table(-cell)?)$/i.test(containingBlockComputedStyle.display)) {  
                containingBlock = containingBlock.parentNode;  
                containingBlockComputedStyle = window.getComputedStyle(containingBlock, null);  
            }  
            var distanceLeft; // horizontal distance to containing block  
            if (containingBlock == offsetParent) {  // containing block is positioned  
                distanceLeft = element.offsetLeft;  
            } else { // containing block has position:static -> containingBlock.offsetParent = root element  
                distanceLeft = element.offsetLeft - containingBlock.offsetLeft;  
                do {  
                    distanceLeft += offsetParent.offsetLeft;  
                } while (offsetParent = offsetParent.offsetParent) // confusing, eh?  
            }  
            if (elementComputedStyle.position == 'relative')  
                return (distanceLeft - parseFloat(containingBlockComputedStyle.paddingLeft) - parseFloat(elementComputedStyle.left)) + 'px';  
            else // elementComputedStyle.position = 'static'  
                return (distanceLeft - parseFloat(containingBlockComputedStyle.paddingLeft)) + 'px';  
        }  
        
        

        Und alles nur weil

        The CSS Object Model doesn't provide an access to the specified or actual values of the CSS cascade.

        Wenn euch eine einfachere Lösung einfällt, her damit!

        1. Hi,

          Wenn euch eine einfachere Lösung einfällt, her damit!

          Ich wuesste bis jetzt nicht mal, zu was fuer einem *Problem* eigentlich.

          Bis jetzt hast du nur beschrieben, dass du mit JavaScript exzessiv irgendwelche Werte berechnest - aber wofuer du die eigentlich brauchst ...?

          MfG ChrisB

          --
          „This is the author's opinion, not necessarily that of Starbucks.“
  3. Bug im Firefox?

    Mittlerweile habe ich rausgefunden: Ja. (Wen's interessiert: Bug #381328)
    Dummerweise führt der auch zu falschen Anzeigen in Firebug. *heul* *tieflufthol*

    marginLeft == offsetLeft - offsetParent.paddingLeft
    ?

    Mist, das klappt so nicht, weil für statisch oder relativ positionierte Elemente der offsetParent i.A. nicht der Containing Block ist. Ojeoje, das ist aber kompliziert...