В давние времена (в конце 1990-х годов) ширину создаваемых сайтов обычно задавали в процентах. Указание ширины в процентах приводило к подстраиванию страниц к экрану просмотра и приобрело известность как резиновые разметки (fluid layouts).
Вскоре, во второй половине 2000-х годов, появилась промежуточная фиксация с использованием конструкций с фиксированной шириной (я виню в этом дотошных полиграфистов с их приверженностью к абсолютной точности в пикселах). Теперь же, поскольку мы создаем конструкции с адаптивным веб-дизайном, нам нужно обратиться в прошлое, к динамически изменяемым разметкам, и вспомнить обо всех получаемых благодаря им преимуществах.
В главе 2 мы в конечном итоге признали, что наряду с предоставляемой медиазапросами возможностью создания дизайна, адаптируемого к изменяющимся размерам окна просмотра за счет переключения от одного набора стилей к другому, нам нужна какая-либо возможность динамического изменения нашего дизайна в промежутках между контрольными точками, предоставляемыми медиазапросами. Эта возможность успешно реализуется путем программирования подстраиваемой разметки, способной легко растягиваться для заполнения разрывов между контрольными точками медиазапросов.
В 2015 году в нашем распоряжении имеются такие эффективные средства для создания сайтов с адаптивным веб-дизайном, которых прежде не было. Это новый модуль CSS-разметки под названием Flexible Box (больше известный как Flexbox), который в настоящее время приобрел довольно широкую поддержку со стороны браузеров, став полноценным средством повседневного использования.
Он способен на большее, нежели просто предоставлять механизм динамически изменяемой разметки. Хотите получить возможность легко и просто выровнять содержимое по центру, изменить порядок в источнике разметки и вообще относительно легко создавать великолепные разметки? Тогда механизм разметки Flexbox для вас. Основная часть этой главы посвящена Flexbox, она охватывает самые интересные из предлагаемых им возможностей.
Есть еще одна ключевая область адаптивного веб-дизайна, которую теперь можно рассмотреть намного предметнее, чем когда-либо раньше, — я имею в виду адаптивные изображения. Теперь уже есть точно определенные методы и синтаксис для отправки на устройства наиболее подходящей для их окон просмотра версии изображения. Последний раздел главы будет посвящен разъяснению порядка работы адаптивных изображений и изучению способов, благодаря которым мы можем заставить их работать на нас.
В этой главе будут рассмотрены следующие вопросы:
• преобразование фиксированных размеров в пикселах в пропорциональные размеры;
• существующие механизмы CSS-разметки и их недостатки;
• разбор модуля Flexible Box Layout Module и предоставляемых им преимуществ;
• изучение допустимого синтаксиса для переключения разрешения и режиссуры адаптивных изображений.
Все графические составляющие, созданные в таких программах, как Photoshop, Illustrator, Fireworks (RIP) или Sketch, имеют фиксированные размеры в пикселах. Когда разработчик перерабатывает дизайн в подстраиваемую разметку для отображения в браузере, элементы дизайна нуждаются в преобразовании в пропорциональные величины.
Для этого преобразования есть красивая и простая формула, которую отец адаптивного веб-дизайна, Итан Маркотт (Ethan Marcotte), разместил в своей статье 2009 года Fluid Grids ():
Цель / Среда = Результат.
Если все, что относится к математике, вас раздражает, воспринимайте эту формулу следующим образом: разделите нужные вам составные части на то, в чем они помещаются. Введем это в обиход в качестве понятия, позволяющего выполнить преобразование любой разметки с фиксированными размерами в ее адаптивные (подстраиваемые) эквиваленты.
Рассмотрим очень простую разметку страницы, предназначенную для просмотра на настольном компьютере. В идеале мы всегда будем подходить к разметке для настольного компьютера, начиная с разметки для более скромных экранов, но с целью приведения примеров пропорций рассмотрим две данные ситуации в обратном порядке.
Эта разметка имеет следующий вид.
Ее ширина — 960 пикселов. Заголовок и подвал (нижний колонтитул) выводятся на всю ширину разметки. Область слева имеет ширину 200 пикселов, а область справа — 100 пикселов. Даже при моей недостаточной математической подкованности я могу вас заверить, что средняя часть будет иметь ширину 660 пикселов. Нам нужно преобразовать среднюю и боковые части, приведя их к пропорциональным размерам.
Начнем с левой стороны. Она имеет ширину 200 единиц (в нашей формуле это цель). Разделим этот размер на 960 единиц (среду) и получим 0,2083 33333. Теперь, вычислив результат по формуле, нужно переместить десятичный разделитель на две позиции вправо. В результате получим 20,83 33333 %. Именно так 200 пикселов описываются в процентах к 960 пикселам.
А как насчет средней части? Здесь 660 единиц (цель), разделенные на 960 (среда), дают нам 0,6875. Переместим десятичный разделитель на две позиции вправо и получим 68,75 %. И наконец, правая сторона: 100 единиц (цель), разделенные на 960 (среда), дают 0,1041 66667. После перемещения десятичного разделителя получим 10,41 66667 %. Как видите, ничего сложного. Повторяйте за мной: цель, разделенная на среду, дает результат.
В качестве доказательства быстро создадим эту простую разметку в виде блоков в браузере. Код разметки можно увидеть в файле каталога example_03-01. Вот как выглядит код HTML:
<div class="Wrap">
<div class="Header"></div>
<div class="WrapMiddle">
<div class="Left"></div>
<div class="Middle"></div>
<div class="Right"></div>
</div>
<div class="Footer"></div>
</div>
А вот как выглядит код CSS:
html,
body {
margin: 0;
padding: 0;
}
.Wrap {
max-width: 1400px;
margin: 0 auto;
}
.Header {
width: 100%;
height: 130px;
background-color: #038C5A;
}
.WrapMiddle {
width: 100%;
font-size: 0;
}
.Left {
height: 625px;
width: 20.83 33333%;
background-color: #03A66A;
display: inline-block;
}
.Middle {
height: 625px;
width: 68.75%;
background-color: #bbbf90;
display: inline-block;
}
.Right {
height: 625px;
width: 10.41 66667%;
background-color: #03A66A;
display: inline-block;
}
.Footer {
height: 200px;
width: 100%;
background-color: #0 25059;
}
Если пример кода открыть в браузере и изменить размер страницы, вы увидите, что размер средней части останется пропорциональным по отношению к другим частям. Можно также попробовать изменять значение свойства max-width для класса .Wrap, чтобы сделать окружающие размеры для разметки больше или меньше (в примере установлено значение 1400 пикселов).
совет
Если при изучении разметки вас беспокоил вопрос, почему я не воспользовался такими семантическими элементами, как header, footer и aside, не стоит волноваться. Эти элементы HTML5 подробно рассматриваются в главе 4.
Теперь посмотрим, каким будет то же самое содержимое на экранах меньших размеров. Сначала оно динамически подстраивается под контрольную точку, после чего подстраивается под среду, а затем изменяется под ту разметку, которую мы уже видели. Окончательный вариант кода этой разметки можно увидеть в файле каталога example_03-02.
Суть замысла в том, что для экранов меньшего размера у нас будет одна колонка содержимого. Левосторонняя часть будет видна как область, выходящая за пределы холста, обычно эта область отводится под меню или что-то подобное, что не попадает на просматриваемое пространство экрана и выплывает при нажатии кнопки меню. Основное содержимое помещается ниже заголовка, еще ниже помещаются правосторонняя часть и, наконец, область подвала. В нашем примере левостороннюю область меню можно показать после щелчка в любом месте заголовка. Обычно при реализации схемы дизайна подобного рода для активизации бокового меню используется кнопка меню.
совет
Для переключения класса тела документа я воспользовался небольшим сценарием на JavaScript. Но он не отвечает требованиям готовности к полноценному использованию, поскольку в JavaScript применяется обработчик события щелчка 'click', а в идеале должно быть предусмотрено что-нибудь для работы на сенсорном экране (для удаления задержки 300 мс, которая до сих пор имеется в устройствах, работающих под управлением iOS).
Как вы, наверное, и ожидали, применив только что приобретенные навыки создания медиазапросов, мы можем настроить окно просмотра, и дизайн просто адаптируется под эту настройку, перейдя от одной разметки к другой и растягиваясь при этом в промежуточных позициях между этими двумя разметками.
Я не собираюсь показывать здесь весь код CSS, доступный в файле каталога example_03-02, и привожу лишь его пример, относящийся к левосторонней части:
.Left {
height: 625px;
background-color: #03A66A;
display: inline-block;
position: absolute;
left: -200px;
width: 200px;
font-size: .9rem;
transition: transform .3s;
}
@media (min-width: 40rem) {
.Left {
width: 20.83 33333%;
left: 0;
position: relative;
}
}
Как видите, сначала идет разметка без медиазапроса, предназначенная для небольшого экрана. Затем для более крупных экранов ширина задается в пропорциях, позиционирование задается относительным, а left присваивается значение 0. Значения таких свойств, как height, display или background-color, переписывать не нужно, поскольку их мы не изменяем.
Дело сдвинулось с места. Мы объединили две уже рассмотренные основные технологии адаптивного веб-дизайна, преобразовав фиксированные размеры в пропорции и воспользовавшись медиазапросами для создания целевых CSS-правил, относящихся к размеру окна просмотра.
совет
В предыдущем примере есть два примечательных момента. Во-первых, вам могла показаться странным необходимость учитывать все десятичные знаки после разделителя. Дело в том, что значения ширины будут в итоге преобразованы браузером в пикселы и их еще предстоит вычислить (например, более точно определить ширину вложенных элементов). Из этого следует, что я рекомендую никогда не трогать числа, стоящие после разделителя. Во-вторых, в реальном проекте мы предоставили бы что-нибудь на случай отключения JavaScript и сохранения необходимости просмотра содержимого меню. Такой сценарий еще будет прорабатываться в главе 8.
Давайте углубимся в подробности использования модуля CSS Flexible Box Layouts, более известного как Flexbox.
Но полагаю, что перед этим было бы разумно рассмотреть недостатки существующих технологий разметки, таких как линейные блоки, плавающие элементы и таблицы.
Самой большой проблемой использования линейных блоков (inline-block) является механизм разметки, выводящий пробелы между элементами HTML. Это не считается серьезном недостатком (хотя многие разработчики были бы не прочь узнать способ удаления пробела), но означает, что для удаления нежелательного пробела нужно прибегать к особым приемам, что, на мой взгляд, отнимает около 95 % времени. Существует множество способов решения этой проблемы, в предыдущем примере мы воспользовались обнулением размера шрифта — 'font-size zero', у которого есть собственные недостатки и ограничения. Но вместо перечисления всех возможных способов устранения свободных пространств при использовании линейных блоков я предлагаю ознакомиться со статьей неугомонного Криса Койера (Chris Coyier): /.
Стоит также заметить, что простого способа центрирования содержимого внутри линейного блока по вертикали не существует. Кроме того, при использовании линейных блоков отсутствует способ получения двух одноуровневых элементов, один их которых имеет фиксированную ширину, а другой подстраивается для заполнения всего оставшегося пространства.
Я ненавижу плавающие элементы. И этим все сказано. Их положительным свойством является довольно устойчивая работа при любых обстоятельствах. Но у них есть две весьма досадные особенности.
Во-первых, при указании ширины плавающих элементов в процентах вычисленная ширина не округляется всеми браузерами одинаково (некоторые округляют вверх, а некоторые — вниз). Это означает, что иногда разделы вопреки задуманному будут выпадать из общей картины, а иногда будут оставлять с одной из сторон портящие внешний вид пробелы.
Во-вторых, плавающие элементы приходится вычищать, поскольку в противном случае родительские блоки или элементы не схлопываются. Конечно, особого труда это не составляет, но все же служит постоянным напоминанием о том, что плавающие элементы не следует использовать в качестве надежного механизма разметки ни при каких условиях.
Не нужно путать display: table и display: table-cell с соответствующими элементами HTML. Эти CSS-свойства просто имитируют разметку своих собратьев из HTML и на структуру HTML не влияют.
Я считаю табличную CSS-разметку исключительно полезной. Как минимум она позволяет осуществлять единообразное и надежное выравнивание элементов по центру друг в друге. Кроме того, элементы, имеющие настройку отображения display: table-cell внутри элемента, имеющего настройку display: table, отлично справляются с расстановкой пустых пространств и не страдают от проблем округления, как плавающие элементы. А поддержка этих свойств уходит корнями аж к Internet Explorer 7!
Но и здесь не обошлось без ограничений. Зачастую возникает необходимость заключать элемент в дополнительную оболочку (чтобы получить четкое выравнивание по центру, ячейка таблицы (table-cell) должна находиться внутри элемента, настроенного как таблица (table)). Кроме того, элементы, имеющие настройку отображения display: table-cell, не могут переносить свое содержимое с одной строки на другую.
В заключение необходимо отметить, что ограничения имеются у всех существующих методов разметки. Но, к нашему глубокому удовлетворению, есть новые CSS-методы разметки, справляющиеся с данными проблемами, которые способны не только на это, но и на многое другое. Дуйте в фанфары, расстилайте красный ковер. К нам идет Flexbox.
Модуль Flexbox предназначен для устранения недостатков, имеющихся в каждом из упомянутых ранее механизмов отображения. Коротко перечислю его исключительные возможности.
• Он легко справляется с выравниванием содержимого по вертикали.
• Он может изменить порядок визуального отображения элементов.
• Он может автоматически заполнять пространство пробелами и выравнивать элементы внутри блока, автоматически распределяя между ними доступное пустое пространство.
• Он может заставить вас выглядеть на десять лет моложе (наверное, все же не может, но, в чем я смог лично убедиться, уменьшая количество проб и ошибок, он снижает у вас уровень стресса).
Прежде чем Flexbox превратился в сегодняшнюю относительно стабильную версию, он прошел через несколько основных стадий. Рассмотрим, к примеру, изменения, произошедшие со времени выхода версии 2009 года ( 90723/), версии 2011 года ( 11129/) и версии 2014 года, на которой основаны приводимые здесь примеры (/). Можно заметить, что у этих версий имеются существенные синтаксические различия.
Наличие различных спецификаций означает, что есть три основные версии реализации. Скольким версиям следует уделить внимание, зависит от необходимого вам уровня поддержки со стороны браузеров.
Сразу обозначим исключения: Internet Explorer 9, 8 и более ранних версий Flexbox не поддерживает.
Что же касается всех остальных браузеров, чью поддержку хотелось бы получить (и практически всех браузеров мобильных устройств), то у вас есть возможность воспользоваться большинством, если не всеми свойствами Flexbox. Информацию о поддержке можно получить по адресу /.
Прежде чем углубиться в изучение Flexbox, нужно сделать небольшое, но важное отступление.
Я надеюсь, что, посмотрев на примеры Flexbox, вы отдадите должное пользе от его применения и вдохновитесь на его использование. Но вводить вручную весь код, необходимый для поддержки различных Flexbox-спецификаций, — задача не из легких. Вот пример, в котором я собираюсь задать три относящихся к Flexbox свойства и значения. Рассмотрим его код:
.flex {
display: flex;
flex: 1;
justify-content: space-between;
}
Именно так свойства и значения будут выглядеть в самой последней версии синтаксиса. Но если нужно получить поддержку со стороны Android-браузеров (v4 и ниже), а также IE 10, потребуется следующий код:
.flex {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-flex: 1;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
}
Необходимость написания всего этого обусловлена тем, что в последние несколько лет во всех браузерах стали доступны экспериментальные версии новых функциональных возможностей, но с использованием так называемого префикса производителя (vendor prefix). У каждого производителя имелся собственный префикс. Например, -ms- для Microsoft, -webkit- для WebKit, -moz- для Mozilla и т. д. Для каждой новой функциональной возможности это означало необходимость написания нескольких версий одного и того же свойства, сначала в форме версий с префиксами, а в конце — в форме официальной версии консорциума W3C.
Результатом такого написания в веб-истории является код CSS, подобный приведенному в предыдущем примере. Это единственный способ получить функцию, работающую на широком круге устройств. В наши дни производители довольно редко добавляют префиксы, но в обозримом будущем нам придется жить, сообразуясь с реальностью существования множества браузеров, по-прежнему требующих использования префиксов для включения конкретных функций. Это возвращает нас к Flexbox, который является ярким примером необходимости указания префиксов производителей не только из-за нескольких версий от разных производителей, но и из-за различных спецификаций функций. Но понимание и запоминание всего, что необходимо для написания текущего формата и каждого предыдущего формата, не составляет полной картины сомнительных удовольствий.
Не знаю, как вы, а я предпочитаю тратить свое время на более продуктивные занятия, чем всякий раз записывать весь этот объем кода! Короче говоря, если вы собираетесь тратить свои нервы на использование Flexbox, потратьте время на настройку решения для автоматической расстановки префиксов.
Чтобы сберечь нервы и аккуратно, без особых усилий добавить к CSS префиксы производителей, воспользуйтесь решением для автоматической расстановки префиксов. Лично я на данный момент предпочитаю пользоваться средством Autoprefixer (). Оно работает довольно быстро, легко настраивается и отличается высокой точностью работы.
Существуют версии Autoprefixer для большинства настроек, и вам не обязательно пользоваться средством создания на основе использования командной строки (например, Gulp или Grunt). К примеру, если пользоваться средством Sublime Text, то существует версия, которая будет работать непосредственно из его палитры команд: . Есть также версии Autoprefixer для Atom, Brackets и Visual Studio.
С этого момента, если не понадобится конкретная иллюстрация, префиксы производителей в примерах кода использоваться не будут.
У Flexbox имеются четыре основные характеристики: направление (direction), выравнивание (alignment), определение порядка (ordering) и динамическое изменение (flexibility). Мы рассмотрим все эти характеристики и их взаимоотношения на нескольких примерах.
Это намеренно простые примеры, касающиеся простого перемещения блоков и их содержимого и позволяющие понять принципы работы Flexbox.
Этот первый пример использования Flexbox можно найти в файле каталога example_03-03.
Разметка выглядит следующим образом:
<div class="CenterMe">
Hello, I'm centered with Flexbox!
</div>
А вот полное CSS-правило, придающее стиль этой разметке:
.CenterMe {
background-color: indigo;
color: #ebebeb;
font-family: 'Oswald', sans-serif;
font-size: 2rem;
text-transform: uppercase;
height: 200px;
display: flex;
align-items: center;
justify-content: center;
}
Большинство пар «свойство — значение» в этом правиле просто устанавливают цветовые решения и размер шрифта. Нам интересны лишь три свойства:
.CenterMe {
/* другие свойства */
display: flex;
align-items: center;
justify-content: center;
}
Если вы еще не пользовались Flexbox или какими-либо свойствами из родственной спецификации Box Alignment Specification (/), эти свойства, возможно, покажутся вам несколько странными. Рассмотрим, что делает каждое из них.
• display: flex — это хлеб с маслом Flexbox. А именно, простая настройка элемента на его принадлежность к Flexbox (в противоположность блоку-контейнеру, линейному блоку и т. д.).
• align-items — это свойство приводит к выравниванию элементов внутри Flexbox по поперечной оси (в нашем примере текст выравнивается по вертикали).
• justify-content — это свойство задает выравнивание содержимого по центру главной оси. Что касается строки Flexbox, то об этом свойстве можно думать как о кнопке в текстовом процессоре, выравнивающей текст по левому или правому краю или по центру (хотя существуют и другие значения justify-content, которые также вскоре будут рассмотрены).
Итак, перед тем, как продолжить изучение свойств Flexbox, рассмотрим еще несколько примеров.
совет
В некоторых из этих примеров использовался имеющийся у Google шрифт Oswald (с откатом к шрифту sans-serif). В главе 5 мы рассмотрим способы использования правила @font-face, предназначенного для привязки к заказным файлам шрифтов.
А как вам понравится простой список элементов перехода, в котором один из этих элементов смещен в другую сторону?
Вот как это выглядит.
Вот разметка:
<div class="MenuWrap">
<a href="#" class="ListItem">Home</a>
<a href="#" class="ListItem">About Us</a>
<a href="#" class="ListItem">Products</a>
<a href="#" class="ListItem">Policy</a>
<a href="#" class="LastItem">Contact Us</a>
</div>
А вот код CSS:
.MenuWrap {
background-color: indigo;
font-family: 'Oswald', sans-serif;
font-size: 1rem;
min-height: 2.75rem;
display: flex;
align-items: center;
padding: 0 1rem;
}
.ListItem,
.LastItem {
color: #ebebeb;
text-decoration: none;
}
.ListItem {
margin-right: 1rem;
}
.LastItem {
margin-left: auto;
}
Как видите, не нужны никакие отдельно взятые плавающие элементы, линейные блоки или ячейки таблицы (table-cell)! При настройке display: flex;, примененной в отношении элемента-контейнера, его дочерние элементы становятся подстраиваемыми, выводимыми затем с использованием модели динамически изменяемой разметки. Все волшебство здесь заключается в свойстве margin-left: auto, которое заставляет этот элемент использовать все незаполненное место, доступное в данной стороне.
Хотите изменить порядок следования элементов на обратный?
Можно просто добавить к элементу-контейнеру свойство flex-direction: row-reverse;, а для смещенного элемента вместо margin-left: auto написать margin-right: auto:
.MenuWrap {
background-color: indigo;
font-family: 'Oswald', sans-serif;
font-size: 1rem;
min-height: 2.75rem;
display: flex;
flex-direction: row-reverse;
align-items: center;
padding: 0 1rem;
}
.ListItem,
.LastItem {
color: #ebebeb;
text-decoration: none;
}
.ListItem {
margin-right: 1rem;
}
.LastItem {
margin-right: auto;
}
Да запросто. Измените свойство элемента-контейнера на flex-direction: column; и удалите автоматическую установку полей:
.MenuWrap {
background-color: indigo;
font-family: 'Oswald', sans-serif;
font-size: 1rem;
min-height: 2.75rem;
display: flex;
flex-direction: column;
align-items: center;
padding: 0 1rem;
}
.ListItem,
.LastItem {
color: #ebebeb;
text-decoration: none;
}
Хотите расположить элементы друг под другом в обратном порядке? Измените настройку на flex-direction: column-reverse;, и все будет сделано как надо.
примечание
Следует отметить, что для установки в одной настройке значений сразу двух свойств, и flex-direction, и flex-wrap, можно воспользоваться сокращением в виде свойства flex-flow. Например, настройка flex-flow: row wrap; установит строчное направление и включит возможность размещения блоков в нескольких строках. Но я считаю, что по крайней мере на первых порах проще будет указать эти два свойства по отдельности. Свойство flex-wrap также отсутствует в более ранних реализациях, поэтому в определенных браузерах его объявление может игнорироваться.
Что касается поведения списка элементов в столбце на экранах меньшего размера и стиля разметки строки, Flexbox в соответствии со своим названием изначально способен динамически изменять разметку. При использовании Flexbox эта задача существенно облегчается:
.MenuWrap {
background-color: indigo;
font-family: 'Oswald', sans-serif;
font-size: 1rem;
min-height: 2.75rem;
display: flex;
flex-direction: column;
align-items: center;
padding: 0 1rem;
}
@media (min-width: 31.25em) {
.MenuWrap {
flex-direction: row;
}
}
.ListItem,
.LastItem {
color: #ebebeb;
text-decoration: none;
}
@media (min-width: 31.25em) {
.ListItem {
margin-right: 1rem;
}
.LastItem {
margin-left: auto;
}
}
Все это можно посмотреть, запустив в браузере файл каталога example_03-05. Чтобы увидеть различные разметки, нужно изменить размеры окна браузера.
У Flexbox имеется линейный вариант для дополнения линейных блоков (inline-block) и линейных таблиц (inline-table). Нетрудно догадаться, что для этого имеется объявление display: inline-flex;. Благодаря его превосходным возможностям по выравниванию по центру вы можете легко добиться весьма впечатляющих результатов.
Разметка выглядит следующим образом:
<p>Here is a sentence with a <a href="-
flexbox-1/#flex-containers" class="InlineFlex">inline-flex link</a>.</p>
А вот для нее и код CSS:
.InlineFlex {
display: inline-flex;
align-items: center;
height: 120px;
padding: 0 4px;
background-color: indigo;
text-decoration: none;
border-radius: 3px;
color: #ddd;
}
Когда свойство inline-flex придается элементам анонимно (например, когда их родительский элемент не имеет настройки display: flex;), они сохраняют пробелы между элементами точно так же, как это происходит при использовании линейных блоков или линейных таблиц. Hо если такие элементы находятся внутри flex-контейнера, пробелы удаляются, что уже похоже на элементы, являющиеся ячейками таблицы внутри самой таблицы.
Разумеется, никто вас не заставляет всегда центрировать элементы внутри Flexbox. Существует несколько различных вариантов. Их мы сейчас и рассмотрим.
Если вы хотите попрактиковаться с этим примером, его можно найти в файле каталога example_03-07. Не забудьте, что загружаемый код примера будет находиться в том состоянии, к которому мы придем к концу раздела, поэтому, если есть желание проработать все самостоятельно, лучше удалить CSS из файла примера и приступить к его созданию с нуля.
При изучении выравнивания, осуществляемого средствами Flexbox, важно разобраться с концепцией осей. В ней рассматриваются две оси: главная (main axis) и поперечная (cross axis). Что представляет собой каждая из них, зависит от направления, по которому распространяется Flexbox-контейнер. Например, если направление Flexbox-контейнера настроено на строку, главная ось будет горизонтальной, а поперечная ось — вертикальной.
И наоборот, если направление распространения вашего Flexbox-контейнера настроено на столбец, главная ось будет вертикальной, а поперечная ось — горизонтальной.
В помощь авторам в спецификации () приводится следующая иллюстрация.
Основная разметка нашего примера имеет такой вид:
<div class="FlexWrapper">
<div class="FlexInner">I am content in the inner Flexbox.</div>
</div>
Зададим основные стили, относящиеся к Flexbox:
.FlexWrapper {
background-color: indigo;
display: flex;
height: 200px;
width: 400px;
}
.FlexInner {
background-color: #34005B;
display: flex;
height: 100px;
width: 200px;
}
В браузере будет получена следующая картинка.
Хорошо, а теперь проведем тестирование ряда свойств.
Свойство align-items позиционирует элементы относительно поперечной оси. Если применить это свойство к нашему элементу-контейнеру следующим образом:
.FlexWrapper {
background-color: indigo;
display: flex;
height: 200px;
width: 400px;
align-items: center;
}
то нетрудно представить, что элемент внутри контейнера получит вертикальное выравнивание по центру.
Точно такой же эффект будет применен к любому количеству находящихся внутри контейнера дочерних элементов.
Иногда нужно применить другую настройку выравнивания всего лишь к одному из элементов. Для самостоятельного выравнивания отдельных flex-элементов может использоваться свойство align-self. Сейчас я удалю прежние свойства выравнивания, добавлю в разметку еще два элемента, которые получат HTML-класс .FlexInner, а к среднему элементу добавлю еще один HTML-класс (.AlignSelf) и воспользуюсь им для добавления свойства align-self. Возможно, более наглядное представление об этом вы получите при просмотре следующего кода CSS:
.FlexWrapper {
background-color: indigo;
display: flex;
height: 200px;
width: 400px;
}
.FlexInner {
background-color: #34005B;
display: flex;
height: 100px;
width: 200px;
}
.AlignSelf {
align-self: flex-end;
}
А вот такой эффект будет получен на экране браузера.
Великолепно! Flexbox действительно с легкостью справился с этими изменениями. В данном примере свойству align-self было присвоено значение flex-end. Рассмотрим возможные значения, которыми можно будет воспользоваться относительно поперечной оси, а потом рассмотрим возможности выравнивания относительно главной оси.
Для выравнивания относительно поперечной оси в модуле Flexbox имеются следующие значения:
• flex-start — настройка элемента на flex-start заставит его начинаться с начальной границы своего flex-контейнера;
• flex-end — настройка элемента на flex-end заставит его выровняться по конечной границе своего flex-контейнера;
• center — заставит элемент расположиться посредине flex-контейнера;
• baseline — заставит все flex-элементы в контейнере выровняться по нижним строкам;
• stretch — заставит элементы растянуться по размеру их flex-контейнера (по поперечной оси).
Есть подробное описание, касающееся использования этих свойств, поэтому, если что-то не получается, всегда обращайтесь к спецификации за любым самым актуальным вариантом применения: /.
Выравнивание по главной оси управляется свойством justify-content (для элементов, не находящихся в Flexbox-контейнере, предлагается также свойство justify-self, см. /). У свойства justify-content могут быть следующие значения:
• flex-start;
• flex-end;
• center;
• space-between;
• space-around.
Действие первых трех из них для вас вполне ожидаемо. А вот что получается при использовании space-between и space-around, мы сейчас увидим. Рассмотрим следующую разметку:
<div class="FlexWrapper">
<div class="FlexInner">I am content in the inner Flexbox 1.</div>
<div class="FlexInner">I am content in the inner Flexbox 2.</div>
<div class="FlexInner">I am content in the inner Flexbox 3.</div>
</div>
А затем рассмотрим следующий код CSS. Мы настроили каждый из трех flex-элементов (FlexInner) на ширину 25 %, заключив их во flex-контейнер (FlexWrapper), настроенный на ширину 100 %.
.FlexWrapper {
background-color: indigo;
display: flex;
justify-content: space-between;
height: 200px;
width: 100%;
}
.FlexInner {
background-color: #34005B;
display: flex;
height: 100px;
width: 25%;
}
Все три элемента займут только 75 % доступного пространства, а свойство justify-content объясняет, что именно мы хотим получить от браузера относительно оставшегося пространства. Значение space-between заставит распределить свободное пространство поровну между элементами, а значение space-around заставит разместить его в равных долях вокруг элементов. Возможно, разобраться со всем этим помогут скриншоты — это работа значения space-between.
А это результат использования вместо него значения space-around.
Полагаю, что сомневаться в практической пользе этих двух значений у вас нет никаких оснований.
совет
Имеющиеся в модуле Flexbox различные свойства выравнивания теперь приводятся и в описании спецификации CSS Box Alignment Module Level 3. Тем самым закладывается общая основа с эффектами выравнивания других свойств отображения, такими как display: block; и display: table;. Спецификация все еще остается в силе, поэтому проверяйте ее состояние, обращаясь по адресу /.
Мы уже использовали в отношении flex-элементов свойство width, но свойство flex позволяет определить по вашему желанию либо ширину, либо адаптивность. Чтобы проиллюстрировать его возможности, рассмотрим следующий пример, в котором для элементов используется та же разметка, но уже с исправленным кодом CSS:
.FlexItems {
border: 1px solid #ebebeb;
background-color: #34005B;
display: flex;
height: 100px;
flex: 1;
}
Фактически свойство flex является сокращенным определением трех отдельных свойств: flex-grow, flex-shrink и flex-basis. Более подробно спецификацию, в которой дается развернутое описание всех этих отдельных свойств, можно найти по адресу /. Но в этой спецификации рекомендуется использовать сокращенную форму в виде свойства flex, поэтому мы здесь его и рассмотрим.
Если для flex-элементов имеется свойство flex и браузер его поддерживает, то оно используется для указания размера элемента, а не значений ширины или высоты, если таковые имеются. Даже если после свойства flex указано значение ширины или высоты, оно все равно не будет действовать. Посмотрим, на что влияет каждое из этих значений.
• flex-grow (первое значение, которое может быть передано свойству flex) является величиной относительно других flex-элементов, до которой может увеличиваться flex-элемент при наличии свободного пространства.
• flex-shrink является величиной, до которой может уменьшаться flex-элемент относительно других flex-элементов, когда имеется дефицит пространства.
• flex-basis (последнее значение, которое может быть передано свойству flex) является базовым размером, к которому приводится размер flex-элемента.
Хотя можно просто написать flex: 1, я рекомендую записывать в свойство flex все три значения. Полагаю, вы понимаете, что должно произойти. Например, flex: 1 1 auto означает, что элемент будет увеличиваться на одну часть доступного пространства, он также станет уменьшаться до одной части, когда будет существовать дефицит пространства, и базовым размером для динамического изменения будет служить внутренняя ширина содержимого (размер, который был бы у содержимого, если бы динамическое изменение не требовалось).
Рассмотрим еще один вариант: настройка flex: 0 0 50px означает, что элемент не будет ни увеличиваться, ни уменьшаться и его базовая величина составит 50px (то есть он будет иметь размер 50 пикселов независимо от величины свободного пространства). А теперь разберем вариант flex: 2 0 50% — элемент будет стремиться занять два «лота» доступного пространства, он не станет уменьшаться и его базовый размер будет определяться значением 50%. Надеюсь, эти небольшие примеры немного развеяли мистику вокруг свойства flex.
совет
Если установить для свойства flex-shrink нулевое значение, то свойство flex-basis поведет себя как задание минимальной ширины.
Свойство flex можно представлять в виде способа задания отношений. Когда для каждого flex-элемента этому свойству присвоено значение 1, то все они занимают одинаковое пространство.
Хорошо, но чтобы проверить теорию на практике, внесем изменения в HTML-классы нашей разметки:
<div class="FlexWrapper">
<div class="FlexItems FlexOne">I am content in the inner Flexbox 1.</div>
<div class="FlexItems FlexTwo">I am content in the inner Flexbox 2.</div>
<div class="FlexItems FlexThree">I am content in the inner Flexbox 3.</div>
</div>
А так будет выглядеть измененный код CSS:
.FlexItems {
border: 1px solid #ebebeb;
background-color: #34005B;
display: flex;
height: 100px;
}
.FlexOne {
flex: 1.5 0 auto;
}
.FlexTwo,
.FlexThree {
flex: 1 0 auto;
}
В этом примере элемент с классом FlexOne занимает 1,5 того пространства, которое занято элементами с классами FlexTwo и FlexThree.
Этот сокращенный синтаксис проявляет свою реальную практичность для быстрой установки соизмеримости элементов. Например, если выдвигается требование «это должно быть в 1,8 раза шире всего остального», то его можно будет легко выполнить, используя свойство flex.
Надеюсь, вы уже начинаете понимать всю необычную эффективность свойства flex?
О Flexbox можно написать не одну главу! Примеров, достойных рассмотрения, великое множество. Но перед тем, как перейти к другой основной теме этой главы — адаптивным изображениям, мне хочется поделиться с вами еще двумя особенностями.
Предположим, нужно, чтобы подвал находился в самом низу окна просмотра, даже когда основного содержимого недостаточно, для того чтобы он там оказался. Добиться нужного результата нелегко, но только не с Flexbox. Рассмотрим следующую разметку, которую можно увидеть в файле каталога example_03-08:
<body>
<div class="MainContent">
Here is a bunch of text up at the top. But there isn't enough
content to push the footer to the bottom of the page.
</div>
<div class="Footer">
However, thanks to flexbox, I've been put in my place.
</div>
</body>
А вот так выглядит код CSS:
html,
body {
margin: 0;
padding: 0;
}
html {
height: 100%;
}
body {
font-family: 'Oswald', sans-serif;
color: #ebebeb;
display: flex;
flex-direction: column;
min-height: 100%;
}
.MainContent {
flex: 1;
color: #333;
padding: .5rem;
}
.Footer {
background-color: violet;
padding: .5rem;
}
Посмотрите на окно браузера и попробуйте добавить содержимое в .MainContentdiv. Станет видно, что при недостаточном объеме содержимого подвал фиксируется в нижней части окна просмотра. Когда содержимого достаточно для заполнения окна, подвал располагается ниже содержимого.
Такая работа обусловливается тем, что наше свойство flex настроено на увеличение при наличии доступного пространства. Поскольку тело является flex-контейнером со 100 % минимальной высоты, основное содержимое может увеличиваться на все доступное пространство. Превосходно.
В CSS с момента появления этой технологии был только один способ переключения визуального порядка следования HTML-элементов на веб-странице. Такое переключение достигалось за счет помещения элементов внутрь какого-нибудь контейнера с настройкой display: table с последующим переключением свойства display в отношении находящихся внутри элементов между display: table-caption (элемент помещался в верхнюю часть контейнера), display: table-footer-group (элемент помещался в нижнюю часть контейнера) и display: table-header-group (элемент помещался непосредственно под элементом с настройкой display: table-caption). Но, несмотря на всю грубость этой технологии, ее воспринимали как весьма удачное обстоятельство, не принимая во внимание истинное назначение таких настроек.
А вот в модуле Flexbox имеется встроенная функция изменения порядка следования отображаемых элементов. Посмотрим, как она работает.
Рассмотрим следующую разметку:
<div class="FlexWrapper">
<div class="FlexItems FlexHeader">I am content in the Header.</div>
<div class="FlexItems FlexSideOne">I am content in the SideOne.</div>
<div class="FlexItems FlexContent">I am content in the Content.</div>
<div class="FlexItems FlexSideTwo">I am content in the SideTwo.</div>
<div class="FlexItems FlexFooter">I am content in the Footer.</div>
</div>
Обратите внимание на то, что третий элемент внутри общего контейнера имеет HTML-класс FlexContent, и представьте себе, что в этом div-контейнере предполагается размещать основное содержимое страницы.
Давайте не будем все усложнять. Добавим несколько простых цветовых настроек, чтобы было проще различать разделы, и поместим эти разделы в стопку в том самом порядке, в котором они появляются в разметке:
.FlexWrapper {
background-color: indigo;
display: flex;
flex-direction: column;
}
.FlexItems {
display: flex;
align-items: center;
min-height: 6.25rem;
padding: 1rem;
}
.FlexHeader {
background-color: #105B63;
}
.FlexContent {
background-color: #FFFAD5;
}
.FlexSideOne {
background-color: #FFD34E;
}
.FlexSideTwo {
background-color: #DB9E36;
}
.FlexFooter {
background-color: #BD4932;
}
Предположим, что нам нужно изменить порядок .FlexContent, сделав его первым разделом, не касаясь при этом разметки. С Flexbox эта задача решается простым добавлением всего лишь одной пары «свойство — значение»:
.FlexContent {
background-color: #FFFAD5;
order: -1;
}
Свойство order позволяет легко и просто пересмотреть порядок следования элементов внутри Flexbox. В данном примере значение -1 говорит о том, что нам нужно поместить элемент перед всеми остальными элементами.
совет
Если есть намерение часто менять элементы местами, я бы порекомендовал расширить описание и присвоить каждому элементу порядковый номер. Это упростит понимание задачи в сочетании с медиазапросами.
Объединим наши новые возможности по изменению порядка следования с медиазапросами, чтобы получилась не просто различная разметка для разных размеров, а разный порядок следования элементов.
примечание
Код примера в окончательном виде можно найти в файле каталога example_03-09.
Пересмотрим разметку и поместим основное содержимое в начале документа, поскольку такой порядок обычно считается более разумным:
<div class="FlexWrapper">
<div class="FlexItems FlexContent">I am content in the Content.</div>
<div class="FlexItems FlexSideOne">I am content in the SideOne.</div>
<div class="FlexItems FlexSideTwo">I am content in the SideTwo.</div>
<div class="FlexItems FlexHeader">I am content in the Header.</div>
<div class="FlexItems FlexFooter">I am content in the Footer.</div>
</div>
Сначала идет содержимое страницы, затем две боковые области, после этого заголовок и, наконец, подвал. Поскольку используется Flexbox, мы можем структурировать HTML в том порядке, который имеет смысл для документа независимо от того, как все должно располагаться при отображении на экране.
Для самых мелких экранов (вне каких-либо медиазапросов) порядок будет такой:
.FlexHeader {
background-color: #105B63;
order: 1;
}
.FlexContent {
background-color: #FFFAD5;
order: 2;
}
.FlexSideOne {
background-color: #FFD34E;
order: 3;
}
.FlexSideTwo {
background-color: #DB9E36;
order: 4;
}
.FlexFooter {
background-color: #BD4932;
order: 5;
}
Соответственно, в браузере будет наблюдаться такая картина.
А затем в контрольной точке произойдет переход к следующим настройкам:
@media (min-width: 30rem) {
.FlexWrapper {
flex-flow: row wrap;
}
.FlexHeader {
width: 100%;
}
.FlexContent {
flex: 1;
order: 3;
}
.FlexSideOne {
width: 150px;
order: 2;
}
.FlexSideTwo {
width: 150px;
order: 4;
}
.FlexFooter {
width: 100%;
}
}
Что в браузере будет выглядеть таким образом.
примечание
В данном примере использовалось сокращение flex-flow: row wrap. Это позволило flex-элементам располагаться на нескольких строках. Данное свойство относится к числу наименее поддерживаемых, поэтому в зависимости от того, насколько глубоко в прошлое должна простираться поддержка вашего продукта, может понадобиться заключить содержимое и две боковые панели в другой элемент.
Благодаря присущей Flexbox возможности внесения динамических изменений (flexiness) при использовании этой системы разметки мы располагаем практически неисчерпаемыми возможностями, что великолепно подходит для создания адаптивного дизайна. Если раньше вам еще не приходилось создавать что-либо с использованием Flexbox, все новые свойства и значения покажутся немного странными, а та легкость, с какой получаются разметки, в которые прежде приходилось вкладывать намного больше труда, может вызвать небольшое замешательство. Чтобы еще раз проверить особенности реализации функциональных возможностей на соответствие самой последней версии спецификации, зайдите на сайт /.
Я думаю, что созидательная работа с использованием Flexbox вам понравится.
примечание
На пятки Flexible Box Layout Module уже наступает Grid Layout Module Level 1: /.
Этот модуль еще сыроват по сравнению с Flexbox (как и в ранней истории Flexbox, grid-разметка уже претерпела ряд существенных изменений), и поэтому мы не станем проявлять к нему пристальный интерес. Тем не менее его не нужно сбрасывать со счетов, поскольку этот модуль обещает дать еще более эффективные средства разметки веб-страниц.
Предоставление пользователям изображений, наиболее подходящих для конкретных характеристик применяемого устройства и среды, всегда было задачей не из легких. Особое звучание она приобрела с появлением адаптивного веб-дизайна, сама природа которого приспособлена для использования единой кодовой базы абсолютно для всех устройств.
Разработчик не может заранее знать или включать в свой план любое возможное устройство, с которого могут заходить на сайт сейчас или в будущем. Особенности устройства на момент обслуживания и вывода на экран содержимого (к примеру, размеры экрана и возможности устройства) известны только браузеру, который используется на этом устройстве.
И наоборот, только разработчик (вы и я) знает, какие версии изображения имеются в его распоряжении. Например, могут существовать три версии одного и того же изображения: малая, средняя и большая — и у каждой размер будет больше, чем у предыдущей, чтобы охватить множество вариантов размеров и плотностей экрана. Браузеру об этом ничего не известно. Наша задача заключается в доведении до него данной информации.
Подводя черту под этими осложнениями, можно констатировать, что у нас есть половина решения, то есть мы знаем, какими изображениями располагаем, а второй половиной решения располагает браузер, знающий, с какого устройства зашли на сайт и какие размер и разрешение изображения будут наиболее подходящими.
Как сообщить браузеру об имеющихся в нашем распоряжении изображениях, чтобы он мог выбрать самое подходящее для пользователя?
В первые несколько лет после появления адаптивного веб-дизайна какого-либо способа сделать это просто не было. Но, к общему удовольствию, теперь есть спецификация встроенного содержимого — Embedded Content: .
В этой спецификации описываются способы работы с простым переключением разрешения изображений (чтобы упростить пользователю получение на экран с более высоким разрешением соответствующей улучшенной версии изображения) и варианты «режиссуры», при которых разработчики в зависимости от ряда характеристик устройства (возникают мысли о медиазапросах) хотят, чтобы пользователи видели совершенно другое изображение.
Продемонстрировать примеры адаптивных изображений довольно трудно. На одном и том же экране невозможно дать оценку различным изображениям, которые могут быть загружены с применением конкретных синтаксиса или технологии. Поэтому следующие примеры будут в основном в виде кода, и вам придется поверить мне на слово, что в поддерживающих эту технологию браузерах он будет выдавать нужный вам результат.
Рассмотрим два наиболее распространенных сценария, для которых, вероятнее всего, понадобятся адаптивные изображения. Они будут переключать изображение, когда потребуется другое разрешение, и полностью менять изображение в зависимости от доступного пространства окна просмотра.
Предположим, что имеются три версии изображения. Они выглядят одинаково, за исключением того, что одно из изображений имеет наименьшие размер или разрешение и предназначено для самых мелких окон просмотра, другое предназначено для окон просмотра среднего размера, и, наконец, самое большое изображение предназначено для всех остальных окон просмотра. О наличии у нас этих трех версий браузер оповещается следующим образом:
<img src="scones_small.jpg" srcset="scones_medium.jpg 1.5x, scones_
large.jpg 2x" alt="Scones taste amazing">
Это почти так же просто, как и все то, что касается адаптивных изображений, поэтому давайте вникнем в смысл данного синтаксиса.
Сначала идет уже знакомый вам атрибут src, который здесь играет двойную роль. Он указывает на самую простую версию изображения, а также служит указателем на изображение отката, если браузер не поддерживает атрибут srcset. Именно поэтому он используется для указания самого простого изображения. Благодаря этому старые браузеры, игнорирующие информацию в srcset, получат самое простое и, возможно, самое динамичное изображение.
Браузерам, понимающим атрибут srcset, предоставляется список изображений, разделенных запятыми, из которых браузер может сделать выбор. После имени изображения (например, scones_medium.jpg) выдается простое указание на разрешение. В данном примере использованы указания 1.5x и 2x, но допускается применение любого целого числа. Например, 3x или 4x тоже будут работать — при условии, что отыщется подходящий экран высокого разрешения.
Но здесь есть одна проблема: устройство с шириной экрана 1440 пикселов и разрешением 1x получит то же самое изображение, что и устройство с шириной экрана 480 пикселов и разрешением 3x. Такой исход может оказаться нежелательным.
Рассмотрим еще одну ситуацию. В адаптивном веб-дизайне довольно часто случается, что при небольших окнах просмотра изображение занимает все их пространство, а при окнах просмотра большего размера — всего лишь его половину. Это может быть проиллюстрировано основным примером из главы 1. Довести намерения до браузера можно следующим образом:
<img srcset="scones-small.jpg 450w, scones-medium.jpg 900w"
sizes="(min-width: 17em) 100vw, (min-width: 40em) 50vw"
src="scones-small.jpg" alt="Scones">
Внутри тега изображения снова используется srcset. Но на этот раз после указания изображений добавляется значение с суффиксом w. С его помощью браузеру сообщается о ширине изображения. В нашем примере имеются изображения шириной 450 пикселов (scones-small.jpg) и 900 пикселов (scones-medium.jpg). Важно отметить, что значение с суффиксом w не является настоящим размером. Это всего лишь указание браузеру, приблизительно соответствующее ширине в так называемых пикселах CSS.
совет
Я задался вопросом: как именно определяется пиксел CSS? Затем нашел объяснение по адресу / и понял, что лучше бы я этим вопросом не задавался.
Значение с суффиксом w обретает больший смысл, когда учитывается значение атрибута sizes. Этот атрибут позволяет сообщить браузеру о намерениях относительно изображений. В предыдущем примере первое значение равноценно следующей установке: «Для устройств, имеющих ширину как минимум 17 em, я хочу, чтобы показывалось изображение с параметрами, близкими к 100 vw».
примечание
Если вы не можете разобраться в некоторых используемых единицах измерения, например в vh (где 1 vh является эквивалентом 1 % высоты окна просмотра) и vw (где 1 vw является эквивалентом 1 % ширины окна просмотра), обратитесь к материалам главы 5.
Вторая часть фактически указывает: «Браузер, я хочу, чтобы для устройств шириной как минимум 40 em показывалось изображение шириной 50 vw». Пока учет ведется в dpi (или в dpr, что означает device pixel ratio), это может показаться излишним. Например, на устройстве шириной 320 пикселов с разрешением 2x (при выводе на полную ширину для него требуется изображение шириной 640 пикселов) браузер может решить, что изображение шириной 900 пикселов подойдет больше, поскольку первый из имеющихся у него вариантов касается изображения, которое будет достаточно большим для заполнения требуемого размера.
Важно запомнить, что атрибуты sizes всего лишь дают браузеру подсказку. Это не гарантирует повиновения со стороны браузера. И это, уж поверьте, совсем неплохо и означает, что в будущем, если появится надежный способ для браузеров выяснить возможности сети, он сможет предпочесть одно изображение другому, поскольку к тому моменту будут известны обстоятельства, неизвестные нам как разработчикам программы. Возможно, пользователь настроит свое устройство на загрузку только изображений с разрешением 1х или только изображений с разрешением 2х, при таких сценариях браузер сможет выбрать вызов самого подходящего кода.
Альтернативой решению браузера является использование элемента picture. Использование этого элемента гарантирует использование браузером конкретно запрошенного вами изображения. Посмотрим на его работу.
И последний сценарий, с которым вы можете столкнуться, предполагает наличие разных изображений, применимых при различных размерах окон просмотра. Рассмотрим, к примеру, нашу булочку, взятую опять же из примера главы 1. Возможно, для самых маленьких экранов мы предпочтем булочку, изображенную крупным планом, щедро политую сверху вареньем и сливками. Для более крупных экранов, наверное, предпочтем воспользоваться более широким изображением. Возможно, это будет общий план стола с разнообразной выпечкой. И наконец, в еще более крупных окнах просмотра мы, наверное, предпочтем увидеть кондитерскую на деревенской улице, людей, сидящих возле нее за столиками, лакомящихся булочками и запивающих их чаем (понимаю, похоже на некую идиллию). Нам нужны три разных изображения, наиболее подходящих к различным диапазонам окон просмотра. Решить задачу с помощью элемента picture можно следующим образом:
<picture>
<source media="(min-width: 30em)" srcset="cake-table.jpg">
<source media="(min-width: 60em)" srcset="cake-shop.jpg">
<img src="scones.jpg" alt="One way or another, you WILL get cake.">
</picture>
Во-первых, следует иметь в виду, что элемент picture — это просто контейнер, помогающий другим изображениям попасть в тег img. Если нужно придать изображениям то или иное стилевое оформление, переключите свое внимание на тег img.
Во-вторых, атрибут srcset работает здесь точно так же, как и в предыдущем примере.
В-третьих, тег img предоставляет альтернативное изображение, а также изображение, которое будет показано, если браузер распознает изображение, но не найдет соответствие ни одному из медиаопределений. Нужно четко уяснить, что не следует убирать тег img из контейнера picture, иначе все плохо кончится.
Основной особенностью контейнера picture является наличие в нем тега source. В этом теге можно применять выражения в стиле медиазапросов, конкретно сообщая браузеру, какой из ресурсов применять в той или иной ситуации. Например, в первом теге из предыдущего примера браузеру предписывается: «Если экран шириной не менее 30 em, нужно загрузить изображение cake-table.jpg». При совпадении условий браузер будет подчиняться предписаниям.
Продвижение новомодных форматов изображений. В качестве бонуса элемент picture также помогает вам в предоставлении альтернативных форматов изображений. WebP (информацию о котором можно получить на сайте /) является новейшим форматом, не получившим еще достаточного уровня поддержки во многих браузерах (/). Тем браузерам, которые обеспечивают его поддержку, можно предложить файл в этом формате, а тем, которые с этим не справляются, — файл в обычном формате:
<picture>
<source type="image/webp" srcset="scones-baby-yeah.webp">
<img src="scones-baby-yeah.jpg" alt="Again, you WILL eat cake.">
</picture>
Надеюсь, что теперь ситуация прояснилась. Вместо атрибута media используется атрибут type (с ним мы еще встретимся в главе 4), который, хотя и используется чаще всего для указания на видеоисточники (возможные типы видеоисточников можно найти на сайте ), позволяет нам в данном случае определить в качестве наиболее предпочтительного формат WebP. Если браузер в состоянии его отобразить, он это сделает, а если нет, возьмет исходное изображение, указанное в теге img.
совет
Есть множество устаревших браузеров, которые никогда не смогут воспользоваться официально заявленными консорциумом W3C адаптивными изображениями. Мой совет: пока на то не будет конкретных причин, не отказывайтесь от возможностей использования встроенных резервных вариантов. Чтобы не портить пользователям таких браузеров впечатление от вашего сайта, воспользуйтесь резервными изображениями подходящих размеров, а усовершенствованные возможности оставьте для более способных на их реализацию устройств.
В данной главе было рассмотрено множество важных вопросов. Много времени было потрачено на ознакомление с Flexbox, самой последней, эффективной и теперь уже широко поддерживаемой технологией. Были также рассмотрены способы обслуживания для наших пользователей любого количества альтернативных изображений в зависимости от требующих решения задач. Благодаря применению srcset, sizes и picture пользователи всегда будут получать самые подходящие изображения, отвечающие их потребностям как сейчас, так и в будущем.
К этому моменту нами рассмотрены довольно большой объем кода CSS и некоторые возникающие в этой технологии перспективы и возможности, но более современной разметки мы касались только в отношении адаптивных изображений. Далее уделим внимание именно этому вопросу.
Следующая глава будет целиком посвящена HTML5. Мы разберемся с тем, что предлагается в этой версии языка, что изменилось по сравнению с его предыдущей версией, и в значительной мере с тем, как наилучшим образом воспользоваться новыми семантическими элементами для создания более понятных и осмысленных HTML-документов.