Feature detection of foreignObject in SVG - svg

I am using the foreignObject element in SVG, however IE9 does not support this element. I am looking at a way the detect this feature. Modernizr does not detect this feature and it seems I can not use createSVGForeignObject (not available on SVGSVGElement) like they do for rectangle (createSVGRect).
Thanks!

This should work if you want to use foreignObject because it integrates html content...
<switch>
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" requiredExtensions="http://www.w3.org/1999/xhtml">
<foreignObject >
</foreignObject>
</g>
<text font-size="10" font-family="Verdana">
No foreignObject
</text>
</switch>
The requiredExtensions part proposed to w3c and this was their response. Firefox does implement this, but I havent tested anything else though. You may be able to get away with just the requiredFeatures attribute as Erik suggests.
If you want to test in javascript try
var supported = document.implementation.hasFeature("http://w3.org/TR/SVG11/feature#Extensibility", "1.1"); –

There is a way to test this feature in JS, the following was borrowed from a recent commit to modernizr (https://github.com/Modernizr/Modernizr/commit/ee836f083f29a9e634df731400027c24630a75f3):
var toStringFnc = ({}).toString;
Modernizr.addTest('svgforeignobject', function() {
return !!document.createElementNS &&
/SVGForeignObject/.test(toStringFnc.call(document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject')));
});

Related

Making screen-readers read out <text> items in SVG graphics?

I've searched all over the place and not have any success with this.
I'm making SVGs like the following one in order to make them scalable, and also help people who are dyslexic so they can highlight the text and use plugins like Read Out Loud:
https://www.ole.bris.ac.uk/bbcswebdav/institution/TEL/TEL%20guides/Published%20TEL%20guides/Replay/record-now-instructions-web.svg
But I've not been able to get my copy of NVDA to read out the tab-indexed fields as I tab through them. I've tried fields and aria-label on various things...
Is there something simple I can change so NVDA (and similar screen readers) will read out the text as I tab through (NVDA does this on HTML pages).
Or should I just put the full description of all the text in my description at the top?
I noticed you have role="img" in your svg root. That's borking everything, since it tells the accessibility API that it is just a single element, whose accessible name is always aria-labelledby="svgTitle svgDesc"
Try changing that to role="graphics-document" (or perhaps role="application" if you want fancier interactions) and I think you'll have a whole lot more luck.
The other option is to remove the role attribute from the <svg> element. It sounds counterintuative, but it should make any <text> elements accessible.
For an example, see tip 5 in this SitePoint article, which has great background and other helpful tips on making SVG more accessible in different use cases:
Tips for Creating Accessible SVG
From the above article:
<svg version="1.1" width="300" height="200" aria-labelledby="title desc">
<title id="title">Green rectangle</title>
<desc id="desc">A light green rectangle with rounded corners and a dark green border.</desc>
<rect width="75" height="50" rx="20" ry="20" fill="#90ee90" stroke="#228b22" stroke-fill="1" />
<text x="35" y="30" font-size="1em" text-anchor="middle" fill="#000000">Website</text>
</svg>

How to config for using svg file in sveltekit?

To import and use svg file in sveltekit I refer to this article
https://riez.medium.com/svelte-kit-importing-svg-as-svelte-component-781903fef4ae
By the way, when I finally input the code
<svelte:component this={Logo} />
I got the error like below
<svelte:component this={...}> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules
I wish someone help me with this problem.
There is a SvelteKit plugin for inlining SVG:s. You can use the plugin in three different ways:
As a Svelte Component
As URL (e.g for use in an img tag)
As raw text (e.g for use in {#html rawText})
https://www.npmjs.com/package/#poppanator/sveltekit-svg
Looking through the article it seems to be solving a problem that doesn't exist in a way that is much more elaborate than needed.
In Svelte you can make a .svelte component that only contains SVG markup (inline), then use the svelte:component tag as you would with any other content.
Parent.svelte
<script>
import Circle from './Circle.svelte'
</script>
<svelte:component this={Circle} />
Circle.svelte
<svg viewbox="0 0 200 200">
<circle cx="100" cy="100" r="20"/>
</svg>
Here's a REPL showing how to switch between components that only have SVG in them.
You can even add stuff to the SVG components to make them dynamic since it's just markup like shown in this REPL.
In svelte-kit You can fix it by trying
<img src={YourSVGComponent} />
It worked for me.

Why doesn't StencilJS "hydrate" components in <svg> tags?

I have a Stencil component that should draw SVG shapes over an image.
If I generate the shapes (simple rect below) directly in the svg tag, it's ok, but if I use Stencil subcomponents instead, they're not hydrated.
But they are if I place them outside the svg tag (of course they do not render properly scaled over the image in this case...)
render() {
return (
<Host>
<svg viewBox={this.size}>
<image xlinkHref={this.Image} x="0" y="0"
width={this.width} height={this.height}
preserveAspectRatio="xMinYMin meet"
/>
{this.Bands.map((d) => // THESE ARE NOT HYDRATED
<bands-list data={d} />
)}
{this.Bands.map(() => // BUT THIS IS SHOWN CORRECTLY
<rect x={0} y={0} width={100} height={100} />
)}
</svg>
{this.Bands.map((d) => // HYDRATED, but outside SVG...
<bands-list data={d} />
)}
</Host>
);
}
here is what it produces :
what am I missing please ?
You got it wrong, you are using custom Web Components to dynamically render SVGs. Not WebComponents inside SVGs. Think of it that way - SVG is its own language for basically everything vector-related, basically any HTML inside SVG doesn't make sense. If you want a WebComponent as an abstraction for dynamically generated SVG content, you either generate the whole SVG our you could give StencilJS functional components a try.
Stencil components won't "hydrate" inside SVG, because they are at the heart of it all WebComponents, which are not supported within SVGs. Although you could use <foreignObject> I doubt it will serve you needs.

without smil, is gif my only option?

So I've recently encountered this warning
SVG's SMIL animations (<animate>, <set>, etc.) are deprecated and will be removed. Please use CSS animations or Web animations instead.
Doing as much research as I could, I keep finding excuses about replacing SMIL with web animations (which SMIL is if we're being technical) but this all involves JavaScript and CSS. I use animated SVGs in <img> tags because that's the point of the SVG format: it's an image.
This was really nice and all because it allowed me to at least organize my images on a web that's notorious for being a giant mess (e.g. JavaScript has no imports so you have to fill the global scope).
Now that I can't animate with SVG, is GIF the only option for self-contained animations?
SMIL is not as dead/deprecated as you believe it is. The Chrome developers recently posted this:
We value all of your feedback, and it's clear that there are use cases serviced by SMIL that just don’t have high-fidelity replacements yet. As a result, we’ve decided to suspend our intent to deprecate and take smaller steps toward other options.
In SVG2, most of the SMIL functionality should be available through CSS animations.
But these are still in draft, and only chrome has started implementing some.
Also, chrome message is just a deprecation message, it' not removed yet from this browser, and I doubt other browsers supporting it will remove it any soon.
Anyway, you can already achieve SMIL like animations on browser not supporting it (e.g IE) thanks to javascript polyfills like fakesmile.
Unfortunately, scripts in svg documents loaded through the HTMLImage element (<img>) won't run. So you have to switch from the <img> tag to the <iframe>, <object> or <embed> tags. These tags do allow the execution of scripts, so you just have to import the polyfill in your svg document, and then load your image as you would do within an <img> tag.
Here is an example that will work on IE :
SMILTest.svg
<svg width="120" height="120"
viewPort="0 0 120 120" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="10" y="10" width="100" height="100">
<animate attributeType="XML"
attributeName="x"
from="-100" to="120"
dur="10s"
repeatCount="indefinite"/>
</rect>
<script xlink:href="https://cdn.rawgit.com/FakeSmile/FakeSmile/master/smil.user.js"></script>
</svg>
index.html
...
<object data="SMILTest.svg"></object>
...
Live example
If all your svg images are served from the same domain as your main page, you could also automate it with something like that :
window.addEventListener('load', function(){
var obj = document.querySelectorAll('object[data*=".svg"],iframe[src*=".svg"],embed[src*=".svg"]');
Array.prototype.forEach.call(obj, function(o){
var doc = o.contentDocument;
var s = document.createElementNS('http://www.w3.org/2000/svg','script');
doc.documentElement.appendChild(s);
s.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'https://cdn.rawgit.com/FakeSmile/FakeSmile/master/smil.user.js');
});
});
Live example

Using <switch> with <foreignObject> in SVG

I am trying to properly implement the switch tag for a foreignObject tag in SVG so that Internet Explorer can display something else (nothing new in IE, always leaving features out). The documentation is almost perfectly clear on how to do this:
<switch>
<!-- Process the embedded XHTML if the requiredExtensions attribute
evaluates to true (i.e., the user agent supports XHTML
embedded within SVG). -->
<foreignObject width="100" height="50"
requiredExtensions="http://example.com/SVGExtensions/EmbeddedXHTML">
<!-- XHTML content goes here -->
<body xmlns="http://www.w3.org/1999/xhtml">
<p>Here is a paragraph that requires word wrap</p>
</body>
</foreignObject>
<!-- Else, process the following alternate SVG.
Note that there are no testing attributes on the 'text' element.
If no testing attributes are provided, it is as if there
were testing attributes and they evaluated to true.-->
<text font-size="10" font-family="Verdana">
<tspan x="10" y="10">Here is a paragraph that</tspan>
<tspan x="10" y="20">requires word wrap.</tspan>
</text>
The example is nice and clear and shows how to use the requiredExtensions attribute. However, the hyperlink "http://example.com/SVGExtensions/EmbeddedXHTML" is meaningless to me. What would I have to put in place of this in order to denote that XHTML is the requiredExtension for this foreignObject?
I have found the answer after much fiddling. The example should probably be added to the documentation... I have tested in IE, FF, and Chrome so far and all three have treated the switch properly:
Instead of using the "requiredExtensions" attribute, I used the "requiredFeatures" attribute and linked to "http://www.w3.org/TR/SVG11/feature#Extensibility"
So it would look like:
<switch>
<foreignObject width="100" height="50"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<!-- whatever external user-agent stuff -->
</foreignObject>
<!-- Alternate SVG content if foreignObject is not supported -->
</switch>
This works for testing if foreignObject is supported by the user-agent, but it isn't perfect as you still aren't denoting which external namespace you plan to use in the foreignObject which that user-agent may not support. It works better than nothing though.
Unfortunately, no standard says what to do but Firefox uses http://www.w3.org/1999/xhtml to indicate that it supports xhtml in foreignObject tags (and http://www.w3.org/1998/Math/MathML for mathml). I believe other UAs may have copied this but I haven't checked.

Resources