Google PageSpeed: CSS стили и JavaScript скрипты, блокирующие загрузку страницы на WP

В этом посту будет подразумеваться, что вы знакомы с инструментом Google по оптимизации скорости загрузки страниц сайта — PageSpeed Insights. Слушайте, да прямо сейчас вбейте туда свой сайт нажмите кнопку «Analize».

Окей, а теперь — о чём этот пост?

Вполне возможно, что в результатах проверки вашего сайта есть пункт «Eliminate render-blocking JavaScript and CSS in above-the-fold content».

Eliminate render-blocking JavaScript and CSS - по результатам проверки в PageSpeed Insights

Я заметил, что этот пункт один из самых трудноразрешимых (трудоёмких) и практически на всех сайтах, даже на очень быстрых, он присутствует.

Как его исправить в теории:

  1. Объединяем все JavaScript файлы и размещаем то, что получилось перед закрывающим тегом </body> сайта.
  2. Объединяем все CSS, суём прямо перед JavaScript, которые мы уже переместили, затем выбираем из них те стили, которые необходимы для корректного отображения страницы, а в особенности её верхней части (первого экрана) и помещаем их в тег <style> в <head> сайта.

Как же обстоит дело на практике, и в данном конкретном случае — для сайтов на WordPress?

1. Воспользуемся зависимостью других скриптов от jQuery

В корректно состряпанной теме WordPress все CSS и JS файлы подключаются через wp_head() и wp_footer() — то есть в <head> и в конце </body> соответственно.

Также у файлов есть зависимости, то есть например плагин fancybox.js должен подключаться после jquery.js, а это значит, что если библиотека jQuery находится в wp_footer(), то FancyBox ну никак не может попасть в wp_head().

Перемещаем jQuery в футер сайта

Делается это очень просто — при помощи функций wp_deregister_script(), wp_register_script(), wp_enqueue_script() и хука wp_enqueue_scripts (иногда используют хук init в связке с is_admin()). Всё, что требуется от вас, это вставить код следующего содержания в файл functions.php вашего сайта.

add_action('wp_enqueue_scripts', 'true_peremeshhaem_jquery_v_futer');  
 
function true_peremeshhaem_jquery_v_futer() {  
 	// снимаем стандартную регистрацию jQuery
        wp_deregister_script('jquery');  
 
        // регистрируем для подключения в футере, описание параметров - в документации функции (ссылка чуть выше)
        wp_register_script('jquery', includes_url('/js/jquery/jquery.js'), false, null, true);  
 
	// подключаем
        wp_enqueue_script('jquery');  
 
}

Хочу обратить ваше внимание на то, что это автоматизированное решение, и хотя оно работает практически в 100% случаев, бывает такое, что некоторые скрипты не хотят переноситься в футер сайта. Тогда уже потребуется более внимательный к каждому вашему файлу JavaScript.

На этом наша работа с JS заканчивается, конечно прирост в скорости даст ещё и объединение скриптов (то есть снимаете их все с регистрации и потом просто подключаете свою объединенную версию) — но Google сейчас это уже не требует.

2. Объединение CSS в WordPress

Если объединение всех JavaScript в один файл — не всегда хорошая идея, то CSS-ки я бы рекомендовал объединять по возможности всегда.

Помните скриншот в самом начале статьи (10 blocking CSS resources)? Откуда берется такое количество файлов стилей, ведь разработчик темы наверное понимал, что делает?

Ответ — из плагинов.

Например плагин «Contact Form 7» подключает свою собственную таблицу стилей, и хотя сама по себе она невелика, то лучше всё же избежать лишних HTTP-запросов.

Давайте пошагово разберем как.

  1. Копируете содержимое таблицы стилей плагина и вставляете его в конец основного файла стилей — style.css.
  2. Проверяете, проставлены ли в данных стилях относительные ссылки на изображения, например url('images/load.gif'). Если да, то либо заменяете их на абсолютные, либо переносите изображения из плагина в папку с темой.
  3. Заходите в настройки плагина и смотрите, есть ли возможность где-нибудь снять галочку и не подключать CSS плагина. В «Contact Form 7» такой возможности нет, а значит мы переходим к следующему пункту.
  4. Отрубаем файлы через functions.php. Для стилей «Contact Form 7» код будет следующий:
    add_action( 'wp_print_styles', 'true_otkljuchaem_stili_contact_form', 100 ); // по идее вы можете использовать и хук wp_enqueue_scripts, хотя конкретно его я не тестировал
     
    function true_otkljuchaem_stili_contact_form() {
    	wp_deregister_style( 'contact-form-7' ); // в параметрах - ID подключаемого файла
    }

Также иногда при помощи условных тегов файлы плагинов (как CSS, так и JS) отключают только с тех страниц, на которых они не используется.

Ок, с «Contact Form 7» разобрались, а как узнать ID файлов CSS других плагинов?

Да легко, открываем исходный код страницы и видим там подобную картину:

ID файла CSS в WordPress

Также есть плагин, который позволит выполнить объединение CSS и JavaScript автоматически — JS & CSS Script Optimizer.

Если у вас остались вопросы, либо я забыл упомянуть о чем-либо в этой статье, пожалуйста, оставьте свой комментарий.

Подпишитесь, чтобы раз в неделю получать свежие статьи с блога по email.

Ещё про ускорение сайта

Комментарии 27

  • вадик12 июня 2015 в 16:06 #

    вообще да проблема с этими джаваскриптами и цсс, чуть ли не каждый плагин норовит впихнуть по файлу а то еще и шрифты подключает. а если уж посмотреть современные темы вордпресс - то там вообще миллион файлов цсс, джава, шрифты.

    а еще некоторые плагины пихают в код между хеадер и боди цсс код напрямую.

    вообще не понимаю почему все это происходит. никто из разрабов не заботится о том что внутри, лишь бы снаружи было красиво?

    ну это ладно. сам использую наподобие функции true_peremeshhaem_jquery_v_futer и вот что странно. я хотел сначала вообще отключить два стандартных вордпрессовских джаваскрипта, использовал эту функцию и прописал вместо

    wp_register_script('jquery', includes_url('/js/jquery/jquery.js'), false, null, true);
    wp_register_script('jquery', '', false, null, true);

    тоесть пустое место. но тогда вообще весь jquery перестал загружаться (от плагинов в том числе).
    в итоге понадобился всетаки 1 библиотека мне и оставил ее.

    причем некоторые решения ведь требуют загрузку библиотеки перед скриптом? это так? а то у меня сейчас висит в хеадере 1 джаваскрипт в итоге.
    а вот еще допустим яндекс карты не загружаются если подключение библиотеки после блока карты идет. так что все в подвал не запихнуть, а хотелось бы.

    кстати на самом сайте контактной формы в факе написан такой код для отключения джаваскрипта и цсс

    add_filter( 'wpcf7_load_js', '__return_false' );
    add_filter( 'wpcf7_load_css', '__return_false' );

    не знаю разницы правда

  • вадик12 июня 2015 в 16:06 #

    смысл прошлого поста - хотел сначала отключить два вордпрессовских джаваскрипта (из хедера), но решения не нашел. в итоге подключил также как у вас только 1 библиотеку вместо двух водрпрессовских, но оставил ее в хеадере, потомучто скрипты на странице иначе не работали (если поместить библиотеку в футер - после скриптов).

    кстати. для древовидных комментариев вордпресс также требует загрузку 1 файла. я решил впихнуть его код под форму комментария (благо он небольшой) и при условии что есть хотябы 1 комментарий. таким образом на 1 файл меньше загружается - тоже неплохо

  • Анастасия13 июня 2015 в 06:06 #

    Добрый день. Я выбираю нужные стили, которые надо в

    <style></style>

    вставить при помощи jonassebastianohlsson.com/criticalpathcssgenerator/
    Жалко только, что при работе с Генезис Фреймворк он не дает критическим путем пользоваться =(

  • Anton13 июня 2015 в 16:06 #

    Стили для Contact Form 7 можно отключить фильтром

    add_filter( 'wpcf7_load_css', '__return_false' );

    Об этом, кстати, упомянуто в документации

    • Миша13 июня 2015 в 19:06 #

      Да, да, об этом уже было упомянуто одним комментарием выше, в любом случае, спасибо.

      Целью же этой статьи было показать способ отключения дополнительных CSS плагинов.

  • Daria15 июня 2015 в 03:06 #

    Браво, Миша! Отличная статья - четко, понятно и для меня своевременно! Я несколько раз приступала и отступала к этому ускорению, если со скриптами разобралась, то с CSS объединить никак не получалось. Вот теперь я поняла почему - ID CSS плагинов задавала неправильно.
    Миша, теперь куча вопросов:
    1)при обновлении плагина все снова проделывать - ведь кто знает, затронул автор цсс или нет?
    2)использовать или плагин JS & CSS Script Optimizer или то объединение, что разбирали в статье, все вместе лишнее?
    3)еще вопрос об ускорении - у меня включен плагин кеширования, почему же PageSpeed пишет "Используйте кеш браузера для следующих ресурсов ....". Что тут следует исправить и где?
    Заранее спасибо вам

    • Миша15 июня 2015 в 13:06 #

      1) Ну если что-то перестало работать, то можно обновить CSS, либо глянуть changelog,
      2) всё вместе думаю ни к чему,
      3) плагин кэширования — это совсем другое, через PHP.

  • Егор16 июня 2015 в 20:06 #

    Здравствуй, Михаил. А у тебя не было такой проблемки? Я экспериментирую немного :)
    jQuery скрипт плагина подключаю в footer, а он утягивает за собой и файл стилей. Валидатор при этом выдает ошибку.

    Тупо переношу стили прямо в файл плагина,

    <style></style>

    в исходном коде стили выводятся в footer уже вот так:

    <footer>
         <style>
                 .стили{     }
         </style>
    <footer>

    Ошибки валидности при этом нет. И скрипт и стили грузятся после отрисовки страницы. Гуд. Но все-же интересно, почему скрипт тянет за собой стили?
    Вот как я подключаю cкрипт и стили плагин-виджета:

     wp_register_style( 'accordion-widget-style', plugins_url( '/bsaw.css', __FILE__ ), array(), '20120206', 'all' );
            wp_enqueue_style('accordion-widget-style');
     
            wp_register_script('bootstrap-accordion-js', plugins_url('collapse.js', __FILE__), array('jquery'));
            wp_enqueue_script('bootstrap-accordion-js');
  • Егор16 июня 2015 в 20:06 #

    И еще вопрос есть. Подключил библиотеку jQuery (сейчас сравнивал, точно как у тебя в примере) в footer. Все норм. Она даже зависящие от нее плагины в footer тянет. Но установил плагин WP-Polls опросы. И теперь библиотека опять в header :))) . Хотя остальные скрипты, от нее зависящие по прежнему внизу страницы.

  • Артур19 июня 2015 в 22:06 #

    Ну и блог... Зачитаешься. )
    И + отличный вкус в оформлении.

    К слову о скорости, чтобы лишний раз не подгружать библиотеку иконок font-awesome, или изображения.
    Подскажите пжл., как вы сделали все эти иконки (возле даты, комментариев) похожие на fontawesome в символы utf-8, и где достать "font family: rudrapr" чтобы значения работали и у меня.
    Спасибо)

    • Миша20 июня 2015 в 08:06 #

      Благодарю)
      rudrapr — это просто набор иконок из разных шрифтов, есть иконки и от font-awesome.

      Если же вы хотите реально выиграть в скорости, оптимальным решением будет создание SVG-спрайта из нужных вам иконок.

      • Артур20 июня 2015 в 09:06 #

        Спасибо вам большое, Михаил. Ваша отзывчивость к аудитории несказанно радует )

        И как же удобно, что моё имя и Email помнит ваша форма отпр. комментариев. =)

        • Миша20 июня 2015 в 21:06 #

          Пожалуйста :) Стараюсь, хотя с ростом посещаемости это становится всё труднее)

  • mdva5 сентября 2015 в 11:09 #

    Приветствуем.

    На сдл проекте решил своими руками попробовать сие дело - увеличение скорости работы сайта...
    Позднее выложу на своем блоге mdva.biz, а пока посетителям сайта Миши Рудрастых подскажу тру вещи, которые сэкономят время:
    1. Действуем четко по инструкции выше, что дал Мишка.
    2. Сжимаем (Minify) оригинальный style.css через любой сервис, мы использовали: http://www.cleancss.com/css-minify/
    3. Сжимаем собственный .js файл, опять же - http://www.danstools.com/javascript-minify/
    4. Устанавливаем плагин - W3 Total Cache. Настройки выставляем в зависимости от конфигурации сервера. Мы поставили настройки по умолчанию.
    5. У нас оказался сервер на апачи. Посему устанавливаем как порекомендовал Module mod_deflate. Стояла CentOS (путь к /etc/httpd/conf/httpd.conf). Проверьте включен ли модуль.
    В конце вставить:

    <ifmodule mod_deflate.c>
        AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript    
        DeflateCompressionLevel 8
    </ifmodule>

    1. Просим помощи у Вас: как включить кеш браузера на сервере или через плагины?
    http://i.imgur.com/FoVsDAs.jpg
    2. В каких случаях PageSpeed Insights все равно дает совет включить сжатие, хотя в заголовке запроса присутствует запись:

    Accept-Encoding: gzip, deflate

    p.s. Via, Forwarded или Proxy-Connection отсутствует...

  • Сергей8 марта 2016 в 23:03 #

    Здравствуйте, Михаил. Вопросы такие:

    1. Для удаления из верхний части скриптов следовал по Вашей инструкции, в результате то слайдер не работал, то скрипты в подвал не опускались. Вот сайт http://uborka-365.ru/. В комментариях статьи https://truemisha.ru/blog/wordpress/wp_head.html попробовал код асинхронной загрузки

    add_filter( 'clean_url', function( $url ) {
    	if ( FALSE === strpos( $url, '.js' ) ) {
    		return $url;
    	}
    	return "$url' defer='defer";
    }, 11, 1 );

    и замечания PageSpeed Insights исчезли сразу по всем скриптам. Можно ли оставить все так как есть? Если все же лучше будет опустить их в подвал сайта, подскажите как правильно это сделать.

    2. Стили CSS все объединил в один файл, в итоге осталось два файла ( с гугловскими шрифтами не знаю как поступить). У Вас в статье выше написано "Объединяем все CSS, суём прямо перед JavaScript, которые мы уже переместили". Подскажите пожалуйста как файлы

    http://fonts.googleapis.com/…300%2C400%2C700&subset=latin%2Clatin-ext
    http://uborka-365.ru/…mes/i-transform/style.css?ver=2013-07-18

    опустить в подвал?

    Буду очень благодарен за ответ с пояснениями.

    • Миша9 марта 2016 в 05:03 #

      Здравствуйте, Сергей!

      1. Не все jQuery-плагины поддерживают то, чтобы их опускали в подвал. Какие тут есть варианты:

      • Перенести всё в подвал тем способом, которым вы это сделали и затем уже разбираться со слайдером. Совсем недавно кстати я в этом вопросе полностью перешёл на OwlCarousel2 - на мой взгляд самый лучший адаптивный слайдер + карусель, с которым не возникает проблем.
      • Если вы добавили defer на скрипты, они остались в хедере, при этом всё работает и PageSpeed не ругается — конечно можно так всё оставить (но вижу на вашем сайте, что вы вдобавок перенесли их в футер, это как говорится «масло масляное»).
      • Ещё один, уже менее оптимальный вариант — оставить в хедере jquery.js и слайдер, а всё остальное — в подвал.

      2. Не смотря на то, что в моей статье написано мной же, что CSS тоже опускать в подвал, сейчас я могу с уверенностью сказать — не надо!

      Дело в то, что сайты мы делаем для людей, а не для Google PageSpeed. Поясню — если перенести CSS в подвал, то сайт будет загружаться просто ужасно! Видел сайт одного агенства, которые так сделали, да и сам вроде пробовал когда-то. Просто попробуйте отключить все стили и открыть свой сайт — вот таким и будут видеть его посетители первые несколько секунд загрузки. Я считаю, что пойнты PageSpeed даже близко не стоят этого.

      А что касается объединения, то внешние стили со внутренними объединять не обязательно. Но есть вариант, который имеет место быть — на моём сайте используется Open Sans, однако он не подгружается извне, я загрузил шрифт к себе на сервер и таким образом избавился от внешних CSS.

      • Сергей9 марта 2016 в 10:03 #

        Спасибо Михаил за подробный ответ. Но все же подскажите пожалуйста способ размещения стилей в подвале? Хочется поэкспериментировать.

        Есть задумка отключить слайдер ( зачем он если там всего один элемент) и подредактировать первый экран. Если не смогу своими силами, можно обратиться к Вам? Какова будет стоимость данной услуги?

        • Миша9 марта 2016 в 13:03 #

          Тут опять-таки зависит от того, каким образом они у вас подключаются. Если рассмотреть пошагово, то:

          1. Для начала стили нужно убрать из <head>. Если они у вас прописаны прямо в header.php, то вообще без проблем. Если они подключаются через функцию wp_enqueue_style(), тогда вам пригодится wp_dequeue_style(). В общем всё как и со скриптами.
          2. В отличии от скриптов, функции подключения стилей WordPress не поддерживают их добавление в подвал сайта, поэтому это уже делается вручную в файле footer.php.

          Если в слайдере один элемент, то конечно лучше заменить его обычным HTML+CSS, это будет определённо плюс к скорости загрузки и «лёгкости» сайта. Да, пишите мне на емайл, если понадобится помощь со слайдером.

          • Сергей9 марта 2016 в 14:03 #

            Спасибо, буду пробовать.

          • Сергей11 марта 2016 в 01:03 #

            Здравствуйте, Михаил. У меня стили подключаются через wp_enqueue_style(), можно поподробнее как именно использовать wp_dequeue_style()? Я пробую подключить как у Вас указанно в статье https://truemisha.ru/blog/wordpress/wp_dequeue_style.html " Перед тем, как указанный CSS подключится на странице, используем код...." почему-то не изменяется ничего.

            • Миша11 марта 2016 в 06:03 #

              Здравствуйте :)

              Хочу обратить ваше внимание на один момент — инструкции, приведённые до этого, больше подходят либо для использования в плагинах, либо в дочерних темах (дочерние темы нужны для того, чтобы во время обновления родительской темы не сбрасывались сделанные изменения).

              Глянул ваш сайт и (поправьте меня, если ошибаюсь) похоже, что подключение и переподключение стилей и скриптов у вас происходит в основном файле functions.php, либо подключенных к нему файлов через require().

              Просто в таком случае вам достаточно удалить функцию wp_enqueue_style() из файла и потом уже просто вставить CSS в футер при помощи:

              <link rel="stylesheet" href="" />
              • Сергей14 марта 2016 в 00:03 #

                Если честно, я сначала так и поступил, просто удалил функцию и вставил CSS в футер. Но у меня почему-то PageSpeed Insights все равно писал тоже замечание, поэтому я подумал что так делать нельзя. Но раз Вы тоже советуете это сделать, я теперь вообще ничего не понимаю.

                Вот опустил шрифты в подвал http://uborka-365.ru/ (понимаю что начальное отображение никуда не годится, это просто чтобы Вам показать, потом исправлю)

                И вот сервис https://developers.google.com/speed/pagespeed/insights/?url=http%3A%2F%2Fuborka-365.ru%2F&tab=mobile выдает все ту же ошибку. Как такое может быть подскажите пожалуйста Михаил?

                • Миша25 марта 2016 в 13:03 #

                  Прошу прощения за задержку с ответом — был в отъезде с 13-го числа до сегодня.

                  Вижу, что вы решили встроить свой CSS в тело документа, ну в принципе, если CSS небольшой, то можно и так сделать.

            • Егор11 марта 2016 в 10:03 #

              Код приведенный ниже - это правильное, валидное подключение CSS файлов в footer по версии W3C валидатора.

              <link rel="stylesheet" property="stylesheet" href="folder/file.css" type="text/css" media="screen">

              Но здесь нужно смотреть, как себя будет вести страница при загрузке. Например шрифты так включать не следует, а стили Fancybox и прочих расширений, вполне себе.

              А вообще, если взять скрипты, собираю их в кучу плагином типа Autoptimize или подобными ему (для клиентов) и гружу jQuery в footer. А стили избирательно, смотрю как лучше. Вот как-то так.

              • Сергей14 марта 2016 в 00:03 #

                Спасибо Егор, я стараюсь использовать минимум плагинов, поэтому в этом вопросе хочется обойтись без них.

Оставить комментарий / вопрос

phpjsHTMLCSSSQLПросто код
  Для того, чтобы оставить комментарий, пожалуйста, зарегистрируйтесь или авторизуйтесь на сайте.
Получайте новости блога по email или следите за мной в социальных сетях.
  • Миша: Да, точно)

  • Владимир: и на третьей строке не хватает скобки ) закрывающей if :)

  • Миша: Добрый вечер! Рекомендую получить ID пользователя через функцию get_current_user_id().

  • Дмитрий: Миша, подскажите пожалуйста, я использую такой редирект, но он не срабатывает: add_action( 'template_redirect', funct...

  • Миша: Ну как не определена - это аргумент функции. Или я просто вас не до конца понимаю.