PageSpeed Insights, шта с тобой случилось?
/* Превью
Напрягаемся и жмём сайт в маленький брелиант, и гугл счастлив. Оптимизация сокрости загрузки сайта
*/
Доброго времени суток %USER_NAME%! В этом материале ты найдешь краткие инструкции по оптимизации скорости загрузки сайта, дабы пройти PageSpeed Insights!
Начнём мы с самого важного, подбора музыки, на этот раз это классика..
PageSpeed Insights уже не тот
PageSpeed Insights старый добрый инструмент от google для оценки качества сайтов и web-приложений.
12 ноября на него накатили мощьное обновление, которое коснулось не только дизайна самого инструмента но и нервов обладателей сайтов! Ведь это обновление наглядно показывает что пока мы живём в 2018 гугл уже в 2666 где на замену кожаным ублюдкам пришли роботы! Или это просто какой то троллинг, так как многие разработчики пишут что зделанные изменения не увеличивают оценку скорости загрузки, либо гугл далеко не сразу замечает изменения.
Замер скорости теперь производится на основе Lighthouse и отчета о пользователях Chrome (CrUX).
- Где Lighthouse, инструмент разработанный тоже в гугл, и вшитый по умолчанию в google chorome, позволяющий производить полный аудит сайта.
Этот инструмент имеет открытый исходный код по этому его используют и некоторые другие замерщики скорости, например gtmetrix - Отчет о пользователях Chrome (CrUX) данные о сайте собранные от различных пользователях и хранящиеся в отдельной базе данных, которая обновляется раз в месяц.
Важно понимать что этот сервис еще обкатывает обновления и периодически выдаёт недоставерную информацию, бывает что при нескольких замерах подряд он выдаёт разброс до 20 балов, а иногда и вовсе не замеряет скорость а выдаёт ошибку backend error. У меня такое было с одним сайтом, помощи в гугл не нашёл, заработало после того когда я убрал пару строчек js кода отвечающего за анимацию загрузки перед появлением контента сайта.
В таких случаях можно пользоватся Lighthouse через браузер chrome, там он работает стабильно.
* Lighthouse, находится в инструментах разработчика (ctrl + alt + i или f12)
Изображения
Используйте современные форматы изображений - говорит инструмент замерки, а это форматы JPEG 2000, JPEG XR, WebP, и тут важно понимать что некоторые пользователи используют браузеры которые не поддерживают ничего современного, по этому выберем формат с наибольшей поддержкой среди браузеров, лучше всех с этим справляется WebP, даже Edge в октябре 2018 начал его поддерживать, но к сожалению IE и Safary не знают о его существовании, с ними разберёмся позже.
Для конвертации и сжатия картинок в webp я использовал онлайн приложение image.online-convert.com, в photoshop к сожалению для сохранения изображений в webp нужно дополнительно приложение, zeplin этого тоже не может, вроде как avocode может.
Кхм, зажимаем японку так сказать, берём изображение с прозрачностью, так как это зачастую нужно для дизайна, и вот что выходит:
Если ваш браузер не поддерживает webp то вы не увидете последнюю японку, а жаль, она самая горячая (:
Исправить это недоразумение можно используя тег picture.
<picture>
<source srcset="img/articles/9m.webp" type="image/webp">
<img src="img/articles/9m_tinypng.png" alt="Alt Text!">
</picture>
Таким образом картинки будут отображаться и на старых и на новый браузерах, на выходе получаем:
Теперь перейдём к стилям, как определить что браузер поддерживает webp для CSS? Для этого нужно использовать JS, а конкретно плагин Modernizr, на сайте этого плагина мы можем выбрать для скачивания только необходимые нам функции, отслеживание поддержки webp, через поиск на странице находим всё связанное с webp и добавляем в сборку, скачиваем и прикручиваем на сайт.
Теперь у нас появляется специальные классы у body, .no-webp и .webp на основе чего мы можем писать следующие стили
.no-webp .elementWithBackgroundImage {
background-image: url("img/articles/9m_tinypng.png");
}
.webp .elementWithBackgroundImage{
background-image: url("img/articles/9m.webp");
}
К счастью гугл не жалуется на формат SVG
Ну и для фула, проверяем включен ли JS на сайте, добавляем класс no-js к html
<html class="no-js">
И скрипт для проверки включенного JS
<script>
document.documentElement.classList.remove("no-js");
</script>
На заметку, проверка поддержки браузером webp с помощью php
if( strpos( $_SERVER['HTTP_ACCEPT'], 'image/webp' ) !== false ) {
// webp is supported!
}
А также определение браузера с помощью JS, webp хорошо работает в Chrome и соответственно в Opera
function GetBrowserAgentName($user_agent) {
if (strpos($user_agent, 'Opera') || strpos($user_agent, 'OPR/')) return 'Opera';
elseif (strpos($user_agent, 'Edge')) return 'Edge';
elseif (strpos($user_agent, 'Chrome')) return 'Chrome';
elseif (strpos($user_agent, 'Safari')) return 'Safari';
elseif (strpos($user_agent, 'Firefox')) return 'Firefox';
elseif (strpos($user_agent, 'MSIE') || strpos($user_agent, 'Trident/7')) return 'Internet Explorer';
return 'Other';
}
Про отложенную загрузку можно почитать тут
Подключение файлов (js, css, html)
Тут есть большое изменение, раньше большинство разработчиков стремились для оптимизации скорости склеить все js файлы в один, как и css, теперь надо наоборот разбивать на файлы в зависимости от важности и устройства на котором открывается сайт.
Если эти правила не будут соблюдены замерщик посчитает это ошибкой и определит подключаемые файлы как блокирующие отображение.
Теперь подробнее
Рекомендуется подключать самые важные влияющие на отрисовку и структуру контента файлы js и css в теге head следующим образом
<head>
...
<link rel="preload" href="styles.css" as="style">
<link rel="preload" href="ui.js" as="script">
...
</head>
Остальные подключаемые файлы должны соответствовать следующим требованиям
блокирующим отображение <script> тег или JS файл становится если:
- <script> находится в теге <head>.
- Не имеет defer атрибута.
- Не имеет async атрибута.
* Атрибут async поддерживается всеми браузерами, кроме IE9, находя скрипт с таким атрибутом браузер будет загружать страницу дальше, а скрипт будет загружатся на фоне, когда он будет загружен то выполнится, не зависимо какой он идёт по очереди.
* Атрибут defer поддерживается всеми браузерами, скрипт тоже подгружается на фоне, но соблюдается порядок подключения скриптов с таким атрибутом, скрипт будет выполнен после обработки всего документа.
блокирующим отображение <link rel="stylesheet"> тег становится если:
- Не имеет disabled атрибута. Когда этот атрибут присутствует, браузер не загружает таблицу стилей.
- Не имеет media атрибута, соответствующего пользовательскому устройству.
блокирующим отображение <link rel="import"> тег становится если:
- Не имеет async атрибута.
Для сжатия эти файлов рекомендую использовать программу Koala.
Подключение шрифтов
Параметр метрики "Время загрузки для взаимодействия" зависит от того как быстро сайт перестал дёргатся и менять размеры блоков, замер этого параметра происходит дополнительно по скриншотам сделанным на протяжения загрузки старницы, их вы можете увидеть в результате теста.
Из чего мы собственно и получаем проблему со шрифтами (и не только), Настройте показ всего текста во время загрузки веб-шрифтов, тоесть пока подгружаются шрифты страница пляшет, исправить это можно следующими настройками
В код подключения шрифта надо добавить параметр font-display который может иметь следующие значения:
- auto - использует значение браузера по умолчанию, обычно block
- block - браузер рисует невидимый шрифт на 3 секунды, как только будет загружен шрифт он добавит его
- swap - браузер выводит текст шрифтом по умолчанию, после загрузки нужных шрифтов заменяет на них
- fallback - так же как и swap но если шрифт не загрузится за 3 секунды то и нафиг его
- optional - как и fallback но если шрифт не уложился в 3 секунды то в зависимости от скорости интернета он или перестанет загружатся или будет загружатся с меньшим приоритете, после загрузки произведёт замену
Судя по всему замерщик ждёт от нас swap, дадим ему его.
@font-face {
font-family: 'Arvo';
font-display: swap;
src: local('Arvo'), url(https://fonts.gstatic.com/s/arvo/v9/rC7kKhY-eUDY-ucISTIf5PesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
}
Раз уж мы добрались до шрифтов, разсмотрим современные форматы для сжатия шрифтов.
Самый софременный формат в вебе это woff2, вооружившись сервисом сжатия font-converter.net мы сжимаем шрифты, и вот что выходит
Подключаем woff2 дополнительным, так как он неподдерживается IE и некоторыми другими браузерами.
Результат не очень, так как на лицо, качество шрифта упало, но вот woff не потерял качества и жикор скинул не плохо.

otf 222кб

woff 121кб

woff2 73кб
Кэширование файлов
Даже если заданы параметры кэширования картинок и скриптов замерщик гугла смотрит на сайт как на говно, почему? Потому что нужно больше времени кэшировани! От месяца до года!
И тут я столкнулся с проблемой, хостинг beget как и многие использует связку nginx и apache, nginx обрабатывает статистические файлы, например js и css, и время жизни кэша Cache-Control указывается в его параметрах а не в .htaccess для apache, доступ к редактированию параметров nginx закрыт, благо beget замечательный хостинг, после переписки с тех поддержкой они перенаправили обработку js и css на Apache. Ошибки кэша пропали но добавилось требование добавить сжатие этих файлов при помощи gzip, deflate или brotli.
В итоге добавляем в .htacces следующий код
# Enable Compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
</IfModule>
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_item_include file .(html?|txt|css|js|php|pl)$
mod_gzip_item_include handler ^cgi-script$
mod_gzip_item_include mime ^text/.*
mod_gzip_item_include mime ^application/x-javascript.*
mod_gzip_item_exclude mime ^image/.*
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>
# Leverage Browser Caching
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType image/webp "access 1 year"
ExpiresByType application/octet-stream "access 1 year"
ExpiresByType application/x-font-otf "access 1 year"
ExpiresByType text/css "access 1 month"
ExpiresByType text/html "access 1 month"
ExpiresByType application/pdf "access 1 month"
ExpiresByType text/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresDefault "access 1 year"
</IfModule>
<IfModule mod_headers.c>
<filesmatch "\.(ico|flv|jpg|jpeg|webp|png|gif|css|swf)$">
Header set Cache-Control "max-age=31536000, public"
</filesmatch>
<filesmatch "\.(html|htm)$">
Header set Cache-Control "max-age=7200, private, must-revalidate"
</filesmatch>
<filesmatch "\.(pdf)$">
Header set Cache-Control "max-age=86400, public"
</filesmatch>
<filesmatch "\.(js|otf|ttf|woff|woff2)$">
Header set Cache-Control "max-age=31536000, private"
</filesmatch>
</IfModule>
Сократите глубину вложенности критических запросов
Не смотря на все попытки, в этом списке остаются подключаемые шрифты. Файлы стилей можно исключить из этого списка выкатив их содержимое в тег style расположенный в head. как вариант можно попробовать добавить атрибут rel="preload", не проверял
Метки и промежутки пользовательского времени (User Timing API)
Как понятно из навзания пункта, это инструмент, вшитый в большенство браузеров для замера скорости выполнения JS скриптов. подробнее
Этот инструмент содержит 2 основных типа методов, одни для внесения данных в замеры, другие для их получения.
Пример замера:
performance.mark("startWork");
doWork(); // Код для замера
performance.mark("endWork");
Получение результатов:
var items = performance.getEntriesByType('mark');
console.log(items)
Как правило один такой замер уберёт этот пункт из PageSpeed Insights
Итог
Таким образом я получил 100 балов загрузки, несмотря на то что остались некоторые ошибки, но и 100 балов далеко не на все страницы из за этих мутотеней со шрифтами и прочее.
…
…
Когда я так прописал у меня вообще перестали стили отображатся