Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SVG examples should be written in proper XML syntax #37761

Open
TriMoon opened this issue Jan 22, 2025 · 9 comments
Open

SVG examples should be written in proper XML syntax #37761

TriMoon opened this issue Jan 22, 2025 · 9 comments
Labels
Content:SVG SVG docs needs decision The task needs consensus through discussion

Comments

@TriMoon
Copy link

TriMoon commented Jan 22, 2025

MDN URL

https://developer.mozilla.org/en-US/docs/Web/SVG/Element/style

What specific section or headline is this issue about?

Description and Example

What information was incorrect, unhelpful, or incomplete?

<style>
...
</style>

What did you expect to see?

<style><![CDATA[
...
]]</style>

Do you have any supporting links, references, or citations?

https://www.w3.org/TR/SVG11/styling.html#StyleElementExample

Do you have anything more you want to share?

Without this <![CDATA[...]] encapsulation, your style rules won't be able to use the <, >, &, and " characters which are used for selectors, strings or content inside strings !
What's worse is that, without this encapsulation, your SVG will be rejected by FireFox's XML-parser (with error), maybe other browsers too have not tried.

Perhaps Firefox and/or some specification should explicitly allow usage of those characters inside the contents of the SVG <style> tag without the need to "escape" them using char-entities like &amp; for &...

Example SVG that will trigger the parser-error on each nesting level, if im correct: (Have only tested the & one)

<svg>
  <style>
    selector1 {
      &#selector2 {
        > selector3 {
          ...
        }
      }
    }
  </style>
  ...
</svg>

MDN metadata

Page report details
@TriMoon TriMoon added the needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. label Jan 22, 2025
@github-actions github-actions bot added the Content:SVG SVG docs label Jan 22, 2025
@Josh-Cena
Copy link
Member

Josh-Cena commented Jan 23, 2025

This is tricky. Our examples are always in HTML, and the <svg> is just an HTML exotic element. We don't show SVG as XML, and we can't because our live sample system doesn't support embedding XML. I have the intention to make all SVG use proper XML syntax but we need a platform upgrade first.

@Josh-Cena Josh-Cena added needs decision The task needs consensus through discussion and removed needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. labels Jan 23, 2025
@Josh-Cena Josh-Cena changed the title SVG: Contents of the style element needs CDATA encapsulation SVG examples should be written in proper XML syntax Jan 23, 2025
@TriMoon
Copy link
Author

TriMoon commented Jan 26, 2025

I'm unsure if you understood the problem properly...
You don't need to embed the SVG on the example page, but you need to add what i wrote to the example text for it to work properly as a standalone SVG when the user copy&pastes that text in a fresh file...

It's like the difference between showing the markup needed &amp; vs showing the actual & as end product...

@Josh-Cena
Copy link
Member

Josh-Cena commented Jan 26, 2025

CDATA is not a thing in HTML. If you use CDATA in an embedded HTML it will be treated as a comment. Our invariant here is not "this code has to be valid standalone SVG"; it's "it has to be renderable within our live example system", and that means it has to work as

<html>
  <svg>
    [content]
  </svg>
</html>

And served as HTML. You are free to play around and see what works.

@TriMoon
Copy link
Author

TriMoon commented Feb 4, 2025

I have no words left to make my point, because you are looking at it from a different angle as i am...
Your angle could be solved by escaping / using <pre> / etc but anyhow, i gave my feedback 😉

Bottom line is that the shown example is non-functional "as-is", because the example is actually an SVG content and not a HTML content like it is labeled now...
In other words the page is about using the style element inside SVG documents, NOT how to use the same element while using SVG elements inside HTML documents...
When a visitor copy&pastes the example inside a *.svg file and views it, it will not render as intended...

Image

Image

@TriMoon
Copy link
Author

TriMoon commented Feb 4, 2025

I take back my words, as i just tried in Firefox nightly and it seems to accept the markup in an SVG file without CDATA now and refuses when using WITH CDATA, which was the opposite when i opened this issue... 🤷‍♀

@Josh-Cena
Copy link
Member

I'm not sure what you are proposing; I already gave a way for you to test what you may believe to work. Our live sample system just inserts this code block into an iframe as HTML, so it has to work as HTML syntax, not pasted into an .svg file.

@TriMoon
Copy link
Author

TriMoon commented Feb 4, 2025

I "think" the CDATA is needed when the SVG is referenced using an <img> element or style definition that uses it as image or background...
Because the style was not applied when i used it like that but WAS applied when directly viewing the SVG file.
Might be a bug in FireFox or an imposed restriction related to using SVG's that way...
In the case it's due to an imposed restriction, it renders the usage of that element void because the outcome will differ when using the SVG on it's own or indirect from HTML....

Our live sample system just inserts this code block into an iframe as HTML, so it has to work as HTML syntax, not pasted into an .svg file.

And that's the whole point i'm making here, the page on it's own is about the element usage inside an .svg file, not indirect usage from HTML.
I understand the technical implementation of the site, but the info on a REFERENCE documentation has nothing todo with the technicality of the site providing that info, am i correct?

I think in this case it's best to mention this difference in usage, with example code, with respect to how the SVG code is used. (On it's own or indirect)

It just happened by chance that i made use of this in this post, you might want to test usage of that as a direct svg file and by indirect usage from with an HTML document... 🤷‍♀
(By indirect i don't mean embedded as <SVG></SVG> inside HTML...)

@Josh-Cena
Copy link
Member

I understand the technical implementation of the site, but the info on a REFERENCE documentation has nothing todo with the technicality of the site providing that info, am i correct?

Which is why this issue remains open and is titled the current way: it needs changes in the platform as well as widespread content changes. It's not going to be a change to a single page.

@TriMoon
Copy link
Author

TriMoon commented Feb 5, 2025

To demonstrate what i wrote in OP, here are 2 practical examples of one and the same SVG that i created, which made me become aware of this need:
(Best viewed with tab-size=2)

1. With use of the CDATA encapsulation: (Working, no error)
<svg viewBox="0 0 100 100"
	xmlns="http://www.w3.org/2000/svg"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
	xmlns:cc="http://web.resource.org/cc/"
	xmlns:xlink="http://www.w3.org/1999/xlink">
	<metadata>
		<dc:creator>TriMoon</dc:creator>
		<dc:rights>Copyright © 2025+ TriMoon</dc:rights>
		<dc:description>Licensed under a "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International" license.</dc:description>
		<dc:version>1.0.0-rc</dc:version>
		<dc:identifier>https://gitlab.com/TriMoon</dc:identifier>
		<dc:identifier>https://github.com/TriMoon</dc:identifier>
		<dc:identifier>https://discord.com/users/510413297900716048</dc:identifier>
		<cc:license rdf:resource="https://creativecommons.org/licenses/by-nc-nd/4.0/" />
	</metadata>
	<title>Colored Spotlights</title>
	<desc>
		A color circle using spotlights that are evenly aranged on a ring and blending together to form intermediate colors.
		We use "screen" as blending mode for the radial-gradients so they behave like spotlights.
		</desc>
	<defs>
		<!-- Needs CDATA, see: https://www.w3.org/TR/SVG11/styling.html#StyleElementExample -->
		<style><![CDATA[
			/* @import url(coloredSpotlights.css) */
			:scope {
				--Overlay-color: white;
				--Spot-R: 150%;
				background-color: black;
			}

			radialGradient {
				--Spot1-color: red;
				--Spot2-color: green;
				--Spot3-color: blue;
				--Spot4-color: yellow;
				--Spot5-color: cyan;
				--Spot6-color: purple;

				&#gradient-ring {
					/* display: none; */
					opacity: 25%;
					> stop {
						stop-color: var(--Overlay-color);
					}
				}
				&#gradient-spot1 > stop {
					stop-color: var(--Spot1-color);
				}
				&#gradient-spot2 > stop {
					stop-color: var(--Spot2-color);
				}
				&#gradient-spot3 > stop {
					stop-color: var(--Spot3-color);
				}
				&#gradient-spot4 > stop {
					stop-color: var(--Spot4-color);
				}
				&#gradient-spot5 > stop {
					stop-color: var(--Spot5-color);
				}
				&#gradient-spot6 > stop {
					stop-color: var(--Spot6-color);
				}
			}

			circle {
				--Spot1-angle: 0deg;
				--Spot2-angle: 120deg;
				--Spot3-angle: 240deg;
				--Spot4-angle: 60deg;
				--Spot5-angle: 180deg;
				--Spot6-angle: 300deg;

				mix-blend-mode: screen;
				transform: scale(1,-1);

				&#ring, &#center-dot {
					/* display: none; */
					opacity: 25%;
					cx: 0;
					cy: 0;

					&#ring {
						r: 100%;
						stroke: var(--Overlay-color);
						stroke-width: 1%;
					}
					&#center-dot {
						r: 1%;
						fill: var(--Overlay-color);
					}
				}
				/* All Spot's same radius */
				&:is(#spot1, #spot2, #spot3, #spot4, #spot5, #spot6) {
					r: var(--Spot-R);
				}
				&#spot1 {
					cx: calc(sin(var(--Spot1-angle))*100%);
					cy: calc(cos(var(--Spot1-angle))*100%);
				}
				&#spot2 {
					cx: calc(sin(var(--Spot2-angle))*100%);
					cy: calc(cos(var(--Spot2-angle))*100%);
				}
				&#spot3 {
					cx: calc(sin(var(--Spot3-angle))*100%);
					cy: calc(cos(var(--Spot3-angle))*100%);
				}
				&#spot4 {
					cx: calc(sin(var(--Spot4-angle))*100%);
					cy: calc(cos(var(--Spot4-angle))*100%);
				}
				&#spot5 {
					cx: calc(sin(var(--Spot5-angle))*100%);
					cy: calc(cos(var(--Spot5-angle))*100%);
				}
				&#spot6 {
					cx: calc(sin(var(--Spot6-angle))*100%);
					cy: calc(cos(var(--Spot6-angle))*100%);
				}
			}
			]]></style>
		<radialGradient id="gradient-ring">
			<desc>A whitepoint to increase the whiteness of the center.</desc>
			<stop offset="0%" stop-opacity="1"/>
			<stop offset="100%" stop-opacity="0"/>
			</radialGradient>
		<radialGradient id="gradient-spot1">
			<stop offset="0%" stop-opacity="1"/>
			<stop offset="100%" stop-opacity="0"/>
			</radialGradient>
		<radialGradient id="gradient-spot2">
			<stop offset="0%" stop-opacity="1" />
			<stop offset="100%" stop-opacity="0" />
			</radialGradient>
		<radialGradient id="gradient-spot3">
			<stop offset="0%" stop-opacity="1"/>
			<stop offset="100%" stop-opacity="0"/>
			</radialGradient>
		<radialGradient id="gradient-spot4">
			<stop offset="0%" stop-opacity="calc(100% / 3)"/>
			<stop offset="100%" stop-opacity="0"/>
			</radialGradient>
		<radialGradient id="gradient-spot5">
			<stop offset="0%" stop-opacity="calc(100% / 3)"/>
			<stop offset="100%" stop-opacity="0"/>
			</radialGradient>
		<radialGradient id="gradient-spot6">
			<stop offset="0%" stop-opacity="calc(100% / 3)"/>
			<stop offset="100%" stop-opacity="0"/>
			</radialGradient>
	</defs>
	<g transform="translate(50 50) scale(.5 .5)">
		<g>
			<circle id="ring" fill="url(#gradient-ring)">
				<desc>The ring where the spotlights are aranged upon.</desc>
				</circle>
			<circle id="center-dot"/>
			<circle id="spot1" fill="url(#gradient-spot1)"/>
			<circle id="spot2" fill="url(#gradient-spot2)"/>
			<circle id="spot3" fill="url(#gradient-spot3)"/>
<!--
			<circle id="spot4" fill="url(#gradient-spot4)"/>
			<circle id="spot5" fill="url(#gradient-spot5)"/>
			<circle id="spot6" fill="url(#gradient-spot6)"/>
-->
 			<animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" dur="10s" repeatCount="indefinite">
				<desc>Animate this group in a circle</desc>
				</animateTransform>
		</g>
	</g>
</svg>
2. Without the CDATA encapsulation: (NOT-Working, with error)
<svg viewBox="0 0 100 100"
	xmlns="http://www.w3.org/2000/svg"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
	xmlns:cc="http://web.resource.org/cc/"
	xmlns:xlink="http://www.w3.org/1999/xlink">
	<metadata>
		<dc:creator>TriMoon</dc:creator>
		<dc:rights>Copyright © 2025+ TriMoon</dc:rights>
		<dc:description>Licensed under a "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International" license.</dc:description>
		<dc:version>1.0.0-rc</dc:version>
		<dc:identifier>https://gitlab.com/TriMoon</dc:identifier>
		<dc:identifier>https://github.com/TriMoon</dc:identifier>
		<dc:identifier>https://discord.com/users/510413297900716048</dc:identifier>
		<cc:license rdf:resource="https://creativecommons.org/licenses/by-nc-nd/4.0/" />
	</metadata>
	<title>Colored Spotlights</title>
	<desc>
		A color circle using spotlights that are evenly aranged on a ring and blending together to form intermediate colors.
		We use "screen" as blending mode for the radial-gradients so they behave like spotlights.
		</desc>
	<defs>
		<!-- Needs CDATA, see: https://www.w3.org/TR/SVG11/styling.html#StyleElementExample -->
		<style>
			/* @import url(coloredSpotlights.css) */
			:scope {
				--Overlay-color: white;
				--Spot-R: 150%;
				background-color: black;
			}

			radialGradient {
				--Spot1-color: red;
				--Spot2-color: green;
				--Spot3-color: blue;
				--Spot4-color: yellow;
				--Spot5-color: cyan;
				--Spot6-color: purple;

				&#gradient-ring {
					/* display: none; */
					opacity: 25%;
					> stop {
						stop-color: var(--Overlay-color);
					}
				}
				&#gradient-spot1 > stop {
					stop-color: var(--Spot1-color);
				}
				&#gradient-spot2 > stop {
					stop-color: var(--Spot2-color);
				}
				&#gradient-spot3 > stop {
					stop-color: var(--Spot3-color);
				}
				&#gradient-spot4 > stop {
					stop-color: var(--Spot4-color);
				}
				&#gradient-spot5 > stop {
					stop-color: var(--Spot5-color);
				}
				&#gradient-spot6 > stop {
					stop-color: var(--Spot6-color);
				}
			}

			circle {
				--Spot1-angle: 0deg;
				--Spot2-angle: 120deg;
				--Spot3-angle: 240deg;
				--Spot4-angle: 60deg;
				--Spot5-angle: 180deg;
				--Spot6-angle: 300deg;

				mix-blend-mode: screen;
				transform: scale(1,-1);

				&#ring, &#center-dot {
					/* display: none; */
					opacity: 25%;
					cx: 0;
					cy: 0;

					&#ring {
						r: 100%;
						stroke: var(--Overlay-color);
						stroke-width: 1%;
					}
					&#center-dot {
						r: 1%;
						fill: var(--Overlay-color);
					}
				}
				/* All Spot's same radius */
				&:is(#spot1, #spot2, #spot3, #spot4, #spot5, #spot6) {
					r: var(--Spot-R);
				}
				&#spot1 {
					cx: calc(sin(var(--Spot1-angle))*100%);
					cy: calc(cos(var(--Spot1-angle))*100%);
				}
				&#spot2 {
					cx: calc(sin(var(--Spot2-angle))*100%);
					cy: calc(cos(var(--Spot2-angle))*100%);
				}
				&#spot3 {
					cx: calc(sin(var(--Spot3-angle))*100%);
					cy: calc(cos(var(--Spot3-angle))*100%);
				}
				&#spot4 {
					cx: calc(sin(var(--Spot4-angle))*100%);
					cy: calc(cos(var(--Spot4-angle))*100%);
				}
				&#spot5 {
					cx: calc(sin(var(--Spot5-angle))*100%);
					cy: calc(cos(var(--Spot5-angle))*100%);
				}
				&#spot6 {
					cx: calc(sin(var(--Spot6-angle))*100%);
					cy: calc(cos(var(--Spot6-angle))*100%);
				}
			}
			></style>
		<radialGradient id="gradient-ring">
			<desc>A whitepoint to increase the whiteness of the center.</desc>
			<stop offset="0%" stop-opacity="1"/>
			<stop offset="100%" stop-opacity="0"/>
			</radialGradient>
		<radialGradient id="gradient-spot1">
			<stop offset="0%" stop-opacity="1"/>
			<stop offset="100%" stop-opacity="0"/>
			</radialGradient>
		<radialGradient id="gradient-spot2">
			<stop offset="0%" stop-opacity="1" />
			<stop offset="100%" stop-opacity="0" />
			</radialGradient>
		<radialGradient id="gradient-spot3">
			<stop offset="0%" stop-opacity="1"/>
			<stop offset="100%" stop-opacity="0"/>
			</radialGradient>
		<radialGradient id="gradient-spot4">
			<stop offset="0%" stop-opacity="calc(100% / 3)"/>
			<stop offset="100%" stop-opacity="0"/>
			</radialGradient>
		<radialGradient id="gradient-spot5">
			<stop offset="0%" stop-opacity="calc(100% / 3)"/>
			<stop offset="100%" stop-opacity="0"/>
			</radialGradient>
		<radialGradient id="gradient-spot6">
			<stop offset="0%" stop-opacity="calc(100% / 3)"/>
			<stop offset="100%" stop-opacity="0"/>
			</radialGradient>
	</defs>
	<g transform="translate(50 50) scale(.5 .5)">
		<g>
			<circle id="ring" fill="url(#gradient-ring)">
				<desc>The ring where the spotlights are aranged upon.</desc>
				</circle>
			<circle id="center-dot"/>
			<circle id="spot1" fill="url(#gradient-spot1)"/>
			<circle id="spot2" fill="url(#gradient-spot2)"/>
			<circle id="spot3" fill="url(#gradient-spot3)"/>
<!--
			<circle id="spot4" fill="url(#gradient-spot4)"/>
			<circle id="spot5" fill="url(#gradient-spot5)"/>
			<circle id="spot6" fill="url(#gradient-spot6)"/>
-->
 			<animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" dur="10s" repeatCount="indefinite">
				<desc>Animate this group in a circle</desc>
				</animateTransform>
		</g>
	</g>
</svg>

You can test by copy & paste the code inside a fresh .svg file and viewing it directly or referencing it using a css-rule of a HTML document.


See the diff to see the difference between the two and assure it is only the use of CDATA or lack of it.

--- coloredSpotlights-error.svg	2025-02-05 11:39:41.888707668 +0300
+++ coloredSpotlights.svg	2025-02-05 11:35:07.439853175 +0300
@@ -21,7 +21,7 @@
 		</desc>
 	<defs>
 		<!-- Needs CDATA, see: https://www.w3.org/TR/SVG11/styling.html#StyleElementExample -->
-		<style>
+		<style><![CDATA[
 			/* @import url(coloredSpotlights.css) */
 			:scope {
 				--Overlay-color: white;
@@ -120,7 +120,7 @@
 					cy: calc(cos(var(--Spot6-angle))*100%);
 				}
 			}
-			></style>
+			]]></style>
 		<radialGradient id="gradient-ring">
 			<desc>A whitepoint to increase the whiteness of the center.</desc>
 			<stop offset="0%" stop-opacity="1"/>

The actual error is caused by the nested CSS-Rules that make use of & like:

&#gradient-ring {
	/* display: none; */
	opacity: 25%;
	> stop {
		stop-color: var(--Overlay-color);
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Content:SVG SVG docs needs decision The task needs consensus through discussion
Projects
None yet
Development

No branches or pull requests

2 participants