SVG Triangle of Compromise
me.micahrl.com
me.micahrl.com
Can't you say that about anything in HTML? Like, imagine you had a huge `<head>` tag that contained a bunch of stuff, but it's essentially the same (except for, like, the title) for all documents. Don't you wanna do this?
<html>
<head>
<<< include head.html >>>
<title>Cool page!</title>
</head>
<body>
<svg>
<<< include logo.svg >>>
</svg>
</body>
<html>
Where the `<<< include ... >>>` is a pretend bit of HTML that makes the browser fetch that from somewhere else. A preprocessor, more or less.I realize this is what templating languages are for, but if this happened on the HTML layer, the browser could do way better caching.
One of the things said in there is that they look for usage of userland solutions. I mentioned in another comment, but there are custom elements that do client-side includes, like: https://www.npmjs.com/package/html-include-element
Something I find a bit funny now is that for the longest time back in the 2000s, nearly the entirety of my usage of PHP was comprised of PHP includes to make up for this gap in HTML functionality (I had no idea XSLT existed then).
Other cool web tech that should have "won": XForms[1]. Imagine if HTML forms had things like declarative data-binding (with XPath expressions! Imagine jq built directly into the browser 20 years ago and usable by forms) and types/constraints/validation built right in. This would be 1000x more useful for your average web dev than something like USB or GPU support or Wasm. You'd be able to make complex interactive forms in much the same way that you do a spreadsheet.
[0] https://web.archive.org/web/20040727061732/http://www.w3scho...
All <<<include whatever.html>>> could be replaced with contents first. Then it's just a page of html as now.
Also, at least back when we excised the last bits of it from our old codebase, no useful caching of either stylesheets or included resources (other stylesheets), so if you tried to mix client-side processing with HTTPS you were in for quite some pain unless you had a fast, very low latency, uncongested, link.
Still, it's possible with XSLT 1.0 to produce documents in the common subset of XML and HTML5 ("XHTML5"). It can't produce the usual <!DOCTYPE html> at the top of the document, but it can produce the alternative <!DOCTYPE html SYSTEM "about:legacy-compat">.
On the input side, every XSLT version only accepts valid XML, as far as I am aware.
[0] https://www.w3.org/TR/xslt-xquery-serialization-30/#html-out...
As for output, the difference is largely irrelevant for browser purposes since they just want a tree.
I'm not sure how many extensions the browsers allow, but a major part of the reason XSLT 2/3 failed to take off is because libxslt already provides most of the useful features from newer versions as extensions (many via EXSLT-namespaced modules, at least partially supported in browsers - see MDN); what it doesn't do is implement the unnecessary complexity that the Java world loves.
But most HTML in the wild today is not valid XML. There is XHTML as mentioned by a sibling comment but it's rarely used. So if you were to start with an existing base of HTML documents, you couldn't easily add XSLT preprocessing to them. The issue is with the input rather than the output.
Here is what I know about using XHTML in practice: https://www.nayuki.io/page/practical-guide-to-xhtml
If you have someone else's documents, or need to mass convert your own to fix them, there's HTML tidy[0]. This one is quite useful to be able to run XML processing CLI tools on scraped web pages.
But the real power is in delivering XML to the client, not HTML. This lets you work in the domain model directly on the frontend, and use XSLT to transform that into HTML for display. So of course you'd use well-formed XML in that case.
Imagine if you didn't have a distinction between APIs and pages; you just returned the data along with a link to a template that says how to display it and (ideally) a link to a schema definition. Modifying templates for components could be as easy as modifying CSS attributes in the browser console, giving the next generation an easy way to peak and play around with how it all works as they're growing up. We were so close, and then things veered off into the hellworld that is the modern web.
You could put something like this in your markup
<!--#include file="footer.html" -->
And the web server would apply it and inline the contents. It had a bunch of other directives, but this was the good one.https://developer.mozilla.org/en-US/docs/Web/SVG/Element/def...
Alternatively, though, SVGs in ``<svg>`` elements could just, yknow, retain their stylability. (is there a reason they don't? this has been a long-running frustration of mine)
I'd definitely love to see something like this built into the browser.
You can make them with <defs> and <use> tags pretty easily if you understand svg a bit. I usually bundle two-state icon into a single svg file, and then use `object-position: left/right` property on the <img> tag to switch between the variants. You can also combine this with some simple css animations.
include sprite-1.snippet
include sprite-2.snippet
and it would write the defs into the page. Then later in the page, `<use>` the defs you included.You can play with a sample SVG sprite on https://boxy-svg.com/#demo-symbols. Individual icons are shown under "Defs Panel -> Symbols". To edit an icon just double-click its thumbnail. To make part of an icon recolorable, select that part and then click "Fill Panel -> Paint -> Type -> Inherit".
You could then create separate symbols which contain a recolored instance of the original symbol. The underlying markup will look something like this:
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="recolorable" viewBox="0 0 100 100">
<rect width="100" height="100" style="fill: inherit;"/>
</symbol>
<symbol id="blue" viewBox="0 0 100 100">
<use width="100" height="100" style="fill: blue;" xlink:href="#recolorable"/>
</symbol>
<symbol id="green" viewBox="0 0 100 100">
<use width="100" height="100" style="fill: green;" xlink:href="#recolorable"/>
</symbol>
</defs>
</svg>
Finally, use a fragment identifier to show a specific icon in HTML: <img src="sprite.svg#green">To make it work you would have to either replace <img src="sprite.svg#green"/> with <svg ...><use href="sprite.svg#green"></use></svg> or add views to the sprite file:
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="recolorable" viewBox="0 0 100 100">
<rect width="100" height="100" style="fill: inherit;"/>
</symbol>
<view id="blue" viewBox=" 0 0 100 100"></view>
<view id="green" viewBox="100 0 100 100"></view>
</defs>
<use x="0" y="0" width="100" height="100" style="fill: blue;" xlink:href="#recolorable"/>
<use x="100" y="0" width="100" height="100" style="fill: green;" xlink:href="#recolorable"/>
</svg>P.S. I actually went ahead and changed the implementation to a separate file on my website after I saw your comment :D
The icon:
<!-- the icon width is 2x wider, to accommodate both 26x26 variants -->
<svg xmlns="http://www.w3.org/2000/svg" width="52" height="26">
<defs>
<!-- here's the icon defined, you can basically put anything here and
mark it with an id (you can even use another svg) -->
<path id="icon" path="..."/>
</defs>
<!-- first variant with no fill -->
<use stroke="#fff" href="#icon"/>
<!-- second variant with fill, shifted by 26 (dimensions of the icon) -->
<use x="26" fill="#00ACA0" stroke="#00ACA0" href="#a"/>
</svg>
HTML: <!-- make sure you use dimensions of the single variant -->
<img src="icon.svg" width="26" height="26" class="hover-icon">
CSS: .hover-icon {
/* make sure that only first block of the image is visible */
object-fit: cover;
object-position: left;
}
.hover-icon:hover {
object-position: right;
}Btw, for such simple re-colouring I'd probably rather used CSS hue shift filter or similar effect, and kept the SVG "dumb". But for having different shapes or geometric properties this approach is indeed nifty.
Example: svg poster - includes svg diagrams - that include svg maps (maps are generated programmatically)
https://kxygk.github.io/imergination/
Though.. if you open the SVG itself (in a separate window/tab) most elements refuse to display for "security"
https://raw.githubusercontent.com/wiki/kxygk/imergination/ag...
It's honestly an unreliable format for anything that's mildly complex.. this poster will render differently in different browsers (and inkscape) and can't be turned into a PDF consistently. It's a mess
It pretty much solves the cache issue to me.
About the cross-origin issue, you mean it lacks something like a crossorigin attribute? That's only an issue if you plan to load svgs from other websites, I don't think it's a very common usecase. If you use them at multiples places in your website, you should probably have them served from your sever anyway, if not then I guess caching is less of an issue.
If you mean applying static styles, you can do that with any form of SVG (that is, <img> qualifies as well).
If you mean inheriting styles from the parent document, you can only do that with inline SVG (that is, <iframe> doesn’t qualify).
But by the actual usage in the article (that it’s <svg> and <iframe> but not <img>), I think what is actually meant is interactive—that you can run scripts, have :hover styles, links, things like that.
1. changing the foreground and background of the SVG based on the web page theme or light/dark mode;
2. using the SVG in a link or button and styling the image according to the hover, pressed, etc. state, e.g. when providing custom checkbox/radio/toggle buttons.
For your first example:
If you’re talking about using the prefers-color-scheme media query, you can do this with any technique—<img> qualifies as well. That’s applying static styles.
If you’re talking about things like styling based on an <html class="…"> value, <iframe> doesn’t qualify: that’s inheriting styles from the parent document and you can’t do it.
For your second example: that’s about whether the SVG is interactive.
However I look at it, “stylable” is simply the wrong word.
Interactivity is different -- i.e. the SVG using JavaScript to be interacted with.
For the second example, it's just applying CSS styling:
input:checked > svg { color: red; }
button:hover > svg { color: teal; }
No need/use of JavaScript.What CSS stands for is quite immaterial in the definition of “stylable”. Especially the C. Cascading says nothing about cross-document application.
And when I speak of interactivity, I believe I’m using a term that has been employed in some of the specs and implementations to control most or all of the distinctions I’m talking about, though I have a vague feeling there was some other magic term too that I just can’t remember. I can’t trivially find the relevant definition in the SVG spec, and the HTML Standard these days says that <img src> refers to a “non-interactive, optionally animated, image resource that is neither paged nor scripted”, admittedly separating interactivity and scripting. Interactivity includes things like links and hover states.
> To solve this, we could create an HTML file that contains only the <svg> tag, and reference it on the site via an <iframe>
Therefore you can attach the stylesheet containing the styles for the button/checkbox/etc. in the head of that document.
I don't know exactly how you would do this (w.r.t. propagating hover, etc. state) as I've used the embedded SVG element approach when I need styling.
Can you give an example of statically styling an element of an SVG image, that’s linked in an html document via the img tag?
What you can do is just the totally basic style element or attribute:
<svg …>
<style>path { fill: red }</style>
<path d="…" style="stroke: green" />
</svg>
But I’m not saying you can apply styles to the inside of an image from outside; that, as I have remarked, is a different matter, about heritability—you can’t do that with any technique but inline SVG. Not <img>, not <iframe>, because it’s not cross-document.You can put SVGs into a <TEMPLATE>. I've used this for "site and social icons" to great effect.
(the OP does mention the <use/> tag in the final notes but only for in-document fragment references, not for remote URLs)
All that said, if you're doing an include from the same host as the parent page, yes, `use` absolutely does tick all three boxes!
A few years ago a made a Monopoly-Deal-Clone game using mostly SVG + CSS + Svelte.
I was intrigued by the promise of SVG:
- Loss-Less Scaling
- Looks the same (or somewhat) the same on all browsers
- Text would also scale and be readable up and down.
Build playing cards on the fly with SVG elements dynamically (base-card-svg + text + icon/image/glyph)All of these were never true-enough even for even a card-based game.
The SVG text never looked good-enough or readable at all sizes used. Depending on scaling the text/icons and lines got blurred worse.
The "fix" for many of these were endless and browser version-dependent magic-css properties and values.
TL;DR I wouldn't use SVG for more than 50% of your game or professional product that uses images/visual-elements. Its not worth the pain and effort !
https://myfonj.github.io/tst/SVG-decimal-precision-results.h...
Back in about 2008 I made an SVG diagram showing the height of various satellite orbits above earth, specifying the SVG at 1:1 scale - making the image 84,000 km wide.
Sadly a load of file viewers choked on it, so I had to settle for a downscaled version. It seems the 'scalable' in 'scalable vector graphics' only goes so far.
Your story implies there actually were some viewers that could handle it correctly? Could you recall more details what were they? (My testing was pitifully limited to current browsers only, but I know there must be vast amount of other viewers.)
And if I may ask, did you map one SVG "point" to some length unit (e.g. meter, so getting 84e6 wide wiewBox), or did you assume 90 DPI "pixel" mapping to ~0.2822 mm?
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="84000000000mm" height="84000000000mm"
viewBox="0 0 84000000000mm 84000000000mm"
version="1.1" id="svg5"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<ellipse
style="fill:none;stroke:#000000;stroke-width:0.812697;stroke-opacity:1"
id="path111" cx="42000000000mm" cy="42000000000mm"
rx="42000000000mm" ry="42000000000mm" />
</svg>
However the browsers don't crash or run out of memory, so they've got that going for them. And if you embed the image in a web page with <img src='84km.svg' width=1000 height=1000> chromium almost manages to display it.SVG lets you specify sizes in a bunch of different units, but there's actually a fixed ratio between them - in SVG, 1mm means is 3.78px regardless of your display or printer's DPI.
So I didn't scale mm to SVG's arbitrary length units - but the standard did.
> However the browsers don't crash or run out of memory
Good news for your sample. Yet in some browsers there prevail some open issues, just the limits are now farther. For example feeding this SVG to my Firefox almost instantly exhausts my RAM and makes the browser window unusable for a while:
data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"
viewBox="-1e11,-1e11,2e11,2e11"><circle r="1e11"/></svg>
I guess for more beefed machines would be necessary to bump exponents slightly higher. It's a known issue [1].- https://docs.aspose.com/svg/net/drawing-basics/coordinate-sy...
- https://www.w3.org/TR/SVG2/coords.html
- https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Po...
You can use “cm” and “mm” in SVG.
It will then be up to the viewer program (web browser or which ever program you are using) to make it correct for the DPI of your display.
// Coincidentally played with this test yesterday: https://myfonj.github.io/sandbox.html#%3C!doctype%20html%3E%...
I was generating diagrams using my own code so I'm positive they were circular arcs. Tangents weren't tangent and it took me a while to realise that the problem was the browser rendering something that wasn't quite a circle. I assumed it was a bezier approximation but I didn't verify that. Whatever it was it seems to be fixed.
/images/icons/9bac00/door.svg
/images/icons/ffffff/door.svgBut even when not: in practice an SVG will have hundreds or thousands of XML elements (nodes) to draw rather simple-looking shapes even.
Thousands of XML elements is the ideal case, compresses extremely well.
No point to waste CPU cycles rasterizing same SVG image repeatedly.
Just load a .svg and put it into a <SVG>.
In CSS: hold it as a background-image with the SVG in a data URL (requires some encoding).
Works for me.
I would suggest editing your Venn diagram a bit so that it makes more sense. Something like this
<circle class="property stylable" cx="190" cy="145" r="70"></circle>
<text class="stylable" x="150" y="140" fill="black">stylable</text>
<circle class="property cacheable" cx="310" cy="145" r="70"></circle>
<text class="cacheable" x="300" y="140" fill="black">cacheable</text>
<circle class="property dimensional" cx="250" cy="260" r="70"></circle>
<text class="dimensional" x="210" y="280" fill="black">dimensional</text>
This way, the region where your three circles overlap actually disappears, signifying that you can't indeed get all three at the same time.Holy shit there is. When my dark theme is enabled, the diagram is black on black. Amazing. (all that's visible is the emoji!)
Like it injects/modifies the styles of pages willy-nilly? The beauty of browsers is that you're fully able to do that, but seems like a great way to just have a broken browsing experience all the time...
The page is already pretty dark!
However, the SVG seems to get all its color from CSS; the color is not part of the SVG itself. Maybe that's not working in your browser?
It's a first class citizen, put it in a React Component, anything goes. Cacheable, stylable, and dimensional.