Привет! Меня зовут Андреева Саша, я веб-разработчик в компании iSpring. Два года назад мы столкнулись с тем, что всё больше и больше страниц нашего ведущего сайта начали падать в выдаче, а рост органического трафика заметно уменьшился. Основной причиной было то, что просели показатели сайта — мы постоянно обновляли страницы, но не уделяли должное внимание оптимизации. Мы проанализировали показатели, выбрали инструмент для отслеживания данных по всем страницам, в нём же настроили алерты и взялись за активную работу по оптимизации.
Перед вами рабочий чек-лист, в нём собраны основные наработки и советы по оптимизации, которые мы реализовали и продолжаем применять. Если вы работаете с CMS, то помимо перечисленных, есть дополнительные способы улучшить показатели — спрашивайте в комментариях 🙂
Инструменты для проверки качества оптимизации
Lighthouse выполняет тестирование на одном устройстве и с одной конфигурацией, что даёт точные, но не всегда отражающие реальное поведение пользователя данные.
Core Web Vitals — набор показателей, которые оценивают опыт пользователей на сайте с точки зрения производительности и удобства взаимодействия.
Для проверки показателей мы используем сервис DebugBear, где собрали список нужных страниц, сравниваем их по показателям, периодам и типам устройств. Также показатели можно проверять в PageSpeed Insights и WebPageTest.
При работе с сайтом основное внимание мы уделяли улучшению LCP(Largest Contentful Paint), чуть меньше — FCP (First Contentful Paint) и TBT (Total Blocking Time). Но естественно, оптимизация положительно сказалась и на остальных показателях, чему мы весьма рады 🙂
Оптимизация страницы
1. Картинки
Оптимизация изображений на сайте напрямую влияет на Largest Contentful Paint (LCP): сжатие изображений, предзагрузка картинок первого экрана и использование правильных форматов улучшают показатель.
1.1. Форматы
Для лого и иконок используем формат svg, который позволяет масштабировать изображения без потери качества. Для остальных картинок используем формат webp, который сохраняет качество и при этом сильно уменьшает вес картинки.
Наши размеры для разных экранов:
-
‘img_min_src’ => до 430px
-
‘img_min_src_x2’ => до 430px * 2 для ретины (дисплеев на устройствах Apple)
-
‘img_medium_src’ => до 1920px
-
»img_medium_src’_x2′ => до 1920px * 2 для ретины
-
‘img_large_src’ => для экранов больше 1920
-
‘img_large_src_x2’ => для экранов больше 1920 * 2 для ретины
Обязательно сжимаем картинки, например, с помощью сервиса compresspng или iloveimg. В результате сжатия получаем экономию в 50-70% от веса изображений. В статье про оптимизацию графики для Retina-экранов объясняется, зачем для ретины увеличивать картинки в два раза.
1.2. Автоматическая конвертация изображений.
Мы написали скрипт, который перевел все существующие картинки в формат webp, и конвертирует новые загружаемые png и jpg в webp. Используем библиотку modernizr для проверки на поддержку webp, а для конвертации библиотеку cwebp.
Если интересно узнать подробнее про библиотеку, могу рассказать в комментариях, спрашивайте 🙂
1.3. Тег picture
Применяем тег <picture> для использования картинок в зависимости от размера экрана пользователя. Picture позволяет указать разные изображения для различных размеров экрана или плотности пикселей, чтобы браузер мог выбрать оптимальную версию изображения для каждого пользователя.
Пример использования тега:
<picture class="picture_class"> <source srcset="img_min.png" media="(max-width: 430px)"> <source srcset="img_medium.png" media="(max-width: 1920px)"> <source srcset="img_large.png" media="(min-width: 1921px)"> <img class="img_class" alt="image description" title="image title" width="680" height="530" loading="lazy"/> </picture>
1.4. Лайфхак css
Смотрим на дизайн и, если можно, разбиваем его на элементы. Например, картинку, представленную ниже, лучше разделить на два элемента: сама картинка и зелёный фон. Картинку выгружаем как обычно, а фон рисуем отдельно — псевдоэлементом.
2. Шрифты
Оптимизация шрифтов на сайте влияет на показатели FCP, LCP и CLS(Cumulative Layout Shift):
-
блокировка рендеринга при загрузке веб-шрифтов может задерживать отображение контента,
-
оптимизация загрузки шрифтов напрямую влияет на скорость первичного отображения страницы,
-
отрисовка шрифтов влияет на стабильность макета.
2.1. Оставляем только нужное
Чтобы ускорить загрузку шрифтов, оставляем только используемые языки, необходимые начертания и символы. Такая чистка помогает уменьшить размер шрифта. Убрать лишнее поможет сервис для оптимизации quick-site-upgrade.
2.2. Отрисовка шрифтов
В первые секунды, пока браузер подключает шрифты к странице, пользователь видит тот альтернативный шрифт, который вы указали. В нашем случае это ‘Roboto’ и семейство sans-serif:
$actualFontFamilyRegular: 'Euclid Circular B Regular', 'Roboto', sans-serif; $actualFontFamilyMedium: 'Euclid Circular B', 'Roboto', sans-serif; $actualFontFamilySemiBold: 'Euclid Circular B SemiBold', 'Roboto', sans-serif; $actualFontFamilyBold: 'Euclid Circular B Bold', 'Roboto', sans-serif;
Чтобы увидеть, как шрифт меняется, поставим скорость загрузки страницы на Slow 3G:

Если ваш альтернативный шрифт сильно отличается от кастомного, размер блока будет лишний раз “скакать” и перерисовываться. Поэтому важно максимально близко подобрать размер и начертание шрифта, который отображается до загрузки вашего кастомного, чтобы перерисовка была минимально-заметной.
3. Стили
3.1. Разделение стилей страницы на mobile & desktop
Для стилей всех блоков используем подход Mobile First, а для первого блока выносим в отдельные файлы стили для мобилки и десктопа и подключаем их в зависимости от используемого устройства.
3.2. Critical css
Браузер загружает css до отображения страницы, а это значит, что css блокирует рендер и от него напрямую зависит показатель FCP.

Критичными (critical css) для страницы являются те стили, которые необходимы для отображения первой видимой части страницы. Их стоит вынести инлайново в <head> HTML-документа, что позволит максимально быстро отрисовать содержимое первого экрана для пользователя, а остальные стили можно подгружать позже. Важно сделать это автоматически, чтобы стили сами добавлялись инлайново при сборке или загрузке страницы.
В critical css у нас чаще всего вынесены шрифты, так как именно они занимают бóльшую часть экрана. Если файл шрифтов у вас подключается в css, то обязательно добавьте его в critical css.
4. Отложенная загрузка
Все что можно загрузить отложено, — загружаем отложено. Главное — чтобы это не мешало первоначальной отрисовке страницы. Lazy loading значительно ускоряет начальную загрузку страницы, снимает лишние блокировки основного потока, чем улучшает не только LCP, но и FCP и TBT.
4.1. Картинки
Для картинок, добавленных через тег <img> используем атрибут loading=»lazy». Для остальных картинок и иконок, которые добавляем через background или псевдоэлемент, используем IntersectionObserver и подгружаем картинки при попадании контента в зону видимости пользователя.
Для картинки прописали класс js-lazy-background по которому подключается скрипт lazyLoadBackground:
document.addEventListener('DOMContentLoaded', () => lazyLoadBackground()) const lazyLoadBackground = () => { const lazyBackgroundClass = 'js-lazy-background' const options = { rootMargin: '100px 0px', threshold: 0 } const elements = document.querySelectorAll(`.${lazyBackgroundClass}`) if ('IntersectionObserver' in window) { let observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.remove(lazyBackgroundClass) entry.target.classList.add('active') observer.unobserve(entry.target) } }) }, options) elements.forEach(element => observer.observe(element)) } else { elements.forEach(e => { e.classList.remove(lazyBackgroundClass) e.classList.add('active') }) } }
Важно не прописывать lazyload для картинки в первом экране, так как это замедлит отрисовку. Для тега img в первом экране прописываем fetchpriority=»high» для предзагрузки важных изображений.
4.2. Скрипты
Подключаем скрипты по событию DOMContentLoaded с учётом IntersectionObserver. У тяжёлых элементов подключаем скрипты и стили только когда пользователь доскроллил до элемента.
Стили и скрипты библиотеки слайдера подключаются через скрипт lazyLoadSources:
const lazyLoadSources = params => { const { selector, styles = [], scripts = [], callback, } = params const elements = document.querySelectorAll(selector) if ('IntersectionObserver' in window) { ...
По нужному селектору подключаем библиотечные скрипты и стили для слайдера:
document.addEventListener('DOMContentLoaded', () => { lazyLoadSources({ selector: '.js-slider-industries-container', scripts: [ '/js/lib/tiny-slider/tiny-slider.min.js', ], styles: [ '/css/lib/tiny-slider/tiny-slider.css', ], callback: block => { const controls = '#' + block.nextElementSibling.getAttribute('id') ...
Совет: чтобы можно было отложить загрузку JS, проверьте, как будет выглядеть страница без него прямо в браузере. Если требуется, поправьте стили, чтобы она выглядела аккуратно и без JS:
-
в консоли разработчика откройте командное меню через Ctrl+Shift+P или Cmd+Shift+P,
-
введите Disable JavaScript, выберите данную опцию и нажмите Enter.

5. Кэш
Использование кэша снижает нагрузку на основное хранилище, позволяет сократить время доступа к данным, даёт системе возможность выполнять больше действий одновременно и экономит трафик. Кэширование ресурсов значительно улучшает LCP и FCP, сокращая время до первого рендеринга.
5.1. Кэш на стороне сервера
Используя кэширование, мы генерим страницу один раз и сохраняем результат в памяти на определенный период времени — TTL (Time to live). Пока не истечёт срок действия TTL, клиент будет извлекать сохраненную в памяти версию страницы. Так как релизы проходят не каждый день и контент меняется далеко не на всех страницах, мы установили время кэширования на 7 дней.
Что не стоит кэшировать:
-
куки,
-
хендлеры,
-
корзину и аккаунт,
-
методы post и put,
-
страницы с ценами,
-
данные для залогиненных пользователей.
Если есть возможность, добавляйте кэширование в Memcached или Redis, а не в файлах, так как это увеличивает скорость получения данных. А подробнее про про настройку кэша в статье про Nginx cache.
5.2. Прогрев кэша
После чистки кэша первая отдача страницы пользователю может быть очень долгой, так как страница формируется с нуля. Чтобы долгая прогрузка не портила впечатление пользователя о сайте, мы написали скрипт для автоматического прогрева кэша на мобилки и десктоп.
6. Использование CDN
Мы работаем по всему миру, и если вы тоже, то это мастхэв: CDN (Content Delivery Network) — сеть серверов, расположенных в разных частях мира. Она доставляет контент пользователю (изображения, видео, стили, скрипты) с ближайшего к нему сервера. CDN улучшает скорость загрузки и производительность сайта, а также снижает нагрузку на основной сервер.
Подключаем CDN не только для статики, но для всей станицы, иначе пользы будет мало. Мы используем и рекомендуем платформу Cloudflare: она объединяет в себе CDN и инструменты для оптимизации веб-сайтов.
7. Ускорение кода
7.1. Чистка и упрощение кода
Мы полностью отказались от использования JQuery и привели JS проекта к единообразию, попутно удалив все неиспользуемые скрипты и библиотеки. Скрипты на чистом JS работают быстрее без промежуточного слоя, лучше поддерживаются браузерами и используют меньше зависимостей.
7.2. Замена JS на CSS
Всё, что можно сделать с помощью css, делаем без использования JS. Например, слайдеры можно реализовать с помощью свойства transform, а аккордеон с помощью transition.
7.3. Заглушки вместо блока
Для тяжелых блоков, которые долго прогружаются, ставим заглушку-скелетон. Заглушка даёт пользователю понять, что идет процесс загрузки и он вот-вот получит нужную информацию. Такой подход создаёт более профессиональное впечатление от сайта, и пользователи реже покидают страницу во время загрузки.

Итоги
Показатели, с которых мы начали усиленную оптимизацию, выглядят весьма грустно: 869 страниц требующих улучшений на мобилке и больше сотни на десктопе.
Несколько десятков закрытых задач по оптимизация — и ВЖУХ — мы улучшили показатели для мобилки и десктопа в 8 раз и полностью избавились от страниц с низкой производительностью. Ура!

ссылка на оригинал статьи https://habr.com/ru/articles/914820/
Добавить комментарий