Оставим за скобками вопрос о целесообразности использования SVG на сайте. Каждый сам для себя должен определить полезность этой технологии. Тем более что эта тема поднималась уже неоднократно.
Сейчас мы рассмотрим методы встраивания SVG, их плюсы и минусы, а так же возможности манипулирования элементами SVG.
Статья рассчитана в первую очередь на тех, кто до сих пор не использует векторную графику на своих сайтах, но очень хочет быть одной ногой в
Для любопытных сразу приведу сводную таблицу:
Иконочный шрифт | IMG, background-image | Object | Inline | |
---|---|---|---|---|
CSS Манипуляции | Частично1 | Нет | Частично2 | Да |
JS манипуляции | Частично1 | Нет | Да | Да |
SVG анимации | Нет | Да | Да | Да |
Интерактивные SVG анимации | Нет | Нет | Да | Да |
2 Стили должны быть прописаны или в самом SVG файле, или подключены внешним стилем в SVG в начале файла:
<?xml-stylesheet type="text/css" href="svgstyle.css"?>
По правде говоря стили прописанные внутри SVG так же будут работать и при использовании тега IMG или background-image, но в этом нет никакого смысла.
Иконочный шрифт
Пример на codepen.io
Да, из SVG можно создать иконочный шрифт, более того есть свободно распространяемые иконочные шрифты. Но есть ряд серьезных ограничений. Как и любой символ шрифта SVG иконки в шрифте не могут иметь больше одного цвета.
Вот несколько сервисов, на которых можно скачать готовые наборы иконок, или загрузить свои, и создать собственный иконочный шрифт:
Нужно учесть что при создании собственного шрифта нужно преобразовать все объекты в пути. Тэги и атрибуты которые будут пропущены: circle, rect, stroke, stroke-width, fill, fill-rule.
При использовании иконочного шрифта все элементы SVG объекта объединяются в один символ, и взаимодействовать с ним через CSS и JS можно только как с символом шрифта: менять размер при помощи font-size, менять цвет при помощи color, анимировать при помощи CSS animation или JS и прочее.
Плюсы и минусы такого подхода:
+ иконка ведет себя как символ шрифта, и все параметры настраиваются так же через CSS (размер, цвет, выравнивание и прочее);
+ единственный способ работающий в IE 8 без дополнительных манипуляций;
– все элементы SVG файла объединяются в один символ, поэтому управлять им при помощи CSS или JS можно только как единым целым;
– поддерживаются только одноцветные иконки;
– при сбое загрузки шрифта у пользователя либо не отобразятся иконки совсем, либо, при совпадении кодов иконок с символами юникода, отобразятся соответстующие символы.
SVG как OBJECT
К сожалению (или к счастью) codepen и jsfiddle блокируют загрузку внешних object в целях безопасности.
Встраивание выглядит следующим образом:
<object type="image/svg+xml" data=”your.svg" id=’object’ class=’icon’></object>
Объект встраивает элмемент атрибута data наподобие iframe, добавляя внутрь себя разметку подключаемого файла, поэтому к элементам можно обращаться при помощи JS, но не совсем обычным образом:
var object = document.getElementById("’object’"); //получаем элмент object
var svgDocument = object.contentDocument; //получаем svg элемент внутри object
var svgElement = svgDocument.getElementById("some_id_in_svg"); //получаем любой элемент внутри svg
svgElement.setAttribute("fill", "black"); //меняем атрибуты выбранного элемента
Стоит отметить что в CSS стили для SVG элементов отличаются от стандартных, полный список стилей поддерживаемых SVG можно посмотреть тут.
SVG ведет себя не как обычное изображение, его нельзя непропорционально трансформировать, задавая ширину и высоту. Объект внутри будет занимать максимальную площадь и центрироваться в контейнере:
Но объект можно трансформировать используя CSS например так:
transform: scale(2, 1);
IE 8 и ниже не поддерживают SVG от слова «совсем» поэтому, если среди пользователей вашего сайта есть эта специфичная аудитория стоит озаботиться проверкой и заменой svg на растровое изображение. Сделать это можно множеством способов, например используя Modernizr добавлять .no-svg класс для body:
if (!Modernizr.svg) {
$(body).addClass(“no-svg”);
}
.no-svg .icon {
width: 100px;
height: 100px;
background-image: url(“icon.png”);
}
Плюсы и минусы такого подхода:
+ можно использовать внешний CSS файл для управления стилями;
+ поддерживаются SVG анимации и фильтры;
+ поддерживаются интерактивные анимации;
– для IE 8 и ниже необходима замена на растровое изображение.
SVG в IMG или background-image
Пример на codepen.io
Оба способа встраивания чем-то похожи на встраивание при помощи тэга object, например нельзя менять пропорции изменением ширины и высоты контейнера, но имеют больше ограничений.
Подключаемые в SVG внешние стили не будут работать, обратиться к элементам через JS так же не получится. Интерактивные анимации в SVG тоже не сработают. А проблемы с IE 8 и ниже так же остаются.
Но SVG анимации будут работать, в обоих случаях.
В случае с IMG втраивание выглядит как обычная картинка:
<img src="icon.svg">
В случае с background-image как обычный блок:
<div class="icon"></div>
.icon {
background-image: url("icon.svg");
width: 90px;
height: 150px;
}
Так же при помощи background-image можно использовать спрайты, как с png изображениями, а менять размер можно при помощи background-size:
background-size: 90px 150px;
Учитывая что процент людей c экранами device-pixel-ratio которых выше 1 и их устройства не поддерживают svg стремится к нулю(если такие вообще есть), то можно использовать медиа выражения для подключения svg, только для них, а для остальных использовать png версию:
.icon {
background-image: url("icon.png");
}
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (min--moz-device-pixel-ratio: 1.5),
only screen and (-o-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icon {
background-image: url("icon.svg");
}
}
Плюсы и минусы этих подходов:
+ поддерживаются SVG анимации и фильтры;
+ в случае с background-image можно использовать SVG спрайты;
– нельзя менять свойства элементов SVG через CSS или JS;
– не поддерживаются интерактивные анимации;
– для IE 8 и ниже необходима замена на растровое изображение.
Inline SVG
Пример на codepen.io
В этом варианте SVG код, получить который можно открыв любой SVG файл текстовым документом, встраивается непосредственно в код страницы.
Несомненно такая конструкция ухудшает читаемость кода, и увеличивает его объем, но открываются новые возможности.
Например имея набор иконок в SVG файле, можно использовать их повторно простой конструкцией вида:
<svg><use x="0" y="0" xlink:href="#some_svg_element_id" /></svg>
где some_svg_element_id id элемента внутри исходного SVG файла.
К отдельно взятому элементу можно, например, применять SVG трансформации:
<svg><use x="0" y="0" xlink:href="#some_svg_element_id" transform="scale(0.5)" /></svg>
Но если внутри исходного SVG к элементу была применена интерактивная анимация, например по клику, как в демо выше, то при дублировании объекта анимация будет срабатывать на всех элементах одновременно.
SVG анимации и фильтры это тема для отдельной статьи, поэтому ограничусь лишь примером SVG фильтра (подробнее о SVG фильтрах), и примером SVG анимации (подробнее о SVG анимациях).
С обесепечением работоспособности для IE 8 и ниже все несколько сложнее, чем в других вариантах. Необходимо добавить дополнительную разметку:
<div class="my-svg-alternate"></div>
if (!Modernizr.svg) {
$(body).addClass(“no-svg”);
}
.no-svg .my-svg-alternate {
display: block;
width: 100px;
height: 100px;
background-image: url(image.png);
}
Плюсы и минусы этого подхода:
+ никакой подгрузки внешних файлов;
+ доступны манипуляции с элементами SVG через CSS и JS;
+ поддерживаются SVG анимации и фильтры;
+ поддерживаются интерактивные анимации;
+ возможность повторного использования элементов;
– загрязняется код страницы;
– для IE 8 и ниже необходима дополнительная разметка, и замена на растровое изображение.
Заключение
Каждый из способов хорош по своему, и в зависимости от обстоятельств можно использовать любой из них.
Эта статья в первую очередь мой путь по освоению нюансов SVG, и надеюсь многим она будет так же полезна.
P.S. Всем добра и котиков.
Комментарии (18)
WaveCut
24.07.2015 13:33+1Люблю SVG за то, что он легко и непринужденно решает проблемы с High-DPI экранами.
dom1n1k
24.07.2015 16:19-1На мой взгляд, иконочные шрифты изначально были мертворожденным стандартом, который получил некоторую популярность исключительно из-за слабой на тот момент поддержки SVG. Они недобны, неествественны, плохо контролируемы. Полагаю, что в ближайшие год-два они будут полностью и окончательно вымыты из индустрии.
firya Автор
24.07.2015 16:39Не думаю что в ближайшие годы иконочные шрифты куда-то денутся. Да они плохо контролируемы, да бывают проблемы в отображении, но в тоже время для обычного вебмастера это самый простой способ встроить иконки на сайт, за исключением вставки png тегом img
dom1n1k
24.07.2015 16:52Ну тогда они останутся только в виде готовых паков, которые предполагается использовать as is в быстрых шаблонных задачах (типа тех, что входят в bootstrap). Самостоятельно их делать точно никто не будет.
dom1n1k
24.07.2015 16:32+3Что касается фолбека для IE8, то вместо
.no-svg .icon { background-image: url(“icon.png”); }
мне больше нравится хак с множественными фонами, которые не поддерживается IE8, а потому вторая строчка будет проигнорирована:
.icon { background-image: url(“icon.png”); background-image: url(“icon.svg”), none; }
или так, ну общем возможны варианты:
.icon { background: url(“icon.png”); background: url(“icon.svg”), transparent; }
Минус Модернайзер, минус лишние зависимости и тормоза, минус несколько строк кода.firya Автор
24.07.2015 16:42Изящное решение, не думал о таком варианте. Modernizr сам не использую, поскольку в своих проектах не считаю целесообразным грузить лишний файл, ради отображения иконки 1-2% пользователей, которая никак не повлияет на восприятие информации
Aingis
24.07.2015 21:03Пользователи старых андроидных браузеров (андроид 2) и ретрогады на Fx 3.6 увидят пустоту. Старых телефонов не так мало, как может показаться. А если не считаться со старыми браузерами, то зачем даже IE8 поддерживать? К тому же, есть глюки с SVG на фоне и в новых IE, особенно на винфонах. При подходе .no_svg можно просто там выключить. В остальном метод рабочий, да.
dom1n1k
24.07.2015 21:21+1Но как-то и очень не хочется нагружать старые (=тормозные) телефоны лишним JS.
Фиг знает, в среднем по больнице caniuse доля андроидов 2.3 — 0.07%. Не знаю почему так мало. Возможно потому, что владельцы таких телефонов не шарятся с них по интернету, а используют небольшой набор нативных приложений (мессенджеры, социалочки и все). Потому что кто активно серфит — уже проапгрейдился бы.
Суммарная доля FF 2-3 тоже ~0.1%. Один из тысячи.
Конечно, всегда надо смотреть на целевую аудиторию конкретного сайта, потому что она может отличаться от средней. Если аномально много старого — ну тогда просто забиваем на SVG и используем старый добрый растр. Тем более, что старые устройства = медленные устройства.
GreatRash
SVG-анимации не работают как минимум в Android 4.3 (в стоковом браузере). Так что с ними надо быть аккуратней.
firya Автор
Конечно всегда нужно оглядываться на то, чем пользуется ваша аудитория, но судя по статистике с caniuse доля android 4.3 на данный момент меньше чем IE 8
GreatRash
Судя по их статистике, браузером в Android 5 вообще никто не пользуется.
firya Автор
Хорошее замечание:) видимо какой-то баг у них там
alex_rus
потому что в 5ом андройде вместо встроенного используется chrome, а у него 13%
GreatRash
Он на caniuse же в отдельную ветку выделен как хром 40.
alex_rus
не пользуются потому что в Android 5.0 от гугла его просто нет вообще. Им невозможно воспользоваться.
А то что на caniuse.com версия 40 это бывший WebView (для встраивания в приложения) вместо которого сейчас движок от chrome 40.
GreatRash
Ну я про это всё знаю, к чему вы клоните? Процент использования всё равно 0.
SelenIT2
Если речь про SMIL, то у меня они работают в стоковом браузере в Android 4.0. Что согласуется с данными caniuse.
Serator
www.chromestatus.com/feature/5371475380928512 — более того, они считаеются нерекомендуемыми с 45-ой версии Chrome'а.