/ Сайтостроение / Адаптивность / Адаптивные изображения (атрибут srcset)

Адаптивные изображения (атрибут srcset)

Давно интересовал вопрос адаптивности изображений с помощью атрибута srcset. Как это работает и как правильно настроить. Пришло время это выяснить.

Теория srcset

В атрибуте srcset выводятся все варианты миниатюры и с помощью атрибута sizes (который в свою очередь связан с определенной функцией WP) определяется какое изображение получить.

По умолчанию функция wp_calculate_image_sizes работает так: определяет ширину viewport и под эту ширину выдает нужную миниатюру. Но складывается ощущение, что обычно подбираются миниатюры с запасом в 2 раза по ширине.

Структура атрибута sizes:

sizes="(max-width: $width px) 100vw, $width px"
  • max-width: $width px — максимальная ширина экрана
  • 100vw — ширина области просмотра
  • $width px — необходимый размер миниатюры

Запросы на формирование srcset:

<?php
$image_id = get_post_thumbnail_id();
$img_src = wp_get_attachment_image_url( $image_id, 'large' );
$img_srcset = wp_get_attachment_image_srcset( $image_id, 'full' );
$img_alt = get_post_meta( $image_id, '_wp_attachment_image_alt', true ); ?>
...
<img src="<?php echo esc_attr( $img_src ); ?>" srcset="<?php echo esc_attr( $img_srcset ); ?>" sizes="100vw" alt="<?php echo $img_alt; ?>">

Произвольная функция подбора изображений:

function aw_custom_responsive_image_sizes($sizes, $size) {
  $width = $size[0];
  // blog posts
  if ( is_singular( 'post' ) ) {
    // half width images - medium size
    if ( $width === 600 ) {
      return '(min-width: 768px) 322px, (min-width: 576px) 255px, calc( (100vw - 30px) / 2)';
    }
    // full width images - large size
    if ( $width === 1024 ) {
      return '(min-width: 768px) 642px, (min-width: 576px) 510px, calc(100vw - 30px)';
    }
    // default to return if condition is not met
    return '(max-width: ' . $width . 'px) 100vw, ' . $width . 'px';
  }
  // default to return if condition is not met
  return '(max-width: ' . $width . 'px) 100vw, ' . $width . 'px';
}
add_filter('wp_calculate_image_sizes', 'aw_custom_responsive_image_sizes', 10 , 2);

Назначить какому-либо размеру миниатюры неизменяемый от размера экрана вывод, как бы блокировка размера миниатюры. Нужен для того если мы точно знаем где будет выводиться это изображение:

function aw_custom_declare_custom_image_responsive_sizes($attr, $attachment, $size) {
  // Full width header images
  if ($size === 'xxxl') {
    $attr['sizes'] = '100vw';
  }
  return $attr;
}
add_filter('wp_get_attachment_image_attributes', 'aw_custom_declare_custom_image_responsive_sizes', 10 , 3);

Проработал свою функцию изменения размера миниатюры, немного упростив код из найденного примера:

function aw_custom_responsive_image_sizes($sizes, $size) {
	if ( is_singular( 'post' ) ) {
		if ( $width <= 1024 ) { return 'calc( (100vw) / 2)'; } // выводим large
		if ( $width <= 768 ) { return 'calc( (100vw) / 2)'; } // выводим medium_large
		if ( $width <= 425 ) { return 'calc( (100vw) / 2)'; } // выводим medium
		return '(max-width: ' . $width . 'px) 100vw, ' . $width . 'px';
	}
	return '(max-width: ' . $width . 'px) 100vw, ' . $width . 'px';
}
add_filter('wp_calculate_image_sizes', 'aw_custom_responsive_image_sizes', 10 , 2);

Рассуждения на тему вывода вариантов изображений в srcset wordpress

Я создав пользовательский размер миниатюры (add_image_size( ‘mobile’, 420, 210, array( ‘center’, ‘center’ ) );) обратил внимание что в выводе изображений в цикле, не у всех изображений в srcset есть размер этой миниатюры. Думаю, что это связано с пропорциями, т.к. данный размер миниатюры выводился у тех изображений изначальные пропорции которого были близки к этому размеру (именно не точно пропорционально, а близки, погрешность в несколько px).

Атрибут srcset состоит из изображений с одинаковым соотношением сторон

т.е. на атрибуте srcset мы не сможем настроить вывод в desctop прямоугольного изображения, а в mobile квадратного. Это нужно будет делать другими способами.

Непропорциональная адаптивность

Получить массив всех доступных вариантов размеров изображения. Функция:

function prepareImageData( $attachment_id ){
  $uploads_baseurl = wp_upload_dir()['baseurl'];

  $prepared = [];
  $data = wp_get_attachment_metadata($attachment_id);
  $prepared = [
    'mime_type' => get_post_mime_type($attachment_id),
    'url' => $uploads_baseurl.'/'.$data['file'],
    'sizes' => [],
  ];

  foreach( $data['sizes'] as $size => $sizeInfo ){
    $prepared['sizes'][$size] = [
      'url' => $uploads_baseurl.'/'.$sizeInfo['file'],
    ];
  }

  return $prepared;
}

Выводиться так:

$thumb_id = get_post_thumbnail_id($post->ID);
$image_data = prepareImageData( $thumb_id );
echo $image_data;

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

function misha_sources( $sources, $size_array, $image_src, $image_meta, $attachment_id ){
	$image_size_name = 'square500'; // add_image_size('square500', 500, 500, true);
	$breakpoint = 500;
 
	$upload_dir = wp_upload_dir();
 
	$img_url = $upload_dir['baseurl'] . '/' . str_replace( basename( $image_meta['file'] ), $image_meta['sizes'][$image_size_name]['file'], $image_meta['file'] );
 
	$sources[ $breakpoint ] = array(
		'url'        => $img_url,
		'descriptor' => 'w',
		'value'      => $breakpoint,
	);
	return $sources;
}
 
add_filter('wp_calculate_image_srcset','misha_sources',10,5);

Обнаружил косяк в этой функции, если у изображения отсутствует данный размер миниатюры, то ссылка без указания самого файла все равно выводиться, выдавая 403 ошибку.

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

	if (!empty($image_meta['sizes'][$image_size_name]['file'])) {
		$img_url = $upload_dir['baseurl'] . '/' . str_replace( basename( $image_meta['file'] ), $image_meta['sizes'][$image_size_name]['file'], $image_meta['file'] );

		$sources[ $breakpoint ] = array(
			'url'        => $img_url,
			'descriptor' => 'w',
			'value'      => $breakpoint
		);
	}

Собрал из двух предыдущих функций (все таки первая пригодилась!) функцию вывода всех вариантов миниатюр с указанием ширины (w) в конце.

function prepareImageData( $attachment_id ){
  $uploads_baseurl = wp_upload_dir()['baseurl'];

  $prepared = [];
  $data = wp_get_attachment_metadata($attachment_id);

    $size = '';
    $prepared[$size] = [
      'url' => $uploads_baseurl.'/'.$data['file'],
	  'value'      => $data['width'].'w',
    ];
	$prepared[$size] = implode(" ", $prepared[$size]);

  foreach( $data['sizes'] as $size => $sizeInfo ){
    $prepared[$size] = [
      'url' => $uploads_baseurl.'/'.$sizeInfo['file'],
	  'value'      => $sizeInfo['width'].'w',
    ];
	$prepared[$size] = implode(" ", $prepared[$size]);
  }
	
  $thumb_srcset = implode(", ", $prepared);
  return $thumb_srcset;
}

Выводиться при получении ID миниатюры:

$thumb_id = get_post_thumbnail_id($post->ID);
$image_data = prepareImageData( $thumb_id );

Решение основано на функции wp_get_attachment_metadata, которая получает от изображения: ширину, высоту, неполный путь к файлу (от wp-upload) и массив с вариантами миниатюр, а также массив с метаданными изображения. Каждый элемент (название миниатюры) дочернего массива с размерами включает: наименование файла, ширину. высоту и тип файла. Пример:

Array
(
    [width] => 1280
    [height] => 400
    [file] => 2016/07/VS_Panties_Banner.jpg
    [sizes] => Array
        (
            [mobile] => Array
                (
                    [file] => VS_Panties_Banner-420x210.jpg
                    [width] => 420
                    [height] => 210
                    [mime-type] => image/jpeg
                )

            [thumbnail] => Array
                (
                    [file] => VS_Panties_Banner-150x150.jpg
                    [width] => 150
                    [height] => 150
                    [mime-type] => image/jpeg
                )

            [medium] => Array
                (
                    [file] => VS_Panties_Banner-400x125.jpg
                    [width] => 400
                    [height] => 125
                    [mime-type] => image/jpeg
                )

            [medium_large] => Array
                (
                    [file] => VS_Panties_Banner-768x240.jpg
                    [width] => 768
                    [height] => 240
                    [mime-type] => image/jpeg
                )

            [large] => Array
                (
                    [file] => VS_Panties_Banner-1024x320.jpg
                    [width] => 1024
                    [height] => 320
                    [mime-type] => image/jpeg
                )

        )

    [image_meta] => Array
        (
            [aperture] => 0
            [credit] => 
            [camera] => 
             => 
            [created_timestamp] => 0
            [copyright] => 
            [focal_length] => 0
            [iso] => 0
            [shutter_speed] => 0
            [title] => 
            [orientation] => 0
            [keywords] => Array
                (
                )

        )

)

Доработал функцию, упростив, но при этом добавив возможность устанавливать произвольный набор миниатюр.

function prepareImageData( $attachment_id ){
	$uploads_baseurl = wp_upload_dir()['baseurl'];

	$prepared = [];
	$data = wp_get_attachment_metadata($attachment_id);
	$thumb_names = array('mobile', 'medium_large')

	$prepared[$size] = $uploads_baseurl.'/'.$data['file'].' '.$data['width'].'w';

	foreach( $data['sizes'] as $size => $sizeInfo ){
		if (in_array($size, $thumb_names)) {
			$prepared[$size] = [
				'url' => $uploads_baseurl.'/'.$sizeInfo['file'],
				'value'      => $sizeInfo['width'].'w',
			];
			$prepared[$size] = implode(" ", $prepared[$size]);
		}
	}
	
	$thumb_srcset = implode(", ", $prepared);
	return $thumb_srcset;
}

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

И еще одна доработка: пути миниатюр указывались в папке upload без указания года и месяца. Прописал функцию замены:

	foreach( $data['sizes'] as $size => $sizeInfo ){
		if (in_array($size, $thumb_names)) {
			$img_name = str_replace( basename( $data['file'] ), $sizeInfo['file'], $data['file'] );
			$img_url = $uploads_baseurl. '/' .$img_name;
			$prepared[$size] = [
				'url' => $img_url,
				'value'      => $sizeInfo['width'].'w',
			];
			$prepared[$size] = implode(" ", $prepared[$size]);
		}
	}

basename() — функция определения последнего элемента в пути.

Теперь осталось правильно управлять атрибутом sizes в зависимости от ширины экрана.

Тэги:

Поделится информацией с друзьями

  • Похожие записи
  • Комментарии
  • Вложения
Галерея изображений товара в категории

Галерея изображений товара в категории

Создадим переключающиеся изображения товара при наведении мыши, либо галерею изображений товара в шаблоне категории. Под галереей изображений (Featured Images) понимаются дополнительные изображения помимо основного изображения. Выводим дополнительные изображения function woocommerce_feature_gallery() Читать далее »

/
Галерея изображений в виде карусели

Галерея изображений в виде карусели

Нужно переделать стандартное представление галереи изображений в карточке товара. Сделаем данный функционал более похожим на привычный в виде карусели. Для этого подключаем функционал карусели slick, и создать скрипт инициализации $(document).ready(function() Читать далее »

/
Миниатюра — фон сайта

Миниатюра — фон сайта

Мы можем использовать миниатюру записи для самых разных целей. В данной статье рассмотрим вариант использовать миниатюру в виде фонового изображения сайта. Вывод миниатюры в виде фона В цикл вывода миниатюры Читать далее »

/

Добавить комментарий

Пока нет комментариев. Будь первым!

Адаптивные изображения (атрибут srcset)
Плагин Posts 2 Posts
Рекомендации для васПлагин Posts 2 PostsOpttour.ru
Спасибо! Наш менеджер свяжется с Вами в течении 5 минут.