SVG text accessibility - svg

I have the following structure
<h2>
<svg viewBox='-5 -40 100 50'>
<!-- some filters that get applied on the elements below -->
<clipPath id='c'>
<text id='t'>Scooby</text>
</clipPath>
<g clip-path='url(#c)'>
<rect x='-5' y='-40' width='100%' height='100%'/>
<path/>
</g>
<use xlink:href='#t'/>
<use xlink:href='#t'/>
</svg>
</h2>
How can I ensure the text inside the clipPath ("Scooby") gets seen by screen readers and only once?
I know SVG text should be read by screen readers, but is that the still the case when it's inside a clipPath element? And what about use copies of it?
I'm using this structure in order to get some fancy effects (think stuff like this) on the heading text (and ditch the .jpg image that's currently used).

Remove the SVG from your screenreader using aria-hidden and define the label for your h2 using aria-labelledby.
<h2 aria-labelledby="t">
<svg viewBox='-5 -40 100 50' aria-hidden="true">
<!-- some filters that get applied on the elements below -->
<clipPath id='c'>
<text id='t'>Scooby</text>
</clipPath>
<g clip-path='url(#c)'>
<rect x='-5' y='-40' width='100%' height='100%'/>
<path/>
</g>
<use xlink:href='#t'/>
<use xlink:href='#t'/>
</svg>
</h2>

Add aria-hidden to suppress screen reading on specific elements, it'll read "Scooby" just once:
<h2>
<svg viewBox='-5 -40 100 50'>
<!-- some filters that get applied on the elements below -->
<clipPath id='c'>
<text id='t'>Scooby</text>
</clipPath>
<g clip-path='url(#c)'>
<rect x='-5' y='-40' width='100%' height='100%'/>
<path/>
</g>
<use aria-hidden="true" xlink:href='#t'/>
<use aria-hidden="true" xlink:href='#t'/>
</svg>
</h2>

The aria-label attribute is intended for use when text is not visible on screen
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-label_attribute
<h2 aria-label="Scooby">
<svg> ... </svg>
<h2>
or alternatively, I believe most screen readers will use the <title> SVG element.
<h2>
<svg>
<title>Scooby logo</title>
...
</svg>
<h2>
You also have the option of using other ARIA attributes, such as aria-labelledby.

Related

What is the proper way to reference an element inside a SVG file from a HTML file?

I'm trying to construct a buttons collection for a website. Since the buttons share several properties (colours and effects) I've decided to use SVG. In order to reduce the HTTP requests, I tried to nest several elements and filters inside the same SVG file. The idea is instantiate these elements to construct all the buttons, toggle switches, etc by simply using the <use> tag.
After reading great articles like this, this, and this I'm still not being able to do such thing. I found myself stuck. So I decided to simplify the problem as much as I could within the snippet down bellow.
<style>
svg,
img,
object {
width: 50px;
height: 50px;
border: 1px solid black;
}
h3 {
margin-top: 50px;
}
</style>
<h1>Swimming Veggies. The SVG club that's driving me nuts.</h1>
<h3>This is an inline SVG.</h3>
<svg viewBox="0 0 50 50">
<g id="pool">
<rect width="50" height="50" fill="aqua" />
</g>
<symbol id="tomato">
<circle cx="35" cy="35" r="10" fill="tomato" />
</symbol>
<g id="orange">
<circle cx="15" cy="15" r="12" fill="orange" />
</g>
</svg>
<p>Things work as expected here. The <g> elements #pool and #orange show up while the <symbol id="tomato"> doesn't. Great!</p>
<h3>This is a SVG using <use> to referencing elements from the inline SVG above.</h3>
<svg style="border: 1px solid black;" width="50" height="50">
<use xlink:href="#pool"></use>
<use xlink:href="#tomato"></use>
</svg>
<p>Note that the <symbol id="tomato"> element shows up here like the g elemet "pool". The "orange" element is NOT being <use>d. Works fine. Expected behaviour.</p>
<h3>This is a SVG being put as an IMG.</h3>
<img src="club.svg">
<p>Works fine to me and the absence of the <symbol id="tomato"> is the expeted behaviour. I don't want to use SVG this way though.</p>
<p> Unfortunately, IMGUR didn't accept SVGs and I didn't find an image sharing platform that accepts SVG files. The "club.svg" file has the same content as the commented code at the end of this HTML snippet. The SVG file is located ON THE SAME FOLDER of the HTML file. Sorry for the inconvenience :(</p>
<h3>This is a SVG being put as an OBJECT</h3>
<object type="image/svg+xml" data="club.svg"></object>
<p>This works as expected.</p>
<p>Again, the "club.svg" file content is shown as a comment inside and at the end of this HTML snippet.</p>
<h3>An unsuccessful attempt to extract elements from an OBJECT SVG </h3>
<object type="image/svg+xml" data="club.svg#tomato"></object>
<p>The browser is ignoring the "#tomato" after the file name. Is it possible to extract/manipulate elements inside the SVG file this way? If so, how?</p>
<h3>This is a SVG being put as an external reference.</h3>
<svg>
<use xlink:href="club.svg#pool"></use>
<use xlink:href="club.svg#tomato"></use>
<use xlink:href="club.svg#orange"></use>
</svg>
<p>That would be my preferable way to clone/manipulate elements from an external source (in this case, "club.svg"). Unfortunately, it's not working for me. It's not clonning the element. What am I doing wrong?</p>
<h3>Here goes the club.svg content (it's commented inside the snippet).</h3>
<!--
Down bellow is the code inside the club.svg file:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 50 50">
<g id="pool">
<rect width="50" height="50" fill="aqua" />
</g>
<symbol id="tomato">
<circle cx="35" cy="35" r="10" fill="tomato" />
</symbol>
<g id="orange">
<circle cx="15" cy="15" r="12" fill="orange" />
</g>
</svg>
-->
By the way... I tried to open up the file on Brave, Opera, Chrome and Safari. All of them show the same results.
Any help will be very much appreciated.

svg text with clip-path not clipping properly?

We have an issue with applying a clipPath to a text element in the svg below.
<!DOCTYPE html>
<html>
<head>
<title>Svg clipping issue</title>
</head>
<body>
<div style="width:500px;height:180px;">
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" height="100%"
width="100%">
<defs>
<clipPath id="myClip">
<rect transform="matrix(1,-0,-0,1,-0,-25.7478256)" x="198.1017" y="98.565216" width="65" height="25"></rect>
</clipPath>
</defs>
<polygon points="198.1017,98.565216 263.84082,98.565216 263.84082,72.817383 198.1017,72.817383" clip-path="url(#myClip)"
fill="#FF0000" stroke-width="none"></polygon>
<text transform="matrix(1,-0,-0,1,-0,-25.7478256)" clip-path="url(#myClip)" font-family="Microsoft Sans Serif"
font-size="8.25pt" fill="#000000">
<tspan text-anchor="middle" x="230.6017" y="108.755646">Line 1</tspan>
<tspan text-anchor="middle" x="230.6017" y="121.205841">A very very long line</tspan>
</text>
<rect transform="matrix(1,-0,-0,1,-0,-25.7478256)" x="198" y="98" width="65" height="25" fill="none" stroke="#0000FF"></rect>
</svg>
</div>
</body>
</html>
The clipPath is applied to the polygon and to the text element. On the polygon the clipPath is working correctly, as we still see the polygon.
On the text it has the issue that the entire text is clipped, but is should look like this.
If we remove the clipPath from the text element we obviously can we see the entire text, but this is not what we want.
Anybody an idea what's going on or is this a rendering bug in the browser? We get the same result on Firefox, Chrome, Edge, IE.
The problem you are having is because any transform that is applied to an element, also gets applied to the clip path attached to it. So your clip path gets transformed twice by the
transform="matrix(1,-0,-0,1,-0,-25.7478256)"
that is on the <text> element and also on the <clipPath> element.
You can fix this in several ways:
Remove the transform from the <text> element and change it's coordinates so it is correctly over the rectangle. Or do the reverse to the rectangle.
Wrap both the rectangle and the text in a group, and apply the clip path to that (as #Mehdi has suggested)
Make a separate <clipPath> without the transform. See example below
<!DOCTYPE html>
<html>
<head>
<title>Svg clipping issue</title>
</head>
<body>
<div style="width:500px;height:180px;">
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" height="100%"
width="100%">
<defs>
<clipPath id="myClip">
<rect transform="matrix(1,-0,-0,1,-0,-25.7478256)" x="198.1017" y="98.565216" width="65" height="25"></rect>
</clipPath>
<clipPath id="myClip2">
<rect x="198.1017" y="98.565216" width="65" height="25"></rect>
</clipPath>
</defs>
<polygon points="198.1017,98.565216 263.84082,98.565216 263.84082,72.817383 198.1017,72.817383" clip-path="url(#myClip)"
fill="#FF0000" stroke-width="none"></polygon>
<text transform="matrix(1,-0,-0,1,-0,-25.7478256)" clip-path="url(#myClip2)" font-family="Microsoft Sans Serif"
font-size="8.25pt" fill="#000000">
<tspan text-anchor="middle" x="230.6017" y="108.755646">Line 1</tspan>
<tspan text-anchor="middle" x="230.6017" y="121.205841">A very very long line</tspan>
</text>
<rect transform="matrix(1,-0,-0,1,-0,-25.7478256)" x="198" y="98" width="65" height="25" fill="none" stroke="#0000FF"></rect>
</svg>
</div>
</body>
</html>
The problem may be related to the fact that clip-path is not applicable to a tspan.
You may work around it by applying the clipping to a group containing the text and polygon:
<g clip-path="url(#myClip)">
<polygon /* ... */></polygon>
<text transform="matrix(1,-0,-0,1,-0,-25.7478256)" font-family="Microsoft Sans Serif" font-size="8.25pt" fill="#000000">
/* ... */
</text>
</g>
Updated snippet:
<!DOCTYPE html>
<html>
<head>
<title>Svg clipping issue</title>
</head>
<body>
<div style="width:500px;height:180px;">
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" height="100%"
width="100%">
<defs>
<clipPath id="myClip">
<rect transform="matrix(1,-0,-0,1,-0,-25.7478256)" x="198.1017" y="98.565216" width="65" height="25"></rect>
</clipPath>
</defs>
<g clip-path="url(#myClip)">
<polygon points="190.1017,120.565216 263.84082,98.565216 263.84082,72.817383 198.1017,72.817383"
fill="#FF0000" stroke-width="none"></polygon>
<text transform="matrix(1,-0,-0,1,-0,-25.7478256)" font-family="Microsoft Sans Serif" font-size="8.25pt" fill="#000000">
<tspan text-anchor="middle" x="230.6017" y="108.755646">Line 1</tspan>
<tspan text-anchor="middle" x="230.6017" y="121.205841" >A very very long line</tspan>
</text>
</g>
<rect transform="matrix(1,-0,-0,1,-0,-25.7478256)" x="198" y="98" width="65" height="25" fill="none" stroke="#0000FF"></rect>
</svg>
</div>
</body>
</html>

Is it possible to use SVG foreignObject as a mask?

The text element inside the mask works as expected, but the div inside the foreignObject element is ignored.
<svg width='500' height='300' >
<defs>
<mask id='m'>
<text fill='white' x='0' y='35' font-size='35'>text element</text>
<foreignObject width='200' height='200' >
<div style='color:white;'>div element</div>
</foreignObject>
</mask>
</defs>
<rect width='200' height='200' mask='url(#m)' />
</svg>
Does anyone know how to get the foreignObject to work inside a mask? Is it even possible?

transform property not working in IE on <use> in svg image when svg image importing from external html file

index.html
<div class="button-icon">
<svg width="950px" height="605px" viewBox="0 0 950 605" >
<use xlink:href="assets/svgs/front-view-1-g2.svg#front-view-1-g2" />
</svg>
</div>
front-view-1-g2.svg
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
<defs>
<g id="dark-rectangle" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" >
<text id="2" font-family="AvenirPrimaryHMHMath" font-size="10" width="12" height="12" font-weight="normal" fill="#000000">
<tspan x="83" y="15">31</tspan>
</text>
<rect id="path-1" transform="translate(83.000000, 17.000000)" x="0" y="0" width="12" height="12" fill="#9b9b9b" ></rect>
</g>
</defs>
<g id="iPad" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="front-view-1-g2">
<use xlink:href="#dark-rectangle"></use>
<use transform="translate(110.000000, 0.000000)" xlink:href="#dark-rectangle"></use>
</g>
</g>
</svg>
i have only one group but needed to call it 2 times and change the position of second group and that is why i used transform to second use tag but its not working in IE browser.
if i put use tag in html file then also transform not working in IE.
it works properly in Chrome and Mozilla.
Note : use tag not working when mentioned in .svg file and transform not working when use mentioned in .html file.
Hey I found the answer for this.
Transform will work on use tag in IE as IE will not render tag, it directly renders particular group's child elements from .svg file.
In above case of mine, I need to create another rectangle group assign transform to it and use that group.

How I can get text with desired height and width?

I need to get text with desired height and width.
I tried to find something in documentation of svg but found only font-size and also I tried to use scale in such manner:
<text xmlns="http://www.w3.org/2000/svg" id="10996080909940" name="-1"
x="1782.9351809218" y="-751.796133712862" width="1" height="1" style="font:Arial;text-
anchor:start;stroke:#000000" transform="rotate(0) scale(2 2)"> SOME TEXT </text>
But I get too big size of text and in place not where I need.
If you mean you want the text to exactly fill an arbitrary width and height, then there isn't really an easy way to do it in SVG. You can't specifiy a width and height on the <text> element. At least not in the current SVG spec (1.1).
However there are several ways to achieve this effect with a bit of trickery.
One way is by using a transform, as you suggested:
<svg>
<text font-size="10px" font-family="Verdana" transform="translate(99,400) scale(3.5,13.7)">SQUASHED TEXT</text>
<rect x="100" y="300" width="300" height="100" fill="none" stroke="red" />
</svg>
A second way is by using an inner <svg> element and setting the viewBox to match the bounds of the text. You then set preserveAspectRatio="none".
<svg>
<svg x="100" y="100" width="300" height="100" viewBox="0.2 -7.3 86 7.3" preserveAspectRatio="none" overflow="visible">
<text font-size="10px" font-family="Verdana">SQUASHED TEXT</text>
</svg>
<rect x="100" y="100" width="300" height="100" fill="none" stroke="red" />
</svg>
This way is more verbose, but it has the advantage that once you have found the correct viewBox for a piece of text, you can make it fit any sized rectangle very easily. Just set the x,y,width and height of the inner <svg> to the size of the rectangle.
Demo here: http://jsfiddle.net/ZRgEF/3/

Resources