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


Надо сказать, что 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. Её можно скачать и установить локально из репозитория на GitHub, но она также доступна онлайн.
Вот результат оптимизации:
<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-компонентом (обёрткой), получающим содержимое через слот.
Тем не менее цель я считаю достигнутой, а вёрстку и код всегда можно доработать под конкретную задачу 😉
