SVG foreignObject behaves as though absolutely positioned in Webkit browsers
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;
}
Solution 2
position: fixed;
solved the issue for me.
Richard JP Le Guen
Updated on June 11, 2022Comments
-
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 <foreignObject> 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:
What I get in Chrome (15.0.874.121 on Fedora and on an Android Tablet) is this:
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 over 12 yearsThose 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 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 over 12 yearsFurther revision... pretty sure this one nails it. :)
-
Richard JP Le Guen over 12 yearsThis 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 over 12 yearsThe 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 over 12 yearsWhy 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 over 12 yearsSorry, 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 over 12 yearsThanks 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 over 12 yearsIndeed - but it seems doubtful. Thanks so much for finding the WebKit ticket!
-
Richard JP Le Guen over 12 yearsGreen 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 over 12 years... though I had to target the
<body>
element in the<foreignObject>
not just the.widget
-
AiShiguang over 8 yearsfixed but caused a new issue: z-index
-
Codesmith about 6 yearsDuncan 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 about 6 yearsThis 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 about 5 yearsThis fixed it for me as well
-
foxtrotuniform6969 almost 3 yearsThis fixes position, but not scale. 11 years after the first bug report...