- Масштабируем CSS спрайты с SVG, убивая сразу трех зайцев
- Предыстория
- CSS спрайт с SVG
- Создание сложных спрайтов
- Более сложный спрайт с SVG
- В заключении
- Базовые трансформации
- Перемещения
- Вращение
- Смещение углов
- Масштабирование
- Комплексные перемещения с matrix()
- Эффекты на системе координат
- Встраивание SVG в SVG
- Found a content problem with this page?
- Как масштабировать размеры иконок svg
- 1 ответ 1
- Масштабирование иконок до требуемых размеров
- Делаем рабочую версию приложения
Масштабируем CSS спрайты с SVG, убивая сразу трех зайцев
Привет, Хабр.
Сразу хочу отметить, что если мы говорим об иконках, их можно масштабировать двумя способами (других я просто не знаю): конвертировать иконки в шрифт и подключать их через @font-face, либо использовать SVG в качестве формата для этих иконок.
Немного отойду от темы и расскажу предысторию.
Предыстория
Я было решил использовать у себя на сайте шрифтовые иконки, казалось бы все хорошо: и размер менять можно, и цвет задавать и запрос к серверу всего один (на подключение шрифта). Другими словами, подключаемый шрифт это и есть своеобразный «CSS спрайт», верно?
Я давай проверять, везде ли все красиво выглядит. Оказалось, что не все так хорошо как хотелось бы, потому как в некоторых размерах иконки выглядели кособокими, а при отключенном сглаживании вообще противно смотреть на них стало. Что делать? Использовать второй вариант — SVG, о чем и пойдет речь.
CSS спрайт с SVG
Идея складывать спрайт в SVG формат не нова. Наверняка, многие читали этот пост на smashingmagazine. Так вот, я решил развить мысль автора, поэкспериментировать и предложить более гибкий вариант. А чтобы стало все понятно, некоторые примеры повторю здесь.
Итак, для начала нам нужно сделать SVG спрайт. Как сделать SVG файл программно я пока не разобрался (надеюсь сообщество меня простит и даст ссылку где про это почитать). Поэтому я буду делать свой спрайт в CorelDRAW (Illustrator думаю тоже подойдет) и сохранять в SVG.
Для быстрой реализации я использовал шрифт и напечатал вот такие иконки (кликабельно):
Возьмем произвольный HTML код для примера:
Twitter Facebook Вконтакте Google+ RSS
.icons a < float: left; display: inline-block; padding: 4px 0 4px 25px; margin-right: 5px; text-decoration: none; color: #444; /* вызов спрайта и задание размеров */ background-image: url('sprite.svg'); background-repeat: no-repeat; background-size: 20px auto; >/* такой вариант рассмотрен на smashingmagazine.com, только вместо px используются em как относительная величина */ .icons .tw .icons .fb .icons .vk .icons .gl .icons .rs
Стоит отметить одну особенность, что sprite.svg создан с четко заданными размерами 76×520, т.е. максимальный размер до которого мы можем увеличить нашу иконку будет 76×76.
А что если сохранить SVG с относительными размерами, те. в процентах? Это ведь лучше, т.к. иконки теперь можно будет масштабировать до абсолютно любого размера и не терять при этом их качества.
Немного подправим стили в CSS:
/* этот блок остается без изменений */ .icons a < float: left; display: inline-block; padding: 4px 0 4px 25px; margin-right: 5px; text-decoration: none; color: #444; /* вызов спрайта и задание размеров */ background-image: url('sprite.svg'); background-repeat: no-repeat; background-size: 20px auto; >/* а здесь меняем абсолютную величину на относительную */ .icons .tw .icons .fb .icons .vk .icons .gl .icons .rs
Результат одинаковый, но background-size может быть любым, каким угодно.
Создание сложных спрайтов
В примере выше использовано всего 5 иконок и высчитать проценты не так сложно. Давайте рассмотрим более сложный пример. Пока с теми же «шрифтовыми» иконками. Допустим у нас такой спрайт:
Что мы делаем, либо добавлем в html новый тег i , для которого можем написать стили с иконкой:
Twitter Facebook Вконтакте Google+ RSS
Либо оформляем иконку используя псевдоэлементы ::before или ::after . Я буду использовать псевдоэлемент ::before , вы — как вам больше нравится.
Обратите внимание, что я не стал придумывать новые классы для ссылок (ведь спрайт поменялся) и оставил прежние, разумеется для новых иконок классы будут свои. А мы рассмотрим с этими, чтоб не захламить кодом пост.
Итак, внесем изменения в CSS:
.icons a < float: left; display: inline-block; padding: 4px 0 4px 25px; margin-right: 5px; text-decoration: none; color: #444; /* добавляем */ position: relative; >/* создаем общий стиль для ::before */ .icons a::before < position: absolute; left: 0; top: 0; content: ''; width: 25px; height: 25px; /* вызов спрайта и задание размеров */ background-image: url('sprite.svg'); background-repeat: no-repeat; background-size: 20px auto; >/* а здесь дописываем псевдоэлемент и задаем позицию в спрайте (соответственно для нового спрайта позиции будут другие, о чем ниже) */ .icons .tw::before .icons .fb::before .icons .vk::before .icons .gl::before .icons .rs::before
Сделаю несколько пояснений, а то я уже сам чуть было не запутался :).
В background-size: 20px auto; число «20» это необходимый нам размер иконки, а «auto» это оставшийся размер спрайта. Если мы заменим «auto» например на 20px, то у нас вместо одной иконки получится весь спрайт размером 20×20 пикселей.
Кроме того, на размер иконки теперь еще влияет ширина и высота блока формируемая псевдоэлементом, т.е. вместе с background-size теперь нужно менять width и height , чтобы иконка не обрезалась.
Высчитываем относительные размеры
Пожалуй, это ключевой момент и здесь стоит сделать выбор, либо вы задаете абсолютные размеры и при изменении background-size , width и height меняете их тоже, либо (что сложнее) высчитываете относительные размеры и при изменении background-size , width и height больше ничего не меняете.
Итак, фактический размер спрайта 500×250 пикселей, по 10 иконок в строчку и по 5 в столбик, итого 50 иконок (в примере 49) размером 50×50 пикселей каждая.
Высчитать размер довольно просто, т.к. будем отталкиваться от фактического размера спрайта. Кто работал со спрайтами объяснять не стоит. Правда здесь есть одна тонкость — размер иконки у нас уменьшен до 20 пикселей, соотвественно спрайт тоже изменился и стал равен 200×100 пикселей (10*20 и 5*20), а значит и размеры ( background-position ) мы будем считать, либо 0 0, 0 -20px, -20px 0, -20px -20px, 0 -40px, -40px 0, -40px -40px и т.д., либо 0 0, 0 -11,1%, 0 -22,2%, 0 -33,3, 25% 0, 25% -11,1%, 25% -22,2%, 25% -33,3 и т.д.
Таким образом мы можем сделать любой сложности спрайт и высчитать background-position для каждого элемента. К счастью или сожалению, пытливый ум не дает остановиться на сказанном, поэтому бегло рассмотрим еще более сложный пример.
Более сложный спрайт с SVG
Допустим, у нас есть некий дизайн, совсем приблизительно изобразил (кликабельно):
Предположим, что прямоугольники это какие-то красивые клипарты, трудно, но предположим. Что мы можем сделать:
1. Сложить все слои в спрайт не меняя исходный размер и позиционировать каждый объект в соответствующем элементе;
2. Сложить все слои в спрайт, предварительно приведя все объекты к одному размеру и позиционировать каждый объект в соответствующем элементе меняя размер объекта до неоходимой величины.
Приводить пример HTML или CSS кода, думаю, уже не имеет смысла. И так все понятно, настраивается по аналогии с предыдущими примерами.
В заключении
Теперь хочу подвести итог и отметить плюсы спрайтов с SVG. Во-первых, у нас получился всего один файл, а значит один запрос к северу — заяц1 убит, во-вторых, вес SVG файла гораздо меньше, чем например PNG или JPG, а значит и скорость загрузки выше — заяц2 убит, в-третьих, мы получили неограниченных размеров спрайт без потери качества изображения, а значит решили задачу с неограниченным масштабированием изображения — заяц3 убит.
Единственный минус SVG перед шрифтовыми иконками: нельзя украшать иконки с помощью CSS, например, добавлять text-shadow или менять цвет. И очень большой плюс, что при отключенном сглаживании все линии в SVG будут ровные и четкие в отличае от шрифта.
P.S. SVG дает нам огромное поле для деятельности и на примере CSS спрайтов я в этом полностью убедился. Конечно, можно было обойтись сухими словами и сказать «сохраняйте SVG в относительных размерах», но у меня это вылилось в целый пост.
Спасибо за внимание. До новых встреч.
UPD: ::before и ::after это псевдоэлементы, а не псевдоклассы — простите, ошибся, поправил. Спасибо psywalker вовремя подсказал.
UPD: А про «::» я и не вспомнил 🙁 Пруф
Базовые трансформации
Все последующие преобразования суммируются в атрибуте преобразования элемента transform . Преобразования могут быть последовательно суммированы, разделителем выступает пробел.
Перемещения
Иногда необходимо сместить элемент, хотя вы спозиционировали его согласно определённым атрибутам. Для этого используется translate() .
svg width="40" height="50" style="background-color:#bff;"> rect x="0" y="0" width="10" height="10" transform="translate(30,40)" /> svg>
Пример генерирует прямоугольник, перемещённый в точку (30,40) вместо точки (0,0).
если второе значение не задано, то оно приравнивается 0.
Вращение
Вращение элементов — это достаточно типичная задача. Используйте rotate() для этого:
svg width="31" height="31"> rect x="12" y="-10" width="20" height="20" transform="rotate(45)" /> svg>
Данный пример показывает квадрат который повернули на 45 градусов. Значение для rotate() задаётся в градусах.
Смещение углов
Чтобы сделать ромб из нашего прямоугольника, доступны преобразования skewX () и skewY (). Каждый из них принимает угол, определяющий, насколько элемент будет искажён.
Масштабирование
scale() изменяем размер элемента. Он использует 2 параметра. Первый — это коэффициент масштабирования по оси Х, а второй — по оси Y. Коэффициенты выражают сжатие по отношению к оригинальному изображению. Например, 0.5 уменьшает на 50%. Если второй параметр отсутствует, то тогда он принимается равным первому.
Комплексные перемещения с matrix()
Все приведённые выше преобразования могут быть описаны с помощью матрицы перемещений 2×3. Чтобы объединить несколько перемещений, можно установить результирующую матрицу с помощью matrix(a, b, c, d, e, f) , которая преобразует координаты из предыдущей системы координат в новую систему координат посредством:
< x new C o o r d S y s = a x prev C o o r d S y s + c y prev C o o r d S y s + e y new C o o r d S y s = b x prev C o o r d S y s + d y prev C o o r d S y s + f \left< \beginx*<\mathrm
См. конкретный пример документации SVG. Подробную информацию об этом свойстве можно найти в SVG Рекомендациях.
Эффекты на системе координат
В случае использования преобразований вы устанавливаете новую систему координат внутри элемента, к которому применяются изменения. Это означает, что единицы измерения которые вы определяете и его дочерние еи не будут соответствовать 1:1, но также будут искажены, повёрнуты, перемещены и смаштабированы в соответствии с преобразованиями.
svg width="100" height="100"> g transform="scale(2)"> rect width="50" height="50" /> g> svg>
В результата прямоугольник в примере выше будет 100x100px. Более интригующие эффекты возникают, когда вы используете такие атрибуты, как userSpaceOnUse .
Встраивание SVG в SVG
В отличие от HTML, SVG позволяет встраивать другие svg элементы без разрыва. Таким образом вы можете запросто создать новую координатную систему используя viewBox , width и height внутреннего svg элемента.
svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100" height="100"> svg width="100" height="100" viewBox="0 0 50 50"> rect width="50" height="50" /> svg> svg>
На примере выше, так же как и на других примерах ранее, вы можете видеть такой же эффект увеличения изображения в два раза.
Found a content problem with this page?
This page was last modified on 14 февр. 2023 г. by MDN contributors.
Your blueprint for a better internet.
Как масштабировать размеры иконок svg
При размерах 256 пикселей размер svg иконки не 256 пикселей , а где-то ~140
При указании 128 , тоже не 128 и т.д. Почему так происходит?
Я уже перечитал все эти мануалы, в примерах их иконки все нормально отображаются с размерами, а почему эта не работает как надо?!
1 ответ 1
Масштаб определяется соотношением viewport / viewBox , где viewport это width=»X» height=»Y»
В вашем примере масштабирование применяется последовательно несколько раз.
Очень легко запутаться. Поэтому я максимально упрощу ваш пример и поэтапно буду усложнять до практического применения
viewport / viewBox = 100/100=1. Масштаб будет — 1:1 То есть как нарисовано в векторном редакторе, так и будет отражаться на дисплее
На скрине векторного редактора видно, что физически иконка имеет габариты — 56.6 х 56.6px
- Теперь запускаем этот же файл в браузере. И для наглядности я добавил красный прямоугольник, через стили в шапке файла, который показывает границы SVG файла. style=»border:1px solid red;»
Границы svg определяет viewport это — width=»100″ height=»100″
Из примеров видно, что иконка 56 х 56px не полностью занимает viewport — 100 х 100px
Это очень плохо, так как эти свободные пространства добавляют отступы от других элементов верстки HTML
Убираем лишние отступы
width=»56″ height=»56″ viewBox=»0 0 58 58″
Смотрим результаты в векторном редакторе и в браузере:
Масштабирование иконок до требуемых размеров
Размер 256 x 256px
Для этого увеличиваем размер viewport до требуемых размеров
Размер 128 x 128px
Делаем рабочую версию приложения
Основное правило последовательных масштабирований в одном файле SVG
В шапке файла SVG задается самый большой viewport — это прямоугольная область, которую видит пользователь на экране. Если задали width=»256″ height=»256″ , то последующие масштабирования, которые идут в коде ниже могут только уменьшать размер этой области.
Пример с 3 иконками 256×256; 128×128; 64×64