sizes='auto' закрывает 14 лет страданий с адаптивными картинками
Бывший председатель RICG, который 14 лет защищал синтаксис srcset/sizes, признаётся, что половину этого синтаксиса он сам ненавидел. Хорошая новость: одно слово auto закрывает проблему почти везде. Перевели эссе целиком.
Если у вас в шаблоне есть img loading="lazy" с длинным sizes-выражением через media query — теперь его можно заменить на одно слово sizes="auto". Браузер сам померит размер картинки в макете и выберет нужный source. В апреле 2026 поддержка приехала и в Gecko, и в WebKit; раньше так умел только Blink. По этому поводу Mat Marquis — бывший председатель RICG (Responsive Images Community Group, группа стандартизации srcset/sizes в HTML) и человек, который 14 лет защищал нынешний синтаксис, — написал исповедальное эссе на Piccalilli. Перевели его целиком, потому что оно одновременно история стандартизации и практический разбор.
Прежде чем нырять в текст автора — короткая выжимка, ради чего стоит поменять разметку прямо сегодня.
Ключевые выводы
- Что изменилось: Mozilla и Apple наконец смержили патчи (авторы — Simon Pieters в Gecko и Yoav Weiss в WebKit), и
sizes="auto"работает во всех движках. Раньше фича жила только в Blink (Chrome, Edge). Конкретные номера версий Firefox и Safari, в которых оказалась поддержка, лучше сверять по caniuse. - Как использовать: только на изображениях с
loading="lazy". Кimgдобавляетеsizes="auto"— браузер берёт реальный размер элемента из layout и выбирает source изsrcset. - Когда не работает: hero-картинки и LCP-кандидаты (Largest Contentful Paint — самый крупный визуальный элемент в первом экране, ключевая метрика Core Web Vitals), у которых нет
loading="lazy"(их браузер запрашивает до того, как знает layout). Им по-прежнему нужен явныйsizes— но это редкие исключения, а не правило. - Безопасность миграции:
sizes— descriptive-атрибут (описывает факт, а не команду). Браузеры без поддержкиautoпросто проигнорируют ключевое слово и откатятся к запасному значению — например,sizes="auto, (min-width: 1040px) 650px, 100vw". - Уже в продакшене: WordPress использует этот подход после патча от Joe McGill — выходца из RICG (Responsive Images Community Group).
Четырнадцать лет ожидания
Я ждал четырнадцать лет, чтобы написать эту статью. Четырнадцать лет, чтобы рассказать вам про одно относительно недавнее дополнение к тому, как картинки работают в вебе. Для вас — буквально пара символов в разметке, которая улучшит фундаментальную эргономику работы с изображениями. Для пользователей — невидимое, бесшовное и потенциально огромное улучшение фронтенд-производительности, навсегда вшитое в ткань веба. А для меня — наконец-то время признаться в зловещих махинациях; признание, которое зрело почти полтора десятилетия.
Тогда, четырнадцать лет назад, я был достопочтенным председателем RICG (Responsive Images Community Group) — пиратской радиостанции среди web standards bodies, ответственной за то, чтобы привести в платформу разметку для responsive images. Кто-то из вас помнит. Кто-то был там, на заре responsive web design, и помогал находить новые сценарии, в которых веб-платформа не справлялась — когда сборная команда фронтенд-специалистов сплотилась, организовалась и врезалась лбом в процесс веб-стандартов, который не был ей рад. Мы требовали место за столом наряду с производителями браузеров и представляли интересы веб-дизайнеров, разработчиков и тех пользователей, которым мы служили. Нас были сотни. После лет итераций, бесчисленных черновиков спецификаций и прототипов, бесконечных споров, превращавшихся в консенсус через древние мейл-листы и IRC-каналы, мы вместе с вендорами браузеров наконец пришли к рабочему синтаксису. И сделали его реальностью — собрали деньги в коммьюнити, чтобы оплатить независимые реализации в браузерах, написали полифиллы для разгона adoption, прикрутили это всё к крупным CMS, написали статьи, выступили с докладами и распространили — позвольте сказать — лучшие футболки в истории веб-стандартов.
Я понимаю, что многие из вас при всём при этом отсутствовали — это древняя история по меркам веб-разработки. Для вас разметка для responsive images существовала всё то время, что вы делали сайты: плотный, непрозрачный, неотвратимый и неизбежный аспект платформы, замысловатый синтаксис и постоянный источник фрустрации.
Если вы из второй группы — позвольте представиться: это всё я. Прямо здесь — я.
Каждый раз, когда вы безуспешно пытались понять, почему браузер выбирает конкретный source из srcset, — это я вас мучил. Каждый раз, когда приходилось затаскивать огромную third-party библиотеку, чтобы справиться с синтаксисом, который явно не задумывался для написания человеком, — я был причиной; чёрт, я даже мог его соавторствовать. Когда вы запускали bookmarklet, который ломал ваш workflow, в надежде, что он сгенерирует значение sizes, более-менее совпадающее с реальностью ваших layouts. Когда становилось слишком много, и вы опускали руки — сдавались — и в итоге грузили на пользователей огромные оригиналы, от которых те никогда не получат никакой практической пользы, но заплатят всю цену в производительности. Это всё было не вашей виной. Это было моей. Я не только не остановил эти синтаксисы от стандартизации — я был их знаменосцем. Я зубами рвал за разметку, которую вы прокляли.
Ох. И как будто этого мало — вот часть, от которой вы по-настоящему разозлитесь: я её тоже терпеть не могу.
Каждый доклад, который я делал, и каждая статья, которую я писал по теме, — курс про изображения, целая книга про изображения — всё это было сквозь стиснутые зубы. В этом синтаксисе есть части, которые я ненавижу с момента, когда впервые их увидел, — то есть с того же момента, как стал их главным заступником. И мне не жаль. Я бы повторил.
Зверь, которого нужно было приручить
Поймите меня правильно — я не ненавижу сами responsive images. Проблему нужно было решать, никаких сомнений. Тогда, как и сейчас, подавляющая часть transfer size сайта приходится на изображения. Гибкая картинка требует source, достаточно большого, чтобы покрыть максимальный размер, который она занимает в layout — без responsive images картинку, которая занимает в макете, скажем, две тысячи пикселей в ширину, пришлось бы отдавать каждому пользователю в оригинальных 2000 px. Уменьшить её в CSS — тривиально, но запрос-то тот же. Пользователь несёт все издержки трафика, ничего за это не получая.
Не забывайте, что проблема родом из эпохи, когда соединения медленнее 3G были нормой. Не было надёжного способа подстроить эти запросы под контекст пользователя так, чтобы сохранить браузерные оптимизации. И решения, к которым мы пришли, эффективны, и они сэкономили пользователям непостижимые объёмы трафика. Responsive images как концепция — потрясающее дополнение к платформе. Я горжусь, что сыграл в этом маленькую роль.
А вот picture — это отдельная история. picture мне нравится с самого начала. Что не любить-то? Кому не нужен такой уровень контроля? К тому же picture позволил ответственно отдавать новые форматы изображений с быстрым и надёжным механизмом отката между браузерами — открыл двери невероятным успехам в кодировании и сжатии, причём без единой строчки JavaScript. Синтаксис читается осмысленно, он даёт нам шаблон для стандартизации более умных решений вокруг любых медиа-запросов и становится мощнее с каждым добавленным media query. picture крутой, мне нравится picture, всем нравится picture. Мы здесь не про picture.
picture принципиально отличается от srcset и sizes — последние представляют собой descriptive-синтаксис. Чтобы было сразу понятно: descriptive — это «описательный»: вы описываете факт (какие источники у картинки и какого размера она в layout), а решение принимает браузер. Prescriptive — «предписывающий»: вы прямо говорите, что делать. srcset вы используете, чтобы дать браузеру информацию про набор источников, идентичных везде кроме разрешения; sizes — чтобы дать информацию о том, каких размеров изображение будет отрендерено. Ни один из этих атрибутов не говорит браузеру, что делать. Получив эту информацию, браузер делает ровно одну, очень сложную, вещь: определяет источник, наилучшим образом подходящий под контекст пользователя. Визуально источник, выбранный из srcset, неважен — все они выглядят одинаково. Но выбранный кандидат лучше всего подходит под условия пользователя. Вы не получаете никакого контроля над тем, как принимается это решение. Более того — вы даже не имеете права знать, как оно принимается. By design — то есть так задумано: это намеренно вырезано в HTML-спецификации:
Реализация сама определяет, как — выбрав один источник из набора кандидатов. (In an implementation-defined manner, choose one image source from sourceSet.)
Как вам такое? «Тогда браузер», в строгих технических терминах, просто делает что захочет. Этот формально кодифицированный недостаток контроля не случился сам: ответственность могла остановиться на мне — но не остановилась. Я лично проголосовал «за» за решение, что у вас не должно быть права голоса в том, как работают srcset/sizes — что вы даже не можете знать, как они работают. Сейчас, после всех этих лет, при разоблачении меня как злодея этой истории, я наконец могу рассказать почему. И вам это тоже не понравится. Потому что я знал — вы бы сделали неправильно.
Это работа не для человека
Не воспринимайте это слишком лично — я бы тоже сделал неправильно. Чёрт возьми, я и делал неправильно, через десятки предложений и прототипов, в поисках решения, которое можно было стандартизировать. Все делали неправильно. В итоге все эти итерации только доказали: никто не мог сделать эту часть правильно. Та «одна вещь», которую делают srcset/sizes — определение источника, наилучшим образом подходящего под контекст пользователя, включая размер viewport, плотность дисплея, пользовательские настройки, пропускную способность и бесчисленное количество других потенциально непознаваемых факторов? В этих факторах есть вещи, которые мы знать не можем, и столько же — которых нам знать не следует.
Например, мы не можем подстраивать выдачу под скорость соединения пользователя — кажется, что жаль. Но представим на секунду, что могли бы — что мы могли бы сказать «выше этой скорости — этот source, ниже — тот». Теперь это решение ваше. Какие пороги скорости вы бы выставили для своих картинок, и какие я — для своих? Они будут разные. То есть для одной и той же скорости пользователь получит на одном сайте красивые, но забивающие канал картинки, а на следующем — сильно сжатые, но эффективные. Какие из них пользователь хочет? Вопрос с подвохом — все хотят разное. А чего хочет ваша компания? Уф. Все смотрят на вас — на вас, с открытыми тикетами, митингом через полчаса и всем этим контролем, который вам в руки сунула спецификация. Почему сайт ощущается так медленно? Почему наши картинки теперь выглядят хуже, чем у конкурентов? Почему сайт опять ощущается так медленно? Даже когда мы рассматриваем только скорость соединения, цена нашего контроля — это утрата контроля у пользователя. А ведь мы ещё ничего не сказали про остальные факторы.
Я не хотел этого. Я не хотел этого для тех, кто строит веб, не хотел этого для тех, кто пользуется вебом, и точно не хотел смотреть, как сам веб трещит под весом миллиона огромных картинок и сотни тысяч тикетов «надо когда-нибудь подробно расписать нашу политику работы с responsive images», похороненных в трекерах навечно.
У браузера доступа к информации куда больше, чем у нас, — точно больше, чем нам разумно бы хотелось. Поэтому он может принимать решения о размере экрана, плотности дисплея, пропускной способности, пользовательских настройках и любых будущих факторах, о которых мы пока даже не догадываемся, — не делая ничего из этого нашей проблемой. Браузер может тонко настраивать детали — например, избегать ненужных запросов, оставляя крупный source, если он уже в кеше, вместо запроса меньшего, функционально идентичного. Я бы не хотел владеть этой логикой. Браузер может опрашивать пользовательские настройки — давая человеку контроль над этими решениями и стабильность опыта от сайта к сайту.
В итоге нам не нужен контроль, когда речь о выборе источника. Нам нужны просто быстрые картинки — и srcset с sizes закрывают этот use case прекрасно. Лучше, чем кто-то из нас способен был бы лично, если бы пришлось. Было бы кошмаром, если бы пришлось. Descriptive-синтаксис избавляет нас от всего этого ужаса и позволяет браузеру делать то, что он умеет лучше всего: использовать информацию, которая у него уже есть, чтобы сделать один эффективный запрос за источником. Нам остаётся только дать ему ту небольшую часть информации, которой у него нет.
Честно говоря, srcset даже не так уж плох, всё взвесив! Любая CMS, статический генератор или build-tool в мире легко выплюнет список сгенерированных источников и их ширин через запятую. Чем больше значений вы туда положите, тем эффективнее и точнее будут запросы. Никаких страданий, никаких user-facing издержек, кроме нескольких лишних байт разметки. Аккуратный синтаксис, если приглядеться. srcset — норм.
Responsive images — не проблема. picture — не проблема. srcset — даже не проблема.
Мы оба знаем, в чём проблема.
Дилемма sizes
Браузер не может знать, сколько места займёт изображение в макете, потому что принимает решения по запросам картинок задолго до того, как у него будет информация для рендера layout — там просто пока нечего измерять. Размер viewport в этот момент уже доступен — но это ужасный proxy для размера реально отрендеренного изображения. Веб не сделан из full-bleed «hero»-картинок; он сделан из колонок и гридов, сайдбаров и «карточек» и кучи маленьких круглых аватарок. Допущение, что source никогда не будет больше viewport, — неплохое начало (поэтому пропущенный sizes, формально невалидный, работает как sizes="100vw"). Но этого недостаточно. И вот мы с вами вынуждены описывать все размеры, которые элемент примет на всех breakpoints и контейнерных запросах, единой строкой в HTML-атрибуте. Какая мерзость.
Именно потому, что для sizes нужна информация об окружающем layout, его невозможно автоматизировать. Сборочный процесс не может узнать, сколько места займёт картинка в разных макетах без огромных накладных расходов — вроде «собрать всё, отрендерить весь сайт, замерить каждое изображение на каждой странице, сгенерировать sizes для всех, и только потом продолжить сборку». Поэтому мы пишем эти описания вручную — и за исключением совсем простых случаев это нельзя сделать без инструментария. Описание размеров гибкой картинки требует слишком многих вычислений между breakpoints. Вот пример из относительно простого макета:
Никто не должен быть способен это написать. В смысле — как? Изменяя размер браузера и щурясь? Гадая? sizes — один из немногих паттернов разметки, которые буквально требуют инструментария, что максимально далеко от веб-этоса «открой текстовый редактор и собери сайт» — этоса, который я очень ценю. Чёрт, даже если бы вы умудрились описать всё через media query — то есть использовать прескриптивный синтаксис как дескриптивный, говоря «выше такого размера вот это произойдёт» вместо «выше такого размера сделай вот это» — мне делается дурно. Я ненавижу sizes. Я всегда ненавидел sizes.
Поэтому я здесь. Поэтому я наконец об этом пишу. Я не извиняюсь за sizes. Я здесь, чтобы помочь его похоронить.
Начало и конец
Несколько недель назад в Gecko и WebKit залендили патчи — авторы Simon Pieters и Yoav Weiss, два лучших участника RICG. Эти патчи влились тихо, выровняв Gecko и WebKit с Blink — поддержка значения auto в атрибуте sizes. Автоматический sizes — потенциальные размеры отрендеренного изображения, которые браузер определяет сам, наряду со всеми остальными факторами. Полностью автоматические responsive images. Передаёте список кандидатов через srcset, прикручиваете sizes="auto" — и браузер делает остальное.
Как? Центральная проблема srcset/sizes была в тайминге: браузер принимает решения по запросам картинок задолго до того, как у него есть информация о макете страницы, поэтому мы должны были давать ему информацию о layout сами. Это допущение больше не строго истинно. Это всё ещё дефолтное поведение: если в разметке есть img, запрос за ним уйдёт задолго до того, как layout будет известен, — если только картинка не использует атрибут loading="lazy" (исключительно частая лучшая практика для всех картинок, кроме тех, что почти наверняка попадут в viewport при первой загрузке страницы). Добавление loading="lazy" к img меняет всё уравнение: теперь эти изображения запрашиваются в момент пользовательского взаимодействия, гораздо позже момента, когда у браузера уже есть вся информация о размерах будущего рендера. Браузеру больше не нужны мы — и в мире всё стало хорошо.
Готов поспорить, вы ждёте подвоха. Не ждите. Если переживаете за поддержку браузеров — не стоит: встретив строку «auto» в начале sizes, любой браузер с поддержкой скажет «понял, дальше я сам», выкинет остальную часть sizes и продолжит. Браузер без поддержки выбросит auto как бессмысленное и продолжит читать атрибут как обычно. Это значит, что начать использовать можно прямо сейчас — без затрат и накладных расходов, кроме набора слова auto, в начале sizes:
Не первое матерное слово, на которое меня сподвиг sizes, но точно с самым позитивным результатом.
Этот подход — ровно то, что теперь использует WordPress.
Когда <code class="tp-inline-code language-none">sizes</code> ещё нужен
Конечно, это не конец абсолютно — описательные значения sizes вам всё ещё иногда понадобятся. Картинка, которая, скорее всего, попадёт в viewport при первой загрузке, — это сценарий, в котором вы не хотели бы использовать loading="lazy" (а sizes="auto" работает только с ленивыми изображениями). Но такие картинки — исключения, не правило.
Эти редкие исключения — изображения, почти наверняка попадающие в viewport в самом верху страницы, ваши вероятные Largest Contentful Paint элементы (LCP — самый крупный визуальный элемент в первом экране, ключевая метрика Core Web Vitals; лениво грузить такое нельзя — у него слишком ранний дедлайн), которым плохо живётся под loading="lazy"? Ну, вы только что представили их в голове, верно? Большая «hero»-картинка, тип изображения, который, скажем, занимает всю ширину viewport-а или близко к этому. Их относительно легко описать через breakpoints. Может быть, что-то в районе — ну, вытащу значение из воздуха — sizes="100vw". Все остальные картинки — те, что раскиданы по колонкам, гридам, сайдбарам, «карточкам» и кучкам маленьких круглых аватарок, из которых на самом деле и сделан веб? loading="lazy" sizes="auto". Готово. Поздравляю.
Я не буду скучать по всем этим вручную выкованным sizes. У меня к ним любви и не было. Я никогда не испытаю ни проблеска ностальгии по тому, что я помог сделать реальным и неотделимо связал со своим именем. Синтаксис никогда не был целью; целью всегда был механизм. На тот момент платформа не давала браузерам способа принимать более умные решения о том, какой источник запросить и когда — никакие сценарии или markup-трюки никогда не дадут request настолько же быстрый и эффективный, как тот, что делает сам браузер. Мы получили этот механизм — и я заставил всех нас оплатить его стоимость, ради пользователей и ради здоровья веба.
Так что любой из вас, дизайнеров и разработчиков, кто боролся с атрибутами sizes в прошлом, — давайте, нарисуйте мой портрет, какого хотите размера, распечатайте и приклейте к ближайшей дартс-доске. Я держу голову высоко и не приношу извинений. Я был прав. Мы были правы. Я по-прежнему стою за необходимость декларативного синтаксиса. Стою за это ровно настолько же, насколько жалею, что он не мог быть лучше — и ровно настолько же, насколько знаю, что в то время не мог. Конечно, я ёжусь от идеи отдать контроль не меньше, чем любой разработчик, но когда речь о высокопроизводительных изображениях — у нас никогда не могло быть контроля по-настоящему. Было бы самонадеянно даже пытаться. И как бы фрустрирующе это ни было — отказаться от контроля — владеть responsive images было бы бременем; проклятием.
Спросите меня, откуда я знаю.
FAQ
С какой версии браузера это работает?
Blink (Chrome, Edge, Opera) — давно. Gecko (Firefox) и WebKit (Safari) подтянулись в апреле 2026 благодаря патчам Simon Pieters и Yoav Weiss соответственно. Точные номера версий, в которых оказался sizes="auto" в стабильном канале, лучше сверять на caniuse: цифры синхронизируются с релизами браузеров. Старые браузеры просто игнорируют auto и читают остальной sizes как обычно — без поломок.
А если <code class="tp-inline-code language-none">loading="lazy"</code> нет — <code class="tp-inline-code language-none">sizes="auto"</code> вообще не работает?
Так. Без loading="lazy" браузер запрашивает картинку до того, как знает её размер в layout, поэтому автоматический режим невозможен. Для hero-изображений и LCP-кандидатов оставляйте явный sizes. Простейший приближённый вариант — sizes="100vw".
Можно ли использовать <code class="tp-inline-code language-none">auto</code> вместе со старым <code class="tp-inline-code language-none">sizes</code>-выражением?
Да, и это рекомендованный путь: sizes="auto, (min-width: 1040px) 650px, 100vw". Браузер с поддержкой возьмёт auto и забудет остальное; браузер без поддержки проигнорирует auto и прочитает запасной вариант.
Что с <code class="tp-inline-code language-none">picture</code> и <code class="tp-inline-code language-none">srcset</code>?
picture меняется только в части, где внутри source фигурирует sizes — там тоже работает auto. srcset остаётся как есть; именно через него браузер выбирает source-кандидата нужной ширины.
WordPress уже это делает?
Да. Joe McGill прислал патч, который добавляет sizes="auto" для всех lazy-loaded изображений, которые WordPress генерит для контента. Если вы на свежем WordPress — у вас, скорее всего, оно уже включено.
Что делать сегодня
Поправка к шаблонам короткая. У всех img с loading="lazy" в проекте — поставить sizes="auto" (можно с запасным значением auto, … для старых браузеров). Hero-картинки и явные LCP-кандидаты оставить как есть. Сборку и pre-render это не ломает: auto — расширение существующего descriptive-синтаксиса, не замена. Если вы пишете на современном WordPress — вероятно, вам уже ничего делать не нужно.
Оригинал статьи Mat Marquis — на Piccalilli. Спецификация атрибута sizes с поддержкой auto — в WHATWG HTML. Совместимость по версиям браузеров — на caniuse.