Анимированный спойлер для изображений при помощи SVG и CSS

dev18.04.2020

Решил немного поиграться с CSS-анимацией и SVG. Идея следующая: сделать спойлер для изображений в виде шторок, раздвигающихся при наведении.

Я нарисовал эскиз в Adobe XD и экпортировал в SVG.

02
03

Надо сказать, что Adobe XD генерирует довольно грязный, на мой взгляд, код SVG. Вот содержимое файла изображения после экспорта:

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300.001" viewBox="0 0 400 300.001">
	<g id="Group_2" data-name="Group 2" transform="translate(0)">
		<path id="Path_4" data-name="Path 4" d="M175,300H0V0H220L201.915,120.561c-.629-.04-1.273-.061-1.916-.061a29.5,29.5,0,0,0-6.807,58.21L175,300Z" fill="#ff8c00"/>
		<path id="Path_5" data-name="Path 5" d="M175,300H0V0H220L201.915,120.561c-.629-.04-1.273-.061-1.916-.061a29.5,29.5,0,0,0-6.807,58.21L175,300Z" transform="translate(400 300.001) rotate(180)" fill="#00bfff"/>
		<g id="Group_1" data-name="Group 1">
			<path id="Path_6" data-name="Path 6" d="M25,0A25,25,0,1,1,0,25,25,25,0,0,1,25,0Z" transform="translate(175 125)" fill="gray"/>
			<path id="Path_7" data-name="Path 7" d="M1.718,13.2H20.867l-7.809-30H8.573l7.01,26.736H.867Z" transform="translate(195.133 146.805)" fill="#fff"/>
			<path id="Path_8" data-name="Path 8" d="M1.718,13.2H20.867l-7.809-30H8.573l7.01,26.736H.867Z" transform="translate(205.867 153.195) rotate(180)" fill="#fff"/>
		</g>
	</g>
</svg>

Такой вариант меня не устраивал. В поисках решения я наткнулся на неплохую бесплатную утилиту для оптимизации SVG-изображений SVGOMG. Её можно скачать и установить локально из репозиторияopen in new window на GitHub, но она также доступна онлайнopen in new window.

Вот результат оптимизации:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300">
	<g data-name="Group 2">
		<path data-name="Path 4" d="M175 300H0V0h220l-18 120.6-2-.1a29.5 29.5 0 00-6.8 58.2L175 300z" fill="#ff8c00"/>
		<path data-name="Path 5" d="M225 0h175v300H180l18-120.6 2 .1a29.5 29.5 0 006.8-58.2L225 0z" fill="#00bfff"/>
		<g data-name="Group 1">
			<path data-name="Path 6" d="M200 125a25 25 0 11-25 25 25 25 0 0125-25z" fill="gray"/>
			<path data-name="Path 7" d="M196.9 160H216l-7.8-30h-4.5l7 26.7H196z" fill="#fff"/>
			<path data-name="Path 8" d="M204.1 140H185l7.8 30h4.5l-7-26.7H205z" fill="#fff"/>
		</g>
	</g>
</svg>

Выглядит намного лучше 🙂 Осталось наложить SVG на какую-нибудь картинку и добавить анимацию отдельных элементов (path, g) посредством CSS.

Изначально я хотел использовать @keyframes и animation, однако свойства transition здесь оказалось вполне достаточно. Тема выбора между использованием анимаций (animation) и переходов (transition) выходит за рамки данной статьи, но если коротко: animation стоит применять в тех случаях, когда возможностей transition оказывается недостаточно.

В качестве небольшой оптимизации я вынес в JavaScript-код функционал автоматического добавления анимированного SVG внутрь всех элементов с классом capsule.

Теперь достаточно поместить изображение (или любой другой контент) в контейнер с этим классом (например <div class="capsule"></div>) и анимированный спойлер будет наложен автоматически 😎

Данный спойлер нельзя назвать универсальным, он разрабатывался в первую очередь для изображений внутри контента (они как правило имеют соотношение сторон 4:3 либо 16:9). Он будет некорректно отображаться на изображениях (или прямоугольных блоках с другим содержимым) с соотношением сторон меньшим, чем 4:3 (попробуйте уменьшить ширину окна браузера до 400px и посмотрите, как будет отображаться этот блок). Также не стоит накладывать его на сильно вытянутые по ширине блоки, например на блоки текста из нескольких строчек.

Код JavaScript можно заменить Vue-компонентом (обёрткой), получающим содержимое через слот.

Тем не менее цель я считаю достигнутой, а вёрстку и код всегда можно доработать под конкретную задачу 😉