Анализ применения SVG в качестве background-image / Хабр
В последнее время все чаще появляются статьи, в которых авторы рекомендуют использовать SVG для backgroud-image. Действительно, применение SVG приносит большую пользу. Во всех прочитанных статьях очень вскользь упоминалось про производительность отрисовки SVG, что это более затратная операция, так как браузеру необходимо каждый раз заново отрисовывать растр.
И вот в один прекрасный день, открыв одно веб-приложение, я заметил, что мой браузер безумно «пожирает» память — одна вкладка «ела» около 600 МиБ. На МacBook с ретиной дела обстояли еще хуже. С этого момента началось расследование, куда же течет память. Кому интересно, добро пожаловать под кат.
Первым, на что я обратил внимание, был рост памяти при открытии одного попапа, в котором отрисовывались всего 20 элементов с иконками. Сделав профайлинг в chrome, я сделал вывод, что дело не в javaScript, не в CSS, и не в HTML.
Однако я заметил, что чем меньше присутствует элементов с иконками, тем меньше памяти расходуется. Посмотрев, откуда берутся иконки, я увидел, что они взяты из спрайта размером 2000px х 500px. После подмены SVG спрайта на PNG спрайт с такими же размерами, случилось чудо — использование памяти вернулось в разумные рамки. Порассуждав, легко прийти к выводу, что на каждую маленькую иконку отрисовывался большой битмап, на который и расходовалась память.
Прочитав спецификацию по SVG и большое количество различных статей (ссылки в конце статьи), я решил попробовать задавать размер SVG не в px, а в em. В итоге, как я и ожидал, с относительными единицами объем потребляемой памяти оказался приблизительно равным тому, как если бы использовался png-спрайт.
Ниже приведена таблица потребления памяти в chromium на моей машине при отрисовке 16 иконок:
SVG, размеры заданы в em | 9 216k | демо |
SVG, размеры заданы в px | 101 600k | демо |
PNG, малый размер холста | 7 748к | демо |
PNG, большой размер холста | 10 060k | демо |
Какие же выводы можно сделать? Возможны два варианта. Первый — использовать два спрайта PNG, в обычном и ретиновском качестве. Если же вы используете SVG-спрайты, задавайте размер в относительных единицах, например в em.
Список статей, которые рекомендую почитать на тему SVG:
coding.smashingmagazine.com/2012/01/16/resolution-independence-with-svg
habrahabr.ru/post/141654
www.broken-links.com/2012/08/14/better-svg-sprites-with-fragment-identifiers
smus.com/canvas-vs-svg-performance
UPD: И так, в ходе общих исследований было выяснено, что такое поведение присутствует в chromium-based браузерах. В браузерах firefox, opera, ie похожий эффект не наблюдается. В комментариях верно указано, что объем памяти зависит от размера холста, а не от единиц измерения. Но единицы измерения могут повлиять на маштабируемость SVG, так что выбирайте единицы под вашу задачу. Спасибо всем за замечания и проведенные тесты в других браузерах.
UPD: code.google.com/p/chromium/issues/detail?id=196524 добавлен баг в багтрекер.
UPD: Баг закрыт, исправлен в canary build.
Как работает SVG ID? — WebBeaver.ru
Перевод статьи «How SVG Fragment Identifiers Work» от Криса Койера.
Я много рассказывал о теге <use> в SVG и использовал его для вывода иконок. Прелесть в том, что с помощью <use> можно ссылаться на часть SVG и выводить только её. Это позволяет использовать схему «много изображений за один запрос, потому что это суперэффективно», которую раньше решали с помощью CSS-спрайтов и иконочных шрифтов.
Но <use> — это инлайновый SVG. Он не поможет, если вы хотите использовать часть SVG в теге <IMG> или в background-image. Вот тут и появляются идентификаторы фрагментов.
Подготовка SVG-спрайта
Один из способов — привести SVG (давайте называть его просто «спрайт») к виду обычного CSS-спрайта.
Мы специально делаем это именно так, чтобы потом быть в состоянии использовать значения viewBox, для вывода отдельных фрагментов, как мы привыкли это делать в обычных спрайтах.
В этом небольшом демо-спрайте используется три иконки. Каждая иконка имеет размер 32×32. Весь спрайт — 32×96. Давайте посмотрим, каким будет viewBox для отдельных частей спрайта:
ViewBox всего спрайта | 0 0 32 96 |
ViewBox первой иконки | 0 0 32 32 |
ViewBox второй иконки | 0 32 32 32 |
ViewBox третьей иконки | 0 64 32 32 |
Атрибуты viewBox указывают на координаты начала слева, координаты начала сверху, ширину и высоту. Обратите внимаение, что каждый раз позиция начала сверху сдвигается на 32. Мы просто показываем другую часть спрайта.
Добавление viewBox в сам SVG
Вы можете указать эти значения viewBox для каждого элемента <view>, внутри SVG.
<view viewBox="0 0 32 32" /> <view viewBox="0 32 32 32" /> <view viewBox="0 64 32 32" />
Теперь мы можем использовать эти части в других местах. Элементы <view> могут быть самостоятельными, как в примере выше, или могут оборачивать другие элементы. В этом случае viewBox отобразится, если совпадает ID.
<!-- Этот viewBox отобразится, если идентификатор будет #match-me. --> <view viewBox="0 64 32 32"> <rect ...> </view>
Демо в спецификации.
Синтаксис в HTML
Применять значения viewBox в SVG-вставленном-как-IMG вы можете следующим образом:
<!-- top icon --> <img src="sprite.svg#svgView(viewBox(0, 0, 32, 32))" alt="">
Или, если вы уже настроили view-элементы, то можете ссылаться на них по ID:
<!-- middle icon --> <img src="sprite.svg#icon-heart-view" alt="">
Синтаксис в CSS
Вы можете указывать требуемое значение viewBox прямо в пути к изображению в CSS
.icon-clock { background: url("sprite.svg#svgView(viewBox(0, 0, 32, 32))") no-repeat; }
Или, опять же, ссылаться на них по ID:
. icon-clock { background: url(sprite.svg#icon-clock-view) no-repeat; }
Хотя… Если вы используете SVG-спрайт таким образом и у вас пошло что-то не так, то вы можете просто использовать способ из обычных спрайтов:
.icon-heart { background: url("sprite.svg") no-repeat; background-size: 32px 96px; background-position: 0 -32px; }
Я хочу складывать иконки друг на друга
Если у всех иконок одинаковый viewBox и вы хотите просто показывать и скрывать их, когда это необходимо, то это может быть чуть легче.
Поместите их все в одно место (или используйте какой-нибудь сборщик). Вот, я кладу каждую иконку в группу и указывают уникальный ID.
Трюк с отображением нужной иконки заключается в том, чтобы скрыть все иконки и отобразить ту, чей ID совпадает с указанным. Это всё можно сделать на CSS, потому что у нас есть псевдокласс :target.
SVG со всем этим будет выглядеть так:
<defs> <style> g { display: none; } g:target { display: inline; } </style> </defs> <g> <path d="M20. 6,23.3L14,16.7V7.9h5v7.2l5.4,5.4L20.6,23.3z M16-0.1c-8.8,0-16,7.2-16,16s7.2,16,16,16s16-7.2,16-16S24.8-0.1,16-0.1z M16,27.9c-6.6,0-12-5.4-12-12s5.4-12,12-12s12,5.4,12,12S22.6,27.9,16,27.9z"/> </g> <g> <path d="M32,11.2c0,2.7-1.2,5.1-3,6.8l0,0L19,28c-1,1-2,2-3,2s-2-1-3-2L3,18c-1.9-1.7-3-4.1-3-6.8C0,6.1,4.1,2,9.2,2 c2.7,0,5.1,1.2,6.8,3c1.7-1.9,4.1-3,6.8-3C27.9,1.9,32,6.1,32,11.2z"/> </g> <g> <path d="M32,15.9l-16-16v10H0v12h26v10L32,15.9z"/> </g>
Поддержка браузеров
Можно посмотреть поддержку в Can I Use, но не всё так просто, потому что некоторые браузеры поддерживают только использование идентификаторов в HTML, а у некоторых какие-то проблемы.
Это моя тестовая страница:
See the Pen SVG Fragment Identifiers in HTML and CSS by Chris Coyier (@chriscoyier) on CodePen.
Вот основные моменты поддержки браузеров, которые я могу отметить:
- В Firefox всё работает правильно.
- В IE11 тоже. У IE 9 и 10 небольшие проблемы с background-position, но, в целом, всё неплохо.
- В последних Chrome/Opera всё работает.
- Единственное что работает в iOS 8.1 — это ссылка на view внутри img.
- Для Android 4.4 подходит только background-position (который вообще не использует идентификаторы). В Android 5 всё нормально.
SVG в фоновом режиме CSS | Могу ли я использовать… Таблицы поддержки для HTML5, CSS3 и т. д.
Могу ли я использовать
Поиск?
SVG в фонах CSS
— CRГлобальное использование
98,68% + 1,16% «=» 99,84%
Метод использования изображений SVG в качестве фона CSS
Chrome
- 00% — Partial support»> 4: Частичная поддержка
- 5 — 112: Поддерживается
- 113: Поддерживается
- 114 — 116: Поддерживается
Edge
- 12 — 15: Часть ial support
- 16 — 112: Поддерживается
- 113: Поддерживается
Safari
- 3.1: не поддерживается
- 3.2 — 4: частичная поддержка
- 5 — 16.3: поддерживается
- 16.4: поддерживается
- 16.5 — TP: поддерживается
Firefox
- 02% — Not supported»> 2–3.6: не поддерживается
- 4–23: частичная поддержка
- 24–111: поддерживается
- 112: поддерживается
- 113–114: поддерживается
Opera
- 900 72 9: Не поддерживается
- 9,5 — 97: Поддерживается
- 98: Поддерживается
IE
- 5.5–8: не поддерживается
- 9–10: поддерживается
- 11: поддерживается
Chrome для Android
- 9 0092 112: поддерживается
Safari на iOS
- 3.2–4.1: Частичная поддержка 53% — Supported»> 4.2–16.3: Поддерживается
- 16.4: Поддерживается
- 16.5: Поддерживается
Samsung Internet
- 4–19.0: Поддерживается
- 20: Поддерживается
Opera Mini
- все: частичная поддержка
Opera Mobile
- 10–12.1: частичная поддержка
- 73: поддерживается
UC Browser для Android
- 13.4 : Поддерживается
Браузер Android
- 2.1–2.3: не поддерживается
- 3–4.4.4: поддерживается 00% — Supported»> 112: поддерживается
Firefox для Android
- 110: Поддерживается
Браузер QQ
- 13.1: Поддерживается
Браузер Baidu
- 13.18: Поддерживается
Браузер KaiOS
- 2.5: Поддерживается
- 3: Поддерживается
- Ресурсы:
- Учебник по расширенным эффектам
Вставка SVG в ваши документы
Вы можете использовать SVG на своих веб-сайтах несколькими способами. Каждый способ имеет некоторые тонкие различия и небольшие различия в поддержке браузера.
- Как фоновое изображение в CSS
- Внутри элемента изображения
- Как встроенный файл
- Дополнительные ресурсы
Как фоновое изображение в CSS
Вы можете использовать файл svg в качестве фонового изображения в CSS так же, как обычно используете любой другой тип изображения. Это обычная практика для таких вещей, как значки.
В приведенном ниже примере я использовал псевдокласс before, чтобы добавить значок медведя перед текстом.
Медведь
Медведь
Следующий CSS добавляет файл svg в качестве фонового изображения, а затем позиционирует его. Важно установить свойство background-size
при использовании SVG, потому что размер по умолчанию может быть любым.
.bear-icon::before { background: url(images/bear.svg) 0 0 без повторов; размер фона: 22px; содержание: ''; отступ: 0 0 0 28 пикселей; положение: родственник; верх: 3px; }
Внутри элемента изображения
Вы также можете включить файл SVG в элемент img. В приведенном ниже примере я использую тот же файл svg, но как изображение в html. Я также плаваю это право.
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit, eos doloribus enim dolores. Долоре, инцидент iusto vel odit eveniet nemo sit officiis rem sed cupiditate. Minima, ut veniam quam dolor? Lorem ipsum dolor sit amet, consectetur adipisicing elit. Explicabo, neque, cum, repellendus quibusdam possimus rerum illo в предвидении vero saepe accusantium nihil fugiat qui officiis unde consectetur Labore quam aut!
<дел> <р> Lorem ipsum dolor [...] дел>
.bear-изображение { ясно: верно; поплавок: справа; ширина: 40%; }
Как встроенный файл
Самый универсальный способ включения SVG-файла — вставить весь файл в HTML-код. Этот метод позволяет вам стилизовать файл с помощью CSS и легко манипулировать им с помощью JavaScript. Он также имеет лучшую поддержку браузера из всех различных подходов.
В приведенном ниже примере я вставляю файл svg внутри обычного элемента div
.
<дел> дел>
Дополнительные ресурсы
Для получения дополнительной информации о том, как включить изображения SVG, см. ресурсы ниже.- Хитрости CSS: использование SVG
- Встраивание SVG — включает диаграмму с плюсами и минусами
- Jenkov.