🕸️ Как улучшить Core Web Vitals: самые эффективные методы
|
Существует огромное количество способов улучшения производительности веб-приложений. Однако не все они: - Дают ощутимый эффект.
- Применимы к каждому конкретному проекту.
- Просты в реализации.
- Легко вписываются в рамки существующей инфраструктуры проекта.
Поэтому главной задачей фронтендера становится выбор методов оптимизации, обеспечивающих наилучший результат для конкретного приложения. В этом гайде собраны способы оптимизации, которые: - Максимально влияют на реальные показатели производительности.
- Применимы к большинству сайтов.
- Не требуют радикального изменения инфраструктуры.
- Могут быть реализованы любым фронтенд-разработчиком.
|
«Библиотека программиста» ищет менеджеров контента
| Удаленка || Частичная занятость || Сдельная оплата Нужно: - Создавать контент для ТГ-каналов.
- Развивать комьюнити.
- Знать одну из тем: C#, DevOps, QA.
- Грамотно писать.
Почта для откликов: tatyana@proglib.io. |
INP (Interaction to Next Paint, взаимодействие со следующей отрисовкой)
|
INP – один из самых новых показателей Core Web Vitals. Он показывает, насколько быстро сайт реагирует на взаимодействие с пользователем, и предъявляет более строгие требования к отзывчивости приложения, чем метрика FID, которую он заменил в марте 2024 года. Очень многие сайты не достигают желаемого уровня производительности по этому параметру, но есть три надежных способа улучшить показатель. 1. Разделяйте продолжительные задачи Задачи – это любые отдельные действия браузера: рендеринг, верстка, парсинг, компиляция или выполнение скриптов. Если задача занимает больше 50 миллисекунд, она считается продолжительной и может заблокировать главный поток, замедляя отклик на действия пользователя. Чтобы улучшить скорость реакции, старайтесь: - Выполнять в JavaScript как можно меньше операций.
- Передавать контроль основному потоку выполнения с помощью scheduler.yield(). Это позволяет выполнять продолжительные задачи поэтапно и предотвращает блокировки интерфейса. В результате браузер быстрее выполняет рендеринг и реагирует на действия пользователя.
2. Используйте как можно меньше JavaScript Чем больше JavaScript-кода выполняется на фронтенде – тем выше нагрузка на главный поток, особенно при запуске страницы. Это замедляет отклик на действия пользователя. Для оптимизации можно предпринять следующие шаги: - Используйте стандартные веб-функции вместо собственных аналогов, написанных на JavaScript.
- Найдите неиспользуемый код с помощью инструмента Coverage в Chrome DevTools и удалите его.
- Применяйте разделение кода, чтобы выносить функциональность, не требующуюся для первичного отображения страницы, в отдельные бандлы.
- Оптимизируйте теги в менеджере тегов, удаляя устаревшие теги с неиспользуемым кодом, чтобы уменьшить объем загружаемого JavaScript.
3. Избегайте масштабных обновлений страниц Помимо выполнения JavaScript, на отклик страницы влияет рендеринг – при крупных обновлениях страницы отклик на действия пользователя замедляется. Чтобы рендеринг не превращался в длительные задачи: - Оптимизируйте операции с DOM. Правильная организация операций чтения и записи поможет избежать forced layout (принудительного пересчета макета) и его «тряски» (layout thrashing, когда JavaScript многократно и беспорядочно считывает и перезаписывает элементы DOM).
- Уменьшайте размер DOM. Старайтесь держать DOM-дерево компактным и удалять неиспользуемые элементы. Чем меньше размер DOM, тем быстрее работает рендеринг.
- Используйте CSS-свойство contain для отложенного рендеринга скрытого контента, чтобы изолировать сложные элементы и сократить ненужные перестройки и рендеринг. Хотя это не всегда простое решение, оно значительно улучшает производительность.
|
LCP (Largest Contentful Paint, скорость отрисовки самого большого элемента)
|
Эта метрика определяет, как быстро загружается самый большой элемент на странице. Обычно это картинка, видео или блок текста, который первым привлекает внимание пользователя. По данным Chrome UX Report, 40% сайтов испытывают трудности с достижением хороших показателей LCP. Команда Chrome выявила следующие интересные факты: - 72% страниц в качестве LCP-элемента используют изображение.
- У большинства сайтов с плохим LCP только 10% времени тратится непосредственно на загрузку LCP-изображения.
- На страницах с плохим LCP задержка загрузки изображений составляет около 1,290 миллисекунд (75-й перцентиль) – это больше половины допустимого времени для быстрой загрузки.
- 39% LCP-изображений нельзя обнаружить в начальном HTML-ответе.
Все эти проблемы можно решить с помощью нескольких оптимизаций, но перед их реализацией стоит убедиться, что приложение не ждет полной загрузки CSS или JavaScript перед началом загрузки изображений. 1. Оптимизируйте загрузку LCP-элемента Если ваш LCP-элемент – это изображение, URL изображения должен быть обнаружен в HTML-ответе, чтобы сократить задержку загрузки ресурса. Вот несколько рекомендаций, как этого добиться: - Загружайте изображение с помощью элемента <img> с атрибутами src или srcset. Не используйте нестандартные атрибуты, такие как data-src, которые требуют JavaScript для отображения: этот подход всегда работает медленнее. На 9% страниц LCP-изображение скрыто за data-src.
- Предпочитайте серверный рендеринг (SSR) клиентскому (CSR), так как SSR подразумевает, что вся HTML-разметка (включая изображения) присутствует в исходном коде HTML. CSR-решения требуют выполнения JavaScript перед тем, как изображение станет доступным.
- Если изображение нужно указать через внешний CSS или JS файл, его все равно можно добавить в HTML с помощью тега <link rel="preload">. Заметьте, что изображения, указанные через встроенные стили, не обнаруживаются браузером заранее, даже если они есть в HTML-источнике, поэтому их обнаружение может быть заблокировано загрузкой других ресурсов. В таких случаях тоже поможет предзагрузка.
Чтобы дополнительно ускорить загрузку LCP- элемента и задать ему высокий приоритет: - Добавьте атрибут fetchpriority="high" к тегу <img> или <link rel="preload"> для LCP-изображения. Это увеличит приоритет ресурса изображения, и оно начнет загружаться раньше.
- Уберите атрибут loading="lazy" из тега <img> для LCP-изображения. Это предотвратит задержку загрузки, вызванную проверкой видимости изображения в пределах экрана.
- Отложите загрузку некритичных ресурсов, если это возможно. Перемещение этих ресурсов в конец документа, отложенная загрузка второстепенных изображений и фреймов или их асинхронная загрузка с помощью JavaScript помогут ускорить загрузку LCP-изображений.
2. Стремитесь обеспечить мгновенную готовность к навигации Моментальная загрузка предварительно отрендеренных страниц обеспечивает идеальный опыт: пользователь может перейти в нужный раздел с практически нулевым LCP. Для этого используются две основные техники – восстановление и предсказание: - Восстановление страниц. Когда пользователь возвращается на ранее посещенную страницу, она мгновенно загружается из кэша, сохраняя исходный вид. Это возможно благодаря кэшу «назад-вперед» (bfcache). Для этого убедитесь, что страницы соответствуют критериям для использования bfcache. Частые причины, по которым страницы не соответствуют этим требованиям, – это директивы кэширования no-store или наличие обработчиков событий unload.
- Предсказание следующей страницы. С помощью Speculation Rules API можно предсказать, куда пользователь перейдет дальше. Если прогноз верен, следующая страница уже будет загружена и готова к отображению. Аналитические данные помогут точнее предсказать, у каких страниц наибольшая вероятность посещения.
3. Используйте CDN для оптимизации Time to First Byte (TTFB) TTFB – это время до получения первого байта ответа от сервера. Его сокращение поможет быстрее начать загрузку всех ресурсов страницы. Лучшие способы для улучшения TTFB: - Размещайте контент как можно ближе к пользователям, используя CDN.
- Кэшируйте статические HTML-документы даже на короткое время.
- Рассмотрите возможность переноса логики с сервера на CDN, чтобы ускорить доставку контента.
CDN ускоряет загрузку, распределяя контент по серверам по всему миру, снижая задержки и улучшая показатель LCP. |
CLS (Cumulative Layout Shift, совокупный сдвиг макета)
|
Эта метрика измеряет визуальную стабильность макета. Высокий CLS говорит о том, что элементы интерфейса часто или сильно смещаются на странице во время ее загрузки. Вот несколько рекомендаций по снижению CLS и улучшению визуальной стабильности страницы. 1. Устанавливайте размеры для загружаемого контента Часто смещение макета происходит, когда новые элементы (например, изображения) появляются после загрузки страницы и сдвигают уже загруженный контент. Поэтому: - Указывайте ширину и высоту для изображений. Это предотвратит резкое изменение размеров, так как браузер заранее зарезервирует место для изображения.
- Используйте CSS-свойство aspect-ratio для указания соотношения сторон элементов (не только изображений). Это позволяет устанавливать динамическую ширину, а браузер автоматически рассчитает высоту.
Если точный размер элемента неизвестен, можно установить минимальную высоту (min-height). Это уменьшит резкое изменение размера элемента, позволив странице стать более стабильной. 2. Обеспечьте совместимость страниц с кэшем bfcache Если страница совместима с bfcache, это может значительно улучшить CLS, так как весь контент остается на месте при возвращении на страницу. 3. Не используйте элементы, анимации и переходы, которые вызывают смещения макета Некоторые элементы, например, баннеры с рекламой и уведомлениями, которые появляются сверху или снизу и смещают другие элементы, могут ухудшить CLS. Чтобы избежать этого: - Не анимируйте CSS-свойства, влияющие на макет, такие как margin или border. Вместо этого используйте transform: translateX() или translateY() для перемещения элементов. Эти свойства не изменяют макет страницы и не вызывают смещения.
- Избегайте анимации CSS-свойств, при которой требуется перерисовка макета. В случае необходимости такую анимацию можно сделать для реакции на тап или нажатие клавиши, но не для hover.
|
Метрики LCP, INP и CLS помогают оценить самые важные аспекты взаимодействия и визуальной стабильности приложения. Улучшение этих параметров не только повышает скорость загрузки и отзывчивость интерфейса, но и способствует росту доверия пользователей, улучшению SEO-показателей и удержанию аудитории. |
⏭️ Перенаправление в Next.js: redirect() vs router.push()
|
Источник В Next.js есть два основных способа* программно перенаправить пользователя на другую страницу – router.push() и redirect(). Эти методы на первый взгляд кажутся похожими, и многие разработчики приходят в замешательство, как и в каких именно случаях их нужно использовать. | Этот метод используется внутри клиентских компонентов Next.js для перенаправления пользователя на другую страницу. Он вызывается через объект router, который получается с помощью хука useRouter(): |
router.push() работает только на клиенте, не вызывает перезагрузку страницы и добавляет свои действия в History API, так что между ними можно переходить с помощью стандартных кнопок браузера «вперед» и «назад». Этот способ идеально подходит, когда нужно выполнить переход в результате взаимодействия пользователя с компонентом, например, при нажатии на кнопку. |
Этот метод применяется в серверных функциях, таких как getServerSideProps, или в API-маршрутах, когда нужно выполнить перенаправление еще до того, как страница загрузится на клиенте. В клиентских компонентах redirect() можно использовать только во время рендеринга и не в обработчиках событий. В отличие от router.push(), функция redirect() используется в более сложных сценариях, например: - Редиректы на основе состояния сервера.
- Автоматические перенаправления после успешной аутентификации.
- Обработка ошибок на уровне маршрута.
|
Использование redirect в блоке try/catch
|
В Next.js при использовании функции redirect() есть одна особенность: она выбрасывает исключение NEXT_REDIRECT. Это исключение обрабатывается самим фреймворком, который выполняет перенаправление пользователя на указанный адрес. Однако, если вы вызываете redirect() внутри блока try/catch, ваш catch перехватит это исключение и может помешать фреймворку выполнить перенаправление. Если у вас есть блок finally, redirect() можно разместить в нем – там он не помешает срабатыванию перенаправления. |
При использовании функции redirect() в Next.js важно учитывать, что ее поведение зависит от контекста, в котором она вызывается. Вот в чем состоит различие: - Если redirect() используется в обработчике маршрута (например, на сервере в API-роуте), то браузер получает HTTP 307 для перенаправления. Это стандартный HTTP-ответ, который указывает браузеру перенаправить пользователя на другой URL.
- Если redirect() используется в серверной функции (например, в функции с use server), то ответ от сервера будет HTTP 303. В этом случае Next.js отправляет в ответе данные для следующей страницы, и это приводит к тому, что границы Suspense на следующей странице не сработают. Почему? Потому что React будет исполнять серверную функцию и полностью рендерить следующую страницу сразу в одном потоке. Ответ приходит только после полной отрисовки следующей страницы, и Suspense для этой страницы не применяется. В этом примере при использовании redirect("/thank-you") Suspense на следующей странице не будет работать, так как вся страница возвращается только после полной отрисовки:
|
Если вам важно использовать Suspense на следующей странице, лучше организовать перенаправление с клиентской стороны с помощью router.push(). В этом случае процесс будет выглядеть так: - Выполните серверную функцию с клиента.
- После успешного выполнения функции вызовите router.push() для перенаправления.
|
Когда использовать router.push(), а когда – redirect()
|
- router.push() лучше всего использовать в обработчиках событий (например, при клике на кнопку) в клиентских компонентах. Это обеспечивает плавное перенаправление без перезагрузки страницы, работающее на стороне клиента.
- redirect() следует использовать в серверных компонентах, серверных функциях и обработчиках маршрутов.
|
|
|
Понравилась ли вам эта рассылка? |
|
|
Вы получили это письмо, потому что подписались на нашу рассылку. Если вы больше не хотите получать наши письма, нажмите здесь.
|
|
|
|