Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SVG foreignObject behaves as though absolutely positioned in Webkit browsers

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.

like image 716
Richard JP Le Guen Avatar asked Nov 18 '11 16:11

Richard JP Le Guen


2 Answers

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.

like image 172
Duncan Babbage Avatar answered Oct 23 '22 16:10

Duncan Babbage


position: fixed; solved the issue for me.

like image 20
Jules Sam. Randolph Avatar answered Oct 23 '22 16:10

Jules Sam. Randolph