I have a Gatsby project, where where I would like to use an svg as my main heading.
import Header from "../images/header.svg"
return (
<h1>
<Header/>
</h1>
)
Thers is no text in the svg (the text is made purely using rects and paths), so what do I do in terms of accessibility and SEO optimization?
Two ways to address this, visually hidden text or by adding a <title> to your SVG.
Do not use aria-label as support is not great (you will see people recommending that for SVGs, aria-label does not tend to work well on static / non-interactive elements).
Visually Hidden text (screen reader only text)
Visually hidden text is not visible on the screen but will still be read by a screen reader.
Please use the CSS class below to visually hide text, it has better compatibility and is future proofed compared to most current "screen reader only" classes as explained in this answer I gave
.visually-hidden {
border: 0;
padding: 0;
margin: 0;
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need to support legacy browsers */
clip-path: inset(50%); /*modern browsers, clip-path works inwards from each corner*/
white-space: nowrap; /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */
}
<h1>
<span class="visually-hidden">Welcome To Our Site</span>
<svg aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
<path fill="#666" d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z">
</path>
</svg>
</h1>
important: notice how I add focusable="false" as well as aria-hidden="true" to the SVG, this is to fix a bug with Internet Explorer where SVGs are focusable and to hide the SVG from screen readers. I used a youtube icon to represent your text as that was the closest SVG I had to hand!
Add a <title> element to your SVG.
The <title> element is effectively the same as alt on a normal image. Using this gives the screen reader something to announce.
Obviously you would then remove the aria-hidden="true" from it so it can be read by a screen reader!
Update after comments to include best practices for <title> and or <desc>
Thanks to the comments I realised this answer was lacking some key information on how to correctly use a <title>.
In this answer I gave I referenced a series of tests by deque which show that the most reliable method for labelling an SVG for screen readers using WAI-ARIA was to use aria-labelledby and point that to the <title> (and <desc> if you have both).
So a rough idea of how to do this is as follows:
<h1>
<svg aria-labelledby="welcome-title" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
<title id="welcome-title">Welcome To Our Site</title>
<path fill="#666" d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z">
</path>
</svg>
</h1>
Which is better?
Go for visually hidden text.
It works all the way back to IE6 which predates SVG!
It also works in a text only browser (one that does not understand CSS) as it will still be displayed. It is an edge case but still a win for visually hidden text!
I just starting working with svgs and Snap.svg library. Following a tutorial I created an arc progress indicator. What I want now is to add an inner shadow to the animated arc. I read the documentation but the filter.shadow command only gives the option for an outer shadow. I did some research on adding filters to regular svgs and I added one to the svg that I'm binding to my Snap object. It does give me the inner shadow, however it ruins the arc animation; only about half of the arc appears even though the inner shadow is present. I changed some of the filter settings trying to fix it but nothing works. I'm thinking that filter only works for static svgs.
Any help would be appreciated. Thanx
UPDATE
Here is the code that I'm using.
<svg class="gauge" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" viewBox="0 0 400 200" xml:space="preserve">
<path fill="none" stroke="#D1D2D1" stroke-miterlimit="10" d="M199.7,12.7V18h0.4v-5.3H199.7z M382,200c0-50-20.3-95.4-53.1-128.4
l8.4-8.4l-0.4-0.4l-8.4,8.4C295.6,38.4,250.1,18,200,18S104.5,38.3,71.5,71.2l-8.3-8.3l-0.4,0.4l8.3,8.3C38.3,104.5,18,149.9,18,200
h44c0-38,15.4-72.4,40.3-97.4l7.5,7.5l0.4-0.4l-7.5-7.5c24.9-24.8,59.2-40.2,97.1-40.3v10.5h0.5V62c38.1,0.1,72.6,15.6,97.5,40.7
c-0.1-0.1-0.2-0.2-0.3-0.4l-7.4,7.4l0.4,0.4l7.4-7.4c24.8,25,40.2,59.4,40.2,97.3H382z M102.3,102.6l0.3-0.3L102.3,102.6z"/>
</svg>
<script type="text/javascript">
var canvasSize = 400,
centre = canvasSize/2,
radius = canvasSize*0.8/2,
s = Snap('.gauge'),
path = "",
startY = centre-radius,
arc = s.path(path);
function fill(percent) {
var endpoint = percent*180;
Snap.animate(0, endpoint, function (val) {
arc.remove();
var d = val,
dr = d-180;
radians = Math.PI*(dr)/180,
endx = centre + radius*Math.cos(radians),
endy = centre + radius * Math.sin(radians),
largeArc = d>180 ? 1 : 0;
path = "M"+startY+","+centre+" A"+radius+","+radius+" 0 "+largeArc+",1 "+endx+","+endy;
arc = s.path(path);
arc.attr({
stroke: '#fff',
fill: 'none',
strokeWidth: 44,
});
}, 1500, mina.backout);
}
fill(50/100);
</script>
I added this code to the attribute to get an outer shadow.
arc.attr({
filter : s.filter(Snap.filter.shadow(1, 1, 2, 'black', 0.5))
})
I was wondering if there's something similar for an inner shadow.
I also tried adding this to the the embedded svg and then adding the attribute to the animated arc thinking it might work like a regular, static svg. It does give me an inner shadow, however only part of the animated arc gets displayed; it gets displayed within a rectangle.
<defs>
<filter id="inner-shadow">
<feGaussianBlur result="offset-blur" stdDeviation="5"></feGaussianBlur>
<feOffset dx="1" dy="1"></feOffset>
<feFlood flood-color="black" flood-opacity="1" result="color"></feFlood>
<feComposite operator="in" in2="offset-blur"></feComposite>
<feComponentTransfer>
<feFuncA slope="0.5"></feFuncA>
</feComponentTransfer>
<feMerge>
<feMergeNode></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
arc.attr({
stroke: '#fff',
fill: 'none',
strokeWidth: 44,
filter: 'url(#inner-shadow)',
});
You can adjust the filter area that its applied over so that it doesn't get cut off. The Snap code seemed to give an error for me, so I just tried it using the svg filter markup, as the problem seems to be SVG related, rather than Snap.
So the key bit to change would be..
<filter id="inner-shadow" y="-30" x="-30" height="400" width="500">
This gives an offset wider range. You can read more on that at filter docs
jsfiddle
I'm new to svgs and brand new to snap.svg. I'm working on generating elements within an SVG and have the following to work with:
<svg width="600" height="400" style="shape-rendering: geometricPrecision; position: absolute;
left: 0; top: 0;">
<defs>
...
<circle id="dot" r="10" stroke-width="2"></circle>
</defs>
</svg>
I want to use javascript to create mutliple instances of the circle #dot at different positions. So I have some javascript using snap.svg like this:
var dot = svg.use("dot");
var r = dot.attr("r");
dot.attr({ x: shapeData.X-r, y: shapeData.Y-r, class: "dot" });
but the value I'm getting for the radius, r, is null. How can I access values describing my circle like, r, width, height, fill color, etc?
The way use elements work in SVG is they are basically just pointers to the original object. If you place a clone of that dot on the canvas with use, the clone doesn't have a defined radius. It points back to dot, which has a defined radius.
It's not entirely clear to me what all you need to do but I think the right way to approach this is to get a reference to dot that you can then use for this purpose. You can clone dot and add other attributes to it later.
Aside from that you're just missing a lot of Snap stuff you need but maybe that's because you're just giving us a snippet.
Here's some code:
<svg id="svg" width="600" height="400" style="shape-rendering: geometricPrecision; position:absolute;left: 0; top: 0;">
<defs>
<circle id="dot" r="10" stroke-width="2"></circle>
</defs>
</svg>
JS:
// reference to svg
var svg=Snap('#svg')
// reference to dot, stored in a
var a=svg.select('[id="dot"]')
// what's the radius of a?
var r=a.attr('r')
alert('The radius is '+r)
// clone a and add it to the svg
b=a.use()
svg.append(b)
// give b some attributes
b.attr({x:100,y:50})
console.log(b.attr())
Fiddle here: https://jsfiddle.net/ksy7mLsx/1/
I'm developing a prototype to mock this tool and provide minimal functionality like
Drag-n-Drop simple objects
Connect related objects via paths
Generate JSON from this structure
I opted SVG and Snap.svg framework (had hard time in deciding between D3 and Snap.svg but ended up with latter just because it is latest and successor of Raphael) to implement it. I stuck with below during implementation
Question 1: How to drag objects between different SVG elements? Try dragging elements in this Fiddle, objects were hidden when dragged outside of its parent dimension. Fiddle snippet below for your perusal.
HTML/SVG:
<div class="stencil">
<svg id="stencil" height="300" version="1.1" width="120" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
</svg>
</div>
<div class="paper">
<div class="paper__scroller">
<svg id="paper" height="1000" version="1.1" width="1000" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
</svg>
</div>
</div>
Javascript:
(function(){
var pap = Snap("#paper"),
stencil = Snap("#stencil"),
cir = stencil.circle(30, 50, 20),
rec = stencil.rect(70, 33, 35, 35);
stencilElements = stencil.group(rec, cir);
stencilElements.attr({
fill: "#f00",
stroke: "#000",
strokeWidth: 2,
"fill-opacity": 0.5
});
cir.clone().drag();
rec.clone().drag();
}());
Question 2: How to connect related objects via paths that adjust/moves accordingly when the object is dragged?
Question 3: How to convert the generated graph/diagram to JSON structure?
Really appreciate any reference or hints in implementing this.
I have a bunch of line elements created with D3 but the strange thing is that they're appearing in the DOM and when I mouseover them I see it being highlighted but there isn't anything there, everything is just blank. The code somewhat looks like this and the CSS has some weird webkit-transform-origin stuff. Does anyone know what is wrong? (screenshot of issue: http://imgur.com/HRE01Gd)
<div>
<svg width="1000" height="700">
<line x1="420" y1="470" x2="394.9078930250818" y2="369.0723716341295" id="id-1" style="stroke- width: 10px; color: red;"></line>
</svg>
</div>
-webkit-transform-origin-x: 0px;
-webkit-transform-origin-y: 0px;
-webkit-transform-origin-z: initial;
color doesn't do anything. Set stroke instead. At the moment, all of your lines are getting rendered with no stroke at all, which makes them invisible.
You need to change color to stroke. For instance:
<line x1="420" y1="470" x2="394.9078930250818" y2="369.0723716341295" id="id-1" style="stroke-width: 10px; stroke: red;"></line>
I had same problem. Tried to set stroke-width - did not help. Fixed it with correct x position of the element.