HTML & CSS IS HARD - НА РУССКОМ

АДАПТИВНЫЕ КАРТИНКИ

УРОК Nº 11.

Адаптивные изображения - это сложно. Точнее, очень сложно. Но не пугайтесь.

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

Interneting is hard HTML+CSS
Скриншот 1: низкопиксельное изображение, передаваемое на ноутбук/ПК со стандартным экраном и мобильные устройства, в сравнении с высокопиксельным изображением, передаваемым на ноутбуки/ПК с ретина-экраном

Проблема в том, что изображения имеют свои размеры. Мы не можем растянуть фотографию размером 500×250 пикселей до размера, превышающего 500 пикселей в ширину, потому что она будет расплываться. Дисплеи Retina и мобильные устройства усложняют ситуацию еще более. Чтобы сделать наши изображения адаптивными, мы должны учитывать три фактора:

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

подготовка
setup

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

Interneting is hard HTML+CSS
Скриншот 2: веб-страница с большой фотографией в заголовке и линейной иллюстрацией в контенте

Если вы продолжаете работу с предыдущего урока, вам просто нужно скачать эти изображения и добавить их в папку images/ вашего проекта.

Если вы только присоединились к нам, скачайте полный пример проекта, распакуйте его и откройте с помощью Atom. Если вы не знакомы с текстовым редактором Atom, обязательно прочитайте введение к этому учебнику.

Interneting is hard HTML+CSS
Скриншот 3: файловый браузер Atom после распаковки проекта

В итоге файлы вашего проекта должны выглядеть как на скриншоте выше. Обратите внимание, что у нас есть несколько копий изображений PNG и JPG (например, illustration-big.png и illustration-small.png). Мы будем позволять браузеру выбирать, какое из них загружать, в зависимости от размера и разрешения экрана устройства.

ретина-экраны
retina screens

Раз уж речь пошла о "ретиновых" устройствах, давайте немного поговорим о разрешении экрана. Ретина-экраны имеют в два раза больше пикселей на дюйм, чем экраны стандартного разрешения. То есть каждый пиксель Retina эквивалентен 4 стандартным пикселям. Это сильно влияет на то, как изображения отображаются в веб-браузере.

Interneting is hard HTML+CSS
Скриншот 4: экран стандартного разрешения с 4 пикселями и экран высокого разрешения (retina resolution) с 16 пикселями

Для корректного отображения картинки на ретина-устройстве, она должна быть в два раза больше, чем ее конечные размеры на экране. Например, при добавлении на страницу картинки 500×250 пикселей, соответствующий файл картинки должен иметь размер 1000×500 пикселей.

Interneting is hard HTML+CSS
Скриншот 5: картинка высокого разрешения, уменьшенная до половины размера на ретина-экране

На самом деле это некоторое упрощение - не все ретина-экраны созданы одинаковыми. Например, у iPhone 6 Plus в три раза больше пикселей на дюйм, чем у стандартного экрана. Здесь мы рассматриваем использование экрана 2x, но те же приемы применимы и к ретина-экранам 3x.

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

адаптивные svg-изображения
responsive svg images

Самый простой способ решить все эти проблемы - использовать картинки формата SVG. Картинки этого формата "работают на пятерочку". Поскольку они векторные, SVG-картинки позволяют избежать проблемы разрешения экрана (см. ниже). Хотите узнать, как добавить картинку на нашу страницу responsive.html? Замените существующую картинку в div .content так, чтобы она соответствовала следующему:

<div class='section content'>
<img class='illustration' src='images/illustration.svg' />
</div>

Браузеры автоматически масштабируют SVG для ретина-устройств, поэтому SVG 500×250 пикселей будет четко отображаться и на стандартных и на ретина-устройствах.

SVG поможет забыть о проблемах с разрешением экрана, но чтобы картинка вписалась в жидкие макеты [fluid layouts] для планшетов и смартфонов, ее нужно уменьшить. Firefox сделает это автоматически, но если вы откроете эту страницу в Chrome и сделаете окно узким, вы увидите, что картинка осталось того же размера.

Чтобы получить жидкое изображение в Chrome, нужно приказать картинке всегда заполнять ширину своего контейнера. В styles.css вместе с остальными базовыми стилями (вне медиавыражений!) поместите следующее правило:

.illustration {
width: 100%;
}

Задавая ширину картинки 100 %, высота задается автоматически. Предполагается, что мы хотим сохранить соотношение сторон. Это исправляет ситуацию с мобильным макетом, но теперь версия для ноутбуков/ПК становится огромной:

Interneting is hard HTML+CSS
Скриншот 6: SVG-картинка уменьшается до ширины смартфонов и планшетов, но становится огромной на ноутбуках/ПК

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

<div class='section content'>
<img class='illustration' src='images/illustration.svg' style='max-width: 500px' />
</div>

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

Interneting is hard HTML+CSS
Скриншот 7: добавление встроенного стиля для ограничения размера SVG-изображения
адаптивные PNG, GIF, JPG
responsive png, gif, and jpg images

Конечно, не все изображения в Интернете являются SVG. Иногда необходимо включить фотографию. Картинки PNG, GIF и JPG - это "растровые изображения", они определяются попиксельно, а не с помощью векторов. Поэтому они гораздо более чувствительны к разрешению экрана, чем SVG.

Если вы не беспокоитесь об оптимизации, адаптивные растровые изображения действительно ненамного сложнее, чем SVG. Попробуйте заменить наш существующий файл illustration.svg на PNG-файл:

<div class='section content'>
<img class='illustration' />
<img src='images/illustration-big.png' style='max-width: 500px' />
</div>
</div>

Мы немного изменили структуру HTML, вложив наш тег <img/> в другой контейнер. Без него изображение исказилось бы, потому что flexbox попытался бы установить его высоту равной высоте контейнера .content. Это также требует небольшого изменения нашего CSS-правила .illustration:

.illustration img {
width: 100%;
display: block;
}

Также обратите внимание на суффикс -big в имени файла изображения. Это версия PNG с высоким разрешением и размером 1000×500. Ретина-устройствам для четкого отображегния необходим такой размер "2x". Изображение с низким разрешением (500×250 пикселей) выглядит хорошо на стандартных экранах, а на ретина-экранах будет размытым.

Interneting is hard HTML+CSS
Скриншот 8: подача картинки высокого разрешения на стандартные и на ретина-экраны (последнее расточительно)

Данный способ создания адаптивных PNG, GIF и JPG можно назвать "лентяйским". Предполагается, что всем и всегда нужны высокопиксельные картинки. Но это не так. Картинка 1000×500 пикселей - это излишество для всех не ретиновых экранов. Об этом - чуть ниже.

Оптимизация адаптивных изображений
responsive image optimization

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

Первый способ - самый простой. Он отлично подходит для изображений шириной менее 600 пикселей, поскольку они недостаточно велики, чтобы воспользоваться вторым сценарием. Второй способ - очень важная оптимизация для больших изображений, особенно для полноцветных фотографий. Третий - для тех случаев, когда вы чувствуете себя крутым.

оптимизация srcset для ретина-экранов
retina optimization using srcset

Изображения высокого разрешения очень большие. Наш illustration-big.png занимает более чем в два раза больше места на диске, чем его аналог с низким разрешением. Нет смысла пересылать все эти дополнительные данные, если они фактически не нужны пользователю.

Благодаря атрибуту srcset, добавленного к элементу <img/>, изображение с высоким разрешением будет подаваться только на ретина-экраны, а на обычные экраны будет подаваться версия с низким разрешением. Обновите элемент .illustration следующим образом:

<div class='illustration'>
<img src='illustration-small.png'
srcset='images/illustration-small.png 1x,
images/illustration-big.png 2x'

style='max-width: 500px' />
</div>

Атрибут srcset указывает на список альтернативных файлов изображений, а также свойства, определяющие, когда браузер должен использовать каждый из них. Значение 1x велит браузеру отображать illustration-small.png на обычных экранах, а 2x - отображать illustration-big.png на ретина-экранах. Старые браузеры, не понимающие srcset, возвращаются к атрибуту src.

Interneting is hard HTML+CSS
Скриншот 9: подача изображения с низким разрешением на стандартный экран и с высоким разрешением на ретина-экраны

Обычно версии изображения с низким и высоким разрешением абсолютно одинаковы (за исключением их размеров), но мы сделали illustration-small.png желтым, чтобы вы могли легко отличить его от версии для ретина-экрана, которая имеет синий цвет.

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

Interneting is hard HTML+CSS
Скриншот 10: [если цвет желтый, то у вас экран стандартного разрешения. А если синий - то ретина-экран]

Если вы создаете эти примеры на компьютере с ретина-экраном, можно попробовать временно изменить 2x на 1x, чтобы посмотреть, как выглядит изображение без ретина-экрана. Оно будет немного размытым (и желтым).

оптимизация ширины экрана с помощью srcset
screen width optimization using srcset

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

Interneting is hard HTML+CSS
Скриншот 11: низкопиксельная картинка, отправляемая на ноутбуки/ПК и мобильные устройства со стандартным экраном, в сравнении с низкопиксельной картинкой, отправляемой на ноутбуки/ПК с ретина-экраном

Представьте, что в .header мы хотим отобразить большую фотографию. Ширина заголовка в нашем макете для ноутбуков/ПК - 960 пикселей. Тогда для хорошего отображения на ретина-экранах ширина фото должна быть не менее 1920 пикселей. Для стандартных экранов мы также предоставим фотографию шириной 960 пикселей. Теперь рассмотрим смартфон с ретина-экраном. Смартфоны обычно имеют ширину менее 400 пикселей в портретном режиме. Тогда ширина соответствующего фото с качеством "ретина" должна быть всего 800 пикселей.

Ого! Мы можем использовать фото стандартного разрешения на смартфонах с ретина-экраном!

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

<div class='section header'>
<div class='photo'>
<img src='images/photo-small.jpg'
srcset='images/photo-big.jpg 2000w,
images/photo-small.jpg 1000w'
sizes='(min-width: 960px) 960px,
100vw'
/>
</div>
</div>

У нас тот же элемент srcset, что и в предыдущем разделе, но вместо дескрипторов 1x и 2x мы указываем физическую ширину картинки. 2000w говорит браузеру, что photo-big.jpg имеет ширину 2000 пикселей. Аналогично, 1000w означает, что ширина photo-small.jpg равна 1000 пикселям. Символ w это специальная единица, используемая только для такого рода сценариев оптимизации изображений.

Interneting is hard HTML+CSS
Скриншот 12: srcset=1000w - ширина файла низкопиксельной картинки, srcset=2000w - ширина файла высокопиксельной картинки

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

Interneting is hard HTML+CSS
Скриншот 13: sizes=100vw - ширина изображения в мобильном макете, sizes=960px - ширина изображения в десктопном макете

Так, если ширина экрана составляет не менее 960px, то и картинка будет шириной 960 пикселей. Иначе стандартное значение 100vw говорит браузеру, что ширина картинки будет равна 100% от "ширины области просмотра" (англ. viewport width - модный термин для обозначения ширины экрана). Подробнее о vw читайте на сайте MDN. Все это соответствует поведению изменения размера картинки в нашем CSS.

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

.header {
height: auto;
justify-content: inherit;
align-items: inherit;
}

.photo img {
width: 100%;
display: block;
}

Помните, что ширина нашего фото низкого разрешения равна 1000 пикселей. Это означает, что устройства с ретина-экраном 2x могут использовать ее, если ширина их экрана не превышает 500 пикселей. В Firefox теперь можно изменять размер браузера, чтобы видеть версию ретина ("Big") при ширине окна более 500 пикселей и версию без ретина ("Small") при меньшей ширине.

Теперь мы передаем на мобильные устройства изображение размером 115 КБ вместо изображения высокого разрешения размером 445 КБ. Это особенно актуально для сайтов с большим количеством фотографий.

ТЕСТИРОВАНИЕ В БРАУЗЕРЕ ХРОМ
testing with chrome

Эта техника отлично работает в Chrome, но не до конца понятно, как это происходит. Chrome всегда использует картинку с высоким разрешением, если она уже была локально кэширована. Поэтому мы не сможем увидеть картинку с низким разрешением, просто заузив окно браузера. Чтобы избежать локального кэша браузера, сделайте следующее: открыв новое окно Incognito Window, перед загрузкой страницы сделайте окно очень узким. Так можно предотвратить загрузку photo-big.jpg.

<picture> как решение проблемы художественного оформления
art direction using <picture>

Предыдущая секция вполне пригодна для оптимизации использования данных. На этом можно бы и остановиться, но ведь мы хотим стать более искусными и в "художественом оформлении". Считайте художественное оформление [art direction] оптимизацией адаптивных картинок для дизайнеров.

Художественное оформление позволяет оптимизировать макеты [layouts], отправляя пользователю разные варианты в зависимости от его устройства. В предыдущей секции, одну и ту же фотографию мы оптимизировали для разных устройств. Причем эта фотография в заголовке довольно широка. Разве не было бы здорово вместо широкой версии для ноутбуков/ПК, несколько обрезать края для отображения ее на мобильных устройствах?

Interneting is hard HTML+CSS
Скриншот 14: отображение фото, урезанного по высоте [tall-cropped] на мобильных устройствах и урезанного по ширине [wide-cropped] на ноутбуках/ПК с стандартными и ретина-экранами

Для этого нам нужны элементы <picture> и <source>. Первый является просто оберткой, а второй условно загружает картинки на основе медиавыражений. Попробуйте изменить наш элемент .header:

<div class='section header'>
<div class='photo'>
<picture>
<source media='(min-width: 401px)'
srcset='images/photo-big.jpg' />
<source media='(max-width: 400px)'
srcset='images/photo-tall.jpg' />
<img src='images/photo-small.jpg' />
</picture>
</div>
</div>

По своей концепции это похоже на использование медиавыражений в CSS. В каждом элементе атрибут media определяет, когда должна загружаться картинка, а srcset - какой файл должен быть загружен. Элемент <img/> используется только как запасной вариант для старых браузеров. Уменьшив окно браузера, вы сможете увидеть высокую версию фото:

Interneting is hard HTML+CSS
Скриншот 15: в мобильной версии фото урезано по высоте, а в версии для ноутбуков/ПК - по ширине

Такой уровень контроля очень обрадует вашего дизайнера. Однако есть и недостаток - браузер не может автоматически выбирать оптимальное изображение. То есть мы потеряли нашу оптимизацию для ретина-экранов из предыдущей cекции: до тех пор, пока ширина экрана составляет 401 пиксель или больше, браузер всегда будет использовать высокопиксельное изображение, урезанное по ширине [wide-cropped image].

Пытаясь совместить лучшее из двух миров, все быстро усложняется. Мы рекомендуем придерживаться версий srcset 1x и 2x для картинок шириной менее 600 пикселей, использовать метод srcset плюс sizes из предыдущей секции для больших фотографий, а <picture> оставить для тех случаев, когда вместе с дизайнером вы задумаете что-то сногсшибательное.

РЕЗЮМЕ

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

Мы решили первую задачу, заставив изображения всегда растягиваться, чтобы заполнить 100% своего контейнера, и ограничив их размер с помощью встроенного стиля max-width. Чтобы решить вторую задачу, мы использовали srcset для оптимизации под разрешение экрана, srcset и sizes для оптимизации под ширину устройства и, наконец, элемент <picture> для ручного управления отображением файла изображения.

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

Оставшиеся пять глав полностью посвящены верстке. Мы изучили плавающие элементы, flexbox, продвинутое позиционирование и то, как применять все эти концепции для экранов разной ширины. Это практически все, что вам когда-либо понадобится для верстки веб-страниц с помощью HTML и CSS. В следующей главе мы вернемся в мир HTML изучая множество новых элементов, которые сильно "порадуют" поисковые системы оптимизацией наших сайтов.

СЛЕДУЮЩИЙ УРОК >