Недавно начал использовать библиотеку Lazyload от Daniel ‘Eisbehr’ Kern. Работает лучше чем вторая версия от Mika Tuupola.
Особенности Lazyload
Многие параметры схожи с версией Mika Tuupola (MT), инициализируется так:
$(function() {
$(".lazy").Lazy({
effect : "fadeIn",
threshold : 200
});
});
Корректно работает с атрибутом srcset, нужно прописывать data-srcset.
Одной из главных особенностей этого решения является наличие поддержки событий, т.е. подгрузка изображений при совершении какого-либо действия. Всю дорогу у меня была в этом плане проблема с галереей slick. Штатные средства по отложенной загрузке slick работают некорректно (по крайней мере у меня), а lazyload MT тоже не подгружал изображения при автоматической перемотке, а только при прокрутке страницы.
Скрипт для slick (определенного слайдера #index-slider) подгружающий слайды при перемотке:
$(document).ready(function() {
$("button.slick-arrow").click(function() {
$("#index-slider img.lazy").Lazy({
bind: "event"
});
});
$('#index-slider').on('afterChange', function(event, slick, currentSlide, nextSlide){
$("#index-slider img.lazy").Lazy({
bind: "event"
});
});
});
Скрипт для owlCarousel
Вписываем параметр в функцию инициализации карусели (вешаем на событие перемотки слайда функцию):
onTranslated: callback,
Добавляем функцию callback
function callback(event) {
$(".carousel-vertical img").Lazy({
bind: "event"
});
}
функция прописана для конкретной карусели (.carousel-vertical), но это не обязательно.
Функция замены у миниатюр параметра srcset
function lazy_load_responsive_images_modify_post_thumbnail_attr( $attr, $attachment, $size ) {
if ( isset( $attr['sizes'] ) ) {
$data_sizes = $attr['sizes'];
unset( $attr['sizes'] );
$attr['data-sizes'] = $data_sizes;
}
if ( isset( $attr['srcset'] ) ) {
$data_srcset = $attr['srcset'];
unset( $attr['srcset'] );
$attr['data-srcset'] = $data_srcset;
$attr['data-noscript'] = $attr['src'];
unset( $attr['src'] );
}
$attr['class'] .= ' lazy';
return $attr;
}
add_filter( 'wp_get_attachment_image_attributes', 'lazy_load_responsive_images_modify_post_thumbnail_attr', 20, 3);
Дополнение. У миниатюр, размер которых мы прописываем (rectangle), может не выводиться атрибут src-set, если пропорция прописанного размера отличается от базовых. В этом случае дорабатываем функцию, чтобы src заменялся на data-src:
// Lazyload для миниатюр
function lazy_load_responsive_images_modify_post_thumbnail_attr( $attr, $attachment, $size ) {
if ( isset( $attr['sizes'] ) ) {
$data_sizes = $attr['sizes'];
unset( $attr['sizes'] );
$attr['data-sizes'] = $data_sizes;
}
if ( isset( $attr['srcset'] ) ) {
$data_srcset = $attr['srcset'];
unset( $attr['srcset'] );
$attr['data-srcset'] = $data_srcset;
$attr['data-noscript'] = $attr['src'];
unset( $attr['src'] );
} else {
$attr['data-src'] = $attr['src'];
unset( $attr['src'] );
}
$attr['class'] .= ' lazy';
return $attr;
}
add_filter( 'wp_get_attachment_image_attributes', 'lazy_load_responsive_images_modify_post_thumbnail_attr', 20, 3);
Также, нашел функцию замены атрибутов в контенте страниц и записей:
function lazy_load_responsive_images ( $content ) {
if ( empty( $content ) ) {
return $content;
}
$dom = new DOMDocument();
libxml_use_internal_errors( true );
$dom->loadHTML( $content );
libxml_clear_errors();
foreach ( $dom->getElementsByTagName( 'img' ) as $img ) {
if ( $img->hasAttribute( 'sizes' ) && $img->hasAttribute( 'srcset' ) ) {
$sizes_attr = $img->getAttribute( 'sizes' );
$srcset = $img->getAttribute( 'srcset' );
$img->setAttribute( 'data-sizes', $sizes_attr );
$img->setAttribute( 'data-srcset', $srcset );
$img->removeAttribute( 'sizes' );
$img->removeAttribute( 'srcset' );
$src = $img->getAttribute( 'src' );
if ( ! $src ) {
$src = $img->getAttribute( 'data-noscript' );
}
} else {
$src = $img->getAttribute( 'src' );
if ( ! $src ) {
$src = $img->getAttribute( 'data-noscript' );
}
$img->setAttribute( 'data-src', $src );
}
$classes = $img->getAttribute( 'class' );
$classes .= " lazy";
$img->setAttribute( 'class', $classes );
$img->removeAttribute( 'src' );
$noscript = $dom->createElement( 'noscript' );
$noscript_node = $img->parentNode->insertBefore( $noscript, $img );
$noscript_img = $dom->createElement( 'IMG' );
$noscript_img->setAttribute( 'class', $classes );
$new_img = $noscript_node->appendChild( $noscript_img );
$new_img->setAttribute( 'src', $src );
$content = $dom->saveHTML();
}
return $content;
}
add_filter( 'the_content', 'lazy_load_responsive_images', 20 );
Альтернативный и рабочий вариант функции по подгрузке изображений из записей:
// Lazyload Converter
function add_lazyload($content) {
$content = mb_convert_encoding($content, 'HTML-ENTITIES', "UTF-8");
$dom = new DOMDocument();
@$dom->loadHTML($content);
// Convert Images
$images = [];
foreach ($dom->getElementsByTagName('img') as $node) {
$images[] = $node;
}
foreach ($images as $node) {
$fallback = $node->cloneNode(true);
$oldsrc = $node->getAttribute('src');
$node->setAttribute('data-src', $oldsrc );
$newsrc = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
$node->setAttribute('src', $newsrc);
$oldsrcset = $node->getAttribute('srcset');
$node->setAttribute('data-srcset', $oldsrcset );
$newsrcset = '';
$node->setAttribute('srcset', $newsrcset);
$classes = $node->getAttribute('class');
$newclasses = $classes . ' lazy';
$node->setAttribute('class', $newclasses);
$noscript = $dom->createElement('noscript', '');
$node->parentNode->insertBefore($noscript, $node);
$noscript->appendChild($fallback);
}
// Convert Videos
$videos = [];
foreach ($dom->getElementsByTagName('iframe') as $node) {
$videos[] = $node;
}
foreach ($videos as $node) {
$fallback = $node->cloneNode(true);
$oldsrc = $node->getAttribute('src');
$node->setAttribute('data-src', $oldsrc );
$newsrc = '';
$node->setAttribute('src', $newsrc);
$classes = $node->getAttribute('class');
$newclasses = $classes . ' lazy';
$node->setAttribute('class', $newclasses);
$noscript = $dom->createElement('noscript', '');
$node->parentNode->insertBefore($noscript, $node);
$noscript->appendChild($fallback);
}
$newHtml = preg_replace('/^<!DOCTYPE.+?>/', '', str_replace( array('<html>', '</html>', '<body>', '</body>'), array('', '', '', ''), $dom->saveHTML()));
return $newHtml;
}
add_filter('the_content', 'add_lazyload');
add_filter('post_thumbnail_html', 'add_lazyload');
Если основная миниатюра итак работает с lazy, то последний фильтр нужно убрать.
Функция Lazyload для товаров WC
Функции взяты из плагина Lazy Load for WooCommerce (500+)
// Lazyload для изображений Woocommerce
if (!function_exists('woocommerce_template_loop_product_thumbnail')) {
remove_action('woocommerce_before_shop_loop_item_title', 'woocommerce_template_loop_product_thumbnail', 10);
add_action('woocommerce_before_shop_loop_item_title', 'woocommerce_template_loop_product_thumbnail', 10);
function woocommerce_template_loop_product_thumbnail() {
$llwoo_image_src = wp_get_attachment_image_src(get_post_thumbnail_id(), 'shop_catalog');
$llwoo_placeholder = get_option('lazyload-woo_placeholder');
$llwoo_placeholder_fallback = wc_placeholder_img_src();
$alt = get_post_meta(get_post_thumbnail_id(), '_wp_attachment_image_alt', true);
$size = wc_get_image_size('shop_catalog');
$llwoo_width = $size['width'];
$llwoo_height = $size['height'];
if (!empty($llwoo_placeholder)) {
echo '<img src="' . $llwoo_placeholder . '" data-src="' . $llwoo_image_src[0] . '" width="' . $llwoo_width . '" height="' . $llwoo_height . '" class="attachment-shop_catalog wp-post-image lazy" alt="' . $alt . '"><noscript><img src="' . $llwoo_image_src[0] . '" width="' . $llwoo_width . '" height="' . $llwoo_height . '" class="attachment-shop_catalog wp-post-image lazy" alt="' . $alt . '"></noscript>';
} else {
echo '<img src="' . $llwoo_placeholder_fallback . '" data-src="' . $llwoo_image_src[0] . '" width="' . $llwoo_width . '" height="' . $llwoo_height . '" class="attachment-shop_catalog wp-post-image lazy" alt="' . $alt . '"><noscript><img src="' . $llwoo_image_src[0] . '" width="' . $llwoo_width . '" height="' . $llwoo_height . '" class="attachment-shop_catalog wp-post-image lazy" alt="' . $alt . '"></noscript>';
}
}
}
if (!function_exists('woocommerce_subcategory_thumbnail')) {
//For WooCommerce Category
remove_action('woocommerce_before_subcategory_title', 'woocommerce_subcategory_thumbnail', 10);
add_action('woocommerce_before_subcategory_title', 'woocommerce_subcategory_thumbnail', 10);
function woocommerce_subcategory_thumbnail($category) {
$small_thumbnail_size = apply_filters('single_product_small_thumbnail_size', 'shop_catalog');
$dimensions = wc_get_image_size($small_thumbnail_size);
$thumbnail_id = get_term_meta($category->term_id, 'thumbnail_id', true);
$llwoo_image_src_cat = wp_get_attachment_image_src($thumbnail_id, $small_thumbnail_size);
$llwoo_placeholdercat = get_option('lazyload-woo_placeholdercat');
$llwoo_placeholdercat_fallback = wc_placeholder_img_src();
$sizecat = wc_get_image_size('shop_catalog');
$llwoo_widthcat = $sizecat['width'];
$llwoo_heightcat = $sizecat['height'];
if (!empty($llwoo_placeholdercat)) {
echo '<img src="' . $llwoo_placeholdercat . '" data-src="' . $llwoo_image_src_cat[0] . '" width="' . $llwoo_widthcat . '" height="' . $llwoo_heightcat . '" class="attachment-shop_catalog wp-post-image lazy"><noscript><img src="' . $llwoo_image_src_cat[0] . '" width="' . $llwoo_widthcat . '" height="' . $llwoo_heightcat . '" class="attachment-shop_catalog wp-post-image lazy"></noscript>';
} else {
echo '<img src="' . $llwoo_placeholdercat_fallback . '" data-src="' . $llwoo_image_src_cat[0] . '" width="' . $llwoo_widthcat . '" height="' . $llwoo_heightcat . '" class="attachment-shop_catalog wp-post-image lazy"><noscript><img src="' . $llwoo_image_src_cat[0] . '" width="' . $llwoo_widthcat . '" height="' . $llwoo_heightcat . '" class="attachment-shop_catalog wp-post-image lazy"></noscript>';
}
}
}
Отложенная загрузка для background-image
Чтобы подгрузить background-image нужно в целевом объекте прописать атрибут:
data-src="/wp-content/plugins/site-feedback-form/img/neon-ring.jpg"
И добавить класс .lazy