Недавно я создал образец кирпичной стены как часть моего #МаленькиеУзоры серия, задача, в которой я создаю органично выглядящие узоры или текстуры в SVG в пределах 560 байт (или размером примерно с два твита). Чтобы соответствовать этому ограничению, я прошел путь, который научил меня некоторым радикальным способам оптимизации шаблонов SVG, чтобы они содержали как можно меньше кода, не влияя на общее качество изображения.
Я хочу провести вас через весь процесс и показать вам, как мы можем использовать шаблон SVG, который начинается со 197 байтов, вплоть до всего лишь 44 байтов — колоссальное сокращение на 77.7%!
Шаблон SVG
Это то, что называется кирпичным рисунком «бегущей связки». Это самый распространенный узор из кирпичей, который вы наверняка видели раньше: каждый ряд кирпичей смещен на половину длины кирпича, создавая повторяющийся узор в шахматном порядке. Расположение довольно простое, что делает SVG <pattern>
элемент идеально подходит для воспроизведения его в коде.
SVG <pattern>
элемент использует предопределенный графический объект, который может быть реплицирован (или «замощен») через фиксированные интервалы вдоль горизонтальной и вертикальной осей. По сути, мы определяем шаблон прямоугольной плитки, и он повторяется для закрашивания области заливки.
Во-первых, давайте установим размеры кирпича и зазор между каждым кирпичом. Для простоты будем использовать четкие круглые числа: ширина 100
и высотой 30
для кирпича и 10
для горизонтальных и вертикальных зазоров между ними.
Далее нам нужно определить нашу «базовую» плитку. И под «плиткой» я имею в виду плитки с шаблонами, а не физические плитки, не путать с кирпичиками. Давайте используем выделенную часть изображения выше в качестве плитки узора: два целых кирпича в первом ряду и один целый, зажатый между двумя половинками кирпичей во втором ряду. Обратите внимание, как и где включены промежутки, потому что они должны быть включены в плитку повторяющегося узора.
Когда используешь <pattern>
, мы должны определить шаблон width
и height
, которые соответствуют ширине и высоте базовой плитки. Чтобы получить размеры, нам понадобится немного математики:
Tile Width = 2(Brick Width) + 2(Gap) = 2(100) + 2(10) = 220
Tile Height = 2(Bright Height) + 2(Gap) = 2(30) + 2(10) = 80
Итак, наша плитка с узором 220✕80
. Мы также должны установить patternUnits
атрибут, где значение userSpaceOnUse
по сути означает пиксели. Наконец, добавление id
к шаблону необходим, чтобы на него можно было ссылаться, когда мы рисуем с его помощью другой элемент.
<pattern id="p" width="220" height="80" patternUnits="userSpaceOnUse"> <!-- pattern content here -->
</pattern>
Теперь, когда мы установили размеры плитки, задача состоит в том, чтобы создать код для плитки таким образом, чтобы отображать графику с наименьшим возможным количеством байтов. Вот что мы надеемся получить в самом конце:
Начальная разметка (197 байт)
Самый простой и наиболее декларативный подход к воссозданию этого шаблона, который приходит мне на ум, — нарисовать пять прямоугольников. По умолчанию fill
элемента SVG черный, а stroke
прозрачный. Это хорошо работает для оптимизации шаблонов SVG, поскольку нам не нужно явно объявлять их в коде.
Каждая строка в приведенном ниже коде определяет прямоугольник. То width
и height
всегда установлены, и x
и y
позиции устанавливаются только в том случае, если прямоугольник смещен от 0
позиции.
<rect width="100" height="30"/>
<rect x="110" width="100" height="30"/>
<rect y="40" width="45" height="30"/>
<rect x="55" y="40" width="100" height="30"/>
<rect x="165" y="40" width="55" height="30"/>
Верхний ряд плитки содержал два полноразмерных кирпича, второй кирпич располагался x="110"
позволяющий 10
пикселей зазора перед кирпичом. Точно так же есть 10
пикселей зазора после, потому что кирпич заканчивается на 210
пикселей (110 + 100 = 210
) по горизонтальной оси, хотя <pattern>
ширина 220
пикселей. Нам нужно немного дополнительного пространства; в противном случае второй кирпич слился бы с первым кирпичом соседней плитки.
Кирпичи во втором (нижнем) ряду смещены, поэтому ряд содержит два полукирпича и один целый кирпич. В этом случае мы хотим, чтобы кирпичи половинной ширины сливались, чтобы не было зазора в начале или в конце, что позволяло бы им плавно перетекать с кирпичами в соседние плитки узора. При смещении этих кирпичей мы также должны учитывать половинные зазоры, поэтому x
значения 55
и 165
, Соответственно.
Повторное использование элементов (-43B, всего 154B)
Кажется неэффективным так явно определять каждый кирпич. Нет ли способа оптимизировать шаблоны SVG путем повторного использования фигур?
Я не думаю, что широко известно, что SVG имеет <use>
элемент. Вы можете ссылаться на другой элемент с ним и отображать этот ссылочный элемент везде, где <use>
используется. Это сэкономит довольно много байтов, потому что мы можем не указывать ширину и высоту каждого кирпича, кроме первого.
Тем не менее, <use>
действительно идет с небольшой ценой. То есть мы должны добавить id
для элемента, который мы хотим использовать повторно.
<rect id="b" width="100" height="30"/>
<use href="#b" x="110"/>
<use href="#b" x="-55" y="40"/>
<use href="#b" x="55" y="40"/>
<use href="#b" x="165" y="40"/>
Кратчайший id
возможен один символ, поэтому я выбрал «b» для кирпича. То <use>
элемент может быть расположен аналогично <rect>
, С x
и y
атрибуты как смещения. Поскольку теперь каждый кирпич имеет полную ширину, когда мы перешли на <use>
(помните, мы явно разделили пополам кирпичи во втором ряду плитки шаблона), мы должны использовать отрицательное x
значение во второй строке, затем убедитесь, что последний кирпич выходит за пределы плитки для бесшовного соединения между кирпичами. Однако это нормально, потому что все, что выходит за пределы плитки шаблона, автоматически обрезается.
Можете ли вы найти несколько повторяющихся строк, которые можно записать более эффективно? Давайте поработаем над следующими.
Перезапись в путь (-54Б, всего 100Б)
<path>
вероятно, самый мощный элемент в SVG. Вы можете нарисовать практически любую фигуру с помощью «команд» в ее d
атрибут. Доступно 20 команд, но нам нужны только самые простые для прямоугольников.
Вот где я приземлился с этим:
<path d="M0 0h100v30h-100z M110 0h100v30h-100 M0 40h45v30h-45z M55 40h100v30h-100z M165 40h55v30h-55z"/>
Я знаю, супер странные цифры и буквы! Все они имеют значение, конечно. Вот что происходит в этом конкретном случае:
M{x} {y}
: Перемещается в точку по координатам.z
: Закрывает текущий сегмент.h{x}
: Рисует горизонтальную линию из текущей точки длинойx
в направлении, определяемом знакомx
. Нижний регистрx
указывает относительную координату.v{y}
: Рисует вертикальную линию из текущей точки длинойy
в направлении, определяемом знакомy
. Нижний регистрy
указывает относительную координату.
Эта разметка намного короче, чем предыдущая (разрывы строк и пробелы в отступах предназначены только для удобства чтения). И, эй, нам удалось вырезать половину исходного размера, получив 100 байт. Тем не менее, что-то заставляет меня чувствовать, что это могло бы быть меньше…
Ревизия плитки (-38B, всего 62B)
Разве наша плитка с узором не имеет повторяющихся частей? Понятно, что в первом ряду повторяется целый кирпич, а во втором ряду? Это немного сложнее увидеть, но если мы разрежем средний кирпич пополам, это станет очевидным.
Ну, средний кирпич точно не разрезается пополам. Есть небольшое смещение, потому что мы также должны учитывать разрыв. В любом случае, мы только что нашли более простой шаблон базового тайла, что означает меньшее количество байтов! Это также означает, что мы должны вдвое сократить width
нашей <pattern>
элемент от 220 до 110.
<pattern id="p" width="110" height="80" patternUnits="userSpaceOnUse"> <!-- pattern content here -->
</pattern>
Теперь давайте посмотрим, как рисуется упрощенная плитка с помощью <path>
:
<path d="M0 0h100v30h-100z M0 40h45v30h-45z M55 40h55v30h-55z"/>
Размер уменьшен до 62 байт, что уже меньше трети исходного размера! Но зачем останавливаться на достигнутом, когда мы можем сделать еще больше!
Команды сокращения пути (-9B, всего 53B)
Стоит немного углубиться в <path>
элемент, потому что он предоставляет больше подсказок для оптимизации шаблонов SVG. Одно заблуждение, которое у меня было при работе с <path>
относится к тому, как fill
атрибут работает. Много играя с MS Paint в детстве, я понял, что любая фигура, которую я хочу залить сплошным цветом, должна быть замкнутой, т.е. не иметь открытых точек. В противном случае краска вытечет из формы и зальет все.
Однако в SVG это не так. Позвольте мне процитировать спецификация сам:
Операция заполнения заполняет открытые вложенные пути, выполняя операцию заполнения так, как если бы к пути была добавлена дополнительная команда «closepath», чтобы соединить последнюю точку вложенного пути с первой точкой вложенного пути.
Это означает, что мы можем опустить команды закрытия пути (z
), так как вложенные пути считаются автоматически закрытыми при заполнении.
Еще одна полезная вещь, которую нужно знать о командах пути, заключается в том, что они бывают в верхнем и нижнем регистре. Строчные буквы означают, что используются относительные координаты; заглавные буквы означают, что вместо них используются абсолютные координаты.
Это немного сложнее, чем с H
и V
команды, потому что они включают только одну координату. Вот как я бы описал эти две команды:
H{x}
: Рисует горизонтальную линию от текущей точки до координатx
.V{y}
: Рисует вертикальную линию от текущей точки до координатy
.
Когда мы рисуем первый кирпич в плитке шаблона, мы начинаем с (0,0)
координаты. Затем мы проводим горизонтальную линию, чтобы (100,0)
и вертикальная линия к (100,30)
, и, наконец, нарисуйте горизонтальную линию, чтобы (0,30)
. Мы использовали h-100
в последней строке, но это эквивалентно H0
, то есть два байта вместо пяти. Мы можем заменить два похожих вхождения и сократить код нашего <path>
вплоть до этого:
<path d="M0 0h100v30H0 M0 40h45v30H0 M55 40h55v30H55"/>
Срезаны еще 9 байт — насколько меньше мы можем уменьшить?
Мост (-5B, всего 48B)
Самые длинные команды, стоящие на нашем пути к полностью оптимизированному шаблону SVG, — это команды «move to», которые занимают 4, 5 и 6 байтов соответственно. У нас есть одно ограничение:
Сегмент данных пути (если он есть) должен начинаться с команды «moveto».
Но это нормально. В любом случае первая самая короткая. Если мы поменяем местами ряды, мы можем придумать определение пути, в котором нам нужно перемещаться только по горизонтали или по вертикали между кирпичиками. Что, если бы мы могли использовать h
и v
команды там вместо M
?
На приведенной выше диаграмме показано, как можно нарисовать три фигуры с помощью одного пути. Обратите внимание, что мы используем тот факт, что fill
операция автоматически закрывает открытую часть между (110,0)
и (0,0)
. При этой перестановке мы также переместили зазор левее полноразмерного кирпича во втором ряду. Вот как выглядит код, все еще разбитый на один блок в строке:
<path d="M0 0v30h50V0 h10v30h50 v10H10v30h100V0"/>
Конечно, мы нашли самое маленькое решение теперь, когда у нас осталось 48 байт, верно?! Хорошо…
Обрезка цифр (-4B, всего 44B)
Если вы можете быть немного гибкими с размерами, есть еще один способ оптимизировать шаблоны SVG. Мы работали с кирпичом шириной 100
пикселей, но это три байта. Изменение его на 90
означает, что на один байт меньше, когда нам нужно его записать. Точно так же мы использовали зазор 10
пикселей, но если мы изменим его на 8
вместо этого мы сохраняем байт для каждого из этих вхождений.
<path d="M0 0v30h45V0 h8v30h45 v8H8v30h90V0"/>
Конечно, это также означает, что мы должны соответствующим образом скорректировать размеры паттерна. Вот окончательный оптимизированный код шаблона SVG:
<pattern id="p" width="98" height="76" patternUnits="userSpaceOnUse"> <path d="M0 0v30h45V0h8v30h45v8H8v30h90V0"/>
</pattern>
Вторая строка в приведенном выше фрагменте — не считая отступов — 44 байт. Мы получили здесь 197 байт за шесть итераций. это коренастый Уменьшение размера на 77.7%!
Мне интересно, хотя… это действительно самый маленький возможный размер? Мы рассмотрели все возможные способы оптимизации шаблонов SVG?
Я предлагаю вам попробовать еще больше минимизировать этот код или даже поэкспериментировать с альтернативными методами оптимизации шаблонов SVG. Я хотел бы посмотреть, сможем ли мы найти настоящий глобальный минимум с помощью мудрости толпы!
Подробнее о создании и оптимизации шаблонов SVG
Если вам интересно узнать больше о создании и оптимизации шаблонов SVG, прочитайте мою статью о создание шаблонов с фильтрами SVG. Или, если вы хотите просмотреть галерею из более чем 60 шаблонов, вы можете просмотреть Коллекция CodePen PetitePatterns. Наконец, вы можете посмотреть мои уроки на ютубе чтобы помочь вам еще глубже изучить шаблоны SVG.
Оптимизация шаблонов SVG до их наименьшего размера первоначально опубликовано CSS-хитрости, Вам следует получить информационный бюллетень.
- "
- 10
- 100
- 77
- 9
- 98
- О нас
- Absolute
- Учетная запись
- дополнительный
- Все
- Позволяющий
- уже
- Другой
- подхода
- ПЛОЩАДЬ
- гайд
- Атрибуты
- доступен
- ОСИ
- Немного
- Черный
- вызов
- изменение
- закрыто
- код
- Общий
- связи
- содержит
- содержание
- координировать
- может
- Создающий
- Текущий
- данным
- более глубокий
- вниз
- окончания поездки
- установленный
- многое
- пример
- Кроме
- эксперимент
- в заключение
- First
- соответствовать
- поток
- найденный
- далее
- разрыв
- получающий
- Глобальный
- имеющий
- высота
- помощь
- здесь
- Выделенные
- Как
- HTTPS
- определения
- изображение
- включают
- включены
- IT
- саму трезвость
- известный
- утечка
- УЧИТЬСЯ
- узнали
- Используя
- линия
- мало
- смотрел
- любят
- ДЕЛАЕТ
- Создание
- управляемого
- математике
- против
- БОЛЕЕ
- самых
- двигаться
- MS
- номер
- номера
- смещение
- Хорошо
- открытый
- оптимизированный
- в противном случае
- шаблон
- физический
- Точка
- расположены
- возможное
- мощный
- довольно
- цена
- процесс
- приводит
- год
- Бег
- Сказал
- бесшовные
- Серии
- набор
- формы
- аналогичный
- просто
- ШЕСТЬ
- Размер
- So
- Решение
- удалось
- Space
- Спотовая торговля
- Начало
- начинается
- Поддержанный
- говорить
- Через
- топ
- прозрачный
- учебные пособия
- использование
- ценностное
- Вид
- W3
- Смотреть
- добро пожаловать
- Что
- в
- без
- Работа
- работает
- работает
- стоимость
- YouTube