Поддержка адаптивных изображений была добавлена в ядро WordPress в версии 4.4, чтобы решить проблему с выбором изображений на основе вьюпорта (области просмотра). В данном случае браузер запрашивает изображение того размера, который будет идеально отвечать конкретной области просмотра.
Изображения, встречающиеся в тексте записей, автоматически обрабатываются в адаптивной манере, в то время как изображения, обрабатываемые темами или плагинами – как, к примеру, миниатюры или галереи – могут использовать для этого функции и фильтры, заданные разработчиками. Благодаря небольшим дополнениям, в WordPress можно реализовать интересную технику, которая связана с адаптивными изображениями и называется арт-дирекшн (art direction). С помощью этой техники можно создать такой дизайн, в котором изображения будут обрезаться или менять свои пропорции в определенных контрольных точках.
В данной статье я покажу вам, как задать арт-дирекшн в WordPress. Нам понадобится добавить PHP-код, polyfill-скрипт, а также плагин для обрезки изображения.
- Автоматическая поддержка адаптивных изображений в записях в WordPress
- Изображение переменной ширины в баннере на странице
- Арт-дирекшн в шаблоне страниц
- Шаг 1. Подключаем скрипт Picturefill.
- Шаг 2. Продумываем контрольные точки и настраиваем размеры изображений.
- Шаг 3. Устанавливаем плагин и обрезаем изображения.
- Шаг 4. Кодируем изображение с помощью элемента Picture
Автоматическая поддержка адаптивных изображений в записях в WordPress
Поддержка автоматических изображений реализована следующим образом: мы предоставляем массив с файлами изображений браузеру, а браузер в зависимости от ширины и плотности пикселей области просмотра запрашивает файл с наиболее подходящим разрешением. Главным атрибутом здесь является srcset, который может использоваться с тегами img и source. Он представляет собой «набор исходных файлов» — т.е. список файлов изображений, доступных для скачивания.
Начиная с версии 4.4, WordPress автоматически добавляет атрибут srcset к любому изображению, которое пропускается через фильтр the_content. Иными словами, когда WordPress создает HTML-код для страницы, он сканирует текст записи или страницы на наличие тегов img, после чего добавляет атрибут srcset ко всем тегам, которые не имеют его. Вы не увидите srcset в редакторе записей (если только вы явно не добавите его, хотя лучше всего предоставить это дело WordPress), однако этот атрибут будет присутствовать в исходном коде страницы.
Чтобы предложить несколько размеров изображений в srcset, WordPress использует стандартное поведение по автоматическому созданию нескольких уменьшенных версий ваших изображений, когда они загружаются в медиатеку. Вы можете найти эти размеры файлов на экране Media Settings (в разделе Settings меню администраторского интерфейса WordPress), где они будут приведены вместе со своими значениями по умолчанию; отсутствует только размер medium_large (768 пикселей в ширину без ограничений по высоте), который может корректироваться темами и плагинами, но его не поменять через панель администратора.
По умолчанию автоматически генерируемые размеры изображений medium, medium_large и large остаются с тем же самым соотношением сторон, что и исходный файл (можно сказать, что они масштабируются). В этих случаях ширина, которая задана на странице Media Settings, является ограничительным параметром. В противоположность этому размер thumbnail жестко обрезается до квадрата размерами 150 пикселей. По этой причине он обычно имеет другое соотношение сторон, нежели его более крупные собратья. WordPress опирается именно на соотношение сторон, чтобы определить, какие размеры должны быть включены в srcset; мы рассмотрим это на примерах.
Допустим, что мы загрузили изображение 1400 x 952 пикселей в медиатеку WordPress. Размеры изображений возьмем по умолчанию. WordPress создаст следующие версии этого изображения:
Если вы теперь вставите «large» (1024 пикселя в ширину) версию изображения в запись и посмотрите исходный код HTML для опубликованной страницы, вы увидите нечто следующее:
<img src="sample-1024x696.jpg" width="1024" height="696" class="alignnone size-large" srcset="sample-300x204.jpg 300w, sample-768x522.jpg 768w, sample-1024x696.jpg 1024w" sizes="(max-width: 1024px) 100vw, 1024px" alt="A meaningful sample image">
WordPress сгенерировал srcset, используя размеры medium, medium_large и large, поскольку эти изображения имеют те же самые соотношения сторон. Версия thumbnail не была включена, что вполне оправданно – ведь мы хотим, чтобы эти изображения выглядели одинаково во всех вьюпортах.
Также в srcset были добавлены и другие данные. Во-первых, дескрипторы w в srcset, которые сообщают браузеру фактическую ширину файлов в пикселях; без этого браузеру придется загрузить изображения, чтобы узнать их размеры. Во-вторых, значение по умолчанию для всех атрибутов sizes, которое сообщает браузеру, насколько широким должно быть изображение в имеющейся разметке. В данном случае для областей просмотра, не превышающих 1024 пикселя, изображение должно быть масштабировано с учетом размера вьюпорта; иначе изображение должно быть выведено с шириной по умолчанию (1024 пикселя), не шире. Теперь, имея всю информацию, браузер может вывести соответствующее изображение: файл высокого разрешения для Retina-дисплеев или файл низкого разрешения для небольших телефонов.
Изображение переменной ширины в баннере на странице
Теперь, когда мы разобрались с тем, как WordPress использует стандартные размеры изображений для создания srcset, пришла пора познакомиться с новыми функциями, которые недавно вошли в ядро WP. В качестве примера мы рассмотрим баннер, который занимает всю ширину статичной главной страницы.
Предположим, что у нас есть сайт, использующий текущую версию WordPress, и что поддержка миниатюр добавлена к нашей теме (миниатюры – устоявшийся перевод для featured images; на самом деле они могут вполне занимать и все пространство экрана). Предположим также, что изображение для баннера формируется на основе миниатюры для главной страницы. Если шаблон нашей главной страницы использует тег the_post_thumbnail() для генерации HTML-кода баннера, то в таком случае у нас все готово: эта функция уже выводит тег img, включающий в себя атрибуты srcset и sizes. Это одна из причин, почему лучше всего использовать функции шаблонов в WordPress, когда они доступны!
Хотя может быть и так, что наш шаблон страницы формирует HTML-код для баннера по частям, что нередко бывает, если баннер входит в карусель изображений. Чтобы сделать изображение адаптивным в этом случае, мы запрашиваем у WordPress атрибуты srcset и sizes, используя функции wp_get_attachment_image_srcset() и wp_get_attachment_image_sizes():
<?php if ( has_post_thumbnail() ) : ?> $id = get_post_thumbnail_id(); $src = wp_get_attachment_image_src( $id, 'full' ); $srcset = wp_get_attachment_image_srcset( $id, 'full' ); $sizes = wp_get_attachment_image_sizes( $id, 'full' ); $alt = get_post_meta( $id, '_wp_attachment_image_alt', true); <img src="<?php echo esc_attr( $src );?>" srcset="<?php echo esc_attr( $srcset ); ?>" sizes="<?php echo esc_attr( $sizes );?>" alt="<?php echo esc_attr( $alt );?>" /> <?php endif; ?>
В данном случае мы помещаем в srcset и sizes размеры исходного изображения. Делается это с помощью ключевого слова full. Если изображение составляет 1280 x 384 пикселей, и если мы зададим базовые размеры изображения в качестве значений по умолчанию, то в таком случае HTML-вывод будет следующим:
<img src="banner.jpg" srcset="banner.jpg 1280w, banner-300x90.jpg 300w, banner-768x231.jpg 768w, banner-1024x308.jpg 1024w" sizes="(max-width: 1280px) 100vw, 1280px" alt="Front page banner alt text">
В этом случае, как и в прошлом примере, значение, которое WordPress передает нам в качестве атрибута sizes, приемлемо для нашей гипотетической разметки. В целом, значение по умолчанию для sizes прекрасно подходит для изображений во всю ширину страницы, однако для других разметок вам, возможно, придется его корректировать. Все разметки разные. Атрибут sizes для адаптивных сеток с изображениями – простой случай, однако макеты могут быть и сложнее, они могут меняться при прохождении разных контрольных точек.
Арт-дирекшн в шаблоне страниц
Давайте вернемся к HTML-коду в примере с баннером и обратим внимание на размер самого маленького изображения в srcset. Оно составляет всего 90 пикселей в высоту, а потому, скорее всего, его будет сложно разглядеть. Соотношение сторон является фиксированным, оно высчитывается на основе исходного изображения, поэтому мы увидим 96-пиксельную строку на телефоне с 320-пиксельным экраном.
Темы в настоящее время позволяют избежать проблемы «баннера в виде полосы», выводя изображение как CSS-бэкграунд в гибком DIV, корректируя его height и background-size с помощью медиа-запросов. Это решение адаптивно с точки зрения внешнего вида, но оно не является в действительности таковым. Перейдем к арт-дирекшну – возможности задать разные источники изображений для разных областей просмотра прямо в HTML. С помощью данной техники мы можем избежать проблемы превращения баннера в полосу, задав новые пропорции изображения при переходе через контрольную точку, чтобы меньшие размеры имели лучшее разрешение. Мы можем также использовать арт-дирекшн для акцентирования внимания на определенной области изображения при различных размерах или ориентации экрана.
В нашем примере мы будем использовать изображение 1400 x 952 пикселей из нашего первого примера для создания адаптивного изображения. На крупных вьюпортах изображение будет выглядеть примерно так:
Однако для небольших областей просмотра оно будет обрезаться в WordPress:
Такой подход дает нам два изображения по цене одного – изображение во всю ширину и обрезанное изображение – каждое со своим собственным srcset.
Чтобы применить данную технику, нужно соответствующим образом настроить среду WordPress. Как в прошлом примере, изображение будет являться миниатюрой для главной страницы сайта, и мы будем редактировать шаблон главной страницы. Все изменения лучше всего вносить в дочернюю тему.
Шаг 1. Подключаем скрипт Picturefill.
Мы будем кодировать наше изображение путем обертывания его в HTML5 элемент picture. Этот элемент позволяет нам задавать множественные источники для изображения, а также медиа-запросы для определения того, когда источник будет использован. На момент написания статьи элемент picture поддерживался 62% браузеров, таким образом, нам придется положиться на polyfill-скрипт Picturefill, чтобы обработать этот элемент в неподдерживаемых браузерах. Проект Picturefill был основан Filament Group; JS-файл Picturefill может быть загружен с GitHub.
Чтобы подключить скрипт Picturefill в раздел head страниц, мы расположим файл скрипта в директории с нашей дочерней темой, после чего добавим следующий код в functions.php дочерней темы:
// adds Picturefill to 'js' subdirectory inside child theme function theme_add_javascripts() { wp_enqueue_script( 'picturefill-js', get_stylesheet_directory_uri() . '/js/picturefill.min.js', '', '', false ); } add_action( 'wp_enqueue_scripts', 'theme_add_javascripts' );
Шаг 2. Продумываем контрольные точки и настраиваем размеры изображений.
Чтобы задать наш srcset, мы должны определиться с тремя вещами:
- Контрольной точкой, в которой мы будем переключаться от обрезанного к полноэкранному изображению;
- Соотношением сторон для обрезанного изображения;
- Одним или несколькими уменьшенными размерами обрезанного изображения для небольших вьюпортов.
Давайте разберемся с каждым из этих пунктов.
Контрольная точка
Для нашего примера допустим, что в зеркале заднего вида становится сложно что-то разглядеть, если изображение уже, чем 768 пикселей. Мы установим контрольную точку на 768 пикселях; это будет означать, что мы можем сохранить размеры medium_large и large со значениями по умолчанию.
Соотношение сторон
Наша простая реализация арт-дирекшна не требует от нас загрузки множественных миниатюр или вводить значение для контрольной точки. Однако нам нужен способ, чтобы srcset для полноэкранного изображения не перекрывался значением srcset для обрезанного изображения. С этим нам поможет функция wp_get_attachment_image_srcset() — она отбирает файлы изображений только с тем же самым соотношением сторон, что и размер, который мы передали в нее. Мы задали соотношение сторон 5:3 (1.67) для обрезанного изображения, которое отличается от соотношения сторон исходного изображения (1.47).
Размеры изображений
Размер обрезанного изображения, основанный на нашей контрольной точке и соотношении сторон, будет составлять 767 x 460 пикселей. Обрезанное изображение не будет полностью адаптивным, но только до тех пор, пока мы не определим дополнительные размеры изображений для обрезки вместе с ним. Мы создадим произвольные размеры, которые будут составлять 560 и 360 пикселей в ширину, что позволит нам получить разницу примерно в 20 Кб для размера файла в трех обрезанных версиях (поскольку размер файла сжатого изображения зависит от его цветов и глубины детализации, я задал эти размеры эмпирически с базовым 90% сжатием JPEG в WordPress). Произвольные размеры изображений будут создаваться путем добавления соответствующего кода в functions.php дочерней темы:
// cropped hero add_image_size( 'mytheme-hero-cropped', 767, 460, true ); // scaled-down cropped hero 1 add_image_size( 'mytheme-hero-cropped-smaller', 560, 336, true ); // scaled-down cropped hero 2 add_image_size( 'mytheme-hero-cropped-smallest', 360, 216, true );
Четвертый параметр в функции add_image_size определяет, является ли версия изображения обрезанной, что мы установим в true; многие плагины не позволяет нам выполнить обрезку изображения, пока мы не установим этот параметр. В итоге мы будем иметь следующие версии изображений:
Шаг 3. Устанавливаем плагин и обрезаем изображения.
Встроенный редактор изображений WordPress позволяет выполнять обрезку изображений, однако изменения применяются ко всем размерам (или только к миниатюрам), в то время как нам нужно провести обрезку только трех размеров. Для большего контроля мы установим сторонний плагин обрезки из каталога WordPress.
Практически любой плагин для обрезки должен работать с нашей арт-дирекшн техникой, однако идеальный плагин для этого – тот, который может обрезать множественные версии изображения, имеющие одинаковое соотношение сторон. Я нашел два плагина, которые позволяют это делать: Crop-Thumbnails и Post Thumbnail Editor. Протестировав оба плагина, я обнаружил, что Crop-Thumbnails распознал только два размера из трех, и мне пришлось проделывать процесс обрезки два раза (проблема была с округлением значений: размер mytheme-hero-cropped остался без обрезки, поскольку его ширина была 460 пикселей, а не 460.2, как того требует соотношение сторон 5:3). Плагин Post Thumbnail Editor позволил мне обрезать все три размера сразу.
Шаг 4. Кодируем изображение с помощью элемента Picture
Теперь, когда все размеры готовы, мы можем добавить код для нашего изображения в шаблон главной страницы дочерней темы. Элемент picture может содержать тег img и один или несколько тегов source. В нашем примере один элемент source будет содержать запрос media и srcset для изображения в полную ширину, а тег img будет содержать srcset для обрезанного изображения; обрезанное изображение будет выступать в качестве изображения по умолчанию, когда условие контрольной точки не выполняется.
<?php if ( has_post_thumbnail() ) : ?> $id = get_post_thumbnail_id(); $alt = get_post_meta( $id, '_wp_attachment_image_alt', true); /* get the width of the largest cropped image to calculate the breakpoint */ $hero_cropped_info = wp_get_attachment_image_src( $id, 'mytheme-hero-cropped' ); $breakpoint = absint( $hero_cropped_info[1] ) + 1; // pass the full image size to these functions $hero_full_srcset = wp_get_attachment_image_srcset( $id, 'full' ); $hero_full_sizes = wp_get_attachment_image_sizes( $id, 'full' ); // pass the cropped image size to these functions $hero_cropped_srcset = wp_get_attachment_image_srcset( $id, 'mytheme-hero-cropped' ); $hero_cropped_sizes = wp_get_attachment_image_sizes( $id, 'mytheme-hero-cropped' ); <picture> <source media="(min-width: <?php echo $breakpoint; ?>px)" srcset="<?php echo esc_attr( $hero_full_srcset ); ?>" sizes="<?php echo esc_attr( $hero_full_sizes ); ?>" /> <img srcset="<?php echo esc_attr( $hero_cropped_srcset ); ?>" alt="<?php echo esc_attr( $alt );?>" sizes="<?php echo esc_attr( $hero_cropped_sizes ); ?>" /> </picture> <?php endif; ?>
Этот код интересен и еще по двум причинам. Во-первых, обратите внимание на то, что мы не прописываем жестко ширину для контрольной точки, хоть мы и знаем, что она должна быть в данном случае 768 пикселей. Мы рассчитываем контрольную точку на основе ширины самого крупного обрезанного изображения, поэтому в будущем мы можем сменить размеры изображений без необходимости редактирования шаблона. Во-вторых, в противоположность примеру с баннером, тег img здесь не получает атрибута src. Это особенность использования polyfill-скрипта для поддержки элемента picture: браузеры, которые не поддерживают picture, будут предварительно загружать файл, заданный в атрибуте src, что выльется в двойную загрузку данного изображения.
HTML-код, который мы получим, приведен ниже:
<picture> <source media="(min-width: 768px)" srcset="hero.jpg 1400w, hero-300x204.jpg 300w, hero-768x522.jpg 768w, hero-1024x696.jpg 1024w" sizes="(max-width: 1400px) 100vw, 1400px"> <img srcset="hero-767x460.jpg 767w, hero-560x336.jpg 560w, hero-360x216.jpg 360w" alt="Front page hero alt text" sizes="(max-width: 767px) 100vw, 767px"> </picture>
Мы могли бы закончить здесь, но мы сделаем еще одно уточнение по нашему HTML-выводу. Обратите внимание, что изображение medium, содержащее 300 пикселей в ширину, добавлено в srcset для полноэкранного изображения. Этот файл никогда не будет использован, а потому мы можем добавить фильтр wp_calculate_image_srcset для удаления его из srcset. Следующий код для functions.php дочерней темы рассматривает только потенциальный srcset (массив $sources) для полноэкранного изображения; он проходит по изображениям и удаляет те, чья ширина меньше, чем ширина для контрольной точки:
add_filter( 'wp_calculate_image_srcset', 'mytheme_remove_images_below_breakpoint', 10, 5 ); function mytheme_remove_images_below_breakpoint( $sources, $size_array, $image_src, $image_meta, $attachment_id ) { if ( is_front_page() && has_post_thumbnail() ) { // check if we're filtering the featured image if ( $attachment_id === get_post_thumbnail_id() ) { // get cutoff as width of the largest cropped image size // (in HTML, breakpoint = cutoff + 1 ) $cutoff = $image_meta['sizes']['mytheme-hero-cropped']['width']; // check if our version is the full-sized version by // comparing its width to the cutoff if ( $cutoff < $size_array[0] ) { // for each element in tentative srcset foreach ( $sources as $key => $value ) { // if image width is at or below cutoff, // we don't need it if ( $cutoff >= $key ) { unset( $sources[ $key ] ); } } } } } return $sources; }
Спасибо очень хорошая и полезная статья
Согласен, статья хорошая.