Menu

#1916 CSS declarations may have priority over inline style depending on evaluation order

Latest SVN
closed
RBRi
None
1
2017-08-30
2017-08-28
No

When inline style is evaluated before CSS stylesheets, the stylesheet style may get priority over the inline style when combining "margin-left" with "margin". Example:
Html file:

<!DOCTYPE html>
<html>
<head>
<title>Margin test</title>
<style type="text/css">
div {
    margin: 10px 10px 10px 5px;
}
</style>
</head>
<body>
    <div id="pos" style="margin-left: 100px"></div>
    <script>
    // <![CDATA[
        var div = document.getElementById("pos");
        // Force evaluation of the style
        var mLeft = div.style.marginLeft;
        // Triggers lazy evaluation of the CSS
        var oLeft = div.offsetLeft;
        div.innerHTML = oLeft;
// ]]>
    </script>
</body>
</html>

HtmlUnit test:

        WebClient webClient = new WebClient();
        HtmlPage page = webClient.getPage(TEST_PAGE);
        int offsetWidth = Integer.parseInt(page.querySelector("div#pos").asText());
        assertThat(offsetWidth, Matchers.greaterThanOrEqualTo(100));
        webClient.close();

This fails with:

java.lang.AssertionError:
Expected: a value equal to or greater than <100>
but: <13> was less than <100>

Analysis

The third script line reads the "marginLeft" property of the inline style, which forces the evaluation of this style. It generates a StyleElement with index 13 (in this example).
The next line requires the evaluation of the full stylesheet and we get the following call stack:

  1. HTMLElement.getOffsetLeft()
    • Triggering evaluation of the stylesheet which defines the "margin" property as a StyleElement with index 15 (in this example).
  2. ComputedCSSStyleSheet.getLeft()
  3. ComputedCSSStyleSheet.getMarginLeftValue()
  4. ComputedCSSStyleSheet.getMarginLeft()
  5. CSSStyleDeclaration.getMarginLeft()
  6. CSSStyleDeclaration.getStyleAttribute(MARGIN_LEFT, MARGIN)

This last method finds both declarations: the margin-left inline and the margin on the CSS. Because the CSS version was evaluated last, it is returned.

Proposed fix

Make use of the StyleElement.specificity and StyleElement.priority to determine the winner, if they are not equal. Only fall back to index as last resort. We might even redefine StyleElement.compareTo() to make use of all this information, but I don't know if there is currently any code depending on the current order definition (pure index-based).

Discussion

  • RBRi

    RBRi - 2017-08-28
    • status: open --> accepted
    • assigned_to: RBRi
     
  • RBRi

    RBRi - 2017-08-28

    Great finding and great description. Fix is on the way....

     
  • RBRi

    RBRi - 2017-08-30

    This shold be fixed now. Please download the latest build from our ci server and have a look. Hope it works now for you.

     
  • Sander van Schouwenburg

    Looks like that fixed it. Thanks!

     
  • RBRi

    RBRi - 2017-08-30

    You are welcome. Enjoy HtmlUnit.

     
  • RBRi

    RBRi - 2017-08-30
    • status: accepted --> closed
     

Log in to post a comment.