Background
I am encountering an issue where an SVG data URL used as a background image property inside an HTML element within a <foreignObject>
nested within an SVG data URL is not rendering properly in Google Chrome. If this structure was outside of an image context, it would render correctly. What could be causing this problem and how can it be resolved?
Wait, what? Why?
Further explanation on the issue will be provided below, including a tree structure and a code snippet to better illustrate the complex scenario described above.
Tree Structure:
(exhibit A)<img src="data:image/svg+xml;utf8,
<svg>
(exhibit B)<foreignObject>
<html>
<div style="background: url('data:image/svg+xml;utf8,
<svg>
(exhibit C)
Exhibit C is failing to render completely, but if exhibit A is removed so that exhibit B becomes the top-level element, exhibit C renders properly.
Short Code Example:
<div>Standalone:</div>
<svg xmlns="http://www.w3.org/2000/svg" width="75" height="50" style="position:relative"><circle cx="25" cy="25" r="25" fill="red" /><foreignObject style="width: 100%; height: 100%"><html xmlns="http://www.w3.org/1999/xhtml"><style>.x {position: absolute;background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='50'><circle cx='50' cy='25' r='25' fill='blue'/></svg>"); width: 100%; height: 100%;}</style><div class="x"></div></html></foreignObject></svg>
<div>As image source:</div>
<img style="position:relative" src='data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="75" height="50" style="position:relative"><circle cx="25" cy="25" r="25" fill="red" /><foreignObject style="width: 100%; height: 100%"><html xmlns="http://www.w3.org/1999/xhtml"><style>.x {position: absolute;background: url("data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="50"><circle cx="50" cy="25" r="25" fill="blue"/></svg>"); width: 100%; height: 100%;}</style><div class="x"></div></html></foreignObject></svg>'>
Additionally, using a PNG data URL instead of an SVG data URL resolves the issue. The problem seems specific to SVG data URLs.
Reason Behind the Issue
The main reason for this problem lies in embedding HTML inside an <img>
, which enables HTML rendering on a canvas using context.drawImage
. This method is commonly employed by popular libraries like https://github.com/tsayen/dom-to-image. However, complications arise when dealing with embedded SVG content within the HTML, as explained in the question. Various workaround methods have been attempted, including converting innermost SVG data URLs to PNG data URLs before rendering the top-level HTML element.
Another challenge arises when introducing scaling into the process, as scaling PNG images may lead to quality issues. Additionally, applying scaling at different stages can result in image elements becoming too large for their respective containers, further complicating the situation.
(notably, background-image supports scaling, while clip-path does not support scaling - creating additional conversion challenges).
Other Browser Considerations
It's worth noting that Internet Explorer and Edge do not support HTML within <foreignObject>
, making the issue irrelevant in those browsers. Firefox supports this feature, but there are still rendering issues with its "standalone" version that need addressing.
Related Discussions
- Append foreignObject containing some HTML inside an SVG element - focuses on namespace declaration concerns.
- img Inside a foreignObject Inside an svg Inside an img - discusses external image usage rather than data URLs.