Оставим за скобками вопрос о целесообразности использования SVG на сайте. Каждый сам для себя должен определить полезность этой технологии. Тем более что эта тема поднималась уже неоднократно.

Сейчас мы рассмотрим методы встраивания SVG, их плюсы и минусы, а так же возможности манипулирования элементами SVG.

Статья рассчитана в первую очередь на тех, кто до сих пор не использует векторную графику на своих сайтах, но очень хочет быть одной ногой в будущем настоящем.
Для любопытных сразу приведу сводную таблицу:
Иконочный шрифт IMG, background-image Object Inline
CSS Манипуляции Частично1 Нет Частично2 Да
JS манипуляции Частично1 Нет Да Да
SVG анимации Нет Да Да Да
Интерактивные SVG анимации Нет Нет Да Да
1 Можно менять цвет, размер, выравнивание и прочее стили обычного текста
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)


  1. GreatRash
    24.07.2015 13:22

    SVG-анимации не работают как минимум в Android 4.3 (в стоковом браузере). Так что с ними надо быть аккуратней.


    1. firya Автор
      24.07.2015 14:16

      Конечно всегда нужно оглядываться на то, чем пользуется ваша аудитория, но судя по статистике с caniuse доля android 4.3 на данный момент меньше чем IE 8


      1. GreatRash
        24.07.2015 14:34

        Судя по их статистике, браузером в Android 5 вообще никто не пользуется.


        1. firya Автор
          24.07.2015 14:41

          Хорошее замечание:) видимо какой-то баг у них там


        1. alex_rus
          24.07.2015 16:39

          потому что в 5ом андройде вместо встроенного используется chrome, а у него 13%


          1. GreatRash
            24.07.2015 18:07

            Он на caniuse же в отдельную ветку выделен как хром 40.


            1. alex_rus
              24.07.2015 22:01

              Судя по их статистике, браузером в Android 5 вообще никто не пользуется.

              не пользуются потому что в Android 5.0 от гугла его просто нет вообще. Им невозможно воспользоваться.
              Он на caniuse же в отдельную ветку выделен как хром 40.

              А то что на caniuse.com версия 40 это бывший WebView (для встраивания в приложения) вместо которого сейчас движок от chrome 40.


              1. GreatRash
                27.07.2015 11:02

                Ну я про это всё знаю, к чему вы клоните? Процент использования всё равно 0.


    1. SelenIT2
      25.07.2015 01:58

      Если речь про SMIL, то у меня они работают в стоковом браузере в Android 4.0. Что согласуется с данными caniuse.


    1. Serator
      26.07.2015 02:22

      www.chromestatus.com/feature/5371475380928512 — более того, они считаеются нерекомендуемыми с 45-ой версии Chrome'а.


  1. WaveCut
    24.07.2015 13:33
    +1

    Люблю SVG за то, что он легко и непринужденно решает проблемы с High-DPI экранами.


  1. dom1n1k
    24.07.2015 16:19
    -1

    На мой взгляд, иконочные шрифты изначально были мертворожденным стандартом, который получил некоторую популярность исключительно из-за слабой на тот момент поддержки SVG. Они недобны, неествественны, плохо контролируемы. Полагаю, что в ближайшие год-два они будут полностью и окончательно вымыты из индустрии.


    1. firya Автор
      24.07.2015 16:39

      Не думаю что в ближайшие годы иконочные шрифты куда-то денутся. Да они плохо контролируемы, да бывают проблемы в отображении, но в тоже время для обычного вебмастера это самый простой способ встроить иконки на сайт, за исключением вставки png тегом img


      1. dom1n1k
        24.07.2015 16:52

        Ну тогда они останутся только в виде готовых паков, которые предполагается использовать as is в быстрых шаблонных задачах (типа тех, что входят в bootstrap). Самостоятельно их делать точно никто не будет.


  1. 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;
    }
    

    Минус Модернайзер, минус лишние зависимости и тормоза, минус несколько строк кода.


    1. firya Автор
      24.07.2015 16:42

      Изящное решение, не думал о таком варианте. Modernizr сам не использую, поскольку в своих проектах не считаю целесообразным грузить лишний файл, ради отображения иконки 1-2% пользователей, которая никак не повлияет на восприятие информации


    1. Aingis
      24.07.2015 21:03

      Пользователи старых андроидных браузеров (андроид 2) и ретрогады на Fx 3.6 увидят пустоту. Старых телефонов не так мало, как может показаться. А если не считаться со старыми браузерами, то зачем даже IE8 поддерживать? К тому же, есть глюки с SVG на фоне и в новых IE, особенно на винфонах. При подходе .no_svg можно просто там выключить. В остальном метод рабочий, да.


      1. dom1n1k
        24.07.2015 21:21
        +1

        Но как-то и очень не хочется нагружать старые (=тормозные) телефоны лишним JS.

        Фиг знает, в среднем по больнице caniuse доля андроидов 2.3 — 0.07%. Не знаю почему так мало. Возможно потому, что владельцы таких телефонов не шарятся с них по интернету, а используют небольшой набор нативных приложений (мессенджеры, социалочки и все). Потому что кто активно серфит — уже проапгрейдился бы.
        Суммарная доля FF 2-3 тоже ~0.1%. Один из тысячи.

        Конечно, всегда надо смотреть на целевую аудиторию конкретного сайта, потому что она может отличаться от средней. Если аномально много старого — ну тогда просто забиваем на SVG и используем старый добрый растр. Тем более, что старые устройства = медленные устройства.