Как сделать картинку адаптивной в html
Перейти к содержимому

Как сделать картинку адаптивной в html

  • автор:

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

В данной статье мы изучим концепцию гибких (responsive) изображений — таких, которые отображаются хорошо на устройствах с сильно отличающимися размерами экрана, разрешением, и другими характеристиками — и рассмотрим инструменты, которые имеются в HTML для их реализации. Responsive images — только одна часть (и хорошее начало) гибкого веб-дизайна, темы, которая будет рассмотрена подробнее в будущем модуле на тему CSS.

Требования: Предполагается, что вы уже знакомы с основами HTML и умеете добавлять статичные изображения на веб-страницу.
Цель: Узнать, как использовать такие элементы, как srcset и <picture> чтобы обеспечить работу гибких изображения на веб-сайтах.

Почему адаптивные изображения?

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

Our example site as viewed on a wide screen - here the first image works ok, as it is big enough to see the detail in the center.

Такая вёрстка хорошо выглядит на широкоформатных экранах ноутбуков и настольных ПК, (вы можете посмотреть посмотреть демо-пример и найти исходный код на Github.) Мы не будем подробно рассматривать CSS, скажем только следующее:

  • Содержимому тега main задана максимальная ширина 1200 пикселей. Если ширина окна браузера больше этого значения, то содержимое сайта остаётся на 1200 пикселей и центрирует себя в доступном пространстве. Если ширина окна браузера меньше, содержимое устанавливается в 100% от ширины экрана.
  • Изображение в шапке всегда будет оставаться в центре тега header вне зависимости от ширины браузера. Если сайт будет просматриваться на узких экранах, то важные детали в центре изображения (люди) всё равно будут видны. Все, что выходит за пределы ширины экрана будет скрыто. Высота шапки 200 пикселей.
  • Изображения в содержимом заданы так, что если ширина body становится меньше чем ширина изображения, то изображения начинают сжиматься и остаются всегда внутри body и не выступают за его пределы.

Всё хорошо, однако проблемы начинаются, когда вы просматриваете сайт на устройстве с небольшим экраном – шапка внизу выглядит нормально, но теперь она занимает значительную высоту экрана; первое изображение в контенте напротив, выглядит ужасно – при таком размере едва можно рассмотреть людей!

Our example site as viewed on a narrow screen; the first image has shrunk to the point where it is hard to make out the detail on it.

Было бы намного лучше показывать обрезанную версию изображения, на котором видны важные детали снимка, когда сайт отображается на узком экране, и, возможно, что-то среднее между обрезанным и оригинальным изображениями для экранов средней ширины, таких как планшеты – это известно как art direction problem.

Кроме того, нет нужды встраивать такие большие изображения на страницу, если она просматривается на маленьком экране мобильного устройства; это называется resolution switching problem — растровое изображение представляет собой точно-заданное количество пикселей по ширине и высоте; как мы успели заметить, когда рассматривали векторную графику, растровое изображение становится зернистым и выглядит ужасно, если оно отображается в размере большем, чем оригинальный (тогда как векторное изображение нет). В то же время, если изображение отображается в гораздо меньшем размере, чем оригинальный, это приведёт к напрасной трате трафика — пользователи мобильных устройств будут грузить большое изображение для компьютера, вместо маленького для их устройства. Идеально было бы иметь несколько файлов в разных разрешениях, и отображать нужный размер в зависимости от устройства, обращающегося к веб-сайту.

Сложность в том, что для некоторых устройств с большим разрешением экрана нужны изображения большего чем ожидается размера, чтобы чётче отображалось. По сути это всё одна задача в разных условиях.

Можно предположить, что векторные изображения могли бы решить эти проблемы. В какой-то степени это так. У них небольшой вес и размер, поэтому их можно использовать почти в любом случае. Они хороши для простой графики, узоров, элементов интерфейса и т. д. Сложнее создать векторное изображение с большим количеством деталей, как, например, на фото. Растровые изображения (JPEG) для нашего примера подходят больше.

Такого рода проблемы не было в начале существования веба, в первой половине 90-х годов – тогда единственными устройствами для просмотра веб-страниц были настольные компьютеры и ноутбуки, так что создатели браузеров и авторы спецификаций даже не задумывались о создании решения. Технологии отзывчивых изображений были реализованы недавно для решения проблем, указанных выше. Они позволяют вам предоставить браузеру несколько изображений, каждое из которых отображает одно и то же, но содержит разное количество пикселей (resolution switching), или разные изображения с отдельными областями основного изображения (art direction).

Примечание: Новые возможности обсуждаются в статье — srcset / sizes / <picture> — все они поддерживаются последними версиями современных настольных и мобильных браузеров (включая Microsoft Edge, но не Internet Explorer).

Как сделать изображения отзывчивыми?

В этом разделе рассмотрим две вышеописанные проблемы и покажем, как их решить с использованием инструментов HTML <img> . Как показано на примере выше — изображение в заголовке используется только как украшение сайта и установлено как фоновое с помощью CSS. CSS больше подходит для адаптивного дизайна чем HTML, об этом поговорим в следующем модуле о CSS.

Разные разрешения: Разные размеры

Итак, какую проблему решают разные разрешения? В зависимости от устройства нужно отобразить одно и то же изображение, но разных размеров. Посмотрите на вторую картинку в примере. Стандартный элемент <img> обычно позволяет указать только один путь к файлу:

Однако есть два новых атрибута — srcset и sizes — позволяющих добавить дополнительные изображения с пометками, чтобы браузер выбрал подходящее. Пример на Github: responsive.html (также смотри источник кода).

Атрибуты srcset и sizes кажутся сложными, но они не так плохи, если вы отформатируете их как в примере выше: каждая часть значения атрибута с новой строки. Значение состоит из списка элементов через запятую, каждый из которых включает три части. Давайте рассмотрим эти значения:

srcset включает названия изображений, среди которых браузер выберет нужное и их размеры. Перед каждой запятой части значения в таком порядке:

  1. Название изображения ( elva-fairy-480w.jpg .)
  2. Пробел.
  3. Актуальная ширина картинкив пикселах ( 480w ) — заметьте, что здесь используется w вместо px , как вы могли ожидать. Эта настоящая ширина изображения, которая может быть просмотрена в свойствах картинки на вашем компьютере (например, на Mac нужно открыть картинку в Finder и нажать Cmd + I , чтобы вывести информацию на экран).

sizes определяет перечень медиавыражений (например, ширину экрана) и указывает предпочтительную ширину изображения, когда определённое медиавыражение истинно — это то, о чём мы говорили выше. В нашем случае, перед каждой запятой мы пишем:

  1. Медиа-условие ( (max-width:480px) ) — вы можете больше узнать об этом в CSS topic, но сейчас давайте скажем, что медиа-условие описывает возможное состояние экрана. В этом случае, мы говорим «когда viewport width меньше или равен 480 пикселям».
  2. Пробел.
  3. Ширину слота (в оригинале «width of the slot»), занимаемую изображением, когда медиа-условие истинно. ( 440px )

Примечание: Для ширины слота, вы можете указать абсолютные значения ( px , em ) или значение относительно окна просмотра ( vw ), но НЕ проценты. Вы могли заметить, что у последнего слота нет медиа-условия — это значение по умолчанию, которое станет актуальным, если ни одно из предыдущих медиа-условий не будет истинно. Браузер игнорирует все последующие проверки после первого совпадения, так что будьте внимательнее к порядку их объявления.

Итак, с такими атрибутами, браузер сделает следующее:

  1. Посмотрит на ширину экрана устройства.
  2. Попытается определить подходящее медиа-условие из списка в атрибуте sizes .
  3. Посмотрит на размер слота к этому медиавыражению.
  4. Загрузит изображение из списка из srcset , которое имеет тот же размер, что и выбранный слот, или, если такого нет, то первое изображение, которое больше размера выбранного слота.

И это всё! На текущий момент, если поддерживающий браузер с viewport width 480px загрузит страницу, медиа-условие (max-width: 480px) будет истинно, следовательно, будет выбран слот 440px , тогда будет загружено изображение elva-fairy-480w.jpg , так как свойство ширины ( 480w ) наиболее близко значение 440px . Условно, изображение 800px занимает на диске 128KB, в то время как версия в 480px только 63KB — экономия в 65KB. Теперь представьте, что у вас страница, на которой много изображений. Используя это технику, вы обеспечите мобильным пользователям большую пропускную способность.

Старые браузеры, не поддерживающие эти возможности, просто проигнорируют их и возьмут изображение по адресу из атрибута src .

Примечание: В описании элемента <head> вы найдёте строку <meta name=»viewport» content=»width=device-width»> : это заставляет мобильные браузеры адаптировать их реальный viewport width для загрузки web-страниц (некоторые мобильные браузеры нечестны насчёт своего viewport width, вместо этого они загружают страницу в большем viewport width, а затем ужимают её, что не очень хорошо сказывается на наших отзывчивых изображениях или дизайне. Мы расскажем вам об этом больше в будущем модуле.)

Полезные инструменты разработчика

Есть несколько полезных браузерных инструментов разработчика, чтобы помочь с определением необходимой ширины слотов и т. д., которые вам нужно использовать. Когда я работал над ними, я сначала загружал фиксированную версию моего примера ( not-responsive.html ), затем открывал Responsive Design View (Tools > Web Developer > Responsive Design View), который позволяет взглянуть на layout вашей веб-страницы как если бы они были просмотрены через устройства с различными размерами экрана.

Я устанавливал viewport width на 320px, затем на 480px; для каждой я обращался к DOM Inspector, кликал по элементу <img> в котором мы заинтересованы, далее смотрел размер во вкладке Box Model с правой стороны дисплея. Это должно дать вам необходимую ширину изображения

A screenshot of the firefox devtools with an image element highlighted in the dom, showing its dimensions as 440 by 293 pixels.

А дальше вы можете проверить работает ли srcset если установить значение viewport width таким каким вы хотите (например, установить узкую ширину), открыв Network Inspector (Tools > Web Developer > Network) и затем перезагрузить страницу. Это должно дать вам перечень ресурсов которые были загружены чтобы составить (собрать) web-страницу, и тут вы можете проверить какой файл изображения был выбран для загрузки.

a screenshot of the network inspector in firefox devtools, showing that the HTML for the page has been downloaded, along with three images, which include the two 800 wide versions of the responsive images

Переключения разрешений: Одинаковый размер, разные разрешения

Если вы поддерживаете несколько разрешений экрана, но все видят ваше изображение в одном и том же размере на экране, вы можете позволить браузеру выбирать изображение с подходящим разрешением используя srcset с x-дескриптором и без sizes — более простой синтаксис! Найти пример как это выглядит можно здесь srcset-resolutions.html (смотрите также the source code):

A picture of a little girl dressed up as a fairy, with an old camera film effect applied to the image

В данном примере, к изображению применяется CSS таким образом, что оно имеет ширину в 320 пикселей на экране (также называемое CSS-пикселями):

В этом случае, нет необходимости в sizes — браузер просто определяет в каком разрешении отображает дисплей и выводит наиболее подходящее изображение в соответствии с srcset . Таким образом, если устройство, подключаемое к странице, имеет дисплей стандартного/низкого разрешения, когда один пиксель устройства представляет (соответствует) каждый CSS-пиксель, то будет загружено изображение elva-fairy-320w.jpg (применён x1, то есть вам не надо включать его). Если устройство имеет высокое разрешение, в два пикселя устройства на каждый CSS-пиксель или более, то будет загружено изображение elva-fairy-640w.jpg . 640px изображение имеет размер 93KB, тогда так 320px изображение — всего 39KB.

Художественное оформление

Подводя итоги, проблема художественного оформления заключается в желании изменить отображаемое изображение чтобы оно соответствовало разным размерам отображения изображения. Например, если на веб-сайте отображается большой пейзажный снимок с человеком посередине при просмотре в браузере на настольном компьютере, то при просмотре веб-сайта в мобильном браузере он уменьшается; он будет выглядеть плохо так как человек будет очень маленьким, и его будет тяжело разглядеть. Вероятно будет лучше показать меньшую портретную картинку в мобильной версии на которой человек отображается в увеличении (в приближении). Элемент <picture> позволяет нам применять именно такое решение.

Возвращаясь к нашему оригинальному примеру not-responsive.html, мы имеем изображение которое очень нуждается в художественном оформлении:

Давайте исправим это при помощи элемента <picture> ! Так же как <video> и <audio> , элемент <picture> это обёртка содержащая некоторое количество элементов <source> которые предоставляют браузеру выбор нескольких разных источников, в сопровождении крайне важного элемента <img> . Код responsive.html выглядит так:

  • Элемент <source> принимает атрибут media , который содержит медиа-условие; при помощи этих условий определяется, какое изображение будет выведено. В данном случае, если ширина viewport’a составит 799px или меньше, будет выведено изображение первого элемента <source> . Если ширина составит 800px и более — второго.
  • Атрибут srcset содержит путь изображения, которое будет выведено. Обратите внимание, что, как и в примере с <img> выше, <source> может принимать атрибуты srcset и sizes с несколько предопределёнными изображениями. Так вы можете не только поместить группу изображений внутри элемента <picture> , но и задать группу предписаний для каждого из них. В реальности вы вряд ли захотите заниматься этим очень часто.
  • Вы всегда должны использовать элемент <img> , с src и alt , прямо перед </picture> , иначе изображения не появятся. Это нужно на тот случай, когда ни одно из медиа-условий не удовлетворено (например, если бы вы убрали второй элемент <source>) или браузер не поддерживает элемент <picture> .

Этот код позволяет нам выводить отзывчивое изображение и на широких, и на узких экранах, как показано ниже:

Our example site as viewed on a wide screen - here the first image works ok, as it is big enough to see the detail in the center. Our example site as viewed on a narrow screen with the picture element used to switch the first image to a portrait close up of the detail, making it a lot more useful on a narrow screen

Примечание: вам следует использовать атрибут media только при художественном оформлении; когда вы используете media , не применяйте медиа-условия с атрибутом sizes .

Почему это нельзя сделать посредством CSS и JavaScript?

Когда браузер начинает загружать страницу, он начинает загрузку изображений до того, как главный парсер начал загружать и интерпретировать CSS и JavaScript. В среднем, эта техника уменьшает время загрузки страницы на 20%. Но она не так полезна в случае с адаптивными изображениями, поэтому и необходимы такие решения, как srcset . Например, вы не могли бы загрузить элемент <img> , потом определить ширину вьюпорта при помощи JavaScript и динамически изменить источник изображения. Изначальное изображение было бы уже загружено к тому времени, как вы загрузили его меньшую версию, что плохо.

Смело используйте современные форматы изображений

Есть несколько новых форматов изображения (таких, как WebP и JPEG-2000), которым удаётся сохранять высокое качество при малом размере файла. Тем не менее, браузеры поддерживают их не полностью.

<picture> позволяет нам использовать их в старых браузерах. Вы можете прописать MIME-тип внутри атрибута type , браузер сразу определит файлы такого типа как неподдерживаемые:

  • Не используйте атрибут media , если вам не нужно художественное оформление.
  • В элементе <source> можно указывать путь к изображениям только того типа, который указан в type .
  • Как и в предыдущих примерах, при необходимости вы можете использовать srcset и sizes .

Активное обучение: реализация собственных адаптивных изображений

Самостоятельно создайте отзывчивое, художественно оформленное изображение для широких и узких экранов, используя <picture> и srcset .

  1. Напишите простую HTML-разметку.
  2. Найдите широкоформатное пейзажное фото с какой-нибудь яркой деталью. Создайте веб-версию изображения посредством графического редактора, потом обрежьте его, чтобы крупнее выделить деталь, и создайте второе изображение (примерно 480px достаточно).
  3. Используйте элемент <picture> для работы с художественно оформленной картинкой.
  4. Обозначьте несколько разных размеров для этой картинки.
  5. Используйте srcset / size для описания переключения при смене размеров вьюпорта

Примечание: Используйте инструменты разработчика, чтобы отследить смену размера, как было описано выше.

Заключение

Это все для отзывчивых изображений — мы надеемся, вам понравилось играть с этими новыми технологиями. Напомним, что мы здесь обсуждали две различные проблемы:

  • Художественное оформление: Проблема, при которой вы хотите использовать обрезанные изображения для различных макетов — например, ландшафтное изображение для полных экранов на макете компьютера и портретное изображение, показывающее увеличенный основной объект, для мобильного макета. Всё это может быть решено с помощью <picture> элемента.
  • Переключение разрешений: Проблема, при которой вы хотите использовать файлы изображений меньшего размера на устройствах с узким экраном, поскольку им не нужны огромные изображения, как на настольных дисплеях, а также дополнительно, что вы хотите использовать изображения разного разрешения для экранов с высокой/низкой плотностью. Эту проблему можно решить с помощью векторной графики (SVG изображений), и srcset и sizes атрибуты.

Это так же подводит нас к окончанию целого модуля «Мультимедиа и встраивание»! Единственное, что вам осталось сейчас сделать перед тем, как двигаться дальше — это попробовать наше мультимедийное задание и посмотреть, как вы усвоили материал. Веселитесь!

Заметка: как использовать HTML «picture» для адаптивных изображений.

Изображения заведомо являются одним из самых сложных аспектов адаптивного веб дизайна. Сегодня мы рассмотрим как элемент <picture> , являющийся решением проблемы адаптивных изображений, можно использовать прямо сейчас.

Вначале о проблеме

Времена попиксельного (pixel perfect) и дизайна фиксированной ширины (fixed-width) ушли в прошлое. Теперь во времена широкоформатных мониторов, интернет телевидения, планшетов и смартфонов различных размеров наши дизайны должны удовлетворять любому устройству шириной от 320px до потенциальных 7680px.

Вместе с множеством разрешений экранов приходит необходимость в сжатии или растяжении изображений для того, чтобы соответствовать различным требованиям. Это может оказаться проблей, т.к. за исключением векторной графики, у подавляющего большинства изображений есть базовая ширина в px, которую нельзя изменить.

Так что же нам делать?

Текущее общепринятое решение

Как правило, вы найдете этот код на любом сайте с адаптивные дизайном:

Здесь используется max-width: 100%; для гарантии того, что изображение никогда не выйдет за пределы ширины родительского контейнера. Если родительский контейнер сжимается до ширины, меньшей чем ширина изображения — последнее сжимается вместе с контейнером. Установка height: auto; нужна для сохранения пропорций.

Заметка: как использовать HTML "picture" для адаптивных изображений. Одно «жидкое» изображение под все случаи

Проблема решается лишь в одном ключе, позволяя нам показывать одно и то же изображение для всех случаев. Но это не дает нам возможность устанавливать разные изображения для разных ситуаций.

Новое решение: <picture>

<picture> это новый элемент, который является частью HTML5.

Он реализует способ описания адаптивных изображений таким же способом, как это делается в <audio> и <video> . Таким образом можно размещать несколько тегов <source> , каждый из которых содержит имена файлов различных изображений вместе с условиями, при которых те должны быть загружены.

Это позволит загружать разные изображения в зависимости от:

  • Результатов media выражений, например высоты, ширины или ориентации видимой области
  • Плотности пикселей

Это в свою очередь означает, что вы можете:

  • Загружать файлы изображений соответствующего размера, эффективно используя пропускную способность.
  • Загружать по-разному ориентированные изображения в разных пропорциях для того, чтобы соответствовать изменениям в макете при разных ширинах.
  • Загружать изображения с высоким разрешением для дисплеев с повышенной плотностью пикселей.

Как работает <picture> ?

Основные шаги при работе с <picture> :

  1. Создайте открывающий и закрывающий теги <picture></picture> .
  2. Внутри создайте <source> элемент для каждого выражения, что хотите обработать.
  3. Добавьте атрибут media , содержащий выражения для таких вещей как высота и ширина области просмотра, ориентация и т.д.
  4. Добавьте атрибут srcset с соответствующим именем файла изображения для загрузки.
  5. Добавьте дополнительные имена файлов к атрибуту srcset , если нужно поддерживать разную плотность пикселей, например для Retina дисплеев.
  6. Добавьте резервный (fallback) элемент <img> .

Вот простой пример, где для случая, когда ширина видимой области меньше 768px — загружается уменьшенное (smaller) изображение:

Можно заметить, что синтаксис, используемый в атрибуте media является таким же, как и при использовании в CSS media queries. Вы можете использовать те же самые проверки, т.е. проверять max-width , min-width , max-height , min-height , orientation и т.д.

Эти проверки можно использовать для того, чтобы например загружать альбомную (landscape) или книжную (portrait) версию изображения в зависимости от ориентации устройства, к тому же можно одновременно проверять размеры в этих выражениях. Например:

Этот код загружает уменьшенную альбомную (landscape) версию изображения для устройств с малым экраном и соответствующей ориентацией. И увеличенную версию того же изображения для устройств с большим экраном.

Если устройство имеет книжную (portrait) ориентацию — загружается книжная версия изображения, уменьшенная для устройств с малым и увеличенная для устройств с большим экраном.

Если вы хотите предоставлять изображения в другом разрешении для дисплеев с повышенной плотностью пикселей, это можно сделать, указав дополнительные имена файлов в атрибуте srcset . Давайте к примеру посмотрим на наш первый кусок кода с добавлением обработки для Retina 2x дисплеев:

Т.к. сначала обрабатывается media query, вы можете управлять размерами изображения, с которыми оно будет показано на экране. Затем будет проверяться плотность пикселей: если дисплей поддерживает повышенную плотность и в пользовательских настройках есть на это разрешение — будут загружены соответствующие версии изображений.

Использование <picture> сегодня

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

Тем временем вам не нужно ждать, если хотите использовать <picture> прямо сейчас. Просто воспользуйтесь Picturefill 2.0 ; polyfill от умных людей из Filament Group .

Заметка: как использовать HTML "picture" для адаптивных изображений.

После скачивания файла picturefill.js в свой проект просто подключите его в шапке:

Есть также опция для асинхронной загрузки скрипта, о которой можно прочитать в документации Picturefill .

При использовании этого скрипта элемент <picture> будет работать так, как я и объяснял, но с несколькими ограничениями.

Ограничения Picturefill

Picturefill отлично работает с разными версиями IE, однако IE9 не поддерживает <source> элементы, которые используются внутри <picture></picture> . Чтобы обойти это, оберните source элементы в <video> теги с помощью условных комментариев; это сделает их видимыми для IE9, например:

Android 2.3

Как и IE9, Android 2.3 не показывает <source> элементы внутри <picture> . Однако он понимает атрибут srcset при использовании в обычных <img> тегах. Убедитесь в том, что всегда включаете резервный <img> с именем файла по умолчанию в атрибут srcset для Android 2.3 и других браузеров, которые могут иметь такую же проблему.

Требуется JavaScript и встроенная поддержка Media Query

Соответственно требуется, чтобы JavaScript был включен в браузере. Picturefill 2.0 не предоставляет «no-js» решения, ведь если это будет сделано, то когда браузер выкатит нативную поддержку <picture> — будет показываться уже несколько изображений. Однако, вы можете использовать Picturefill 1.2, если параметр «no-js» является для вас обязательным.

Другим требованием Picturefill является встроенная поддержка media query, чтобы позволить обрабатывать выражения в атрибуте media . Все современные браузеры поддерживают media-выражения, лишь IE8 и ниже не имеют их поддержки, что соответствует лишь малой части пользователей .

Возможны дополнительные HTTP-запросы

Возможно, что в браузерах, которые имеют встроенную поддержку srcset , но пока не имеют поддержки <picture> , указанный в резервном элементе <img> файл может быть запрошен до того, как будет определен подходящий вариант из <source> .

Это лишь временная проблема, и она пропадет как только выкатят встроенную поддержку <picture> .

Responsive Images

In Responsive Design, we learned how to use media queries to create separate mobile, tablet, and desktop layouts. Now, we’re going to add images to the mix. Just as media queries let us conditionally present different CSS rules, we want to display different images based on the user’s device.

Diagram: low-resolution image sent to standard screen desktop devices and all mobile devices versus high-resolution image sent to retina desktop devices

The problem is, images have inherent dimensions. We can’t stretch a photo that’s 500×250 pixels to anything beyond 500 pixels wide because it’ll get pixelated. Retina displays and mobile devices complicate things even more. To make our images responsive, we now have to take three things into consideration:

  • The device’s dimensions
  • The image’s dimensions
  • The device’s screen resolution

This will be more difficult than media queries, which were only concerned with device width. But don’t worry, there are standard ways to solve all these problems, and we’ll walk you through them one step at a time.

Setup

To experiment with responsive images, we need a responsive website to work with. This chapter will be building off of the example web page we put together in the previous chapter. We’ll be adding two images to the page so it looks like the following. This might seem simple, but these images will change depending on the user’s device (which is really cool).

Web page with large photo in header and line art illustration in content

If you’re continuing from the last chapter, you simply need to download these image assets and add them to your project’s images/ folder.

If you’re just joining us, go ahead and download the complete example project, unzip it, and open it up with Atom. If you’re not familiar with the Atom text editor, be sure to take a read through the introduction of this tutorial series.

Screenshot: Atom’s file browser after unzipping the project

In either case, your project files should look like this before moving on. Notice how we have multiple copies of our PNG and JPG images (e.g., illustration-big.png and illustration-small.png ). We’ll be letting the browser pick which one of these it should load depending on the device’s size and screen resolution.

Retina Screens

This is our first time worrying about retina devices, so let’s talk a little bit about screen resolution. Retina screens have twice as many pixels per inch than standard-resolution screens. That is to say, each retina pixel is the equivalent of 4 standard pixels. This has a big impact on how images are displayed in a web browser.

Diagram: standard-resolution screen with 4 pixels versus high-resolution screen with 16 pixels

To render correctly on a retina device, an image needs to be twice as big as its final display dimensions. For example, if you want to add a 500×250 pixel image to the page, the corresponding image file needs to be 1000×500 pixels.

Diagram: High-resolution image shrunk to half size and displayed on retina screen

This is actually a bit of a simplification—not all retina screens are created equal. For instance, the iPhone 6 Plus has three times as many pixels per inch as a standard screen. This tutorial focuses on the 2x use case, but the same techniques apply to 3x retina screens as well.

What’s more, standard displays and smaller devices don’t need all those extra pixels in high-resolution images, and sending that much unnecessary data usually results in a bad user experience.

Responsive SVG Images

The easiest way to solve all these problems is with SVG images. They “just work.” Since they’re vector-based, SVGs avoid the screen resolution problems that we’ll see in the next section. Let’s take a look by adding an illustration to our responsive.html page. Replace the existing image in the .content div so that it matches the following:

Browsers automatically scale up SVGs for retina devices, so this 500×250 pixel SVG image will render crisply on both standard and retina devices.

SVGs let us forget about screen resolution issues, but we do need to shrink the illustration to fit neatly into our fluid tablet and mobile layouts. Firefox will do this automatically, but if you open this page with Chrome and make your browser very narrow, you’ll find that the image stays the same size.

To get a fluid image in Chrome, we need to tell the illustration to always fill the width of its container. In styles.css , put the following rule with the rest of the base styles, outside of the media queries:

When we specify 100% width on an image, it’ll assume we want to maintain its aspect ratio and calculate its height automatically. This fixes the mobile layout, but now the desktop version is huge:

SVG image shrinking to fit mobile and tablet widths, but very large in desktop layout

This behavior is perfect for some designs (like the full bleed photo we’ll see in the next section), but not right now. We want to cap the width of the illustration to its inherent width, which is 500 pixels. We can do this with an inline style:

This is one of the rare times an inline style is acceptable, due to the fact that it’s describing an innate property of the image. An image’s physical dimensions are more content than presentation, so it makes sense for this to appear in the HTML rather than the stylesheet.

Adding an inline style to limit the size of the SVG image

Responsive PNG, GIF, and
JPG Images

Of course, not all images on the web are SVGs. Sometimes you need to include a photo. PNG, GIF, and JPG images are “raster images”, meaning that they are defined pixel-by-pixel instead of with vectors. As a result, they are much more sensitive to screen resolution than SVGs.

If you’re not worried about optimization, responsive raster images really aren’t that much harder than using SVG images. Try swapping out our existing illustration.svg with a PNG file:

We changed around the HTML structure a bit, nesting our <img/> tag in another container. Without it, the image would get distorted because flexbox would try to set its height to be the same as the .content container. This requires a little tweak to our .illustration CSS rule, too:

Also notice the -big suffix in the image’s filename. This is the high-resolution version of the PNG, which has dimensions of 1000×500. Retina devices need this “2x” size to display the image crisply. If we were to use the low-resolution version of this image (500×250 pixels), it would look fine on standard screens, but fuzzy on retina devices.

Diagram: serving a high-resolution image to both standard screens and retina screens (which is wasteful)

Consider this the lazy way to create responsive PNG, GIF, or JPG images, as it assumes everybody needs a high-resolution image, even if they don’t. That is to say, a 1000×500 pixel image is overkill for non-retina devices. We’ll get a little smarter about this in the next section.

Responsive Image Optimization

Different devices have different image requirements. Fortunately, HTML provides a way to choose the best image for the user’s device. Over the next few sections, we’ll take a look at three scenarios for optimizing responsive images:

  • A standard-resolution screen that doesn’t need a retina-quality image.
  • A retina mobile device that can use a standard-quality image because it’s been scaled down so much.
  • A desktop layout that uses a wide image, and an associated mobile layout that uses a taller image.

The first method is the easiest, and it’s great for images smaller than 600 pixels wide because they aren’t big enough to benefit from the second scenario. The second method is a very important optimization for larger images, especially full-bleed photos. The third is for when you’re feelin’ fancy.

Retina Optimization Using srcset

High-resolution images are big. Our illustration-big.png file takes up more than twice as much disk space as its low-resolution counterpart. It doesn’t make sense to serve all that extra data when the user doesn’t actually need it.

Adding a srcset attribute to our <img/> element lets us present our high-resolution image only to retina devices, falling back to the low-resolution version for standard screens. Update our .illustration element to match the following:

The srcset attribute points to a list of alternative image files, along with properties defining when the browser should use each of them. The 1x tells the browser to display illustration-small.png on standard-resolution screens. The 2x means that illustration-big.png is for retina screens. Older browsers that don’t understand srcset fall back to the src attribute.

Diagram: serving a low-resolution image to a standard screen and a high-resolution image to retina screens

Typically, the low-res and high-res versions of an image would be the exact same (except for their dimensions), but we made illustration-small.png yellow so you can easily differentiate it from the retina version, which is blue.

It’s a little hard to see this in action without a real website, so we included the previous snippet on this page. The image below should be blue if you’re viewing it on a retina device. Otherwise, it will be yellow for standard-resolution screens.

If you’re building these examples on a computer with a retina screen, you can also try temporarily changing that 2x to 1x to see what a non-retina image looks like. It’s a little fuzzy (and yellow).

Screen Width Optimization Using srcset

Great! We can save some extra bytes for non-retina devices. Regrettably, the above srcset technique misses an important use case for larger images: if the user has a retina smartphone, it’ll download the high-resolution image even when the standard version would suffice.

Diagram: low-resolution image sent to standard screen desktop devices and all mobile devices versus high-resolution image sent to retina desktop devices

Imagine that we wanted to display a big photo in our .header element. The header is 960 pixels wide in our desktop layout, so our photo needs to be at least 1920 pixels wide to display well on retina screens. We’ll also provide a 960 pixel-wide photo for standard screens. Now, consider a smartphone with a retina screen. Smartphones are typically less than 400 pixels wide in portrait mode, which means that the corresponding retina-quality image would only need to be 800(ish) pixels wide.

Hey! We can serve our standard-resolution photo to retina smartphones!

The lesson here is that we want to optimize larger images based on their final rendered dimensions, not just the device’s screen resolution. Let’s go ahead and add that big photo to our .header element:

We have the same srcset element as the last section, but instead of the 1x and 2x descriptors, we’re providing the inherent physical width of the image. The 2000w tells the browser that the photo-big.jpg file is 2000 pixels wide. Likewise, the 1000w means photo-small.jpg has a width of 1000 pixels. If you’re wondering about that w character, it’s a special unit used only for this kind of image optimization scenario.

Image width alone isn’t enough for a device to determine which image it should load. We also need to tell it what the final rendered width of the image will be. That’s where the sizes attribute comes in. It defines a series of media queries along with the image’s rendered width when that media query is in effect.

Diagram: sizes=100vw as width of the image in the mobile layout, sizes=960px as width of the image in the desktop layout

Here, we’re saying that when the screen is at least 960px wide, the image will also be 960 pixels wide. Otherwise, the 100vw default value tells the browser that the image’s width will be 100% of the “viewport width” (a fancy term for screen width). You can read more about the vw unit over at MDN. All of this matches the image resizing behavior that’s in our CSS.

Speaking of which, we need to make some changes to position our new header image correctly. Add both of the following rules to our other base styles, right above the mobile styles media query:

Remember that our low-resolution photo is 1000 pixels wide, which means that 2x retina devices can use it as long as their screen is less than 500 pixels wide. In Firefox, you should now be able to resize the browser to see the retina version (“Big”) when the window is wider than 500 pixels and the non-retina version (“Small”) for narrower widths.

We’re now serving a 115KB image to mobile devices instead of forcing them to use the high-res 445KB image. That’s a big deal, especially for websites that use a lot of photos.

Testing With Chrome

This technique works just fine in Chrome, but we can’t really tell because it’s being clever. Chrome will always use the high-res version if it has already been cached locally, which means we can’t see the low-res version by simply making the browser window narrow. We have to avoid the local browser cache by opening a new incognito window, then avoid loading photo-big.jpg by making the window very narrow before loading the page.

Art Direction Using <picture>

The previous section is perfectly acceptable in terms of optimizing data usage. We could stop there and be just fine, but we’re going to get a little bit fancier with “art direction”. Think of art direction as responsive image optimization for designers.

It lets you optimize layouts by sending completely different images to the user depending on their device. Compare this to the previous section, which optimized the same image for different devices. For instance, our header photo is pretty wide. Wouldn’t it be great if we could crop a taller version and present that to mobile devices instead of the wide desktop version?

Diagram: serving a tall-cropped image to mobile devices and a wide-cropped image to standard- and high-resolution desktop devices

For this, we need the <picture> and <source> elements. The former is just a wrapper, and the latter conditionally loads images based on media queries. Try changing our .header element to the following:

Conceptually, this is pretty similar to using media queries in CSS. In each <source> element, the media attribute defines when the image should be loaded, and srcset defines which image file should be loaded. The <img/> element is only used as a fallback for older browsers. You should be able to see the tall version of the photo when you shrink your browser window:

Mobile web page with tall-cropped image and desktop web page with wide-cropped image

This level of control will make your designer very happy, but the trade off is that it doesn’t let the browser automatically pick the optimal image. This means we lost our retina optimization from the previous section: as long as the screen width is 401 pixels or greater, the browser will always use the high-resolution, wide-cropped image.

While it is possible to combine the best of both worlds, it gets complicated real quick. Our recommendation is to stick to the 1x and 2x version of srcset for images less than 600 pixels wide, use the srcset plus sizes method from the previous section for bigger photos, and reserve <picture> for when you’re trying to do something real fancy with your designer.

Summary

Responsive images may seem rather complicated, but there’s really only two problems we’re trying to solve:

  • Make images fit into mobile layouts while respecting their intrinsic size
  • Avoid making the user download unnecessarily large image files

We accomplished the former by making images always stretch to fill 100% of their container while limiting their size with an inline max-width style. For the latter, we used srcset to optimize for screen resolution, srcset plus sizes to optimize for device width, and finally the <picture> element for manual control over which image file is displayed.

Responsive design is an evolving topic. Browsers only recently implemented the image optimization techniques covered in this chapter, despite the fact that responsive design has been the standard for half a decade. While the technology used to create a responsive website may change, the fundamental problem of presenting the same content to different devices will never disappear. So, even if you eventually need to learn some new tools, the foundational concepts we just introduced should stay with you forever.

These last five chapters focused entirely on layout. We explored floats, flexbox, advanced positioning, and how to apply all those concepts to various screen widths. This is pretty much everything you’ll ever need to lay out web pages with HTML and CSS. The next chapter scuffles back into the world of HTML, introducing a bunch of new elements that will make search engines much happier with our websites.

Полное руководство по отзывчивым изображениям!

Workafrolic (±∞)

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

Со временем появилось множество способов реализации отзывчивых изображений, расширяя инструментарий фронтенд-разработчиков. Это так же сделало использование отзывчивых изображений довольно сложным. Вот почему я решил погрузится в эту тему только недавно, несмотря на то, что сама технология существует довольно давно. И именно из-за этой сложности я понимал, что в каждом прочитанном мною источнике чего-то не хватает, не показана вся картина (каламбур).

После прочтения и изучения множества источников я решил написать собственное руководство, в котором я, надеюсь, собрал все способы реализации отзывчивых изображений. Здесь собрана вся информация, нужная для понимания этой технологии, что делает эту статью Полным руководством по отзывчивым изображениям.

Короткое введение в экраны повышенной плотности

Перед тем как погрузится во все методы использования отзывчивых изображений нужно разобраться с важной концепцией пикселя в вебе. Мы привыкли думать, что на мобильных девайсах картинки должны быть меньше потому что ширина экрана девайса меньше. Но это не всегда так.

«Пиксель это не пиксель»

Существует разница между разрешением в CSS и разрешением экрана:

  • разрешение в CSS предназначено для измерений на нашем сайте;
  • разрешение экрана это фактическое количество пикселей на экране.

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

Пример:
Разрешения на Samsung Galaxy S10:

  • Разрешение экрана — 1440 на 3040 пикселей
  • Разрешения в CSS — 360 на 760 пикселей
  • Плотность дисплея — 4х (по 4 физических пикселя на один CSS-пиксель)

Это означает, что если, например, у вас есть место под картинку в 300 пикселей шириной, то вы можете в этом месте загрузить картинку размером в 4 раза больше (1200 пикселей в ширину) и в результате получите действительно более чёткое изображение!

Мы привыкли думать, что на мобильных девайсах картинки должны быть меньше потому что ширина экрана девайса меньше. Но это не всегда так.

Но будьте осторожны: показывая большее изображение вы платите цену. Большие изображения грузятся медленнее, а на мобильных девайсах этот эффект усиливается, поскольку скорость мобильного интернета довольно ограничена. Поэтому вы каждый раз должны взвешивать все «за» и «против» и решать, где чёткость изображения действительно стоит того, чтобы замедлить скорость загрузки страницы.

В этой статье я опишу восемь методов реализации отзывчивого дизайна. Первые два используют элемент <img> с атрибутом srcset ; следующие два используют элемент <picture> ; следующие два используют CSS: в одном применяется атрибут image-set , а в другом используются медиавыражения для отзывчивого дизайна (min-resolution и max-resolution); в последних двух я покажу фичи CSS — функцию image() .

Причина наличия такого большого количества методов в том, что существует несколько проблем, которые призван решать отзывчивый дизайн: показ меньших изображений на меньших экранах; использование преимуществ плотности экранов; изменение фокуса изображений на разных разрешениях; использование типов файлов, которые не поддерживаются всеми браузерами.

Теперь можем перейти непосредственно к методам отзывчивых изображений:

Метод описания плотности экрана

Этот метод подходит для изображений, размер которых фиксирован на экранах повышенной плотности. Это значит, что на некоторых экранах для изображений с размером 200 пикселей в CSS/HTML мы можем загрузить картинку в 600 пикселей — или большего размера— потому что на экранах повышенной плотности оно будет давать лучший визуальный результат.

Для реализации этого подхода мы используем новый атрибут srcset с описанием плотности экрана. Мы пропишем атрибут srcset с набором картинок разного размера и пропишем при какой плотности экрана какая из них должна показываться. Идентификатор плотности экрана указывает какая должна быть плотность дисплея для показа каждой из картинок: 1x , 2x , 4x и так далее.

Внимание! Идентификатор плотности экрана будет выбирать картинку в зависимости от плотности пикселей, а не от фактического размера изображения.

Рекомендуется по прежнему использовать стандартный атрибут src для фоллбэка в браузерах, не поддерживающих srcset (IE и Opera mini).

Метод описания ширины и атрибут sizes

Этот метод подходит для изображений, ширина которых изменяется в зависимости от размера области просмотра и точками останова. Этот приём наиболее распространен на адаптивных сайтах.

Атрибут srcset с описанием ширины

В этом методе мы прописываем атрибут srcset с набором картинок и указанием, на каких ширинах каждая из них должна показываться (мы должны указывать ширину потому что браузер не «знает» фактический размер картинки). В случаях, когда этот подход используется без атрибута sizes он опирается на предположениях браузера, что ширина картинки должна заполнять ширину области просмотра.

Этот метод немного напоминает тот, что мы обсудили выше, с описанием плотности экрана, в котором мы тоже использовали атрибут srcset с набором картинок и условиями их показа. Но они отличаются тем, что теперь мы будем определять какую картинку показывать в зависимости от её ширины, а не от плотности экрана. То есть мы используем описание ширина (ширины картинки, которая нам необходима), но не описываем плотность экрана. Но эти понятия связаны для экранов с повышенной плотностью.

Примечание: даже при условии, что мы описываем ширину, а не плотность экрана, браузер всё равно принимает во внимание экраны повышенной плотности.

Атрибут sizes

Помимо описания списка изображений с уточнением ширины (используя атрибут srcset ) мы должны предоставить браузеру соотношение размера картинки к экрану браузера. И для этого нам пригодится атрибут sizes .

Атрибут sizes это набор медиавыражений с размерами картинки для каждого условия. (Примечание: количество медиавыражений не обязательно должно быть равно количеству картинок, как вы увидите в следующем примере). В конце списка мы должны указать значение ширины без медиавыражения в качестве фоллбэка.

Условие размера картинки — тут есть 3 варианта: единицы vw , единицы px и комбинация этих единиц с применением функции calc() . Например, calc(30vw + 300px) .

Пример со сложным условием:

На простом адаптивном сайте размеры обычно имеют только одно условие и фоллбэк, а в srcset будут указаны несколько комбинаций размеров и ширин изображения:

После того, как вы отдали браузеру массив картинок и настоящий размер картинок в CSS при помощи медиавыражений, браузер выберет нужную картинку с учётом всех этих условий. И не беспокойтесь, на экранах повышенной плотности браузер при выборе картинки будет опираться на реальное соотношение пикселей на устройстве.

Элемент <picture>

До сих пор мы говорили только об элементе <img> и в большинстве случаев этого будет достаточно потому что элемент <img> с атрибутами srcset и sizes покроет большую часть задач. Но элемент <picture> даёт дополнительные возможности для реализации отзывчивых изображений. В следующих двух методах пойдёт речь о более сложных случаях:

Метод с <picture> для изменения направления изображения

Метод изменения направления это способ показывать картинки с разными соотношениями сторон или с разными точками фокуса на разных девайсах. Внутри элемента <picture> мы можем загружать картинки с разных путей в зависимости от CSS ширины экрана устройства. Таким образом вы можете выбирать одно и то же изображение, но нарезанное по-разному, и тем самым фокусироваться на важной части изображения на небольших экранах.

Как работает метод изменения направления?

Внутри элемента <picture> мы используем элемент <source> . В каждом элементе <source> мы прописываем два атрибута: media и srcset . Значением атрибута media является медиавыражение. Точно такое же как обычное медиавыражение. И для каждого медиавыражения определяется атрибут srcset .

Мы можем прописать столько элементов <source> , сколько нам нужно.

После всех элементов <source> мы указываем обычный элемент <img> . Это важный момент потому что без элемента <img> вся конструкция работать не будет. Кроме того для добавления <img> есть ещё несколько важных причин:

  • Если браузер не поддерживает <picture> , то будет использован элемент <img> (например, в случаях IE и Opera mini).
  • Если ни один из элементов <source> не подошёл по условиям, то браузер использует элемент <img> .
  • Атрибут alt для обеспечения доступности можно добавить только на элемент <img> .

Важен так же и порядок указания элементов <source> . Браузер выберет первый источник, который сработает. Ниже иллюстрация того, как это всё работает:

Полный HTML пример:

Известный пример с Котиком от Google. Они сделали его, когда поддержка элемента <picture> появилась в Chrome ��

Метод с использованием <picture> для разных типов файлов

Другая ситуация, в которой очень пригодится элемент <picture> — использование типов файлов с изображениями, которые не поддерживаются всеми браузерами. Например, Google создал новый тип файлов со сжатыми изображениями, который называется webp. Webp не поддерживается всеми браузерами. Например, Safari и IE. И снова элемент <picture> спасёт нас, но в другой конфигурации.

В этой ситуации мы используем новый атрибут type у элемента <source> . Каждый атрибут type будет указывать на разные изображения в комбинации с атрибутом srcset . Ровно как в примерах выше порядок элементов <source> важен. Браузер выберет первый работающий вариант. Если ни один из вариантов не работает, то браузер использует элемент <img> в качестве фоллбэка. Посмотрите иллюстрацию:

В недавнем прошлом SVG не работало в старых версиях IE. И вот такая ситуация с тремя вариантами типов файлов встречалась довольно часто.

Существует большое количество типов изображений и вы можете найти распространённые случаи использования на сайте Mozilla или заглянуть в полный список типов.

Отзывчивые картинки в CSS

До сих пор мы изучали методы реализации отзывчивых изображений при помощи HTML. Для многих задач этого более чем достаточно, но существует для способа реализации отзывчивых изображений при помощи CSS, с которыми вам стоит ознакомиться.

Функция image-set

Параметрами функции image-set являются пары картинок и плотностей. Точно так же как мы указывали это в атрибуте srcset в методе описания плотности экранов. Браузер выберет то изображение, которое соответствует текущему экрану.

Примечание: image-set появилась раньше, чем srcset и не обновлялся. И в нём отсутствует возможность указания ширины. Поэтому браузер выбирает изображения только опираясь на плотность экрана, но не на актуальный размер картинки!

Браузерная поддержка image-set

Складывается ощущение, что все просто забыли про эту функцию — некоторые браузеры вообще её не поддерживают, для некоторых нужно указывать префикс -webkit . Для максимального покрытия всех возможных браузеров используйте эту функцию так, как указанно в примере ниже:

Медиавыражения для определения плотности экрана

Существует два значения медиавыражений, пригодных для адаптивного дизайна: min-resolution и max-resolution. Они также как и image-set , подходят для случаев, когда вы хотите показывать разные изображения в зависимости от плотности экрана устройства. Разница между этими двумя методами в том, что здесь вы можете использовать абсолютно любые стили.

Примечание: Safari до сих пор использует старый синтаксис с префиксом: -webkit-min-device-pixel-ratio и -webkit-max-device-pixel-ratio . Для поддержки всех браузеров вам нужно указывать оба варианта. Пример:

Ожидаемые фичи для отзывчивых изображений

Направление изображения при помощи CSS-функции image()

Как мы видели в методе изменения направления существуют кейсы, в которых мы хотим нарезать изображения по-разному в зависимости от размера области просмотра. В противовес этому методу, использующемуся в HTML, существует спецификация, позволяющая делать это же при помощи CSS!

Эта возможность реализована при помощи функции image() . Её параметрами являются url картинки и четыре цифры: начальная позиция по оси X, начальная позиция по оси Y, ширина и высота.

И если в методе с использованием HTML-метода мы должны указывать разные изображения, то в текущем варианте мы можем использовать одно и тоже изображение, но нарезать его так, как нам нужно, применяя CSS-функцию image() .

CSS для типов картинок

Как мы уже видели раньше, существуют ситуации, в которых мы должны подгружать разны типы файлов с изображениями в зависимости от поддержки в конкретном браузере. Для этой возможности тоже существует спецификация CSS. И в ней так же используется функция image() , но с немного другим синтаксисом. Мы можем указать внутри функции набор изображений и браузер будет рассматривать их в том порядке, в котором они написаны, и использует первый файл, который сработает.

К сожалению, в данный момент у этой фичи нулевая поддержка. Вы можете найти больше информации на сайте Mozilla.

Заключение

Вот и всё.
Я надеюсь, что вы насладились чтением этой статьи и узнали что-то новое. Если вам понравился этот пост, то я буду очень благодарен за аплодисменты и шеринг 🙂

Кто я?

Меня зовут Элад Шехтер, я веб-разработчик, специализирующийся на дизайне и архитектуре CSS и HTML. Я работаю на Investing.com.

Вы можете найти меня в группах на Facebook:
CSS Masters
CSS Masters Israel

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *