If you’ve done any frontend work, you know that SVGs are the new hotness what you should be using for just about everything. They’re vector images that are easily scalable and relatively small in file size, making them a no brainer to use with retina screens and mobile devices.

I was working on a problem this week and ran into a roadblock. The goal was to make this diagram:

And link each one of the rings to an anchor link further down the page and add some animation to create a smooth scrolling effect.

But it turns out that making concentric svg rings that link to anchor points and have an animation is much more irritating than one would think.

Layering svgs on top of one another presents problems when you try to link them, because the clickable areas overlap, with the largest ring overlapping all of the others. After a while, I saved each one of the rings as an svg using Illustrator and pasted the code making the rings directly into the page (you only need the path). Then I wrapped each path with an anchor link using xlink:href (svgs are special snowflakes like that).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 228 228" enable-background="new 0 0 228 228">
	<g transform="scale(.6) translate(165, 155)">
		<path stroke="#fff" stroke-miterlimit="10" d="M49 37.3s11.6-1.5 11.6-12.8c0-7.2-5.9-13.1-13.3-12.8-3-6.1-9.1-10.3-16.3-10.3-9.6 0-17.4 7.5-17.9 16.9-6-1.3-11.6 3.3-11.6 9.4 0 8 6.9 9.4 9.4 9.6" fill="none"/>
		<g fill="#fff">
			<path d="M30.8 18.2c-6.3 0-11.4 5.1-11.4 11.4S24.5 41 30.8 41c6.3 0 11.4-5.1 11.4-11.4s-5.1-11.4-11.4-11.4zm0 19.9c-4.7 0-8.4-3.8-8.4-8.4 0-4.7 3.8-8.4 8.4-8.4 4.7 0 8.4 3.8 8.4 8.4 0 4.6-3.8 8.4-8.4 8.4z"/>
			<circle cx="33.6" cy="26.8" r="2.4"/>
			<circle cx="33.6" cy="32.5" r="2.4"/>
			<circle cx="27.9" cy="32.5" r="2.4"/>
			<circle cx="27.9" cy="26.8" r="2.4"/>
		</g>
	</g>
	<g transform="scale(.4) translate(180,120)">
		<a xlink:href="#link1">
			<path fill="#ff9" d="M114 1C51.7 1 1 51.7 1 114s50.7 113 113 113 113-50.7 113-113S176.3 1 114 1zm0 176c-34.7 0-63-28.3-63-63s28.3-63 63-63 63 28.3 63 63-28.3 63-63 63z"/>
		</a>
	</g>
	<g transform="scale(.4) translate(130,70)">
		<a xlink:href="#link2">
			<path fill="#AA9463" d="M164 1C74.1 1 1 74.1 1 164s73.1 163 163 163 163-73.1 163-163S253.9 1 164 1zm0 276c-62.3 0-113-50.7-113-113S101.7 51 164 51s113 50.7 113 113-50.7 113-113 113z"/>
		</a>
	</g>
	<g transform="scale(.4) translate(80, 20)">
		<a xlink:href="#link3">
			<path fill="#564E5D" d="M214 1C96.6 1 1 96.6 1 214s95.6 213 213 213 213-95.6 213-213S331.4 1 214 1zm0 376c-89.9 0-163-73.1-163-163S124.1 51 214 51s163 73.1 163 163-73.1 163-163 163z"/>
		</a>
	</g>
	<g>
		<a xlink:href="#link4">
			<path fill="#4E6C80" d="M263,0C117.7,0,0,117.7,0,263s117.7,263,263,263s263-117.7,263-263S408.3,0,263,0z M263,476 c-117.4,0-213-95.6-213-213c0-117.4,95.6-213,213-213s213,95.6,213,213C476,380.4,380.4,476,263,476z"/>
		</a>
	</g>
</svg>

Then I tried to use the following Javascript to add smooth scrolling to the anchor links:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
$(document).ready(function() {
	$('a[href^="#"]').on('click',function (e) {
		e.preventDefault();
	
		var target = this.hash;
		var $target = $(target);
	
		$('html, body').stop().animate({
			'scrollTop': $target.offset().top
		}, 900, 'swing', function () {
			window.location.hash = target;
		});
	});
});

This didn’t work because of our delightful xlink:href ! So I changed it to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
$(document).ready(function() {
	$('a[*|href^="#"]').on('click',function (e) {
		e.preventDefault();
	
		var target = $(this).attr('xlink:href');
		var $target = $(target);
	
		$('html, body').stop().animate({
			'scrollTop': $target.offset().top
		}, 900, 'swing', function () {
			window.location.hash = target;
		});
	});
});

Breaking it down, we want to select all the different types of hrefs on the page. By using the jQuery selector *, we say we want to select all the different types of href, regardless of if they’re xlink:href or regular links. .hash() doesn’t work with xlink:href so we use $(this).attr('xlink:href') to grab the anchor link. Then we scroll to the anchor link’s position based on the coordinates of the element we’re linking to.

Hope this helps! Happy anchor linking!