Быстрые переходы с моделью Flexible Box Model

HTML5 Rocks

Введение

Вы наверняка тратили много часов на горизонтальную или вертикальную организацию элементов на странице с помощью стилей. До этого момента в CSS не было подходящего механизма для выполнения этой задачи. Но теперь есть CSS3 и Flexible Box Module (модель гибкого окна, сокращенно Flexbox).

В проекте спецификации Flexbox описывается так:

[...] модель гибкого окна в CSS оптимизирована для разработки интерфейсов. Она предлагает еще одну систему компоновки элементов в дополнение к уже имеющейся в CSS. [CSS21] В новой модели дочерние элементы окна компонуются в столбик или в строку, а оставшееся свободное пространство можно распределить между ними с помощью атрибута flex или назначить одному из них. Вложенные окна (горизонтальные внутри вертикальных или вертикальные внутри горизонтальных) можно использовать для создания двумерных схем компоновки. Эта модель основана на модели окон в языке пользовательского интерфейса XUL, который применяется во многих приложениях на базе Mozilla (например, в браузере Firefox).

Звучит неплохо. Но что из этого можете вынести вы как разработчик – нет, как веб-архитектор™?

  1. Можете смело забыть про плавающие элементы.
  2. Верстать страницы со сложной компоновкой элементов стало проще и удобнее.
  3. Мы можем размещать элементы на странице, как пожелаем, а все вычисления за нас делает браузер.

В модели Flexbox у свойства display появляется новое значение (box), а также добавляется еще восемь свойств, перечисленных ниже.

  • box-orient
  • box-pack
  • box-align
  • box-flex
  • box-flex-group
  • box-ordinal-group
  • box-direction
  • box-lines
Восемь новых свойств? Куда нам столько? Давайте разбираться.

Общие свойства стилей в модели Flexbox

Стили окон

display: box
Новое значение стиля display переводит этот объект и его непосредственные дочерние элементы в модель гибких окон. Модель обрабатывает только непосредственные дочерние объекты.
box-orient
Значения: horizontal | vertical | inherit
Как расположить дочерние окна? Вводятся два дополнительных значения: inline-axis (по умолчанию) и block-axis, которые отвечают за горизонтальную и вертикальную компоновку соответственно.
box-pack
Значения: start | end | center | justify
Это свойство отвечает за расположение содержимого окна относительно оси box-orient. Если ось box-orient горизонтальна, то дочерние окна выравниваются по горизонтали, и наоборот.
box-align
Значения: start | end | center | baseline | stretch
Это свойство похоже на box-pack. Оно предназначено для размещения дочерних элементов в окне. Если выбрана горизонтальная ориентация, оно отвечает за вертикальное выравнивание, и наоборот.

Стили дочерних окон

box-flex
Значения: 0 | любое целое число
Степень гибкости дочернего элемента. Если для одного дочернего объекта установлено значение 1, а для другого 2, то второй элемент будет занимать в родительском окне в два раза больше дополнительного свободного места, чем первый. По умолчанию используется нулевое значение гибкости.

Мы не будем рассматривать свойства box-flex-group, box-ordinal-group, box-direction и box-lines, потому что большинство задач в модели Flexibox выполняется и без них. Чтобы узнать, как они работают, воспользуйтесь ссылками в заключении.

Примечание к синтаксису. В текущей реализации Flexibox для браузеров, использующих модули отображения WebKit и Gecko, необходимо добавлять соответствующие префиксы. В этом руководстве они для простоты опущены. Подробные сведения можно найти в разделе Поддержка браузеров.

Что такое гибкость

Свойство box-flex задает абсолютную гибкость дочернего элемента и его гибкость относительно других объектов того же уровня. Рассмотрим его в действии. Для начала создадим три окна.
<div id="flexbox">
  <p>child 1</p>
  <p>child 2</p>
  <p>child 3</p>
</div>

Предположим, мы хотим расположить их горизонтально друг рядом с другом и сделать так, чтобы они были одинаковой высоты вне зависимости от содержания. Как бы мы добились этого с помощью традиционных инструментов? Скорее всего, мы сделали бы текст плавающим и, возможно, добавили свойство overflow:hidden; в родительское окно, чтобы скрывать лишнее содержание. Такая техника используется давно. Но с помощью Flexbox это можно сделать намного проще:

#flexbox { 
  display: box;
  box-orient: horizontal;
}

Мы определяем поведение родительского окна с помощью модели Flexbox и располагаем его дочерние элементы вдоль горизонтальной оси. Никаких плавающих элементов. Вот и все.

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

Три дочерних элемента с заданной шириной внутри родительского элемента

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

#flexbox { 
  display: box;
  box-orient: horizontal;
}
#flexbox > p:nth-child(3) {
  box-flex: 1;
}

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

Третий (гибкий) дочерний элемент занимает все свободное место

Обратите внимание: элемент является гибким только по одной оси – в данном случае по горизонтали.

Значение box-flex относительно. Чтобы сделать гибкими второй и третий элементы, напишем следующий код:

#flexbox { 
  display: box;
  box-orient: horizontal;
}
#flexbox > p:nth-child(2),
#flexbox > p:nth-child(3) {
  box-flex: 1;
}

В данном случае свободное место будет поровну разделено между этими двумя элементами.

Два из трех дочерних элементов занимают все свободное место в родительском окне
Теперь можно немного поэкспериментировать со свойством box-flex всех трех дочерних элементов: если присвоить им значения 1, 2 и 3, они будут растянуты в родительском окне в указанных пропорциях. Но лучше проверим это свойство на практике.

Простой пример

Код и результат его выполнения представлены ниже.

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

Здесь используются всего два стиля: display: box переводит окна в режим Flexbox, а box-flex: 1 делает дочерние элементы гибкими, позволяя им занимать все свободное место. Горизонтальная ориентация окон задана по умолчанию, поэтому указывать свойство box-orient: horizontal не обязательно, однако лучше это сделать. Свойство box-align отвечает за растягивание, поэтому элементы div занимают все свободное место по высоте в родительском окне. Удобно, правда? На сайте Рафаэля Геттера эта техника использована для навигации.

А теперь немного усложним задачу.

Центрирование элементов

Центрирование объектов по вертикали или горизонтали с помощью таблиц стилей CSS с давних пор представляет собой нетривиальную задачу. Если используется только CSS, то лучшее решение – задать атрибуты position:absolute; left: 50%; top: 50%; и указать для левого (верхнего) поля значение, равное половине ширины (высоты), но со знаком минус. Однако это решение работает, только если явно заданы размеры всех элементов. Это не всегда удобно.

Джеймс Джон Малком написал нам, что для центрирования по вертикали существует способ как минимум шестилетней давности, основанный на использовании атрибута display:table-cell; (еще в 2004 году о нем писал Душан Яновски). Способы центрирования по горизонтали и вертикали подробно описаны на этой странице. Они работают, даже если размеры элементов не заданы.

Однако Flexbox позволяет решить эту задачу намного проще:

Мы не задаем для дочернего элемента свойство box-flex, потому что не хотим, чтобы он занимал все свободное место. Нам нужно, чтобы он всегда находился в центре, как бы мы его ни растягивали. Важным преимуществом является то, что не обязательно задавать размеры, чтобы поместить элемент в центр. То же самое можно сделать с блочным или строчным элементом, и все будет работать.

Поддержка браузеров

Уже представляете, как будете использовать гибкие окна? К сожалению, если вы делаете сайты, которые должны работать в любом браузере, это вряд ли получится. Модель Flexbox пока не поддерживается в браузерах IE9 и Opera 10.60, однако упоминается в обзорах платформы IE9, так что компания Майкрософт рано или поздно должна реализовать ее.

На сайте Caniuse.com можно найти список поддерживаемых браузеров. Если не вдаваться в подробности, это Firefox 3 (и выше), Safari 3 (и выше) и Chrome. Если вы разрабатываете приложения для мобильных устройств на базе WebKit, модель Flexbox станет отличной альтернативой привычным схемам компоновки элементов.

Разумеется, пока что она находится на экспериментальном этапе, поэтому не забывайте про префиксы браузеров:

/* i wish it was as easy as this: */

display: box;
box-orient: horizontal; 
box-pack: center;
box-align: center;
  
/* but in reality you'll need to do this: */

display: -webkit-box;
-webkit-box-orient: horizontal;
-webkit-box-pack: center;
-webkit-box-align: center;

display: -moz-box;
-moz-box-orient: horizontal;
-moz-box-pack: center;
-moz-box-align: center;

display: box;
box-orient: horizontal;
box-pack: center;
box-align: center;
  

Для тех, кому не хочется набирать весь этот код, Алекс Рассел создал несколько вспомогательных классов.

Заключение

Даже если опустить остальные четыре свойства, модель Flexbox дает массу новых возможностей. Чтобы узнать ее ближе, ознакомьтесь с примерами и описаниями в блогах Isotoma и Mozilla Hacks. А тем, кого не смущает обилие текста, предлагаем прочитать спецификацию Flexbox на сайте W3C. И главное – применяйте выученное на практике. Удачной работы!

Здесь использованы фрагменты из руководства Стивена Хэя, любезно предоставленные автором по лицензии Creative Commons.

Comments

0