/ Адаптивность / Адаптивные изображения (атрибут 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 в зависимости от ширины экрана.

Поделиться в соц. сетях:

  • Похожие записи
  • Комментарии
  • Вложения
Атрибуты миниатюры

Атрибуты миниатюры

У миниатюры (thumbnail) есть служебная функция назначения атрибутов. Манипулируя атрибутами можно добиться интересных результатов. Фильтр wp_get_attachment_image_attributes распространяется на миниатюры, а также на вложенные изображения wp_get_attachment_image($image->ID, ‘rectangle’). Как сделать отложенную загрузку Читать далее »

Выравнивание миниатюр товаров

Выравнивание миниатюр товаров

Идеальная ситуация, когда мы загружаем изображения для товаров (хотя бы для главного изображения) квадратными. т.е. заранее подготовленными, откадрированными. Но бывают случаи, когда на сайт начинают заливаться изображения разных пропорций. Сделаем Читать далее »

/
Несколько миниатюр записи

Несколько миниатюр записи

В некоторых случаях необходимо, чтобы у записи было несколько миниатюр. Например, если запись это товар с несколькими изображениями. Добавим эту возможность при редактировании записи. Плагин Multiple Featured Images После установки Читать далее »

/

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

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

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