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

Решил немного поиграться с 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.

В результате экспериментов у меня получилась следующая разметка:

See the Pen Capsule by Kei (@RiseLab) on CodePen.dark

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

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

See the Pen Capsule JS by Kei (@RiseLab) on CodePen.dark

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

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

Код JavaScript также можно развить до отдельного компонента (например для Vue), получающего содержимое анимации в качестве параметра.

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