Нещодавно я створив візерунок цегляної стіни як частину свого #МаленькіВізерунки серії, завдання, де я створюю органічні візерунки або текстури в 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
по суті означає пікселі. Нарешті, додавши an id
до шаблону необхідно, щоб на нього можна було посилатися, коли ми малюємо ним інший елемент.
<pattern id="p" width="220" height="80" patternUnits="userSpaceOnUse"> <!-- pattern content here -->
</pattern>
Тепер, коли ми встановили розміри плитки, завдання полягає в тому, щоб створити код для плитки таким чином, щоб відображати графіку з найменшою можливою кількістю байтів. Ось що ми сподіваємося отримати в самому кінці:
Початкова розмітка (197 байт)
Найпростіший і найбільш декларативний підхід до відтворення цього візерунка, який спадає мені на думку, — це намалювати п’ять прямокутників. За замовчуванням, fill
елемента SVG є чорним і stroke
є прозорим. Це добре працює для оптимізації шаблонів SVG, оскільки нам не потрібно явно оголошувати їх у коді.
Кожен рядок у коді нижче визначає прямокутник. The 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>
має невелику ціну. Тобто ми повинні додати a 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» для цегли. The <use>
елемент можна розташувати аналогічно <rect>
, С x
та y
атрибути як зміщення. Оскільки кожна цеглинка тепер на повну ширину, коли ми перейшли на <use>
(запам’ятайте, ми явно розрізали цеглини вдвічі в другому ряду плитки візерунка), ми повинні використовувати негатив x
значення у другому рядку, а потім переконайтеся, що остання цеглинка виходить із плитки для безшовного з’єднання між цеглинами. Однак це нормально, тому що все, що випадає за межі плитки візерунка, автоматично обрізається.
Чи можете ви помітити кілька повторюваних рядків, які можна записати більш ефективно? Давайте попрацюємо над ними далі.
Перезапис до шляху (-54B, всього 100B)
<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, — це команди «перейти до», які займають 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. Нарешті, ви можете подивитися мої підручники на YouTube щоб допомогти вам ще глибше ознайомитися з шаблонами SVG.
Оптимізація шаблонів SVG до найменшого розміру спочатку опубліковано на CSS-трюки. Ти повинен отримати інформаційний бюлетень.
- "
- 10
- 100
- 77
- 9
- 98
- МЕНЮ
- абсолют
- рахунки
- Додатковий
- ВСІ
- Дозволити
- вже
- Інший
- підхід
- ПЛОЩА
- стаття
- Атрибути
- доступний
- Оси
- Біт
- Black
- виклик
- зміна
- закрито
- код
- загальний
- зв'язку
- містить
- зміст
- координувати
- може
- створення
- Поточний
- дані
- глибше
- вниз
- закінчується
- встановлений
- все
- приклад
- Крім
- експеримент
- в кінці кінців
- Перший
- відповідати
- потік
- знайдений
- далі
- розрив
- отримання
- Глобальний
- має
- висота
- допомога
- тут
- Виділено
- Як
- HTTPS
- ідентифікувати
- зображення
- включати
- включені
- IT
- сам
- відомий
- витік
- УЧИТЬСЯ
- вчений
- використання
- Лінія
- трохи
- подивився
- любов
- РОБОТИ
- Робить
- вдалося
- математики
- mind
- більше
- найбільш
- рухатися
- MS
- номер
- номера
- зсув
- добре
- відкрити
- оптимізований
- інакше
- Викрійки
- фізичний
- точка
- розташовані
- це можливо
- потужний
- досить
- price
- процес
- забезпечує
- якість
- круглий
- біг
- Зазначений
- безшовні
- Серія
- комплект
- форми
- аналогічний
- простий
- SIX
- Розмір
- So
- рішення
- що в сім'ї щось
- Простір
- Spot
- старт
- починається
- Підтриманий
- говорити
- через
- топ
- прозорий
- навчальні посібники
- використання
- значення
- вид
- W3
- годинник
- ласкаво просимо
- Що
- в
- без
- Work
- робочий
- працює
- вартість
- YouTube