Строим с flexbox

от автора

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


Введение

Некоторое время назад я написал ознакомительную статью про flexbox на сайте SitePoint. В данной статье я постарался выяснить и ответить на вопрос:

А готовы ли мы использовать flexbox?

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

Да, мы готовы использовать flexbox!

Если вы еще не знакомы с flexbox, то вот небольшое пояснение. CSS модуль построения гибкой разметки — это модуль, позволяющий легко размещать блоки на экране, в пределах выделенного пространства. Это большое достижение по сравнению с классической блочной моделью, т.к. flexbox позволяет вообще не использовать свойство float. Блоки могут быть объединены в строки или разбиты на колонки. Для каждого flexbox-элемента может быть задан определенный порядок. А также можно сразу управлять выравниванием, отступами и размерами этих элементов.

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

  • Простая сеточная система
  • Разметка трех колоночного сайта
  • Резиновая навигация с изменяющейся шириной поля поиска
  • Два разных варианта вертикального выравнивания

Хорошо, давайте приступать!

Простая сеточная система

Сегодня сеточные системы присутствуют в большинстве разметок проектов, и классическое поведение блочной модели в CSS вынудило нас прибегнуть к использованию плавающих или inline-block элементов, каждый из которых имеет собственные недостатки. Flexbox позволяет нам легко создавать действительно классную и масштабируемую сеточную систему благодаря написанию всего нескольких строчек в CSS. Давайте рассмотрим это поподробнее.

Представьте, что у нас есть следующая простая разметка:

<div class="grid">   <div class="grid__row">     <div class="grid__item">1</div>     <div class="grid__item">2</div>     ...   </div> </div> 

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

<div class="grid">   <div class="grid__row">     <div class="grid__item">1</div>     <div class="grid__item">2</div>   </div>   <div class="grid__row">     <div class="grid__item">1</div>     <div class="grid__item">2</div>     <div class="grid__item">3</div>   </div>   <div class="grid__row">     <div class="grid__item">1</div>     <div class="grid__item">2</div>     <div class="grid__item">3</div>     <div class="grid__item">4</div>   </div> </div> 

А теперь давайте посмотрим на CSS код. Некоторые свойства я использовал чисто в эстетических целях (например, рамки и внутренние отступы), а в остальном все очень просто:

.grid {   border: solid 1px #e7e7e7; }  .grid__row {   display: flex; }  .grid__item {   flex: 1;   padding: 12px;   border: solid 1px #e7e7e7; } 

Вот как-то так! И наша сетка уже готова к использованию. Добавляя display: flex к контейнерам .grid__row, мы создаем, так называемый, flex-контейнер, а каждый дочерний элемент в контейнере сразу становится flex-элементом. Применяя свойство flex: 1 к flex-элементам, мы заставляем их занимать равное количество места относительно общей ширины контейнера. Теперь у вас может быть сколько угодно строк в сетке, а в каждой из них может быть свое собственное количество элементов. И это будет простая полностью отзывчивая сеточная система без всякого дополнительного CSS.

А что можно сказать насчет breakpoint-ов и колоночной разметки? Если мы хотим, чтобы элементы сетки выстраивались в колонки, а не в строки, то мы можем просто объявить свойство flex-direction: column для контейнеров с классом .grid__row. В этом случае мы можем создать очень простую отзывчивую сетку, внеся некоторые изменения. И наша разметка будет выглядеть вот так:

<div class="grid">   <div class="grid__row grid__row--sm">     <div class="grid__item">1</div>     ...   </div>   <div class="grid__row grid__row--md">     <div class="grid__item">1</div>     ...   </div>   <div class="grid__row grid__row--lg">     <div class="grid__item">1</div>     ...   </div> </div> 

А наш CSS вот так:

.grid {   border: solid 1px #e7e7e7; }  .grid__row {   display: flex;   flex-direction: column; }  .grid__item {   flex: 1;   padding: 12px;   border: solid 1px #e7e7e7; }  @media all and ( min-width: 480px ) {    .grid__row--sm {     flex-direction: row;   }  }  @media all and ( min-width: 720px ) {    .grid__row--md {     flex-direction: row;   }  }  @media all and ( min-width: 960px ) {    .grid__row--lg {     flex-direction: row;   }  } 

И вуаля. Супер-простая отзывчивая сеточная система размером всего в несколько CSS строк. Эта система настолько непробиваемая, что вы даже можете вкладывать сетки друг в друга, не заботясь о последствиях:

<div class="grid">   <div class="grid__row grid__row--sm">     <div class="grid__item">       <div class="grid">         <div class="grid__row grid__row--lg">           <div class="grid__item">Nested 1</div>           ...         </div>       </div>     </div>     <div class="grid__item">2</div>   </div>   <div class="grid__row grid__row--md">     <div class="grid__item">1</div>     ...   </div> </div> 

Посмотрите на это в действии.

Разметка трех колоночного сайта

Разметка трех колоночного сайта является довольно известной в веб-дизайне, и даже в эпоху веб-приложений и прочего веселья, данный вариант разметки по-прежнему играет важную роль в вебе — такая разметка постоянно используется на сайтах, у которых много контента. Еще в 2006 году трех колоночная разметка была замечательно разобрана и описана на сайте A List Apart. В ней используются float элементы, отрицательные margin и значения min-width, чтобы совмещенные размеры элементов не конфликтовали друг с другом и не ломали разметку. И все это, с учетом нынешней необходимости в создании отзывчивой разметки, означало использование большого количества вычислений, отмены обтекания и других трюков, чтобы это все работало правильно. И если вы решили поменять ширину боковой колонки, то нужно было заново производить все вычисления.

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

<body class="holy-grail">   <header class="holy-grail__header"></header>   <main class="holy-grail__body">     <div class="holy-grail__content"></div>     <div class="holy-grail__sidebar holy-grail__sidebar--first"></div>     <div class="holy-grail__sidebar holy-grail__sidebar--second"></div>   </div>   <footer class="holy-grail__footer"></footer> </body> 

В моем демо-примере разметка находится внутри документа, поэтому в ней нет тегов body или main, как это показано выше. Но в данном случае, нас интересуют имена классов и сами разделы нашей разметки, а не непосредственно сами элементы. В частности, обратите внимание на классы, которые используются для двух боковых колонок, и на тот порядок, в котором они следуют в разметке. Давайте последовательно рассмотрим, что здесь происходит:

  1. У нас есть родительский контейнер, .holy-grail, а в нем у нас находится три flex-элемента. Это элементы с классами .holy-grail__header, holy-grail__body и holy-grail__footer.
  2. Данные три элемента расположены друг над другом и занимают 100% от ширины экрана. Таким образом, для flex-контейнера должно быть задано колоночное направление.
  3. Тело нашей разметки, .holy-grail__body, является внутренним flex-контейнером. Его дочерние flex-элементы должны иметь колоночную разметку на небольших экранах и строчную разметку на широких экранах.

Учитывая все вышесказанное, давайте построим разметку:

.holy-grail {   display: flex;   flex-direction: column; }  .holy-grail__header, .holy-grail__footer {   flex: 0 0 100%; }  .holy-grail__body {   display: flex; }  .holy-grail__sidebar {   /* ничего на небольших экранах */ }  .holy-grail__sidebar--first {   order: 1; }  .holy-grail__sidebar--second {   order: 3; }  .holy-grail__content {   order: 2; }  @media all and ( min-width: 720px ) {    .holy-grail__body {     flex-direction: row;   }    .holy-grail__sidebar {     flex: 0 0 180px;   }    .holy-grail__content {     flex: 1;   }  }  @media all and ( min-width: 960px ) {    .holy-grail__sidebar {     flex: 0 0 240px;   }  } 

Это действительно настолько просто! Как я уже упоминал, мы изначально определяем два flex-контейнера (для небольших экранов). Для первого breakpoint-а мы изменяем flex-direction для обертки колонок на строчное, а боковым колонкам задаем ширину 180px, используя сокращенную запись — свойство flex. Данная запись позволит нам ограничить значения для свойств flex-grow и flex-shrink, а также явно указать ширину. Для контента используется свойство flex: 1, чтобы он заполнял доступное пространство. Расположение flex-элементов в нужном порядке также оказалось пустяком благодаря свойству order. Пожалуй, остались только дополнительные стили, которые вы захотите добавить с эстетической точки зрения… а в остальном это действительно просто и эффективно. А упомянул ли я о том, что по умолчанию flexbox создает колонки одинаковой высоты? Взгляните на этот демо-пример.

Резиновая навигация с изменяющейся шириной поля поиска

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

<nav class="flexy-nav">   <button id="flexy-nav__toggle" class="flexy-nav__toggle">Toggle Nav</button>   <ul id="flexy-nav__items" class="flexy-nav__items">     <li class="flexy-nav__item"><a href="#" class="flexy-nav__link">Item 1</a></li>     <li class="flexy-nav__item"><a href="#" class="flexy-nav__link">Item 2</a></li>     <li class="flexy-nav__item"><a href="#" class="flexy-nav__link">Item 3</a></li>     <li class="flexy-nav__item"><a href="#" class="flexy-nav__link">Item 4</a></li>   </ul>   <form action="" class="flexy-nav__form">     <input class="flexy-nav__search" type="text" placeholder="Type search terms and hit enter...">   </form> </nav> 

Давайте разберем данную разметку, прежде чем мы перейдем к CSS. У нас есть основной flex-контейнер с классом .flexy-nav. Кнопка используется в качестве переключателя, в ненумерованном списке содержатся пункты основного меню, а в форме содержится поле поиска. Для небольших экранов нам нужно использовать колоночную разметку для всех трех элементов, а также нам нужно, чтобы каждый пункт меню располагался в отдельной колонке. На широких экранах нам нужно спрятать кнопку-переключатель, выстроить элементы списка в строку и задать для формы фиксированную ширину. Элементы списка будут равномерно распределены среди оставшегося пространства. Когда мы переключаемся на текстовое поле (поле поиска), нам бы хотелось, чтобы оно плавно растягивалось по ширине, а все элементы списка, наоборот, плавно сужались. Вот CSS:

/* сброс стилей */  input, button {   font: inherit;   border-radius: none;   box-shadow: none;   appearance: none; }  button {   cursor: pointer; }  /* контейнер навигации */  .flexy-nav {   display: flex;   flex-direction: column; }  /* пункты меню */  .flexy-nav__items {   display: none;   flex: 1;   flex-direction: column;   list-style: none;   margin: 0 0 4px 0;   padding: 4px;   text-align: center; }  .flexy-nav__items--visible {   display: flex; }  .flexy-nav__item {   background-color: #f1f1f1;   border-bottom: solid 1px #e7e7e7; }  .flexy-nav__item:last-child {   border-bottom: 0; }  .flexy-nav__link {   padding: 8px;   display: block; }  /* переключатель меню */  .flexy-nav__toggle {   margin: 0 0 4px 0;   padding: 4px;   color: #fff;   background-color: #f07850;   border: none; }  .flexy-nav__toggle:hover, .flexy-nav__toggle:focus {   outline: none;   background-color: #c93f11; }  /* форма для поля поиска в навигации */  .flexy-nav__form {   height: 48px; }  .flexy-nav__search {   display: block;   margin: 0;   padding: 0 4px;   width: 100%;   height: 48px;   color: #6d6d6d;   background-color: #fff;   border: solid 2px #e7e7e7; }  .flexy-nav__search:focus {   outline: none;   border: solid 2px #6d6d6d; }  /* медиа-запросы */  @media all and (min-width: 768px) {   .flexy-nav {     flex-direction: row;   }    .flexy-nav__items {     display: flex;     flex-direction: row;     margin: 0;     padding: 0;     height: 48px;   }    .flexy-nav__item {     flex: 1;     margin-right: 4px;     border-bottom: none;   }    .flexy-nav__link {     padding: 0;     line-height: 48px;   }    .flexy-nav__toggle {     display: none;   }    .flexy-nav__form {     flex: none;   }    .flexy-nav__search {     width: 240px;     transition: width 0.3s;   }    .flexy-nav__search:focus {     width: 360px;   } } 

Как и обещал, вот, до смешного простой, кусочек JavaScript кода, который позволит нам показывать/скрывать навигацию на небольших экранах:

(function() {   var toggle = document.querySelector("#flexy-nav__toggle");   var nav = document.querySelector("#flexy-nav__items");   toggle.addEventListener("click", function(e) {     e.preventDefault();     nav.classList.contains("flexy-nav__items--visible") ? nav.classList.remove("flexy-nav__items--visible") : nav.classList.add("flexy-nav__items--visible");   }); })(); 

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

Вертикальное выравнивание

Давайте признаем тот факт, что вертикальное выравнивание в традиционном CSS просто никуда не годится. Inline-block элементы могут иногда с этим помочь, есть также хаки с абсолютным позиционированием, а еще есть устаревшие табличные разметки (которые на данный момент неприемлемы для многих случаев с семантической точки зрения). У всех этих способов есть свои особенности, и они точно потребуют от вас дополнительных «танцев с бубнов», чтобы все работало, как надо.

Flexboxс легкостью возьмет это на себя. Мы рассмотрим два примера вертикального выравнивания:

  1. Сначала мы рассмотрим создание, так называемого, «медиа-объекта», в котором используется пользовательский аватар (расположенный слева) и имя пользователя + некоторая информация (расположенные справа). Мы будем использовать flexbox, чтобы изображение и тело медиа-объекта были идеально выровнены по вертикали.
  2. Затем мы просто рассмотрим вертикальное (горизонтальное) выравнивание элемента фиксированной ширины и переменной высоты внутри контейнера. Элемент будет оставаться расположенным точно по центру, несмотря на увеличение высоты.

Давайте начнем с первого примера. Как уже было сказано, нам нужно расположить пользовательский аватар слева, а описание — справа. И неважно насколько длинным или коротким будет описание. Нам нужно, чтобы оно всегда было идеально выровнено с аватаром. Вот стандартная разметка:

<div class="user">   <div class="user__avatar"></div>   <div class="user__description">     <h2 class="user__username">John Doe</h2>     <p class="user__excerpt">I'm John Doe...</p>   </div> </div>  <div class="user">   <div class="user__avatar"></div>   <div class="user__description">     <h2 class="user__username">Harry Potter</h2>     <p class="user__excerpt">I'm Harry Potter...with a really long description...</p>   </div> </div> 

Прежде чем мы перейдем к CSS, обратите внимание на то, что мы будем использовать незнакомое до этого свойство. Это свойство align-items, и оно позволяет нам выравнивать элементы вдоль, так называемой, flex-линии в перпендикулярном направлении. Другими словами, если наша flex-линия расположена горизонтально, то мы можем выравнивать наши элементы в направлении, которое перпендикулярно данной линии. В нашем случае нам нужно выровнять элементы по центру, поэтому мы будем использовать значение align-items: center. Вот CSS:

.user {   display: flex;   align-items: center; }  .user:last-child {   margin-bottom: 0; }  .user__avatar {   flex: 0 0 96px;   width: 96px;   height: 96px;   background-color: #e7e7e7; }  .user__description {   flex: 1;   margin-left: 24px;   padding: 12px;   border: solid 1px #e7e7e7; } 

Вот так просто. Вы можете оформить текст, как вам захочется, сделать описания очень длинными или изменить размеры аватара. Это не имеет значения, функциональность останется прежней. Оцените данную возможность в действии.

Давайте перейдем ко второму примеру. На этот раз представьте, что у нас есть баннер, расположенный в самой верхней части разметки. И мы хотим разместить внутри баннера какой-то заголовок. На маленьких экранах высота баннера будет равна 180px, и она будет изменяться еще дважды, до значения 480px. И при всех изменениях высоты баннера нам нужно, чтобы текст внутри был расположен идеально по центру (как по горизонтали, так и по вертикали). Вот стандартная разметка:

<div class="banner">   <div class="banner__content">     <h2 class="banner__title">Symmetrical Perfection</h2>     <span class="banner__sub">A beautiful sight, achieved with flexbox.</span>   </div> </div> 

На этот раз мы задействовали также свойство justify-content, которое позволит нам распределить пространство вокруг элементов вдоль flex-линии. А вот CSS:

.

banner {   display: flex;   align-items: center;   justify-content: space-around;   height: 180px;   background-color: #e7e7e7; }  .banner__content {   text-align: center; }  .banner__title, .banner__sub {   margin: 0;   padding: 0;   line-height: 1.5; }  @media all and ( min-width: 480px ) {    .banner {     height: 240px;   }  }  @media all and ( min-width: 768px ) {    .banner {     height: 360px;   }  }  @media all and ( min-width: 960px ) {    .banner {     height: 480px;   }  } 

Неважно, насколько «высоким» будет баннер. Контент всегда будет идеально отцентрирован по горизонтали и вертикали. Вот в этом и заключается мощь flexbox. Не забудьте посмотреть демо-пример.

Поддержка и вендорные префиксы

Вы должны знать ваш рынок и аудиторию… это ключевой момент. Flexbox поддерживается во всех современных браузерах, включая IE10 и выше. Если вы занимаетесь созданием современных веб-приложений, то flexbox — это мощный инструмент, и я очень рекомендую его использовать. Если вы создаете или переделываете веб-сайт, то проверьте статистику посещаемости, чтобы узнать вашу аудиторию. В настоящее время есть вероятность того, что около 99% вашей аудитории будет использовать современные браузеры.

Что касается вендорных префиксов, то у flexbox их много. Это очень неразумно всерьез использовать flexbox и при этом вручную прописывать все вендорные префиксы. Лично я использую сборщик проектов (Gulp) для автоматической простановки префиксов.

Заключение

Вот и все! На этом я заканчиваю данную статью. Если вы хотите найти реальный сайт, на котором используется flexbox, то можете даже и не начинать поиски. На новом сайте callmenick.com flexbox используется практически везде! Спасибо, что прочли статью до конца. Не забудьте, что вы можете посмотреть демо-примеры, а также скачать исходники по нижеприведенным ссылкам. Если у вас есть какие-либо вопросы, замечания или пожелания, оставьте их, пожалуйста, в комментариях.

Ссылка на оригинал статьи: http://callmenick.com/post/flexbox-examples

ссылка на оригинал статьи http://habrahabr.ru/post/257253/


Комментарии

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

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