Не так давно я объединился с Мэтом Маркизом из Responsive Images Community Group, чтобы интегрировать адаптивные изображения к платформе WordPress. Мы решили сделать рефакторинг плагина, который я написал несколько месяцев назад, чтобы прийти к более удобоваримому и производительному решению.
После месяцев pull-запросов, обсуждений в Slack и помощи со стороны команды ядра WordPress, мы наконец готовы поделиться нашим проектом. Вы можете загрузить и установить RICG Responsive Images из хранилища плагинов WordPress, отслеживая процесс разработки на Github.
Что делает этот плагин?
Способ вывода тега img не менялся в WordPress на протяжении долгих лет. Несмотря на то что есть много вариантов, как подцепиться к родным функциям WordPress и изменить сниппет img, такой подход может показаться новичкам и некоторым разработчикам достаточно сложным. Отнесите сюда же запутанность Picturefill и спецификации srcset, и в итоге вы поймете, что у пользователей WordPress есть не так много вариантов для применения понятного и грамотно функционирующего решения для адаптивных изображений.
Чтобы решить эту проблему, мы создали плагин, который «выдает» пользователям адаптивные изображения сразу после своей установки без каких-либо дополнительных усилий. Никаких параметров в панели администратора, конфигурирования загрузки медиафайлов или кодирования. Плагин поставляется с одной зависимостью — polyfill-скриптом для браузеров, которые не поддерживают родные адаптивные изображения. Удаление этого файла является опциональным и не влияет на работоспособность плагина, если пользователь работает с современными браузерами.
Как только изображение будет загружено через медиа интерфейс, WordPress автоматически создаст три варианта изображения в разных размерах. Если плагин активирован, добавление миниатюры и изображений в контент записи вернет стандартную разметку для изображений WordPress, к которой будет добавлен атрибут srcset. Мы используем этот атрибут, поскольку его проще всего добавить как разработчикам, так и простым пользователям. В то время как элемент picture предлагает пользователю более обширный набор опций, мы решили, что атрибут srcset более удобен в качестве готового решения. Также он подойдет в том случае, если переключение разрешения для вас выходит за рамки простого Art Direction (об этом мы еще поговорим в статье).
<a href="http://ricg.dev/wp-content/uploads/2015/01/image.jpg"><img class="alignnone size-full wp-image-6" src="http://ricg.dev/wp-content/uploads/2015/01/image.jpg" srcset="http://ricg.dev/wp-content/uploads/2015/01/image-150x150.jpg 150w, http://ricg.dev/wp-content/uploads/2015/01/image-300x300.jpg 300w, http://ricg.dev/wp-content/uploads/2015/01/image-1024x1024.jpg 1024w, http://ricg.dev/wp-content/uploads/2015/01/image.jpg 1800w" alt="a cool responsive image" width="1800" height="1800"></a>
Плагин имеет обратную совместимость. Это означает, что изображения, которые были добавлены до установки плагина, будут адаптивными, если они были добавлены в запись или в раздел миниатюры. Это вызвано тем, что он использует размеры изображений, определенные ранее в WordPress и в файле functions.php активной темы. Размеры изображений будут сохраняться всюду в массиве srcset, что означает, что изображения, отличающиеся от соотношения сторон первоначально загруженного изображения, учитываться не будут.
Разработчики тем могут использовать плагин, чтобы разместить адаптивные изображения везде, где они хотят, используя функцию tevkori_get_srcset_string(), которая принимает в качестве аргументов ID изображения и его размер.
<img src="myimg.png" <?php echo tevkori_get_srcset_string( 11, 'medium' ); ?> />
Есть также функция tevkori_get_srcset_array(), которая принимает те же самые параметры и возвращает массив значений srcset для определенного изображения.
Как работает плагин?
Большая часть функциональности происходит тогда, когда изображение перетаскивается в визуальный редактор WordPress. Поскольку все измененные версии изображения (в разных размерах) создаются в процессе его загрузки, единственное, что можно сделать – это создать массив, содержащий URL-адреса доступных изображений в разных размерах, а также их размеры. Этот массив затем фильтруется, чтобы удалить из него размеры изображений с соотношениями сторон, которые не соответствуют полноразмерному изображению.
Массив создается путем вызова функции wp_get_attachment_image_src(), и хранит в себе результаты. В то же самое время мы используем wp_get_attachment_metadata() для получения тех же самых результатов, однако для каждого возможного варианта изображения. Затем вычисляется коэффициент отношения сторон, который рассчитывается путем умножения ширины каждого изображения на результат деления высоты исходного изображения на его ширину. Если этот результат будет соответствовать высоте исходного изображения, то в таком случае изображение будет помещено в финальный массив, который будет возвращаться функцией tevkori_get_srcset_array().
Функция tevkori_get_srcset_string() вызывает tevkori_get_srcset_array() и помещает результат в атрибут srcset. Фильтр применяется к функции image_send_to_editor, где регулярное выражение используется для помещения результата функции tevkori_get_srcset_string() сразу после атрибута src изображения. Тот же самый процесс происходит и с миниатюрами – фильтр применяется к функции post_thumbnail_html.
Если размер изображения меняется в редакторе записей, то тогда плагин обнаружит такое изменение и обновит соответствующим образом значение srcset. Это гарантирует, что всегда будет сохраняться корректное отношение сторон изображения. Чтобы реализовать такую функциональность, мы используем JavaScript для сцепления с объектом wp.media и повторно вычисляем атрибут srcset, выполняя те же самые вычисления соотношения сторон, определенные в tevkori_get_srcset_array(). Прежде, чем начать этот проект, я не знал про объект wp.media и его обширный функционал. Поскольку по нему существует не так много документации, подробное разъяснение его использования может оказаться полезным. Как выяснилось, вы можете отслеживать событие image-update в редакторе записей, добавив обработчик событий к объекту wp.media.
wp.media.events.on( 'editor:image-update', function( args ) { var image = args.image; //more function logic });
С помощью этой функции разработчик тем может получить доступ к любому изображению, как только оно будет обновлено в редакторе записей. Вы можете также воспользоваться библиотекой Underscore, которая используется как зависимость медиа-загрузчика для редактирования данных изображения на лету. В случае с нашим плагином мы используем полезную утилиту Underscore для получения отношения сторон размеров изображений, как только произойдет событие editor:image-update.
// Grab all of the sizes that match our target ratio and add them to our srcset array. _.each(sizes, function(size){ var softHeight = Math.round( size.width * metadata.height / metadata.width ); // If the height is within 1 integer of the expected height, let it pass. if ( size.height >= softHeight - 1 && size.height <= softHeight + 1 ) { srcsetGroup.push(size.url + ' ' + size.width + 'w'); } });
Если вы хотите узнать больше о том, как мы сцепляемся с объектом wp.media, взгляните на код wp-tevko-responsive-images.js.
Атрибут sizes
В настоящее время плагин не добавляет атрибут sizes для полноты атрибута srcset. Причина состоит в том, что изначально мы поняли, что не можем предсказать, какими могут быть эти размеры, поскольку они зависят от того, как стилизована тема пользователя. Мы продолжаем работать над этой проблемой и призываем пользователей включать атрибут sizes самостоятельно – либо вручную, либо с помощью плагина WordPress, такого как wp-lazysizes. Стоит также сказать о том, что спецификация адаптивных изображений недавно была изменена, и использование дескриптора w должно теперь сопровождаться атрибутом sizes. Исключение атрибута sizes сделает разметку технически неправильной, в то время как откат по-прежнему будет происходить к стандартному размеру 100vh.
Что по поводу функций X, Y и Z?
Вы, вероятно, заметили, что данный плагин не охватывает несколько вариантов использования. Первое, о чем нас обычно спрашивают – это о возможности Art Direction. Что это такое? Термин «Art Direction» описывает загрузку по-разному стилизованных изображений в разных контрольных точках – вне зависимости от того, новые ли это изображения или те же самые изображения, обрезанные или сфокусированные по-другому. Эта возможность требует использования элемента picture, что в свою очередь может привести к более массивной разметке для генерации финального изображения.
Добавление этой возможности не вышло бы без внедрения довольно сложного интерфейса к загрузчику медиа WordPress, поскольку пользователю понадобилось бы определять контрольные точки, после чего выбирать изображения, которые будут загружаться при достижении этих контрольных точек. Наша цель, которую мы преследовали, создавая этот плагин – выполнить базовую реализацию адаптивных изображений, для которых не потребуется никакой конфигурации со стороны пользователя. Таким образом, мы решили опустить функцию Art Direction. Мы, однако, приложим все усилия, чтобы Art Direction работал совместно с нашим плагином, поскольку мы планируем расширять API для разработчиков тем.
«Ленивая загрузка» и сжатие изображений – две других возможности, которые мы не планируем реализовать, поскольку они выходят за рамки «дефолтного» решения для адаптивных изображений. Опять же, разработчики тем смогут использовать эти возможности посредством API.
Что дальше?
В то время как плагин уже доступен для загрузки и установки, мы активно работаем над его улучшением. Так, пользователи могут ожидать более частые обновления, отчеты о решенных проблемах и всестороннее улучшение плагина со временем. Мы планируем добавлять дополнительные опции, как, к примеру, атрибут sizes и хуки, которые позволяют разработчикам тем улучшать плагин в будущем.
Еще одна возможность, которую мы обязательно рассмотрим – это дескрипторы соотношения сторон 2x и 3x для случаев с Retina-дисплеями. Также появится лучшая поддержка и документация. В конечном счете, мы хотели бы, чтобы этот плагин стал частью ядра WordPress, оставаясь все таким же минималистическим, простым в использовании и лишенным настроек.