Files
progcode/editorial/agent-rewrites/193.json
T

8 lines
18 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"index": 193,
"slug": "editorial-2022-08-field-media-performance",
"title": "Когда маленькая картинка тормозит страницу: как найти причину в media-слоте",
"excerpt": "Изображение может быть маленьким на экране и большим в сети. Разбираем source mapping, геометрию, priority и безопасную проверку одной обратимой правки.",
"contentHtml": "<p>Карточка товара занимает большую часть сетевого бюджета, хотя её изображение на экране имеет ширину всего 320 пикселей. Hero появляется поздно. При загрузке фильтра соседний текст прыгает вниз. В отчёте кто-то пишет: «картинка тормозит страницу» — и предлагает добавить priority или заменить файл.</p>\n<p>Такой диагноз слишком широк. Ошибка может находиться в исходнике, в расчёте размера слота, в разметке, в CSS или в составе первого экрана. Если поменять CDN-вариант, размеры и атрибуты сразу, команда потеряет связь между причиной и результатом. Цена ошибки — лишний трафик, поздний полезный контент и релиз, который невозможно уверенно откатить.</p>\n<p><strong>Тезис:</strong> медиа оптимизируют не по размеру файла и не по одному атрибуту. Сначала нужно описать конкретный слот, затем проверить его геометрию и выбор ресурса, после этого сопоставить намерение приложения с фактическим браузерным наблюдением. Одна гипотеза требует одной обратимой правки и повторного прогона в тех же условиях.</p>\n<h2>Механизм: один слот, несколько независимых решений</h2>\n<p>Media-слот — это не только URL картинки. У него есть содержимое, ожидаемый размер, вариант кадрирования, плотность экрана, момент появления и место в композиции страницы. Эти решения связаны, но не заменяют друг друга.</p>\n<p>Сначала браузер получает HTML и видит элемент <code>img</code>. Атрибуты <code>srcset</code> и <code>sizes</code> дают ему набор кандидатов и ожидаемую ширину слота. Браузер сопоставляет эту подсказку с viewport и плотностью экрана, а затем выбирает ресурс. Если <code>sizes</code> описывает слот как 960 пикселей, хотя фактическая колонка занимает 320, браузер может выбрать слишком крупный кандидат. Малый видимый результат не означает малый сетевой расход.</p>\n<p>Геометрия решает другую задачу. Атрибуты <code>width</code> и <code>height</code> задают intrinsic ratio изображения. Когда браузер знает соотношение сторон до загрузки, он может заранее зарезервировать место. Это снижает риск скачка соседнего контента. Но наличие атрибутов не доказывает отсутствие layout shift: контейнер, CSS, шрифт и ветка состояния могут изменить фактический layout.</p>\n<p>Приоритет загрузки тоже имеет две стороны. Код или фреймворк может считать hero критичным и передать это намерение загрузочному пути. Это не равно доказанному порядку сетевых запросов или paint. На порядок влияют разметка, другие ресурсы, браузер, кеш и состояние страницы. Поэтому строка конфигурации — гипотеза о намерении, а trace или performance-запись — наблюдение в конкретных условиях.</p>\n<h2>Пример: описать слот до изменения страницы</h2>\n<p>Ниже — учебный пример разметки. Он показывает контракт компонента: слот имеет размеры, набор кандидатов и текст для доступности. Пример не открывает страницу, не загружает файл и не измеряет LCP или CLS.</p>\n<pre><code>&lt;img\n src=\"/media/product-640.avif\"\n srcset=\"/media/product-320.avif 320w,\n /media/product-640.avif 640w,\n /media/product-960.avif 960w\"\n sizes=\"(max-width: 600px) 320px, 640px\"\n width=\"640\"\n height=\"480\"\n alt=\"Чёрный рюкзак на белом фоне\"\n/&gt;</code></pre>\n<p>В этом примере <code>sizes</code> должен соответствовать реальной ширине слота, а не желаемому размеру самого большого кандидата. Если карточка на узком экране занимает 320 CSS-пикселей, это нужно проверить через фактический layout. Если мобильная композиция показывает другой фрагмент изображения, одного <code>srcset</code> недостаточно: понадобится art direction через <code>picture</code> и отдельные <code>source</code>.</p>\n<p>Нельзя объявлять учебный объект доказательством загрузки. Проверка вроде «в данных есть <code>loaded</code>» говорит только о состоянии модели. Она не подтверждает, что браузер получил response, декодировал изображение и нарисовал его. Для этого нужен отдельный прогон страницы и зафиксированные условия.</p>\n<h2>Симптомы, причины и действия</h2>\n<div class=\"table-scroll\"><table><caption>Диагностика одного media-слота</caption><thead><tr><th scope=\"col\">Симптом</th><th scope=\"col\">Возможная причина</th><th scope=\"col\">Проверка</th><th scope=\"col\">Действие</th></tr></thead><tbody><tr><td>Маленькая картинка скачивает большой файл</td><td>Неверный <code>sizes</code>, отсутствует подходящий кандидат или CDN всегда отдаёт desktop-вариант</td><td>Сравнить rendered width, выбранный URL, response size и значения <code>srcset</code>/<code>sizes</code></td><td>Исправить mapping или подсказку размера; повторить тот же viewport</td></tr><tr><td>Контент прыгает после загрузки</td><td>Нет известного ratio, контейнер меняет размер или CSS переопределяет рамку</td><td>Проверить DOM и computed layout до и после загрузки в одном сценарии</td><td>Задать корректные размеры или ratio; проверить фактический layout</td></tr><tr><td>Hero появляется поздно</td><td>Ресурс конкурирует с другими запросами, находится далеко в разметке или выбран слишком тяжёлый вариант</td><td>Снять trace с route, viewport, кешем и браузером; найти request и paint-события</td><td>Изменить только один слой: source, композицию или загрузочный путь</td></tr><tr><td>Метка priority не дала ожидаемого эффекта</td><td>Намерение приложения приняли за гарантию планировщика браузера</td><td>Разделить config intent и фактический порядок запросов в trace</td><td>Оставить наблюдаемый результат, проверить конкурирующие ресурсы и не добавлять второй флаг без гипотезы</td></tr><tr><td>Изображение стало резким, но объект обрезан</td><td>Поменяли resolution switching вместо art direction</td><td>Сравнить crop на целевом viewport и описание содержимого в alt</td><td>Использовать отдельный источник для композиции, сохранив fallback</td></tr></tbody></table></div>\n<h2>Иллюстрация границы диагностики</h2>\n<figure><img src=\"/assets/editorial/2022/media-performance-2022-diagnosis-rollback.svg\" alt=\"Диагностическая схема media-слота: симптом разделяется на проблемы источника, геометрии и приоритета, после чего выполняется одна обратимая правка и повторный браузерный прогон\" loading=\"lazy\" /><figcaption>Один симптом может иметь разные причины. Сначала выбирается слой проверки, затем меняется один параметр. Если наблюдение не подтвердило гипотезу, возвращается прежнее значение.</figcaption></figure>\n<p>Схема полезна как ограничитель области. Поздний hero нельзя автоматически объяснить отсутствием размеров. Скачок layout нельзя исправить только сменой формата. Большой response нельзя объявить проблемой priority, пока не проверены кандидат и фактическая ширина слота.</p>\n<h2>Порядок действий</h2>\n<ol><li><strong>Зафиксируйте симптом.</strong> Запишите один URL, один media-слот, viewport, браузер, состояние кеша и наблюдаемое событие. Формулировка «страница медленная» не подходит.</li><li><strong>Опишите контракт.</strong> Укажите содержимое, <code>src</code>, кандидаты <code>srcset</code>, <code>sizes</code>, размеры, alt, предполагаемый crop и намерение critical или deferred. Называйте намерение именно намерением.</li><li><strong>Проверьте данные и разметку.</strong> Убедитесь, что ширина и высота положительны, ratio соответствует изображению, fallback существует, а alt описывает изображение, а не имя файла.</li><li><strong>Проверьте браузерный слой.</strong> Откройте тот же сценарий и сравните фактический rendered width, выбранный ресурс, response, порядок запросов и момент появления. Учебная fixture не заменяет этот шаг.</li><li><strong>Выберите одну гипотезу.</strong> Например: «на ширине 320 пикселей выбирается кандидат 960w из-за неверного <code>sizes</code>». Не объединяйте её с изменением CSS и priority.</li><li><strong>Внесите обратимую правку.</strong> Сохраните прежний source mapping или значение атрибута. Не удаляйте evidence: старое наблюдение нужно для сравнения и отката.</li><li><strong>Повторите прогон.</strong> Используйте те же route, viewport, браузер и cache state. Если гипотеза не подтвердилась, откатите правку и расширьте проверку, а не наслаивайте следующую оптимизацию.</li></ol>\n<h2>Ограничения и отрицательный путь</h2>\n<p>Размеры изображения помогают резервировать место, но не исправляют layout, который меняется из-за шрифта, рекламы, пользовательского состояния или позднего CSS. <code>srcset</code> и <code>sizes</code> уменьшают лишний download только при корректном описании слота и доступных кандидатах. <code>picture</code> решает art direction, но добавляет варианты, которые нужно проверить на содержимое и fallback.</p>\n<p>Не делайте вывод о LCP по времени ответа картинки. LCP — это наблюдение о крупнейшем отрисованном элементе в конкретной загрузке. Запрос мог завершиться раньше paint, а другой элемент мог стать кандидатом. Датированный First Public Working Draft W3C от 24 мая 2022 года описывает API и его ограничения, но не гарантирует результат конкретной страницы.</p>\n<p>Если trace не подтверждает гипотезу, отрицательный путь имеет конкретный вид: вернуть прежнее значение, сохранить условия прогона, отметить гипотезу как неподтверждённую и выбрать следующий слой. Если картинка всё ещё поздняя после уменьшения ресурса, проверяйте композицию страницы и конкурирующие запросы. Если скачок остаётся после добавления размеров, проверяйте реальный контейнер и CSS. Если source стал меньше, но crop ухудшился, откатите source mapping и решайте задачу art direction.</p>\n<h2>Проверяемый критерий готовности</h2>\n<p>Разбор готов, когда для одного слота сохранены четыре вещи: воспроизводимый симптом с условиями; проверенная причина или явно отвергнутая гипотеза; одна правка с понятным откатом; повторный результат в том же сценарии. Для source должны быть видны выбранный URL и размер response. Для геометрии — фактическая рамка до и после загрузки. Для priority — разделённые intent и browser observation.</p>\n<p>Не называйте работу завершённой по формулировке «стало быстрее» и не добавляйте выдуманный процент. Учебный HTML подтверждает только структуру примера. Production-вывод требует реальной страницы, реального браузерного прогона и сохранённого артефакта наблюдения. Такой критерий не обещает, что медиа больше никогда не станет проблемой. Он делает следующую ошибку обнаружимой и позволяет откатить спорную правку.</p>\n<h2>Проверяемые источники</h2><ul><li><a href=\"https://www.w3.org/TR/2022/WD-largest-contentful-paint-20220524/\" target=\"_blank\" rel=\"noopener noreferrer\">W3C: Largest Contentful Paint, First Public Working Draft от 24 мая 2022 года</a> — датированная рабочая версия. Она описывает API и его ограничения, но не гарантирует поведение конкретной страницы.</li><li><a href=\"https://www.w3.org/TR/2017/REC-html52-20171214/semantics-embedded-content.html#the-img-element\" target=\"_blank\" rel=\"noopener noreferrer\">W3C: HTML 5.2 — элемент img</a> — стабильная нормативная версия с правилами для элемента изображения и его атрибутов.</li><li><a href=\"https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images\" target=\"_blank\" rel=\"noopener noreferrer\">MDN: Responsive images</a> — практическая документация по <code>srcset</code>, <code>sizes</code> и art direction через <code>picture</code>.</li></ul>"
}