Управляем объектами в SVG на своём домене с помощью параметра адресной строки

SVG представляет подмножество языка XML, но несмотря на древность давно занял свою нишу среди векторных форматов изображений.

Основной недостаток SVG представляет его изоляция от основного кода, т. е. он загружается как отдельная страница. Как правило в современных браузерах небольшой код встраивают непосредственно в страницу, но большой проект возникает непреодолимое желание убрать в отдельный файл. Сильной стороной является возможность встраивать JavaScript и CSS, — ей мы и воспользуемся.

Мы не будем динамически создавать код SVG. Вместо этого создадим единый файл: группы объектов спрячем внутри парного тега <defs>, зададим стили и анимацию CSS, добавим скрипт для смены изображения и выведем его через тег <use>. А управлять всем будем через параметр адресной строки.

За основу возьмём код птицы из темы: https://habr.com/post/230443/.

Для начала нужно задать правильные атрибуты, которые полагаются языку XML.

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ...

Добавим анимацию изображению.

#wing {
	animation: swing 1.5s ease-out infinite;
	transform-origin: 15% 50%; 
}
@keyframes swing {
	from, to { transform: rotate(5deg); }
	50% { transform: rotate(-5deg); animation-timing-function: ease-in; }
}

Для наглядности перекрасим группу объектов и изменим размер, а помогут нам уже известные CSS-переменные. Изменим цвет крыла и тела птицы.

#wing { fill: var(--wing-color, #81CCAA); }
#body { fill: var(--body-color, #B8E4C2); }

В CSS-стили добавим новый класс. В него мы будем трансформировать нашу птицу. Здесь нужно напомнить, что в SVG можно задавать только те значения атрибутов, которые не были заданы для объектов (если цвет в схеме был указан статически, то изменить его не получится).
.tomtit {
	transform: scale(.65) translate(60px, 70px);
	--wing-color: #0099CC;
	--body-color: #FFDF34;
}

Осталось за малым. Спрятать группы внутри парного тега <defs>, отрисовать группу объектов <use id="cloth" xlink:href="#bird"/>, и добавить скрипт для выбора класса из значения параметра "c" адресной строки после загрузки файла (скрипт описан ниже).

<script type="text/javascript"><![CDATA[
	window.onload = () => {
		const search = window.location.search;
			def = document.getElementById("cloth");
			getClass = search.slice(1).split("&")
				.map(item => item.split("="))
				.find(([ key, value ]) => key === "c");

		if (search.length > 1 && getClass) {
			def.setAttribute("class", getClass[1]);
			console.info(`id="cloth" class="${getClass[1]}"`);
		}
	}
]]></script>

Весь код целиком
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
	width="1144.12" height="400" viewBox="0 0 572.06 200">
	<title>Cloth</title>
	<metadata>Create by bopoh13 for publication on the Habr, 2020</metadata>
	<style type="text/css"><![CDATA[
		svg { background-color: white; }
		#wing { fill: var(--wing-color, #81CCAA); }
		#body { fill: var(--body-color, #B8E4C2); }
		#pupil { fill: #1F2600; }
		#beak { fill: #F69C0D; }
		.eye-ball { fill: #F6FDC4; }
		.tomtit {
			transform: scale(.65) translate(60px, 70px);
			--wing-color: #0099CC;
			--body-color: #FFDF34;
		}
		#wing {
			animation: swing 1.5s ease-out infinite;
			transform-origin: 15% 50%; 
		}
		@keyframes swing {
			from, to { transform: rotate(5deg); }
			50% { transform: rotate(-5deg); animation-timing-function: ease-in; }
		}
	]]></style>
	<script type="text/javascript"><![CDATA[
		window.onload = () => {
			const search = window.location.search;
				def = document.getElementById("cloth");
				getClass = search.slice(1).split("&")
					.map(item => item.split("="))
					.find(([ key, value ]) => key === "c");	

			if (search.length > 1 && getClass) {
				def.setAttribute("class", getClass[1]);
				console.info(`id="cloth" class="${getClass[1]}"`);
			}
		}
	]]></script>
	<defs>
	<g id="bird">
		<g id="body">
			<path d="M48.42,78.11c0-17.45,14.14-31.58,31.59-31.58s31.59,14.14,31.59,31.58c0,17.44-14.14,31.59-31.59,31.59S48.42,95.56,48.42,78.11"/>
			<path d="M109.19,69.88c0,0-8.5-27.33-42.51-18.53c-34.02,8.81-20.65,91.11,45.25,84.73c40.39-3.65,48.59-24.6,48.59-24.6S124.68,106.02,109.19,69.88"/>
			<path id="wing" d="M105.78,75.09c4.56,0,8.84,1.13,12.62,3.11c0,0,0.01-0.01,0.01-0.01l36.23,12.38c0,0-13.78,30.81-41.96,38.09c-1.51,0.39-2.82,0.59-3.99,0.62c-0.96,0.1-1.92,0.16-2.9,0.16c-15.01,0-27.17-12.17-27.17-27.17C78.61,87.26,90.78,75.09,105.78,75.09"/>
		</g>
		<g id="head">
			<path id="beak" d="M50.43,68.52c0,0-8.81,2.58-10.93,4.86l9.12,9.87C48.61,83.24,48.76,74.28,50.43,68.52"/>
			<circle class="eye-ball" cx="72" cy="71.5" r="11"/>
			<circle id="pupil" cx="72" cy="71.5" r="7"/>
			<circle class="eye-ball" cx="77" cy="74" r="5"/>
		</g>
	</g>
	</defs>
	<use id="cloth" xlink:href="#bird"/>
</svg>


Теперь можно хранить файл SVG в виде отдельного файла-проекта. Пример загрузки:

<object type="image/svg+xml" data="bird.svg?c=tomtit">Your browser does not support SVGs</object>

SVG позволяет отображать объекты в зависимости от языковых настроек браузера через тег Switch. Часто ли в продакшене вы применяете значение пользовательского языка?
Tags:
csv, векторная графика, css-переменные, верстка сайтов, html-верстка

You can't comment this post because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author's username will be hidden by an alias.