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

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

HIT

Давно интересовал вопрос адаптивности изображений с помощью атрибута 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() Читать далее »

/

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

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

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