В данной обучающей статье мы разберем некоторые реальные и некогда действительно трудновыполнимые моменты, которые сейчас легко решаются благодаря использованию 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, как это показано выше. Но в данном случае, нас интересуют имена классов и сами разделы нашей разметки, а не непосредственно сами элементы. В частности, обратите внимание на классы, которые используются для двух боковых колонок, и на тот порядок, в котором они следуют в разметке. Давайте последовательно рассмотрим, что здесь происходит:
- У нас есть родительский контейнер, .holy-grail, а в нем у нас находится три flex-элемента. Это элементы с классами .holy-grail__header, holy-grail__body и holy-grail__footer.
- Данные три элемента расположены друг над другом и занимают 100% от ширины экрана. Таким образом, для flex-контейнера должно быть задано колоночное направление.
- Тело нашей разметки, .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с легкостью возьмет это на себя. Мы рассмотрим два примера вертикального выравнивания:
- Сначала мы рассмотрим создание, так называемого, «медиа-объекта», в котором используется пользовательский аватар (расположенный слева) и имя пользователя + некоторая информация (расположенные справа). Мы будем использовать flexbox, чтобы изображение и тело медиа-объекта были идеально выровнены по вертикали.
- Затем мы просто рассмотрим вертикальное (горизонтальное) выравнивание элемента фиксированной ширины и переменной высоты внутри контейнера. Элемент будет оставаться расположенным точно по центру, несмотря на увеличение высоты.
Давайте начнем с первого примера. Как уже было сказано, нам нужно расположить пользовательский аватар слева, а описание — справа. И неважно насколько длинным или коротким будет описание. Нам нужно, чтобы оно всегда было идеально выровнено с аватаром. Вот стандартная разметка:
<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/
Добавить комментарий