Frontender Magazine

Использование SVG

SVG - формат векторной графики. Буквально его название значит «масштабируемая векторная графика» (Scalable Vector Graphics). Попросту говоря, это то, с чем вы работаете в Adobe Illustrator. SVG можно легко использовать в вебе, но сперва нужно во многом разобраться.

Зачем вообще нужен SVG?

Создадим изображение SVG, с которым будем работать дальше

Создайте произвольный рисунок в Adobe Illustrator. Вот, например, птица киви на овале.

Птица киви

Обратите внимание, что изображение кадрируется чётко по краям изображения. Холст в SVG играет не меньшую роль, чем в PNG или JPG.

Adobe Illustrator умеет сохранять в SVG.

Сохранение

При сохранении появится ещё одно диалоговое окно с настройками. Честно говоря, я не очень в них разбираюсь. Существует целая инструкция по Профилям SVG. Меня вполне устраивает SVG 1.1.

Настройки

Здесь стоит отметить, что у вас есть возможность нажать OK и сохранить файл или же нажать кнопку “SVG Code...”, которая откроет окно TextEdit (по крайней мере на Mac) с SVG-кодом.

SVG-код

Оба варианта могут пригодиться.

Добавляем SVG на страницу с помощью тега <img>

Если сохранить изображение SVG в файл, то его можно вставить с помощью тега <img>.

<img src="kiwi.svg" alt="Киви на овале">

В Illustrator рабочая область была размером 612px ✕ 502px.

Рабочая область

Именно такие размеры будут у изображения на странице, если их не указать специально. Его размеры можно изменить, задав атрибуты width или height для img, так же как для PNG или JPG. Вот пример:

Посмотрите на этот пример!

Поддержка браузерами

SVG по-разному поддерживается браузерами. Он работает везде, кроме IE до 8 версии и браузерах на Android до версии 2.3.

Если вы хотели бы использовать SVG, но проект поддерживает браузеры, которые не могут вставлять его через img, есть разные варианты. Я описал некоторые приемы в нескольких своих мастер-классах.

Один из вариантов: проверка поддержки через Modernizr и замена src для изображения:

if (!Modernizr.svg) {
  $(".logo img").attr("src", "images/logo.png");
}

Дэвид Бушел (David Bushell) предложил очень простой альтернативный вариант, если вы не имеете ничего против JavaScript в разметке:

<img src="image.svg" onerror="this.onerror=null; this.src='image.png'">

Еще можно использовать SVGeezy. Далее мы рассмотрим другие способы деградации.

Добавляем SVG через background-image

Использовать SVG в качестве фона c помощью CSS-свойства background-image так же просто, как и вставка с помощью тега img.

<a href="/" class="logo">
  Kiwi Corp
</a>

.logo {
  display: block;
  text-indent: -9999px;
  width: 100px;
  height: 82px;
  background: url(kiwi.svg);
  background-size: 100px 82px;
}

Обратите внимание, что для селектора .logo задан размер background-size. Это необходимо, иначе будет видна только верхняя левая часть изображения SVG, у которого исходный размер намного больше. Эти размеры прописаны с учётом соотношения сторон изображения в оригинале. Можно также использовать для background-size значение contain, чтобы убедиться в том, что изображение поместится в родительский контейнер, если вам не известно какого размера оно должно быть.

Поддержка браузерами

Вставка SVG через свойство background-image по-разному поддерживается браузерами, но в общем дела обстоят так же, как и с img. Проблемой являются IE до 8 версии и браузеры на Android до версии 2.3.

В этом случае нам может помочь Modernizr, даже более эффективно, чем при использовании img. Если заменить background-image на изображение, формат которого поддерживается, на сервер будет отправлен один HTTP-запрос, а не два. Modernizr добавляет класс "no-svg" для html-элемента, если SVG не поддерживается:

.main-header {
  background: url(logo.svg) no-repeat top left;
  background-size: contain;
}

.no-svg .main-header {
    background-image: url(logo.png);
}

Общая проблема при использовании <img> и background-image...

Проблема состоит в том, что вы не можете управлять внутренностями SVG с помощью CSS так, как сможете при использовании двух приёмов описанных ниже. Читайте дальше!

Добавляем SVG непосредственно в документ

Помните, как при необходимости можно получить SVG-код прямо при сохранении изображения в Illustrator? Ещё можно просто открыть SVG-файл в текстовом редакторе и скопировать его код. Этот код можно вставить прямо в HTML-документ, и SVG-изображение будет отображаться точно так же, как если бы его вставили с помощью тега img.

<body>

   <!-- вставьте код SVG, и появится изображение! -->

</body>

Этот приём может быть полезным, так как изображение встроено прямо в документ, и для его загрузки не происходит дополнительный HTTP-запрос. У этого метода те же преимущества, как и у использования Data URI. И недостатки у него те же, не обольщайтесь. Среди них: вероятность получения очень тяжелого документа, наличие блоков SVG-кода в нем и невозможность кэширования.

Если вы используете серверный язык, который позволяет получить содержимое файла и вставить его в документ, вы по крайней мере сможете очистить свой документ от блоков SVG кода. Вот так:

<?php include("kiwi.svg"); ?>

Сначала оптимизируем

Без сомнений, для вас не станет сюрпризом то, что SVG, полученные в Adobe Illustrator, не самые оптимальные. Они содержат DOCTYPE, примечания генератора и прочий мусор. У SVG, в общем, и так небольшой размер, но почему бы не уменьшить его еще больше, если есть возможность? Питер Коллингридж (Peter Collingridge) создал SVG Optimiser, инструмент для онлайн-оптимизации SVG. Загружаете старый файл, скачиваете новый. В своём видео Кайл Фостер заходит ещё дальше и удаляет даже переносы строки в процессе оптимизации.

Если вы еще более суровы, вот вам инструмент на Node JS, с помощью которого можно оптимизировать изображения самостоятельно.

Затем управляем с помощью CSS

Видите, насколько сильно теперь SVG похоже на HTML? Это потому, что они оба не что иное, как XML (теги и всякая всячина внутри). В нашем проекте есть два составляющих элемента, <ellipse> и <path>. Можно просто открыть код и присвоить им классы, как любому другому элементу HTML.

<svg ...>
  <ellipse class="ground" .../>
  <path class="kiwi" .../>
</svg>

Теперь эти отдельные элементы можно контролировать с помощью специального CSS для SVG. Необязательно добавлять CSS в сам SVG, его можно разместить где угодно, даже в файле с глобальными стилями. Обратите внимание, что для элементов SVG есть специальный набор свойств CSS. Например, нельзя использовать background-color, вместо него есть fill. Однако кое-что стандартное тоже можно использовать, например, :hover.

.kiwi {
  fill: #94d31b;
}
.kiwi:hover {
  fill: #ace63c;
}

Более того, в SVG можно использовать фильтры, например размытие:

<svg ...>
  ...
  <filter id="pictureFilter" >
    <feGaussianBlur stdDeviation="5" />
  </filter>
</svg>

И его можно применить из CSS:

.ground:hover {
  filter: url(#pictureFilter);
}

Пример того, что может получиться:

Check out this Pen!

Поддержка браузерами

Добавление SVG непосредственно в документ по-разному поддерживается браузерами, однако все сводится к отсутствию поддержки IE младше 8 и браузерам на Android до версии 2.3 1.

Для этого способа вставки SVG можно использовать следующие приемы деградации:

<svg> ... </svg>
<div class="fallback"></div>

И снова используем Modernizr:

.logo-fallback {
  display: none;
  /* Убедитесь, что размер соответствует размеру SVG */
}
.no-svg .logo-fallback {
  background-image: url(logo.png);
}

Добавляем SVG на страницу с помощью тега <object>

Если по какой-либо причине вариант со вставкой SVG непосредственно в документ вам не нравится (он все же имеет парочку недостатков, например, кэширование практически невозможно), можно подключить SVG-файл используя <object> и сохранить возможность управлять его частями посредством CSS.

<object type="image/svg+xml" data="kiwi.svg" class="logo">
  Kiwi Logo <!-- запасное изображение в CSS -->
</object>

На тот случай, если это не поддерживается, реализуем деградацию, используя класс, который добавляет Modernizr:

.no-svg .logo {
  width: 200px;
  height: 164px;
  background-image: url(kiwi.png);
}

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

<svg ...>
  <style>
    /* специальные CSS-фишки для SVG */
  </style>
  ...
</svg>

Внешние файлы со стилями для SVG, вставленного с помощью <object>

Есть способ добавить в SVG-файл внешний файл со стилями, если это необходимо работы для проекта, кэширования или еще чего-то. Я экспериментально выяснил, что он работает только для SVG-файлов, встроенных в документ с помощью тега <object>. Вот что нужно добавить в SVG-файл перед открывающим тегом <svg>:

<?xml-stylesheet type="text/css" href="svg.css" ?>

Если попробовать добавить этот код в HTML, вы получите ошибку, и браузер даже не подумает его подгружать. Если подключить SVG-файл, в котором предложенный код заменяет <img> или background-image, система ругаться не будет, но и работать такой код не будет (SVG, однако, отобразится).

Использование Data URI для SVG

SVG-файл можно уменьшить еще сильнее, если конвертировать его в Data URI. На Mobilefish.com для этого есть онлайн-конвертер. Просто скопируйте содержимое SVG-файла и заполните форму, результат конвертирования можно будет скопировать с текстового поля. Не забудьте удалить переносы строки в полученном коде. Выглядеть он будет как полнейшая тарабарщина:

Data URI

Его можно использовать в любом из приёмов, которые мы рассмотрели (кроме вставки <svg> непосредственно в документ, поскольку это попросту нелогично). Просто скопируйте всю полученную тарабарщину вместо [data] в следующих примерах.

Добавление на страницу с использованием тега <img>

<img src="data:image/svg+xml;base64,[data]">

Добавление на страницу в качестве фона с использованием CSS

.logo {
  background: url(data:image/svg+xml;base64,[data]);
}

Добавление на страницу с использованием тега <object>

<object type="image/svg+xml" data="data:image/svg+xml;base64,[data]">
  fallback
</object>

Кстати, если добавить <style> в SVG до кодирования в base64, он будет работать при добавлении на страницу с использованием тега <object>! А для по-настоящему суровых разработчиков компания Filament group предлагает инструмент grunticon, который автоматизирует этот процесс.

Консольные штучки для перекодирования SVG в base64:

@chriscoyier @hkfoster maybe you could take a shortcut with >>> echo -n `cat logo.svg` | base64 | pbcopy

— Benny Schudel (@bennyschudel) March 2, 2013

Или же Матиас Биненс (Mathias Bynens) предлагает свои приёмы:

Используйте openssl base64 < path/to/file.png | tr -d '\n' | pbcopy или cat path/to/file.png | openssl base64 | tr -d '\n' | pbcopy чтобы пропустить запись в файл и просто скопировать выходные данные в кодировке base64 в буфер без переносов строки.

Материалы для дальнейшего чтения

Нельзя не упомянуть видео Кайла Фостера «Последовательность оптимизации SVG»:

... взгляните также на это видео + слайды.


Примечания

1. Говоря о браузере Android 2.3, вот. Но если вам никак не обойтись без поддержки родного браузера, вот.

Если вы заметили ошибку, вы всегда можете отредактировать статью, создать issue или просто написать об этом Антону Немцеву в skype ravencry.

Chris Coyier
Наталья Фадеева
Переводчик:
Наталья Фадеева
вКонтакте:
natatik_l
Twitter:
@very_busy_girl
GitHub:
NatalieF

Комментарии (17 комментариев, если быть точным)

Автар пользователя
AlexAkhremenko

Широкие возможности, которые предоставляют фильтрМы и интерактивность.

Автар пользователя
SilentImp

Большое спасибо, исправили. Кроме того, если хотите, можете в таких случаях использовать пулл-реквесты. Все статьи — репозитории на github.

Автар пользователя
legomushroom

Большое спасибо за перевод! Вот еще поиски на тему гибкого использования SVG в паре с CSS, может кому пригодится http://habrahabr.ru/post/167085/

Автар пользователя
operatino

Если подключить svg через img, то нельзя подключить для него стили? Какая поддержка svg CSS?

Автар пользователя
SilentImp

Если подключить svg через img, то нельзя подключить для него стили?

Нет, насколько я знаю, только встраивать их в сам файл.

Какая поддержка svg CSS?

Неплохая, но часть свойств обладают другими названиями и синтаксисом. Но исчерпывающий список я например сходу не приведу — слишком редко сталкиваюсь с ним на практике.

Автар пользователя
h4

Я бы сказал, что в стилях для svg применяется css-синтаксис, однако имена свойств соответствуют именам атрибутов svg. То есть background->fill, border->stroke и так далее.

Селекторы — от css, но не уверен, какая часть спецификации поддерживатеся.

Автар пользователя
legomushroom

Вот тут я CSS свойства для SVG собираю, велкам https://gist.github.com/legomushroom/7397561

Автар пользователя
yoksel

Список CSS-cвойств в SVG http://www.w3.org/TR/SVG/styling.html#SVGStylingProperties

Автар пользователя
zendiesel

Спасибо за полеззности, хотел узнать насчет получения responsive, т.е. допустим сделал иконку 18х18 пикселей в svg, и могу ее просто поместить в стили и она будет спокойно расширятся без потери качества? или все же здесь нужен длиннющий svg код?

Автар пользователя
Capitan-vi

Добрый день! Первый пример с сайта codepen не соответствует оригиналу статьи (и по-моему, не про SVG). В оригинале указан вот этот пример: http://codepen.io/chriscoyier/pen/lCEux

Автар пользователя
mankutila

Поясните пожалуйста для неопытного в использовании svg человека: если верстаешь сайт просто с .psd макета и там есть иконки, которые в принципе можно было бы отрисовать в svg — откуда svg взять? Просить отдельно дизайнера, чтобы присылал в этом формате или пытаться самому отрисовать с помощью xml? Как делают опытные ребята?)

Автар пользователя
A

Просить отдельно дизайнера, чтобы присылал в этом формате

@mankutila Именно

Автар пользователя
h4

@mankutila если вы пользуетесь последними версиями фотошопа, то просто попросите дизайнера использовать шейп-лейеры (shape layers). Эта разновидность слоёв прекрасно конвертируется в svg прямо из фотошопа. И бонусом — при конвертации из фотошопа адоби использует более продвинутный конвертер svg, чем тот, что сейчас в Illustrator.

Автар пользователя
P0jar

Отличная статья. Немножко подитожил у себя в блоге: http://phlegdeven.blogspot.com/2016/05/svg.html

Автар пользователя
alsokolov

В настоящее время автор не рекомендует использовать base64 для кодирования SVG. https://css-tricks.com/probably-dont-base64-svg/

В оригинальную статью также был добавлен абзац по этому поводу

Автар пользователя
alexey-vorobyov

SVG Optimizer поменял ссылку. Там дефиз теперь, вместо underscore http://petercollingridge.appspot.com/svg-optimiser В тексте битая ссылка ) http://frontender.info/using-svg/?code=74cbd22591f6ab78746e&state=225107298#snachalaoptimiziruem

Автар пользователя
vkabish

Большое спасибо, исправили.