Ускорение работы сайта. Как мы победили Google Pagespeed и превзошли Lighthouse

 
 
Что позволяет ускорить работу сайта?
 
Как вы думаете? Хостинг, чистый код, кэш, сжатые картинки, gzip, или...
 
Разберемся с этим!
 
 
В конце статьи, увидите реальные замеры...
 
Это показатели, которых мы добились.
 
 

1. Хостинг, сервер

 
Разумеется есть сервера быстрее и медленнее. 
Однако, это незначительные доли секунды, которые мизер, - в сравнении с временем обработки алгоритмов сайта.
Если ваш проект БОЛЬШОЙ, то стоит обратить внимание на CDN (Content Delivery NetWork). 
Они позволят доставлять контент по континентам весьма быстро.
 
Элементарные рейтинги и отзывы хостингов досаточны для принятия решения!
 
Для своих проектов, мы остановились на SPRINTHOST
 

2. Как держать код HTML в простоте и чистоте

 
Для себя выбрали подход минимализма... Однако, не всем подойдет такое мышление. 
Вы можете быть не согласны и это нормально.
 
Суть: чем меньше символов в html тем лучше! 
 

Длинные списки с минимум кода

 
Особенно важно сократить html для длинных списков:
 
  • товарные позиции
  • ветки отзывов
  • разделы каталога
  • другие списки
 
Пример рядового кода товарной позиции в каталоге:
 
<li class="catalog-item">
            <div class="catalogCard">
        <div class="catalogCard-box j-product-container" data-id="36305">

            <div class="catalogCard-main">
                <div class="catalogCard-main-b">
                    <a class="catalogCard-a" href="/1833-samsung-galaxy-s10/chekhol-knizhka-led-view-cover-dlya-samsung-galaxy-s10-g973-ef-ng973pgegru/">
                        <div class="catalogCard-image">
                            <div class="catalogCard-image-i">
                                                                                                     <img alt="Купить Чехол-книжка LED View Cover для Samsung Galaxy S10 (G973) EF-NG973PGEGRU" class="catalogCard-img" width="233" height="215" src="/images/6/chekhol-knizhka-led-view-cover-dlya-samsung-galaxy-s10-g973-ef-ng973pgegru-17136212644987_small4.png">                                                             </div>
                        </div>
                                                                            
                                                                                                </a>
                    <div class="catalogCard-info">
                                                    <div class="catalogCard-meta">
                                <div class="catalogCard-code">Артикул: 216623G</div>
                                                                                                                                                                    </div>
                        
                        <div class="catalogCard-title"><a href="/1833-samsung-galaxy-s10/chekhol-knizhka-led-view-cover-dlya-samsung-galaxy-s10-g973-ef-ng973pgegru/">Чехол-книжка LED View Cover для Samsung Galaxy S10 (G973) EF-NG973PGEGRU - Green</a></div>
                        <div class="catalogCard-purchase">
                                                            <div class="catalogCard-priceBox">
            <div class="catalogCard-price isOldPrice">1 899 грн</div>
<div class="catalogCard-oldPrice">2 099 грн</div>
</div>                            
                                                                                                <div class="catalogCard-order">
                                        <a class="btn __special j-buy-button-add" data-skin="default" id="j-buy-button-widget-36305" data-gift="0" href="javascript:void(0);">
            <span class="btn-content">Купить!</span>
        </a>                                    </div>
                                                                                    </div>
                    </div>
                </div>
            </div>

        </div>
    </div>        </li>
 
Пример нашего кода:
 
<div id="p5631" class="p "> 
 <a href="/samsung-s9/polnoekrannoe-steklo-mocolo-samsung-galaxy-s9"> 
 <u class="d">-25%</u> 
 <img alt="Защитное стекло Mocolo 3D на весь экран для Samsung Galaxy S9" src="/_media/files/img_products/polnoekrannoe-steklo-mocolo-samsung-galaxy-s9-22585.jpg"> 
 <b>Защитное стекло Mocolo 3D на весь экран для Samsung Galaxy S9</b> 
 <div class="in">В наличии</div> 
 <big> <i class="pn">178 грн</i> <s>235 грн</s> </big> 
 <span class="buy">Купить</span> 
 </a> 
</div>
 
Теперь представьте, что код тиражируется 50 раз, при построении списка!
 
Визуальное отображение (количество данных), почти идентично. Смотрите пример:
 
пример оптимизированной карточки товара
 
 
 
Полагаем, идея понятна.
 
Что мы делали:
  1. Использовали в селекторе класса всего один символ "p".
  2. Минимум вложенности по DOM иерархии
  3. Стремились даже теги сокращать. Тщательно выбирали между DIV и B,I,U,S...
  4. После формирования HTML убирали лишние символы пробелов и переносов строки.
  5. Некоторые вставки кода рендерили на стороне клиента.
 
Вы скажете: "Ну, это уже перебор!".
 
Все верно, - не каждому понятна наша философия :)
 
По поводу рендеринга на стороне клиента.
 
Роботы поисковых систем отслеживают работу JS, и понимают весь процесс построения DOM документа.
 
Нет смысла переживать за SEO недочеты.
 
Смело передавайте JSON объекты и рисуйте HTML на стороне клиента (такой же подход приемлем для мобильных версий сайтов).
 
Ваша страница товара будет занимать всего несколько байт:
 
<script>
 var prod = {
       id: 6839,
       a: "p6839",
       atts: {
        "at91": {id:91,t:"Золотой",c:2,p:198,d:0,a:"golden",im:"full_knizhka-nillkin-samsung-s9-27048.jpg"},
        "at11": {id:11,t:"Серый",c:1,p:198,d:0,a:"grey",im:"full_knizhka-nillkin-samsung-s9-27050.jpg"},
        "at4": {id:4,t:"Розовый",c:0,p:198,d:0,a:"pink",im:"full_knizhka-nillkin-samsung-s9-27051.jpg"}
       },
       im: "/_media/files/img_products/full_knizhka-nillkin-samsung-s9-27048.jpg", 
       p: 198, 
       t: "Чехол-книжка Nillkin Sparkle для Samsung Galaxy S9", c: 2,sel: "at91"
     },
     attr = { id: 91 };
</script>
 

SVG в отдельный файл, сжать и кэшировать

 
SVG - это прогрессивный формат графики.
 
Лучше перевести все иконки и логотипы в SVG. 
 
А вот вставлять содержимое векторной графики в HTML не рекомендуется. 
 
Для графики мы создали отдельный svg.js файл. В нем был объект с алиасами необходимых иконок. 
 
После завершения загрузки страницы вставляем SVG в наш HTML.
 
Примерно так это выглядит:
 
JS 
 
var svg = {
    'foreign' : '<svg xmlns="http://www.w3.org/2000/svg" width="1308" height="1833" viewBox="0 0 1308 1833" fill="none"><g filter="url(#A)"><path transform="rotate(90 1288 20)" fill="#fff" d="M1288 20h1793v1268H1288z"/></g><defs><filter id="A" x="0" y="0" width="1308" height="1833" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"><feFlood flood-opacity="0" result="A"/><feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/><feOffset/><feGaussianBlur stdDeviation="10"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"/><feBlend in2="A"/><feBlend in="SourceGraphic"/></filter></defs></svg>',
    'hamburger' : '<svg xmlns="http://www.w3.org/2000/svg" height="32" width="32" viewBox="0 0 32 32"><path d="M4 10h24a2 2 0 1 0 0-4H4a2 2 0 1 0 0 4zm24 4H4a2 2 0 1 0 0 4h24a2 2 0 1 0 0-4zm0 8H4a2 2 0 1 0 0 4h24a2 2 0 1 0 0-4z"/></svg>',
    'close' : '<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" viewBox="0 0 48 48"><path d="M38 12.8L35.2 10 24 21.2 12.8 10 10 12.8 21.2 24 10 35.2l2.8 2.8L24 26.8 35.2 38l2.8-2.8L26.8 24z"/></svg>'
}

var svgclass = {
	'check' : '<svg xmlns="http://www.w3.org/2000/svg" width="41" height="41" viewBox="0 0 41 41"><path d="M20.5 0C9.2 0 0 9.2 0 20.5S9.2 41 20.5 41 41 31.8 41 20.5 31.8 0 20.5 0zm-3.8 31l-9-9 3-3 6 6 13.5-13.5 3 3L16.7 31z"/></svg>',
	'close' : '<svg xmlns="http://www.w3.org/2000/svg" width="52" height="49" viewBox="0 0 52 49" stroke-miterlimit="10"><path d="M26 48c14 0 25-10.5 25-23.5S40 1 26 1 1 11.5 1 24.5 12.2 48 26 48z"/><g stroke-linecap="round"><path d="M14 13.3L38 35.6"/><path d="M38 13.3L14 35.6"/></g></svg>'
}

function e(i){return document.getElementById(i)}

function drwsvg(){
  for(var k in svg){
    if(e(k+'svg') !== null) e(k+'svg').innerHTML = svg[k]; 
    if(e('f'+k+'svg') !== null) e('f'+k+'svg').innerHTML = svg[k]; 
  }

  for(var k in svgclass){
    collection = document.getElementsByClassName(k+'svg');
    for(var i in collection){
      collection[i].innerHTML = svgclass[k];
    }
  }
}

drwsvg();
 
HTML 
В контейнеры помещается svg графика из JS файла (при рендеринге).
 
<i class="checksvg"></i>

<i id="supportsvg"></i>
 

Дополнительный функционал загружать только по требованию

 
Печально, что на многих сайтах попап окна присутствуют на десятках тысяч страниц. 
 
Кому они там нужны? 
 
Из 100 пользователей едва ли 1 хочет оформить подписку. 
 
Из 1000 едва ли 2 найдется кто захочет добавить себя в список ждущих поступления товара.
 
Ориентируйтесь на поведение большинства на своем ресурсе. 
 
Если видите что некоторый функционал является дополнительным, а не крайне необходимым, - лучше вынесите его на событие и AJAX подгрузку.
 
 

3. Уберите CSS, JS мусор. Откажитесь от Bootstrap и прочих фреймворков...

 
Jquery плагины, фреймворки и готовые решения ускоряют работу программиста.
Но, если вы стремитесь создать великолепный "продукт", стоит избегать излишнего мусора в приложении. 
 
Как правило фреймворки, и плагины избыточны. Их весь функционал не нужен для наших потребностей. 
К тому же, всегда в них что-то работает "не по техзаданию". 
 
Для своих проектов мы решили использовать урезанный jQuery (27kb в сжатом виде), и больше ничего стороннего.
 
Нам нужны были:
 
  • селекторы
  • работа с DOM
  • AJAX запросы
 
Все! Больше - уже лишнее.
 
Вся анимация была вынесена на сторону CSS (transition, animate). Запускали ее через добавление и удаление class.
 
На практике все работало быстрее, красивее, глаже.
 
К тому же это сокращает время разработки и сам код.
 
Однозначно после завершения разработки CSS файлы нужно соединить в один и сжать код.
 
То же самое проделать с JS кодом.
 

Как писать краткий и понятный CSS?

 
Мы писали по аналогии HTML, свой подход описывали выше. 
 
Старались выбирать краткие теги: a,b,i,u,s,li,ul,ol,big,div.
 
Также группировали стили под единый (весьма краткий) #ID блока к которому он принадлежит. Своего рода namespace получался. 
 
Так выглядит сложное четырехуровневое выпадающее меню (CSS код).
 
Со всеми анимациями и различными состояниями на страницах.
 
#mm > li,#mm > li > a{display:block;height:36px;line-height:36px;white-space:nowrap;font-size:1.1rem;text-decoration:none;color:#000;transition:.2s;font-style:normal;cursor:pointer}
#mm li b,#mm li a b{display:inline-block;height:36px;width:50px;float:left}
#mm li b svg,#mm a b svg{margin:7px 14px;width:22px;height:22px;fill:#3A6EA5}
#mm > li:hover{cursor:pointer;background:#fff}
#mm > li:hover > a{color:#3A6EA5;font-size:1.2rem;transition:.2s}
.s-m{width:400px;height:100%;background:#fff;position:absolute;top:0;left:190px;overflow-y:hidden;overflow-x:hidden;visibility:hidden;opacity:0;padding-left:0;z-index:3;transition:.2s;transition-delay:.3s}
#mm li:hover > .s-m{width:810px;visibility:visible;opacity:1;transition:.5s;transition-delay:.5s;z-index:3;box-shadow:0 2px 1px 1px #ddd,600px 0 0 0 rgba(255,255,255,0.97)}
#shm.abs #mm li:hover > .s-m{box-shadow:0 2px 1px 1px #ddd}
.s-m ul{height:370px;padding:10px 0;width:150px!important;margin-top:0!important;margin-left:10px;border-left:0!important;list-style:none;overflow-y:auto;overflow-x:hidden;float:left}
.s-m ul li{cursor:pointer}
.s-m ul li.extra{color:#3A6EA5!important;padding-left:10px;height:40px;line-height:40px}
.s-m ul li.ex{display:none}
.s-m ul li ul,.s-m ul li ul li ul{width:430px!important;visibility:hidden;opacity:0;transition:.2s;position:absolute;padding-left:10px!important;left:115px;top:0;overflow-y:auto;overflow-x:hidden}
.s-m ul li ul li ul{width:260px!important;background:#fff;padding-left:10px!important;box-shadow:-1px 0 0 #eee;left:130px;margin-top:0!important;top:0;overflow-y:auto;overflow-x:hidden}
.s-m ul li ul li ul li{padding-left:0}
.s-m ul li a{height:30px;line-height:30px;white-space:nowrap;overflow:hidden;display:block}
.s-m ul li:hover ul.series{visibility:visible;opacity:1;transition:.3s;transition-delay:.3s;left:145px}
.s-m ul li:hover ul li:hover ul{visibility:visible;opacity:1;transition:.3s;transition-delay:.3s;left:160px}
.s-m ul::-webkit-scrollbar{width:4px}
.s-m ul::-webkit-scrollbar-track{background:#eee;box-shadow:inset 0 0 0 1px #fff}
.s-m ul::-webkit-scrollbar-button{background:#fff;height:10px}
.s-m ul::-webkit-scrollbar-thumb{background:#ccc;border-radius:8px}
.s-m ul li a,.s-m ul li ul li a,.s-m ul li ul li ul li a{color:#000;padding-left:10px;font-size:1.1rem;transition:.1s}
.s-m ul li,.s-m ul li ul li,.s-m ul li ul li ul li{font-size:1.1rem!important;color:#000}
.s-m ul.brends li ul.series li ul li:hover > a,.s-m ul.brends li ul.series li:hover > a,.s-m ul.brends li:hover > a{color:#3A6EA5;background:linear-gradient(to right,rgba(142,152,167,0.1),rgba(255,255,255,0) 50%);transition:.2s;font-size:1.3rem}
.s-m ul.brends li ul.series li:hover > a{background:linear-gradient(to right,rgba(142,152,167,0.1),rgba(255,255,255,0) 25%)}
.s-m ul li a:hover{text-decoration:none}
.s-m .sp{display:block;position:absolute;width:190px;height:calc(100% - 10px);top:0;right:20px;background-repeat:no-repeat;background-position:bottom right;background-size:contain}
.s-m .sp ul{width:190px!important}
.s-m .sp ul li{padding-left:0}
.s-m .sp ul li a{padding-left:0;color:#3A6EA5;font-size:1.1rem}
 
Визуально:
 
сжатое меню сайта
 
 
Такой же подход был применен для всех блоков и модулей сайта.
 
Абсолютно весь CSS код в сжатом виде не занимал 5 KB.
 
Для сравнения, - проверьте сколько весят ваши CSS файлы.
 
Углубляясь в тему, изучите как писать быстро обрабатываемый css код.
 

4. Графика сайта (изображения)

 
  • Видимый размер картинок должен совпадать с реальным физическим на диске.
  • Современные форматы и сжатие (до 150 - 200 kb).
  • Для разных устройств и дисплеев свои разрешения.
  • Кэш на максимально длительный период.
  • Lazy Load при многочисленной графике.
 
Гугл дает весьма результативные советы. Просто следуйте им. Мы поступили так же.
 

5. Серверная часть, скорость ответа сервера.

 
Некоторые алгоритмы менять весьма проблематично. Особенно когда вы пользуетесь готовыми движками. 
 
Самое простое - это настроить кэширование.
 
По крайней мере для нагруженных и популярных страниц.
 
Мы кэшировали всю страницу. Динамические данные выносили на асинхронную подгрузку (Залогиненый пользователь или нет, результаты поиска). 
 
Блоки, которые редко изменяются (меню, футер...) генерировали в файл, который просто подключали через include.
 
По тестам это был самый продуктивный способ.
Возможно вы знаете лучший? Расскажите, мы готовы к дискуссии.
 

Вот что получилось 

 
Мы не утверждаем что наш подход единственный верный путь. 
 
Просто делимся своим опытом.
 
Такие результаты мы получили на сложных (обратите внимание!) страницах
 

Данные Google Pagespeed

 
Для Desktop
 
увеличение показателя google pagespeed для ПК
 
 
Для Mobile
 
Увеличения показателя pagespeed для mobile
 

Данные Lighthouse

 
Для Desktop
 
lighthouse данные
 
 
Для Mobile
 
данные lighthouse по загрузке на мобильном
 
 
Если у вас есть вопросы по отдельным пунктам, - дайте знать.
 
Мы рады всему, и критике также!
 
Все предложения, замечания пишите в комментарии.
 


Дальше: Mysql LEFT JOIN : примеры запросов, схемы, объяснение


Дискуссия по теме     0 Комментариев
Добавить комментарий
Просмотров: 183