Кодування та продуктивність Base64, Частина 1: Що нового у Base64?

Автор Гаррі Робертс на майстрі CSS.

Це перша публікація з двох частин. Прочитайте частину 2.

Видатні поради щодо ефективності, що існували кілька років тому, просто заявляли, що нам слід «зменшити кількість запитів, які ми робимо». Незважаючи на те, що це, загалом, цілком слушна порада, вона не позбавлена ​​застережень. Ми можемо зробити так, щоб сторінки завантажувались набагато швидше, елегантно розподіляючи наші ресурси за кількома більш продуманими запитами, а не за меншими.

Однією з рекламованих "найкращих практик", породжених цією порадою, було прийняття кодування Base64: акт взяття зовнішнього ресурсу (наприклад, зображення) та вбудовування його безпосередньо в текстовий ресурс, який би його використовував (наприклад, таблиця стилів). Результатом цього є те, що ми зменшуємо кількість HTTP-запитів, а обидва ресурси (наприклад, таблиця стилів та зображення) надходять одночасно. Звучить як сон, так?

На жаль, ресурси кодування Base64 - це дуже анти-шаблон 1. У цій статті я сподіваюся поділитися деякою ідеєю щодо критичної оптимізації шляху, Gzip і, звичайно, Base64.

Давайте подивимось якийсь код

Причиною того, що мене спонукало написати цю статтю, є те, що я щойно проводив аудит ефективності для клієнта і натрапив на ті самі проблеми, які я збираюся окреслити. Це фактична таблиця стилів від фактичного клієнта: речі анонімні, але це цілком реальний проект.

Я провів швидкий мережевий профіль на сторінці і виявив лише одну таблицю стилів (що є певним чином хорошим, оскільки ми точно не хочемо бачити 12 запитів таблиці стилів), але ця таблиця стилів з’явилася колосальною 925 тис після декомпресії та розширення. Фактична кількість байтів, що надходить через провід, була значно меншою, але все ще дуже великою - 232 КБ.

Як тільки ми починаємо бачити таблиці стилів такого розміру, ми повинні почати панікувати. Я був відносно впевнений - навіть не потрібно дивитись - що тут буде якийсь Base64. Це не означає, що я очікував, що це буде єдиним фактором (плагіни, відсутність архітектури, застарілі дані тощо, ймовірно, зіграють свою роль), але великі таблиці стилів, як правило, свідчать про Base64. Ще:

  1. Base64 чи ні, 925 тис. CSS жахливо.
  2. Зменшення його зменшує лише до 759K.
  3. Gzipping зводить нас до просто 232K. Точно такий же код стиснутий на 693K.
  4. 232K над дротом все ще жахливий.

Для того, щоб проаналізувати таблицю стилів такого розміру, потрібно очей поливати 88 мс. Передача даних через мережу - це лише початок наших проблем:

оптимізація

Я попередньо сформулював файл 2, зберіг його на своїй машині, пропустив через CSSO, а потім запустив цей мініфікований висновок через Gzip на звичайному рівні. Ось як я дійшов до цих цифр, і я залишився дивитись на це:

Наступне, що потрібно було зробити, - це побачити, скільки цих байтів було з кодованих активів Base64. Щоб це вирішити, я просто (і досить грубо) видалив усі рядки/декларації, що містили data: strings (: g/data:/d 3 для користувачів Vim, які читають це). Більша частина цього кодування Base64 стосувалася зображень/спрайтів та кількох шрифтів. Потім я зберег цей файл як no-base64.css і провів ту ж мініфікацію та Gzipping над цим:

У нашому нестисненому CSS нам вдалося втратити цілих 217 тис. Base64. Це все ще залишає нам тривожну кількість CSS (708K досить громіздко), але нам вдалося позбутися добрих 23,45% нашого коду.

Де все справді стає дивовижним, хоча це після того, як ми зішпартували те, що залишилось. Нам вдалося перейти від 708K до всього 68K по дроту! Це економія 90,39%. Ого.

Збереження Gzip…

Gzip неймовірний! Це, мабуть, найкращий інструмент захисту користувачів від розробників. Нам вдалося зробити 90% економії на дроті, просто стиснувши наш CSS. З 708K до 68K безкоштовно.

... іноді

Однак над цим Gzip працює не кодовану версію Base64. Якщо ми подивимось на оригінальний CSS (CSS з кодуванням Base64), ми виявимо, що ми лише заощадили 74,91%.

Base64? Заощадження розміру стисненого розміру
Так 925 тис 232 тис 74,91%
Ні 708 тис 68 тис 90,39%

Різниця між двома варіантами - приголомшливі 164 тис. (70,68%). Ми можемо надіслати на 164 тис. CSS менше, просто перемістивши ці активи кудись більш доцільно.

Base64 жахливо стискає. Наступного разу, коли хтось спробує все, так, але Gzip ... вибачте, скажіть їм про це (якщо вони намагаються виправдати Base64, тобто).

Так чому Base64 такий поганий?

Гаразд, отже, ми цілком зрозуміли, що Base64 збільшує розмір файлу таким чином, що Gzip насправді не може нам допомогти, але це лише одна невелика частина проблеми. Чому ми так боїмося цього збільшення розміру файлів? Одне зображення може важити значно більше 232 тис., Тож чи не краще нам почати там?

Гарне запитання, і я радий, що ви згадали зображення ...

Потрібно поговорити про зображення

Для того, щоб зрозуміти, наскільки поганий Base64, нам спочатку потрібно зрозуміти, наскільки хороші зображення. Суперечлива думка: зображення не настільки погані для продуктивності, як ви думаєте.

Так, зображення є проблемою. Насправді вони найбільше сприяють збільшенню кількості сторінок. Станом на 2 грудня 2016 року зображення складають близько 1623 тис. (Або 65,46%) середньої веб-сторінки. Це робить нашу таблицю стилів 232K схожою на краплю в морі для порівняння. Однак існують принципові відмінності між тим, як браузери обробляють зображення та таблиці стилів:

Зображення не блокують візуалізацію; таблиці стилів.

Браузер почне відображати сторінку незалежно від того, надійшли зображення чи ні. Чорт візьми, браузер відобразить сторінку, навіть якщо зображення взагалі ніколи не надходять! Зображення не є критично важливими ресурсами, тому, хоча вони і складають надмірну кількість байтів над дротом, вони не є вузьким місцем.

CSS, з іншого боку, є критично важливим ресурсом. Веб-переглядачі не можуть розпочати рендерінг сторінки, поки не сформують дерево візуалізації. Браузери не можуть побудувати дерево візуалізації, поки вони не сконструюють CSSOM. Вони не можуть побудувати CSSOM, поки всі таблиці стилів не надійдуть, не будуть стиснуті та проаналізовані. CSS - це вузьке місце.

Сподіваємось, тепер ви можете зрозуміти, чому ми так боїмося байтів CSS: вони просто служать для затримки візуалізації сторінки, і залишають користувача, дивлячись на порожній екран. Сподіваємось, ви також усвідомили болісну іронію кодування Base64 зображень у ваших файлах CSS: ви просто перетворили сотні кілобайт неблокуючих ресурсів на блокуючі у гонитві за виконанням. Всі ці зображення могли пробиватися по мережі, коли б були готові, але тепер вони були змушені з’являтися поряд із набагато легшими критичними ресурсами. І це не означає, що зображення приходять раніше; це означає, що критичний CSS надходить пізніше. Чи справді може стати набагато гірше?!

Браузери розумні. Дійсно розумно. Вони роблять для нас багато оптимізації продуктивності, оскільки - частіше за все - вони знають краще. Давайте подумаємо про реагування:

Ми дали браузеру тут три потенційні зображення, але він завантажить лише одне з них. Він розбирає, який з них йому потрібен, дістає той, а два інших залишає недоторканими.

Як тільки ми базуємо ці зображення, байти для всіх трьох завантажуються, фактично потроюючи (або за їх межами) наші накладні витрати. Ось фактична частина CSS з цього проекту (я видалив закодовані дані зі зрозумілих причин, але повністю цей фрагмент коду склав 26 тис. До Gzip; 18 тис. Після):

Усі користувачі, незалежно від того, на пристроях сітківки чи ні (чорт візьми, навіть користувачі з браузерами, які навіть не підтримують медіа-запити), будуть змушені завантажити ці додаткові 18 КБ CSS, перш ніж їх браузер зможе навіть почати складати для них сторінку.

Кодовані засоби Base64 завжди будуть завантажені, навіть якщо вони ніколи не використовуються. У кращому випадку це марнотратно, але якщо врахувати, що насправді це відходи, які блокують візуалізацію, це ще гірше.

І нам потрібно поговорити про шрифти

Наразі я згадав лише зображення, але шрифти майже однакові, за винятком деяких нюансів щодо того, як браузери обробляють спалах нестильового/невидимого тексту (FOUT або FOIT). Шрифти в цьому проекті складають 166 тис. Нестиснених CSS (124 тис. Gzipped (знову є ця жахлива дельта стиснення)).

Не надто збиваючи статтю з колії, шрифти також є активами, які природно не живуть на вашому критичному шляху, що є чудовою новиною: ваша сторінка може відображатися без них. Однак проблема полягає в тому, що браузери по-різному обробляють веб-шрифти:

  • У Chrome та Firefox текст взагалі не відображається протягом 3 секунд. Якщо веб-шрифт надходить протягом цих трьох секунд, текст замінюється з невидимого на ваш власний шрифт. Якщо шрифт все ще не надійшов через 3 секунди, текст поміняється з невидимого на будь-який із вказаних вами резервних варіантів. Це ФУТ.
  • IE негайно відображає резервний шрифт а потім поміняє його на власний шрифт, як тільки він надійде. Це ФУТ. Це, на мій погляд, найелегантніше рішення.
  • Safari показує невидимий текст поки шрифт не надійде. Якщо шрифт ніколи не надходить, він ніколи не відображає запасний варіант. Це ФУТ. Це також абсолютна гидота. Є всі шанси, що ваші користувачі ніколи не зможуть побачити жодного тексту на вашій сторінці.

Для того, щоб обійти це, люди запустили Base64, вставляючи свої шрифти в свої таблиці стилів: якщо CSS і шрифти надходять точно в той самий час, тоді не буде FOIT або FOUT, тому що відбувається побудова та доставка шрифтів CSSOM більш-менш одночасно.

Тільки, як і раніше, переміщення шрифтів на критичний шлях не пришвидшує їх доставку, це просто затримує ваш CSS. Є кілька досить інтелектуальних рішень для завантаження шрифтів, але Base64 не є одним із них.

І нам потрібно поговорити про кешування

Base64 також впливає на нашу здатність мати більш складні стратегії кешування: поєднуючи наші шрифти, зображення та стилі, всі вони регулюються одним і тим же правилом. Це означає, що якщо ми десь змінимо в нашому CSS лише одне шістнадцяткове значення - зміна, яка може представляти до шести байт нових даних - нам доведеться перезавантажити сотні кілобайт стилів, зображень і шрифтів.

Насправді шрифти тут насправді погано порушують: шрифти дуже, дуже навряд чи колись зміняться. Це дуже рідко модифікований ресурс. Насправді я щойно пішов і перевірив тривалий проект, над яким працюємо ми з іншим клієнтом: остання зміна їх CSS була вчора; остання зміна файлів шрифтів відбулася вісім місяців тому. Уявіть, що ви змушуєте користувача перезавантажувати ці шрифти кожного разу, коли ви оновлюєте щось у своїй таблиці стилів.

Кодування Base64 означає, що ми не можемо кешувати речі самостійно на основі швидкості їх зміни, а також означає, що нам доводиться кешувати бюст непов'язаних речей, коли щось інше змінюється. Це ситуація програш.

Це основне розділення проблем: кешування моїх шрифтів не повинно залежати від кешування моїх зображень і кешування моїх стилів.

Гаразд, давайте швидко підсумуємо:

  • Кодування Base64 збільшує розмір файлів способами, які ми не можемо ефективно пом'якшити (наприклад, Gzip). Це збільшення розміру файлу затримує візуалізацію, оскільки це відбувається із ресурсом, що блокує візуалізацію.
  • Кодування Base64 також змушує некритичні активи виходити на критичний шлях. (наприклад, зображення, шрифти) Це означає, що - у цьому конкретному випадку - замість того, щоб завантажувати 68 000 CSS, перш ніж ми зможемо розпочати візуалізацію сторінки, нам потрібно завантажити більше 3,4 × цієї суми. Ми просто змушуємо користувача чекати об’єктів, яких їм спочатку ніколи не потрібно було б чекати!
  • Кодування Base64 змушує завантажувати всі байти активів, навіть якщо вони ніколи не будуть використані. Це марна трата ресурсів, і знову ж таки, це відбувається на нашому критичному шляху.
  • Кодування Base64 обмежує нашу можливість кешувати активи окремо; наші зображення та шрифти тепер пов’язані з тими ж правилами кешування, що і наші стилі, і навпаки.

Загалом, це досить похмура ситуація: уникайте Base64.

Обговорення даних

Вся ця стаття написана з використанням того, що я вже знаю. Я не проводив тестів і не мав даних: це просто те, як працюють браузери ™. Однак я вирішив провести кілька тестів, щоб побачити, які саме факти та цифри ми розглядаємо. Перейдіть до частини 2, щоб прочитати більше.

Є кілька дуже виняткових випадків, коли це може бути розумним, але ви будете абсолютно впевнені в тих випадках, коли вони виникають. Якщо ви не зовсім впевнені, то, мабуть, це не один із таких випадків. Завжди помиляйтесь з обережністю і вважайте, що Base64 не є правильним підходом. ↩

Відкрийте таблицю стилів на вкладці Джерела Chrome, натисніть значок <> у нижньому лівому куті файлу, готово. ↩

Запустіть глобальну команду (: g) по всіх рядках; знайти рядки, що містять дані: (/ data:), і видалити їх (/ d). ↩

Привіт, я Гаррі. Я є нагороджений консультант Інженер з веб-продуктивності, дизайнер, розробник, письменник, і динамік з Великобританії. Я писати, Твіт, говорити, і код спільного використання про вимірювання та покращення швидкості сайту. Ви повинні найняти мене.