SVG foreignObject behaves as though absolutely positioned in Webkit browsers

14,593

Solution 1

This issue is not specific to Chrome as I could reproduce it in Chrome 15.0.874.121 for Macintosh as well as Safari 5.1.2. (It also occurred in older versions of Firefox for Mac, such as version 3.6.8, but the behavior is correct in the current version.) This currently outstanding Webkit bug is likely to be the cause of the issue. Global coordinates are incorrectly used for elements inside the foreignObject which means when absolute positioning is used, those elements are placed relative to the main document flow rather than the foreignObject container, and thus the SVG translate is not applied to those elements.

I have not been able to locate a general solution to this issue.

For this specific example, this will fix the layout in all of the above-mentioned browsers:

.widget {
    position: relative;
    left: 100px;
    top: 200px;
}

Demonstration on jsfiddle.

Solution 2

position: fixed; solved the issue for me.

Share:
14,593
Richard JP Le Guen
Author by

Richard JP Le Guen

Updated on June 11, 2022

Comments

  • Richard JP Le Guen
    Richard JP Le Guen almost 2 years

    I'm working with SVG in an HTML document. For some reason in Chrome, any content in any <foreignObject> element appears in the top left corner of the <svg> element's parent element; as though the <foreignObject> element was absolutely positioned or something. I don't have this problem in Firefox.

    What could be causing this? How can I fix it?

    Here is my test case: (the example is also on JsFiddle)

    <!DOCTYPE html>
    <html>
    <head>
    <title>SVG bug in Chrome?</title>
    <style type="text/css">
    code {
        background: #FFFAEE;
    }
    pre code {
        display:block;
    }
    .widget-body {
        background:yellow;
        position: relative; /* This is the problem! */
    }
    </style>
    <body>
    <h1>SVG bug in Chrome?</h1>
    <div>
        <p>
            The elemts in the &lt;foreignObject&gt; are not positioned properly unless the <code>.widget-body</code> rule is changed to:
                    <pre><code>.widget-body {
        background:yellow;
    /*  position: relative; /* This is the problem! */
        position: static;
    }</code></pre>
        </p>
            <h2>The Example:</h2>
        <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1000" height="800">
        <g>
        <g transform="scale(1) translate(100, 200)" style="cursor: move;"><foreignobject pointer-events="fill" width="300" height="350">
        <body xmlns="http://www.w3.org/1999/xhtml" style="margin: 0px; height: 100%;">
        <table style="border-collapse: collapse; font-size: 11px; color: rgb(119, 68, 0); font-family: Arial,Helvetica; font-weight: normal; border-style: none;">
        <tbody>
        <tr>
            <td style="text-align: center; vertical-align: middle; white-space: nowrap;">
                <div style="width:300px;height:350px;position:static;">
                    <div class="widget" style="width: 300px;">
                        <div style="-moz-user-select: none;">
                            <span>My Widget Title</span>
                        </div>
                        <div>
                            <div class="widget-body" style="width: 298px; height: 323px;">
                                <div style="width: 298px; height: 323px;">
                                    <div style="width: 298px; height: 323px;">
                                        This position of this yellow square <br />should approximately (100, 200)
                                        <div style="position:absolute;bottom:0;right:0;background:red;color:white;font-weight:bold;">
                                            This red square <br />should be <br />in the bottom right corner <br />of the yellow square.
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </td>
        </tr>
        </tbody>
        </table>
        </body>
        </foreignobject></g>
        </g>
        </svg>
    </div>
    </body>
    </html>
    

    What I expect to see (which is what I see in FireFox) is this:

    The behavior of my example in FireFox

    What I get in Chrome (15.0.874.121 on Fedora and on an Android Tablet) is this:

    The behavior of my example in Chrome. The contents of the foreignObject are not in the right place.

    I have minimal control over my HTML content as I am using both a JavaScript Framework for rich apps and pre-existing widgets.

  • Richard JP Le Guen
    Richard JP Le Guen over 12 years
    Those issues are actually what I'm focusing on. To be honest, I hadn't even realized the red boxes were different shapes! :P My problem is that the yellow box should not have moved up and should not be flush with the left margin. As for the header, it is actually in the right place without this rule; adding this rule (much like how my .widget-body { position: relative; } is breaking the behavior of the yellow box) causes the header to develop the same buggy behavior.
  • Duncan Babbage
    Duncan Babbage over 12 years
    (Having found a full solution, I've removed the example that reunites the title with the rest of the box. It slightly breaks the comment history, but leads to a clearer answer than keeping all the edits visible.)
  • Duncan Babbage
    Duncan Babbage over 12 years
    Further revision... pretty sure this one nails it. :)
  • Richard JP Le Guen
    Richard JP Le Guen over 12 years
    This certainly gets the desired result... but I have several widgets suffering from this problem. I'd have to keep the <g> element's translation synchronized with CSS properties on all of these widgets.
  • Duncan Babbage
    Duncan Babbage over 12 years
    The problem is your incompatible use of translate(100, 200) overall and position:absolute on the red element. position:absolute takes that element and the parent element it is positioned relative to out of the normal flow and they thus do not have the translate applied to them. Is it actually necessary to position this element absolutely?
  • Richard JP Le Guen
    Richard JP Le Guen over 12 years
    Why are they incompatible? Do you mean "according to the spec they're incompatible"? Is this webkit doing something wrong or Firefox doing something wrong?
  • Duncan Babbage
    Duncan Babbage over 12 years
    Sorry, loose language on my part. I only meant "incompatible" in the context of the Webkit browser's current implementation, which as per the bug report I've linked to is acknowledged as being the wrong behavior...
  • Duncan Babbage
    Duncan Babbage over 12 years
    Thanks for the bounty! I'll be interested to hear if you managed to find a more generic solution to this issue, prior to Webkit being patched.
  • Richard JP Le Guen
    Richard JP Le Guen over 12 years
    Indeed - but it seems doubtful. Thanks so much for finding the WebKit ticket!
  • Richard JP Le Guen
    Richard JP Le Guen over 12 years
    Green tick - in the end I was able to catch move/re-size events and re-position things using relative position, just like you said.
  • Richard JP Le Guen
    Richard JP Le Guen over 12 years
    ... though I had to target the <body> element in the <foreignObject> not just the .widget
  • AiShiguang
    AiShiguang over 8 years
    fixed but caused a new issue: z-index
  • Codesmith
    Codesmith about 6 years
    Duncan Babbage's solution still wasn't working for me, but odd enough this did work, and doesn't hoist to the corner as I had expected! However, agreed with @AiShiguang, it does cause a z-index issue in Chrome - though it remains working fine in FireFox with no z-index issue.
  • Codesmith
    Codesmith about 6 years
    This may just be an old answer, and new Chrome / WebKit updates (as per Chrome 65) may have changed things, but this answer doesn't seem to be working for me any longer. The jsfiddle also acts strange - when I comment out position:relative the text doesn't center, though it appears that - according to the html / css - it should.
  • NuclearPeon
    NuclearPeon about 5 years
    This fixed it for me as well
  • foxtrotuniform6969
    foxtrotuniform6969 almost 3 years
    This fixes position, but not scale. 11 years after the first bug report...