-
-
Save aktaumag/1f221ff4774ffb81ad0a7bf97fab46bd to your computer and use it in GitHub Desktop.
Всё о важности картинок и их ускорении |
Оптимизация SVG файлов:
https://github.com/svg/svgo
онлайн - https://jakearchibald.github.io/svgomg/
https://loading.io/ svg preloaders
Новая технология loading="lazy"
- уверен, что приживётся
к <img>
и <iframe>
добавлять атрибуты decoding="async" loading="lazy"
https://www.youtube.com/watch?v=F6KGcb6trXc
Самый важный атрибут картинки — ALT
, должен вписываться в содержание страницы.
alt
не должен равняться заголовку страницы или раздела/блока/секции, в которой находится картинка. Вообще не должен быть дублем другого текста страницы.
alt=""
— если это alt пустой, то по сути картинка должна считаться системной (картинка для дизайна), но на самом деле так не происходит, поэтому все системные картинки лучше использовать в стилях как фон, но не через тег img
.
Чем лучше качество картинки, тем больше вероятность попадания в топ. Хоть до 20.000px в ширину и высоту, но хватает того, чтобы картинки были лучше, чем у конкурентов.
Минимум: 1920 × 1080 пикселей
URL адрес картинки повторяет структуру самой страницы
Например, картинка для страницы https://wseo.kz/redirect/service/https должна лежать по адресу https://wseo.kz/redirect/service/https/pereadresaciya-na-https-protokol.jpg
пример:
<img
src="/path/img-1920.jpg"
srcset="/path/img-640.jpg 640w,
/path/img-920.jpg 920w,
/path/img-1220.jpg 1220w"
alt="Не заголовки, а описание того, что изображено на картинке. Текст любой длины, но учитываются первые 100 символов"
decoding="async"
loading="lazy"
/>
Картинка с тегом src не оптимизируется и содержит максимальное качество. Именно она и индексируется.
Оптимизируются картинки в атрибуте srcset, одна из них и будет отображаться.
Даже если картинки нет (не загрузится), то по дизайну блок под картинку должен сразу иметь нужную ширину и высоту!!!
При последующей загрузке картинки блоки не должны прыгать в размерах.
Картинка должна сочетаться с текстом и должна содержать образы того, о чём написано на странице.
Проверить можно здесь: https://cloud.google.com/vision
Картинка должна быть без водяного знака.
На картинке не должно быть текста.
Картинки должны содержать метатеги в формате IPTC для указания вашего авторства. (Byline/Author/Creator + Copyright Notice + Source)
Тег <picture>
удобный, но в плане технической оптимизации он сильно увеличивает структуру DOM. Минимум в 3 раза для каждого изображения. Верхняя граница DOM дерева страницы = 1500 узлов... мак. глубина = 32 узла... ЧЕМ МЕНЬШЕ, ТЕМ ЛУЧШЕ.
Тег <figure>
вообще не подходит для указания картинок, так как гласит о том, что это отдельный объект страницы, который следует понимать в отрыве от всего остального контента. Иными словами - не SEO картинка и не относится к содержанию страницы.
Картинки, указанные через стили, НЕ ИНДЕКСИРУЮТСЯ: background: url("/path/img.jpg");
Влияние на SEO оказывают только картинки в теге IMG, указанные в атрибуте SRC.
Поэтому, все дизайнерские элементы и иконки (рейтинг, корзина, телефоны, соцсети) должны быть через стили ::after
, ::before
или background:
Желательно важные картинки сайта внедрять сразу с разметкой
<div itemscope itemtype="http://schema.org/ImageObject">
<img
src="/path/img-1920.jpg"
itemprop="contentUrl"
srcset="/path/img-640.jpg 640w,
/path/img-920.jpg 920w,
/path/img-1220.jpg 1220w"
alt="Не заголовки, а описание того, что изображено на картинке. Текст любой длины, но учитываются первые 100 символов"
decoding="async"
loading="lazy"
/>
<meta itemprop="thumbnail" content="/path/img-640.jpg">
<meta itemprop="thumbnail" content="/path/img-920.jpg">
<meta itemprop="thumbnail" content="/path/img-1220.jpg">
<!-- ну и если уместно, и в разметке уже есть данные, то можно дополнить ещё и этими -->
<span itemprop="name">название картинки</span>
<span itemprop="description">описание изображения</span>
<span itemprop="caption">подпись к картинке</span>
</div>
Если картинка в SVG, то её указываем именно в srcset
в единичном варианте для всех размеров, а для атрибута src
создаём растровый вариант из этой картинки:
<img
src="/path/img-1920.jpg"
srcset="/path/img.svg 100w"
sizes="100vw"
alt="Не заголовки, а описание того, что изображено на картинке. Текст любой длины, но учитываются первые 100 символов"
decoding="async"
loading="lazy"
/>
Особенно для логотипа компании на брендовых страницах.
https://responsivebreakpoints.com/
Пример нарезки картинок
ВИДЕО
Вместо iframe ставится картинка (превьюшка) и вешается обработчик по клику, который меняет эту картинку на iframe.
При этом всю нужную для SEO информацию мы передаём через микроразметку Shema.org для разметки видео.
Сейчас нативный loading="lazy"
работает плохо, в том плане, что загружает картинки на 7 экранов вниз, а при плохом 3G соединении вообще на все 14... таких длинных сайтов то редко встретишь.
Поэтому ещё актуально использовать костыли
https://apoorv.pro/lozad.js/
<img style="width:100%; max-width:300px;"
class="demilazyload"
alt="Demimurych Lazy Tester"
src="itak.png"
data-srcset="itak2.webp 100w"
srcset="image.svg 100w"
sizes="100vw"
/>
<script type="text/javascript" src="lozad.js"></script>
<script>
lozad('.demilazyload').observe();
</script>
При таком подходе надо создать пустой SVG как заглушку и указывать у каждой картинки параметры ширины и высоты, чтобы не прыгал дизайн сайта при загрузке.
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"></svg>
<style>
img{
max-width: 100%;
width: auto;
height: auto;
}
img.wsbgll {
background-color: #3333331a;
}
</style>
<img src="/img/picture.png"
width="350"
height="170"
class="wslazy wsbgll"
data-srcset="/img/picture.webp 100w"
srcset="/img/empty.svg 100w"
sizes="100vw"
decoding="async"
loading="lazy"
alt="">
<script src="/js/lozad.js"></script>
<script>
lozad('.wslazy').observe();
</script>
WordPress
<?php
function ws_lazy_load($content){
$include_noscript = false;
// Normal image
$matches = array();
preg_match_all( '/<img[\s\r\n]+.*?>/is', $content, $matches );
$search = array();
$replace = array();
$i = 0;
foreach ( $matches[0] as $imgHTML ) {
if (strpos($imgHTML, 'wsnolazy') === false && strpos($imgHTML, 'data-src') === false && ! preg_match( "/src=['\"]data:image/is", $imgHTML )) {
$i++;
$replaceHTML = $imgHTML;
if ( preg_match( '/class=["\']/i', $replaceHTML ) ) {
$replaceHTML = preg_replace( '/class=(["\'])(.*?)["\']/is', 'class=$1wslazy $2$1', $replaceHTML );
} else {
$replaceHTML = preg_replace( '/<img/is', '<img class="wslazy"', $replaceHTML );
}
if ( !preg_match( '/sizes=["\']/i', $replaceHTML ) ) {
$replaceHTML = preg_replace( '/ src=["\'](.*?)["\']/is', ' src="$1" srcset="/wp-content/themes/newTheme/assets/js/empty.svg 100w" data-srcset="$1 100w" sizes="100vw"', $replaceHTML );
} else {
$replaceHTML = preg_replace( '/<img(.*?) srcset=/is', '<img$1 srcset="/wp-content/themes/newTheme/assets/js/empty.svg 100w" data-srcset=', $replaceHTML );
}
if ( !preg_match( '/decoding=["\']/i', $replaceHTML ) ) {
$replaceHTML = preg_replace( '/<img/is', '<img decoding="async"', $replaceHTML );
}
if ( !preg_match( '/loading=["\']/i', $replaceHTML ) ) {
$replaceHTML = preg_replace( '/<img/is', '<img loading="lazy"', $replaceHTML );
}
if ( !preg_match( '/width=["\']/i', $replaceHTML ) && !preg_match( '/height=["\']/i', $replaceHTML ) ) {
// получаем размеры ширины и высоты картинки
if (preg_match( '/ src=["\'](.*?)["\']/is', $replaceHTML, $wssrc )){
$wssrcpath = $wssrc[1];
if(substr($wssrcpath, 0, 1) == '/') {
$wssrcpath = '.'.$wssrc[1];
}
elseif(substr($wssrcpath, 0, 4) == 'www.') {
$wssrcpath = '//'.$wssrc[1];
}
$imageparam = getimagesize(htmlspecialchars($wssrcpath));
if($imageparam){
$wswidth = $imageparam[0];
$wsheight = $imageparam[1];
$replaceHTML = preg_replace( '/<img/is', '<img width="'.$wswidth.'" height="'.$wsheight.'"', $replaceHTML );
}
}
}
if ( $include_noscript ) {
$replaceHTML .= '<noscript>' . $imgHTML . '</noscript>';
}
array_push( $search, $imgHTML );
array_push( $replace, $replaceHTML );
}
}
$search = array_unique( $search );
$replace = array_unique( $replace );
$content = str_replace( $search, $replace, $content );
return $content;
}
add_filter( 'the_content', 'ws_lazy_load' );
?>
Отложенная загрузка для Яндекс Карты.
Появляется если доскролить до нужного места, но на всякий случай есть ещё и триггеры на наведение мышкой, клик и пр.
<!-- размер контейнера под размер карты и цвет окраски в стиле сайта -->
<div id="wsmainmap" style="display: block; width: 100%; height: 680px;background-color: #0078881a;">
<!-- скрипт карты, которой даём нужное ID и переделываем SRC в DATA-SRC -->
<script type="text/javascript" charset="utf-8" async id="map_wslazy" data-src="https://api-maps.yandex.ru/services/constructor/1.0/js/?um=constructor%3A982500c531973a06e0aa07174eafc6dbaabfdf0cf8785f8e326da852e1963c32&width=100%25&height=680&lang=ru_RU&scroll=true"></script>
</div>
<script>
let map_container = document.getElementById('wsmainmap');
let options_map = {
once: true,
passive: true,
capture: true
};
map_container.addEventListener('click', start_lazy_map, options_map);
map_container.addEventListener('mouseover', start_lazy_map, options_map);
map_container.addEventListener('touchstart', start_lazy_map, options_map);
map_container.addEventListener('touchmove', start_lazy_map, options_map);
var iObserver = new IntersectionObserver(function(entries) {
if (entries[0].isIntersecting === true) {
start_lazy_map();
}
}, {threshold: [0]}); // от 0 до 1, % видимой части элемента на экране
iObserver.observe(map_container);
let map_loaded = false;
function start_lazy_map() {
if (!map_loaded) {
let map_block = document.getElementById('map_wslazy');
map_loaded = true;
map_block.setAttribute('src', map_block.getAttribute('data-src'));
map_block.removeAttribute('data-src');
console.log('YMAP LOADED');
}
}
</script>
Источник: https://codepen.io/fe-nix/pen/PoQvxQa
let observer = new IntersectionObserver(
function (entries) {
for (let i in entries) {
let el = entries[i].target;
if (entries[i].isIntersecting === true) {
if (el.dataset.srcset) {
el.setAttribute("srcset", el.dataset.srcset);
} else {
el.removeAttribute("srcset");
}
el.addEventListener(
"load",
function () {
el.classList.add("loaded");
},
{ passive: true }
);
}
}
},
{ threshold: [0], rootMargin: "100px 0px 100px 0px" } // Здесь вы выбираете на сколько пикселей вверх право низ и лево будут элементы будут считаться внутри вьюпорта и начинут загружаться в текущем примере 100 пикселей сверху и снизу.
);
document.addEventListener(
"DOMContentLoaded",
function () {
let mas = document.querySelectorAll(".lazy"); // Слектор для изображений, здесь используется .lazy
for (let i = 0; i < mas.length; i++) {
observer.observe(mas[i]);
}
},
{ passive: true }
);
Пример вставки:
<img src="https://perfscan.ru/static/gallery/img/320/002.jpg" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" alt="" width="320" height="180" decoding="async" class="lazy">
<img src="https://perfscan.ru/static/gallery/img/320/003.jpg" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" data-srcset="https://perfscan.ru/static/gallery/img/640/003.jpg 2x" alt="" width="320" height="180" decoding="async" class="lazy">
LazyLoad для загрузки картинок при помощи CSS background
<style>
.wsBgLazy{background-image: none !important;}
</style>
<div class="wsbglazy" data-bgimgurl="image.jpg"></div>
<div class="wsbglazy" data-bgurl="image.jpg"></div>
<div class="wsbglazy"></div> <!-- картинка прописана где-то в CSS файлах стилей -->
<script>
const wsBgObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
let wsEl = entry.target;
if (wsEl.dataset.bgurl) {
wsEl.style.background = "url('"+wsEl.dataset.bgurl+"') 0 0 no-repeat";
}
else if(wsEl.dataset.bgimgurl) {
wsEl.style.backgroundImage = "url('"+wsEl.dataset.bgimgurl+"')";
}
wsEl.classList.remove("wsBgLazy");
wsEl.classList.add("wsBgLoaded");
wsBgObserver.unobserve(wsEl);
}
});
});
document.addEventListener(
"DOMContentLoaded",
function () {
const wsBgMass = document.querySelectorAll(".wsBgLazy");
wsBgMass.forEach((el) => {
wsBgObserver.observe(el);
});
},
{ passive: true }
);
</script>
На GitHubе инструкция, которая хорошо работает
Подключаем скрипт (скачиваем или через CDN):
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/lazyload.min.js"></script>
или перед закрытием
</body>
Загружаем какую-нибудь иконку
loading.svg
, которая будет символизировать загрузку и позволит пройти валидацию, так как обязательный параметр SRC должен быть.Для прохождения всех валидаций картинка вставляется так, хотя по инструкции рекомендуется не писать параметр SRC
<img class="lazy" src="/images/loading.svg" data-src="/images/upload/img-name.jpeg" alt="что на картинке...">
Если не вставлять анимированную иконку как SRC параметр, то обязательно в стилях прописать такое:
Если надо применить технологию к картинке, которая загружается как бекграунд, то делаем так:
<div class="lazy" data-bg="url(../img/44721746JJ_15_a.jpg)"></div>
Если применяем технологию к скрытым элементам, например к картинкам, которые находятся в выпадающем меню, то в скрипте, вызывающем открытие этого элемента, нужно прописать
myLazyLoad.update();