Pull to refresh

Picture — новый элемент, которого нет

Reading time 6 min
Views 85K


В девелоперских сборках браузеров Chrome, Firefox и Opera появилась поддержка нового элемета picture, призванного решить ряд проблем возникающих при разработке адаптивных дизайнов. Давайте рассмотрим его подробнее.

Новый элемент picture, решает следующие задачи, встающие перед разработчиком адаптивных веб-приложений (я воспользуюсь классификацией, предложенной pepelsbey на одной из недавних конференций по фронтенду):
  1. Ретина, т.е. экраны с плотностью точек на дюйм 150 и выше, на которых обычное изображение выглядит размыто
  2. Адаптивность, задача изменения размеров изображения согласно вашим правилам, прописанным в дизайне в зависимости от размера вьюпорта.
  3. Формат, возможность использовать современные форматы, такие как WebP, если они поддерживаются браузером
  4. Кадрирование или Художественные цели. Обрезка маловажных частей изображения, при показе на устройствах с меньшим экраном.

Сложив первые буквы, получаем мнемонику РАФК

Синтаксис


Условно, расширенный синтаксис нового элемента выглядит так
<picture>
  <source 
    srcset="<список URL c дескрипторами>" 
    [sizes="<ваши размеры в зависимости от раскладки>"] 
    [media="<медиавыражение>"] 
    [type="<mime/type>"]
  >
 <source ...>
  ...
  <img src="image.jpg" alt="My image" 
    [srcset="<список URL с дескрипторами>"] 
    [sizes="<ваши размеры в зависимости от раскладки>"]>
</picture>

Элемент picture не рендерит никакой контент, а лишь является справочным контейнером для вложенного в него тега img.

Поэтому для большинства задач хватит сокращенной записи, совсем без использования picture
  <img src="image.jpg" alt="My image" 
    [srcset="<список URL с дескрипторами>"] 
    [sizes="<ваши размеры в зависимости от раскладки>"]>


Давайте рассмотрим как решаются вышеозначенные проблемы с помощью нового элемента. Все файлы примеров можно найти в этом репозитории github.com/fetis/picture

Для тестирования примеров из данной статьи на десктопе вам понадобятся либо Firefox Nighlty (поддержка picture включается настройкой dom.image.picture.enable в about:config), либо Chrome Canary, либо Opera Developer. На мобильном устройстве новый элемент можно протестировать в Chrome Beta

Ретина


У нас есть изображение 400х300 пкс, которое мы хотим также красиво показывать при двукратной и трехкратной плотности пикселей. Для этого готовим еще 2 картинки, размерами 800x600 и 1200х900 и пишем следующий код
      <img
        src="images/400.jpg"  
        srcset="images/800.jpg 2x, images/1200.jpg 3x"
        width="400" height="300"
        >


2x и 3x это дескрипторы плотностей пикселей, они говорят браузеру, что вот эти картинки были подготовлены для вот этой плотности, если хочешь, можешь использовать. Обратите внимание, они не заставляют бразуер использовать эти картинки, а только подсказывают ему. Окончательное решение остается за ним в зависимости от других условий, например, текущего соединения.

Атрибут src в данном случае служит источником картинки для плотности < 2 и фолбеком на случай, если браузер не поддерживает новый элемент.

Адаптивность


Представим раскладку, в которой есть единственная контрольная точка (breakpoint) 700пкс. При размере вьюпорта более 700 пкс мы показываем справа сайдбар и размер нашего изображения должен быть 75% от ширины экрана. В противном случае сайдбар располагается в конце страницы и изображение должно быть растянуто на всю ширину. Это реализуется следующим кодом
      <img
        src="images/400.jpg"  
        srcset=" 400w, images/800.jpg 800w, images/1200.jpg 1200w"
        sizes="(min-width: 700px) 75vw, 100vw"
        >

400w, 800w, 1200wэто дескрипторы ширины, они подсказывают браузеру картинка какой ширины находится по данному URL и на основе этой информации браузер принимает решение какое изображение лучше всего подойдет в текущей ситуации. Как и в случае с ретиной информация носит рекомендательный характер и окончательное решение какое изображение грузить остается за браузером.

Одновременное использование дескрипторов плотности и ширины недопустимо.

В атрибуте sizes перечисляются размеры изображения для всех контрольных точек в нашем дизайне. Контрольные точки задаются в виде обычного медиавыражения, браузер берет первое, которое возвращает Истину и дальше цепочку не рассматривает. Для значения ширины используется новая единица длины vw, которая возвращает значение в процентах от ширины вьюпорта.

Если для картинки нет необходимости использовать контрольные точки, то запись можно сократить до такой sizes="100vw". А для более сложных дизайнов можно использовать CSS-функцию calc(), например
sizes="(max-width: 30em) 100vw, (max-width: 50em) 50vw, calc(33vw - 100px)"

Самый сложный в поведении атрибут на мой взгляд. Если не указывать sizes, то браузер всегда выбирал самую большую картинку. В сочетании с width не работает, хотя казалось бы логичное сочетание и ряд других глюков. Возможно это особенности ранней реализации.

Как видите, мы уже покрыли 80% потребностей адаптивной верстки, а еще ни разу не использовали picture, настало время ему тоже вступить в игру.

Формат


Использование различных форматов для изображений мало отличается от способов используемых для тегов video или audio
      <picture>
        <source srcset="images/400.webp" type="image/webp">
        <img src="images/400.jpg"
          width="400" height="300" 
        >
      </picture>

Мы указываем список источников и mime/type для каждого, а браузер уже выбирает первый, который знает. В качестве фолбека используется изображения из атрибута src.

Кадрирование


Когда мы показываем фото на меньшем экране иногда имеет смысл обрезать лишние детали, оставив только основную часть. С этой задачей нам поможет справиться атрибут media
      <picture>
        <source media="(min-width: 900px)" srcset="images/original.jpg 1200w" sizes="100vw">
        <source media="(min-width: 700px)" srcset="images/800crop.jpg 800w" sizes="100vw">
        <img 
          srcset="images/400crop.jpg 400w"
          sizes="100vw"  
          >
      </picture>

В каждом атрибуте media мы задаем медиавыражение, при котором у нас будет меняться исходное изображение и, в отличие от предыдущих примеров, браузер будет обязан ему следовать. Обратите также внимание как кадрирование здесь сочетается с адаптивностью, чтобы растянуть изображение на всю ширину.

РАФК


А теперь все 4 метода в одном флаконе :) Возможно так будет выглядеть вставка картинок через пару лет (пример из блога Оперы)
<picture>
	<source
		media="(min-width: 1280px)"
		sizes="50vw"
		srcset="opera-fullshot-200.webp 200w,
				opera-fullshot-400.webp 400w,
				opera-fullshot-800.webp 800w,
				opera-fullshot-1200.webp 1200w,
				opera-fullshot-1600.webp 1600w,
				opera-fullshot-2000.webp 2000w"
		type="image/webp">
	<source
		sizes="(min-width: 640px) 60vw, 100vw"
		srcset="opera-closeup-200.webp 200w,
				opera-closeup-400.webp 400w,
				opera-closeup-800.webp 800w,
				opera-closeup-1200.webp 1200w,
				opera-closeup-1600.webp 1600w,
				opera-closeup-2000.webp 2000w"
		type="image/webp">
	<source
		media="(min-width: 1280px)"
		sizes="50vw"
		srcset="opera-fullshot-200.jpg 200w,
				opera-fullshot-400.jpg 400w,
				opera-fullshot-800.jpg 800w,
				opera-fullshot-1200.jpg 1200w,
				opera-fullshot-1600.jpg 1800w,
				opera-fullshot-2000.jpg 2000w">
	<img
		src="opera-closeup-400.jpg" alt="The Oslo Opera House"
		sizes="(min-width: 640px) 60vw, 100vw"
		srcset="opera-closeup-200.jpg 200w,
				 400w,
				opera-closeup-800.jpg 800w,
				opera-closeup-1200.jpg 1200w,
				opera-closeup-1600.jpg 1600w,
				opera-closeup-2000.jpg 2000w">
</picture>


Здесь используются 2 формата JPEG и WebP. При ширине экрана более 1280 пкс показывается полноразмерная картинка в половину вьюпорта. При ширине от 640 до 1279 показывается обрезанное фото на 60% ширины вьюпорта. При ширине экрана меньше 640пкс показывается обрезанная фотография на 100% ширины. Выбор под текущее DPI экрана производится на основе ширины исходных файлов.

Дополнительная информация


Поддержка браузерами caniuse.com/#search=picture
Спецификация www.w3.org/html/wg/drafts/html/master/embedded-content.html#the-picture-element
Рабочая группа и типовые задачи, которые они решали с помощью нового элемента responsiveimages.org
Множество примеров использования dev.opera.com/articles/responsive-images
Tags:
Hubs:
+44
Comments 98
Comments Comments 98

Articles