Если вы ещё не знакомы с техникой отзывчивых иконок Джо Харрисона (Joe Harrison), то, скорее всего, будете впечатлены так же сильно, как и я, когда впервые открыл её для себя. В этой статье я бы хотел исследовать, что мы можем делать с SVG, кроме традиционной практики замены PNG. В частности, мы можем рассматривать SVG как независимый модуль, который включает в себя CSS для кастомизации вариантов отображения; также как и правила для отзывчивого поведения, SVG может содержать в себе JavaScript для логики взаимодействий. Теперь давайте рассмотрим эту технику детальнее.
Отзывчивый SVG: ни кола, ни двора
Сайт с отзывчивыми иконками Харрисона устроен достаточно просто. Он создан на основе всем известной техники спрайтов. Если Вы всё ещё не знакомы со спрайтами, позвольте я объясню. Спрайты — это техника, которая прежде использовалась только для растровых изображений, чтобы решить проблему медленных сетей. Главная идея в том, чтобы объединить множество мелких изображений в единый файл, чтобы таким образом пользователь загружал с сервера только один файл с изображениями.
Для использования спрайта необходимо css-позиционирование, чтобы отображался только нужный участок картинки, таким образом пользователю нет нужды загружать каждое изображение по отдельности. (Почитать детальнее о спрайтах можно на CSS-Tricks)
Техника Харрисона делает тоже самое, только в отличие от PNG в спрайтах, используется SVG. Если объединить все изображения в один файл, вот что мы получим:
В дальнейшем этот файл будет установлен в качестве фона для контейнера, в котором одна из иконок и будет отображаться:
.icon {
width: 300px;
height: 300px;
background: url(../images/home_sprite.svg);
background-position: center top;
}
Пример, описанный выше, очень простой, но он имеет определенные недостатки. И избавить его от них не так-то просто. Фактически, для того, чтобы всё работало, нужны две составляющие: внешний CSS и, собственно, SVG спрайт.
Отзывчивый SVG: дырки да заплаты
Поскольку CSS может быть помещён в SVG, давайте рассмотрим представленный пример и сделаем иконку более портативной.
Для начала уберём все пустые места иконок в спрайте. Конечно же, это создаст многослойный бардак из иконок: пример на CodePen.
Далее, давайте переместим все формы и сгруппируем их для каждой иконки, добавляя класс .icon
для каждой из групп и порядковый номер, чтобы было легче идентифицировать каждую (например, #home_icon_0
, #home_icon_1
и так далее до #home_icon_8
):
<svg>
<g id="home_icon_0" class="icon">
<!-- пути и формы -->
</g>
<!-- ... -->
<g id="home_icon_8" class="icon">
<!-- пути и формы -->
</g>
</svg>
Теперь мы готовы к добавлению media queries, чтобы таким образом мы могли выбирать иконку для отображения. Это возможно с помощью написания CSS непосредственно в тег <svg>
используя для этого <defs>
.
<svg>
<defs>
<style>
/* Сначала мы прячем все иконки. */
.icon {
display: none;
}
/* Показываем первую. */
#home_icon_0 {
display: block;
}
/* Показываем нужную иконку и прячем остальные в зависимости от размера вьюпорта. */
@media screen and (min-width: 25em) {
#home_icon_0 {
display: none;
}
#home_icon_1 {
display: block;
}
}
@media screen and (min-width: 30em) {
#home_icon_1 {
display: none;
}
#home_icon_2 {
display: block;
}
}
/* И так далее */
</style>
</defs>
</svg>
В результате та же иконка будут адаптироваться к ширине вьюпорта, только теперь этим управляет CSS, медиавыражения и все иконки находятся в самом SVG-файле. Можете посмотреть как это работает изменяя ширину окна браузера.
Отзывчивый SVG: вооружён и очень опасен
Пример выше выглядит уже гораздо лучше, но вопрос всё ещё остается открытым:
- Возможно ли реализовать SVG лучшим способом?
- Можно ли использовать отзывчивый подход для отображения иконки и кастомизации её элементов, вместо простого прятания/показывания частей файла?
Если на регулярной основе рассматривать приёмы реструктуризации лейаута и контента в отзывчивом дизайне, можно продолжить совершенствовать прототип. Например, можно использовать изменение формы и трансформации для адаптации иконок к разным размерам вьюпорта.
Для начала, давайте перерисуем самую большую и детализированную иконку дома в спрайте, разделяя все пути и соединённые формы в элементарные формы. Результат будет читаться гораздо легче и теперь возможно применение трансформаций к любой части иконки: пример на CodePen.
Перерисованная иконка выглядит точно так же, как и большой спрайт выглядел до этого, но содержит гораздо больше форм и занимает меньше места. Магия в том, что мы добавляем медиавыражения и трансформации в новом варианте, изменяя формы иконки и тот же результат, что и в случае с SVG-спрайтом.
<svg>
<defs>
<style>
@media screen and (max-width: 65em) {
#door-shadow, #tube-shadow, .backyard {
display: none;
}
#door-body {
fill: white;
}
#door-handle {
fill: #E55C3C;
}
#door-body, #door-handle {
-ms-transform: translate(0,0);
-webkit-transform: translate(0,0);
transform: translate(0,0);
}
#window {
-ms-transform: translate(0,0) scale(1);
-webkit-transform: translate(0,0) scale(1);
transform: translate(0,0) scale(1);
}
#house-body {
-ms-transform: scaleX(1) translate(0, 0);
-webkit-transform: scaleX(1) translate(0, 0);
transform: scaleX(1) translate(0, 0);
}
#tube-body {
-ms-transform: translate(0, 0);
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
#tube-upper {
-ms-transform: translate(0, 0);
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
}
/* И так далее */
</style>
</defs>
</svg>
Как только мы добавим трансформации, наша иконка начнет вести себя точно так же, как и пример Джо Харрисона, с той лишь разницей, что у нас все будет содержаться в одном файле.
Вы можете изучить пример на CodePen.
Адаптируем иконки к размерам родительского контейнера
И ещё один момент. Также возможно изменять иконку в зависимости от изменения высоты или ширины родительского элемента.
Для этого я попробовал загрузить SVG в виде элемента img
, который был вложен в div
. Но ни одно из медиавыражений в SVG-файле не сработало.
Моя следующая попытка была загрузить иконку в элемент object
, вложенный в div
. После того, как я это проделал, все медиавыражения заработали. Более того, теперь можно было сделать так, чтобы объект заполнял всё пространство родителя. (Не забудьте установить такие атрибуты как ширина и высота равными 100% для svg
, или уберите их вовсе).
<div style="width: 100%; margin: 0 auto;">
<object>
<embed src="responsive3.svg" style="width: 100%; height: auto;" />
</object>
</div>
Существуют и другие способы внедрения SVG, с медиавыражениями и трансформациями, для этого можно использовать SVG как бекграунд картинку на любой блочный элемент. Инлайн-SVG тоже допустим, но тогда медиавыражения будут реагировать только на общий вьюпорт.
Пример ниже демонстрирует, как иконка реагирует на изменение размеров контейнера.
Помещённые внутри SVG медиавыражения определяют поведение иконок, в зависимости от размеров в которых будет отображаться SVG. Вот пример на CodePen одного и того же SVG который вмещает восемь блоков разного размера.
Добавляем JavaScript в SVG
И это ещё не все хорошие новости! SVG может содержать не только таблицы стилей, но и JavaScript. Таким образом мы можем рассматривать SVG как отдельный и независимый модуль, к которому может применяться любой язык разметки предыдущих версий.
Инлайн JavaScript отлично работает, когда SVG добавлен на страницу с помощью <object>
. Мы живем в замечательном мире, верно?
Поддержка браузеров
Последний и самый сложный пример отлично работает в следующих браузерах:
- Internet Explorer 9+
- Firefox 17+
- Chrome 17+
- Opera 15+
- Safari 6.0+
- Safari на iOS 6.0+
- Android browser на Android 3.0+
Данная техника может работать и в других браузерах, более старых версий, но в них не будут отрабатывать трансформации, такие как, например, масштабирование.
Заключение
Отзывчивые SVG иконки могут использоваться во многих случаях, включая следующие:
- отзывчивая реклама (площадь для рекламы будет занимать всю область, отведённую ей в документе, и, учитывая что CSS и JavaScript работают, большинство действий будут содержаться в едином рекламном SVG файле)
- логотипы
- иконки приложений
Я должен отметить, что нет ничего плохого в использовании практики со спрайтами, которую предложил Джо Харрисон. Она работает, и она необходима в некоторых случаях!
У вас появились интересные идеи? Хотите поделиться своим опытом использования этой техники? Напишите нам об этом в комментариях.
Развлекайтесь!
Автор: Илья Пухальский
Перевод: Саща Ющак, Frontender Magazine