Как сделать выпадающее меню в flexbox. Флексбокс для интерфейсов: основные паттерны

Если говорить коротко, то верстка с Flexbox дает нам простые решения некогда непростых задач. Например, когда нужно выровнять элемент по вертикали, или прижать подвал к низу экрана, или просто вставить несколько блоков в один ряд, так чтобы они занимали все свободно пространство. Подобные задачи решаются и без flex. Но как правило, эти решения больше похожи на «костыли» - приемы использовать css не по назначению. Тогда как с flexbox такие задачи решаются именно так, как задумывает flex-модель.

CSS Flexible Box Layout Module (CSS модуль для макетов с гибкими блоками), коротко flexbox, создана, чтобы убрать недостатки при создании самых разных HTML конструкций, в том числе адаптированных под разную ширину и высоту, и сделать верстку логичной и простой. А логичный подход, как правило работает в неожиданных местах, там где результат не проверялся - логика наше все!

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

Базовые знания

FlexBox состоит из Контейнера и его Дочерних элементов (items) (гибких элементов).

Для включения flexbox, любому HTML элементу достаточно присвоить css свойство display:flex; или display:inline-flex; .

1
2

После включения flex свойства, внутри контейнера создаются две оси: главная и поперечная (перпендикулярная (⊥), кросс ось). Все вложенные элементы (первого уровня) выстраиваются по главной оси. По умолчанию главная ось горизонтальная и имеет направление слева направо (→), а кросс ось соответственно вертикальная и направлена сверху вниз (↓).

Главную и кросс оси можно поменять местами, тогда элементы будут располагаться сверху вниз (↓) и когда перестанут вмещаться в высоту то будут двигаться слева направо (→) - то есть оси просто поменялись местами. При этом начало и конец расположения элементов не меняется - меняются только направления (оси)! Именно поэтому нужно представлять себе оси внутри контейнера. Однако не нужно думать, что есть какие-то там «физические» оси и они на что-то влияют. Ось тут - это только лишь направление движения элементов внутри контейнера. Например, если мы указали выравнивание элементов по центру основной оси и потом изменили направление этой основной оси, то изменится и выравнивание: элементы были в середине по горизонтали, а стали в середине по вертикали... См. пример.

Еще одной важной особенностью Флекс-бокс является наличие рядов в поперечном направлении. Чтобы понять о чем речь, давайте представим что есть главная горизонтальная ось, много элементов и они не «лезут» в контейнер, поэтому переходят на другой ряд. Т.е. контейнер выглядит так: контейнер, внутри него два ряда, в каждом ряду по несколько элементов. Представили? А теперь запомните, что выравнивать по вертикали мы можем не только элементы, но и ряды! Как это работает хорошо видно в примере к свойству . А вот так это выглядит схематически:

CSS свойства, которые могут влиять на модель построения макета: float , clear , vertical-align , columns не работают во flex конструкции. Тут используется другая модель построения макета и эти css свойства просто игнорируются.

CSS свойства Flexbox

Flexbox содержит разные css правила для управления всей flex конструкцией. Одни нужно применять к основному контейнеру, а другие к элементам этого контейнера.

Для контейнера

display:

Включает flex свойство для элемента. Под это свойство попадает сам элемент и вложенные в него элементы: затрагиваются только потомки первого уровня - они станут элементами flex контейнера.

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

flex и inline-flex отличаются тем что по-разному взаимодействуют с окружающими элементами, подобно display:block и display:inline-block .

flex-direction:

Изменяет направление главной оси контейнера. Поперечная ось меняется соответственно.

  • row (default) - направление элементов слева направо (→)
  • column - направление элементов сверху вниз (↓)
  • row-reverse - направление элементов справа налево (←)
  • column-reverse - направление элементов снизу вверх ()
flex-wrap:

Управляет переносом непомещающихся в контейнер элементов.

  • nowrap (default) - вложенные элементы располагаются в один ряд (при direction=row) или в одну колонку (при direction=column) независимо от того помещаются они в контейнер или нет.
  • wrap - включает перенос элементов на следующий ряд, если они не помещаются в контейнер. Так включается движение элементов по поперечной оси.
  • wrap-reverse - тоже что wrap только перенос будет не вниз, а вверх (в обратном направлении).
flex-flow: direction wrap

Объединяет оба свойства flex-direction и flex-wrap . Они часто используются вместе, поэтому чтобы писать меньше кода было создано свойство flex-flow .

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

/* только flex-direction */ flex-flow: row; flex-flow: row-reverse; flex-flow: column; flex-flow: column-reverse; /* только flex-wrap */ flex-flow: nowrap; flex-flow: wrap; flex-flow: wrap-reverse; /* сразу оба значения: flex-direction и flex-wrap */ flex-flow: row nowrap; flex-flow: column wrap; flex-flow: column-reverse wrap-reverse; justify-content:

Выравнивает элементы по основной оси: если direction=row, то по горизонтали, а если direction=column, то по вертикали.

  • flex-start (default) - элементы будут идти с начала (в конце может остаться место).
  • flex-end - элементы выравниваются по концу (место останется в начале)
  • center - по центру (место останется слева и права)
  • space-between - крайние элементы прижимаются к краям (место между элементами распределяется равномерно)
  • space-around - свободное пространство равномерно распределяется между элементами (крайние элементы не прижимаются к краям). Пространство между краем контейнера и крайними элементами будет в два раза меньше чем пространство между элементами в середине ряда.
  • space-evenly
align-content:

Выравнивает ряды, в которых находятся элементы по поперечной оси. То же что justify-content только для противоположной оси.

Заметка: Работает когда есть как минимум 2 ряда, т.е. при наличии только 1 ряда ничего не произойдет.

Т.е. если flex-direction: row , то это свойство будет выравнивать невидимые ряды по вертикали ¦ . Тут важно заметить, что высота блока должна быть задана жестко и должна быть больше высоты рядов иначе сами ряды будут растягивать контейнер и любое их выравнивание теряет смысл, потому что между ними нет свободного места... А вот когда flex-direction: column , то ряды движется по горизонтали → и ширина контейнера почти всегда больше ширины рядов и выравнивание рядов сразу приобретает смысл...

  • stretch (default) - ряды растягиваются заполняя строку полностью
  • flex-start - ряды группируются в верхней части контейнера (в конце может остаться место).
  • flex-end - ряды группируются в нижней части контейнера (место останется в начале)
  • center - ряды группируются по центру контейнера (место останется по краям)
  • space-between - крайние ряды прижимаются к краям (место между рядами распределяется равномерно)
  • space-around - свободное пространство равномерно распределяется между рядами (крайние элементы не прижимаются к краям). Пространство между краем контейнера и крайними элементами будет в два раза меньше чем пространство между элементами в середине ряда.
  • space-evenly - тоже что space-around , только расстояние у крайних элементов до краев контейнера такое же как и между элементами.
align-items:

Выравнивает элементы по поперечной оси внутри ряда (невидимой строки). Т.е. сами ряды выравниваются через align-content , а элементы внутри этих рядов (строк) через align-items и все это по поперечной оси. По главной оси такого разделения нет, там нет понятия рядов и элементы выравниваются через justify-content .

  • stretch (default) - элементы растягиваются заполняя строку полностью
  • flex-start - элементы прижимаются к началу ряда
  • flex-end - элементы прижимаются к концу ряда
  • center - элементы выравниваются по центру ряда
  • baseline - элементы выравниваются по базовой линии текста

Для элементов контейнера

flex-grow:

Задает коэффициент увеличения элемента при наличии свободного места в контейнере. По умолчанию flex-grow: 0 т.е. никакой из элементов не должен увеличиваться и заполнять свободное место в контейнере.

По умолчанию flex-grow: 0

  • Если всем элементам указать flex-grow:1 , то все они растянуться одинаково и заполнять все свободное место в контейнере.
  • Если одному из элементов указать flex-grow:1 , то он заполнит все свободное место в контейнере и выравнивания через justify-content работать уже не будут: свободного места нет выравнивать нечего...
  • При flex-grow:1 . Если один из них имеет flex-grow:2, то он будет в 2 раза больше, чем все остальные
  • Если все flex-блоки внутри flex-контейнера имеют flex-grow:3 , то они будут одинакового размера
  • При flex-grow:3 . Если один из них имеет flex-grow:12 , то он будет в 4 раза больше, чем все остальные

Как это работает? Допустим, что контейнер имеет ширину 500px и содержит два элемента, каждый из которых имеет базовую ширину 100px. Значит в контейнере остается 300 свободных пикселей. Теперь, если первому элементу укажем flex-grow:2; , а второму flex-grow: 1; , то блоки займут всю доступную ширину контейнера и ширина первого блока будет 300px, а второго 200px. Объясняется это тем, что доступные 300px свободного места в контейнере распределились между элементами в соотношении 2:1, +200px первому и +100px второму.

Заметка: в значении можно указывать дробные числа, например: 0.5 - flex-grow:0.5

flex-shrink:

Задает коэффициент уменьшения элемента. Свойство противоположное flex-grow и определяет как элемент должен сжиматься, если в контейнере не остается свободного места. Т.е. свойство начинает работать, когда сумма размеров всех элементов больше чем размер контейнера.

По умолчанию flex-shrink:1

Допустим, что контейнер имеет ширину 600px и содержит два элемента, каждый из которых имеет ширину 300px - flex-basis:300px; . Т.е. два элемента полностью заполняют контейнер. Первому элементу укажем flex-shrink: 2; , а второму flex-shrink: 1; . Теперь уменьшим ширину контейнера на 300px, т.е. элементы должны сжаться на 300px чтобы находится внутри контейнера. Сжиматься они будут в соотношении 2:1, т.е. первый блок сожмется на 200px, а второй на 100px и новые размеры элементов станут 100px и 200px.

Заметка: в значении можно указывать дробные числа, например: 0.5 - flex-shrink:0.5

flex-basis:

Устанавливает базовую ширину элемента - ширину до того как будут высчитаны остальные условия влияющие на ширину элемента. Значение можно указать в px, em, rem, %, vw, vh и т.д. Итоговая ширина будет зависеть от базовой ширины и значений flex-grow, flex-shrink и контента внутри блока. При auto элемент получает базовую ширину относительно контента внутри него.

По умолчанию: auto

Иногда лучше установить ширину элемента жестко через привычное свойство width . Например, width: 50%; будет означать, что элемент внутри контейнера будет ровно 50%, однако при этом все также будут работать свойства flex-grow и flex-shrink . Такое может быть нужно, когда элемент растягивается контентом внутри него, больше указанного во flex-basis. Пример .

flex-basis будет «жестким», если обнулить растяжение и сжатие: flex-basis:200px; flex-grow:0; flex-shrink:0; . Все это можно записать так flex:0 0 200px; .

flex: {grow shrink basis}

Короткая запись трех свойств: flex-grow flex-shrink flex-basis .

По умолчанию: flex: 0 1 auto

Однако можно указать и одно, и два значения:

Flex: none; /* 0 0 auto */ /* число */ flex: 2; /* flex-grow (flex-basis переходит в 0) */ /* не число */ flex: 10em; /* flex-basis: 10em */ flex: 30px; /* flex-basis: 30px */ flex: auto; /* flex-basis: auto */ flex: content; /* flex-basis: content */ flex: 1 30px; /* flex-grow и flex-basis */ flex: 2 2; /* flex-grow и flex-shrink (flex-basis переходит в 0) */ flex: 2 2 10%; /* flex-grow и flex-shrink и flex-basis */ align-self:

Позволяет изменить свойство align-items , только для отдельного элемента.

По умолчанию: от align-items контейнера

  • stretch - элемент растягиваются заполняя строку полностью
  • flex-start - элемент прижимаются к началу строки
  • flex-end - элемент прижимаются к концу строки
  • center - элемент выравниваются по центру строки
  • baseline - элемент выравниваются по базовой линии текста

order:

Позволяет менять порядок (позицию, положение) элемента в общем ряду.

По умолчанию: order: 0

По умолчанию элементы имеют order: 0 и ставятся в порядке их появления в HTML коде и направления ряда. Но если изменить значение свойства order, то элементы будут выстраиваться в порядке значений: -1 0 1 2 3 ... . Например если одному из элементов указать order: 1 , то сначала будут идти все нулевые, а потом элемент с 1.

Так можно, например, первый элемент перекинуть в конец, при этом не меняя направление движения остальных элементов или HTML код.

Заметки

Чем отличается flex-basis от width?

Ниже важные различия между flex-basis и width / height:

    flex-basis работает только для главной оси. Это значит что при flex-direction:row flex-basis контролирует ширину (width), а при flex-direction:column контролирует высоту (height). .

    flex-basis применяется только к flex элементам. А значит если отключить flex у контейнера это свойство не будет иметь эффекта.

    Абсолютные элементы контейнера не участвуют во flex конструкции... А значит, flex-basis не влияет на элементы flex контейнера, если они абсолютны position:absolute . Им нужно будет указать width / height.

  • При использовании свойства flex 3 значения (flex-grow/flex-shrink/flex-basis) можно скомбинировать и записать коротко, а для width grow или shrink нужно писать отдельно. Например: flex:0 0 50% == width:50%; flex-shrink:0; . Иногда это просто неудобно.

По возможности все же отдавайте предпочтение flex-basis . Используйте width только когда не подходит flex-basis .

Отличие flex-basis от width - баг или фича?

Контент внутри flex элемента распирает его и не может выйти за его пределы. Однако если установить ширину через width или max-width , а не flex-basis , то элемент внутри flex контейнера сумеет выйти за пределы этого контейнера (иногда нужно именно такое поведение). Пример:

Примеры Flex верстки

В примерах нигде не используются префиксы для кроссбраузерности. Сделал я так для удобного чтения css. Поэтому примеры смотрите в последних версиях Chrome или Firefox.

#1 Простой пример с выравниванием по вертикали и горизонтали

Начнем с самого простого примера - выравнивание по вертикали и горизонтали одновременно и при любой высоте блока, даже резиновой.

Текст по середине

Или так, без блока внутри:

Текст по середине

#1.2 Разделение (разрыв) между элементами флекс блока

Чтобы расположить элементы контейнера по краям и произвольно выбрать элемент после которого будет разрыв, нужно использовать свойство margin-left:auto или margin-right:auto .

#2 Адаптивное меню на flex

Сделаем меню в самом верху страницы. На широком экране оно должно быть справа. На среднем выравниваться по середине. А на маленьком каждый элемент должен быть на новой строке.

#3 Адаптивные 3 колонки

Этот пример показывает как быстро и удобно сделать 3 колонки, которые при сужении будут превращаться в 2 и затем в 1.

Обратите внимание, что сделать это можно без использования media правил, все на flex.

1
2
3
4
5
6

Перейдите в jsfiddle.net и изменяйте ширину секции «результат»

#4 Адаптивные блоки на flex

Допустим нам нужно вывести 3 блока, один большой и два маленьких. При этом нужно чтобы блоки подстраивались под маленькие экраны. Делаем:

1
2
3

Перейдите в jsfiddle.net и изменяйте ширину секции «результат»

#5 Галерея на flex и transition

Этот пример показывает как быстро можно сделать симпатичный аккордеон с картинками на flex. Обратите внимание на свойство transition для flex.

#6 Флекс во флекс (просто пример)

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

Для решения этой задачи, сами блоки растягиваются флексом и им установлена максимально возможная ширина. Каждый внутренний блок также является флекс конструкцией, с повернутой осью flex-direction:column; и элемент в середине (где находится текст) растягивается flex-grow:1; чтобы заполнить всё свободное пространство, так достигается результат - текст начинался с одной линии...

Еще примеры

Поддержка браузерами - 98.3%

Полной поддержки разумеется нет, однако все современные браузеры поддерживают flexbox конструкции. Для некоторых все еще нужно указывать префиксы. Для реальной картины заглянем в caniuse.com и видим, что без префиксов будут работать 96.3% используемых сегодня браузеров, с префиксами 98.3%. Это отличный показатель для того чтобы смело использовать flexbox.

Чтобы знать какие префиксы актуальны на сегодня (июнь. 2019), приведу пример всех flex правил с нужными префиксами :

/* Контейнер */ .flex { display:-webkit-box; display:-ms-flexbox; display:flex; display:-webkit-inline-box; display:-ms-inline-flexbox; display:inline-flex; -webkit-box-orient:vertical; -webkit-box-direction:normal; -ms-flex-direction:column; flex-direction:column; -ms-flex-wrap:wrap; flex-wrap:wrap; -ms-flex-flow:column wrap; flex-flow:column wrap; -webkit-box-pack:justify; -ms-flex-pack:justify; justify-content:space-between; -ms-flex-line-pack:distribute; align-content:space-around; } /* Элементы */ .flex-item { -webkit-box-flex:1; -ms-flex-positive:1; flex-grow:1; -ms-flex-negative:2; flex-shrink:2; -ms-flex-preferred-size:100px; flex-basis:100px; -ms-flex:1 2 100px; flex:1 2 100px; -ms-flex-item-align:center; align-self:center; -webkit-box-ordinal-group:3; -ms-flex-order:2; order:2; }

Лучше если свойства с префиксами будут идти до оригинального свойства.
В этом списке нет ненужных на сегодня (по caniuse) префиксов, но вообще префиксов больше.

Chrome Safari Firefox Opera IE Android iOS
20- (old) 3.1+ (old) 2-21 (old) 10 (tweener) 2.1+ (old) 3.2+ (old)
21+ (new) 6.1+ (new) 22+ (new) 12.1+ (new) 11+ (new) 4.4+ (new) 7.1+ (new)
  • (new) - новый синтаксис: display: flex; .
  • (tweener) - старый неофициальный синтаксис 2011 года: display: flexbox; .
  • (old) - старый синтаксис 2009 года: display: box;

Видео

Ну и не забывайте про видео, там порой тоже интересно и понятно. Вот парочка популярных:

Полезные ссылки по Flex

    flexboxfroggy.com - игра обучающая flexbox.

    Flexplorer - наглядный конструктор flex кода.

В данном выпуске сделаем горизонтальное меню с эффектом при наведении. Подключим с шрифтовые иконки, задействуем режим наложения слоев при помощи mix-blend-mode: multiply , используем псевдоклассы :hover , и познакомимся с desplay:flax , все сделаем на чистом CSS3 .

Каркас меню в HTML

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

Перенесите все в свою среду разработки, в которой вы работаете. Я весь код буду писать в phpstorm . Копирую все папки и файлы в него, открываю index.html и приступим к описанию каркаса меню.

Прописываем body , тег

, в нем пишем div с классом .dws-menu , далее ul с классом .dws-ul ,затем списки li с классом .dws-li в количестве пяти штук. В списки вложим ссылку, затем I с классом .fa и классом fa- куда пропишем название иконок, далее атрибут aria-hidden=”true” , жмем применить.

Div.dws-menu>ul.dws-ul>li.dws-li*5>a>i.fa.fa-

Название иконок:

  • shopping-cart
  • server
  • folder-open
  • newspaper-o
  • Главная
  • Магазин
  • Услуги
  • Портфолио
  • Новости


Оформление CSS стилей

После того как сделали разметку, приступаем к оформлению стилей. Открываем style.css в body задаем задний фон и шрифт Verdana .

Body{ background-image: url("../img/escheresque_ste.png"); font-family: Verdana; }

Блоку с меню задаем фон, с верху делаем отступы в 100 пик. и ширину на весь экран.

Dws-menu{ background-color: white; margin-top: 100px; width: 100%; }

В блоки Ul выстраиваем списки горизонтально с помощью desplay:flax , убираем отступы, и центруем наши элементы при помощи justify-content:center .

Ul.dws-ul{ display: flex; padding: 0; justify-content: center; }

У списков LI убираем маркер и делаем отступ со всех сторон в 10 пик.

Li.dws-li { list-style: none; padding: 10px; }

У ссылок убираем подчеркивание, увеличим текст до 18 пик. и сделаем его черным цветом.

Li.dws-li a{ text-decoration: none; font-size: 18px; color: #000; }

Иконку немного сдвинем правее при помощи margin-right:10px .

Li.dws-li a i{ margin-right: 10px; }

Анимация при наведении

После того как сделали основное оформление приступим к анимированию при наведении.

Создадим дополнительные псевдо элементы, которые будут при наведении подчеркивать название элемента.

Опишем левую часть, отбираем ссылки и присвоим им псевдоэлемент li.dws-li a::before , пишем пустой content:’’; , шириной в 20 пик. и высоту в 3 пик. достаточно. Зададим цвет и для того что бы блок у нас появился присвоим ссылкам position: relative; , и с позиционируем абсолютно ссылкам, спустим его в самый низ, прижмем к левому краю.

Li.dws-li a{ ... position: relative; } li.dws-li a::before{ ... position: absolute; top: 100%; left: 0; }

Дублируем этот блок и присваиваем ему псевдоэлемент ::after . Меняем параметр left на right , цвет выбираем другой #ff2117 .

Li.dws-li a::after{ content: ""; width: 20px; height: 3px; background-color: #ff2117; position: absolute; top: 100%; right: 0; }

Затем делаем анимацию при наведении. Отбираем li и задаем им background чуть темнее.

Li.dws-li:hover{ background-color: #e5eae8; }

Для этого отбираем списки при наведении и добавляем к ним псевдоэлемент с шириной в 50% и задаем трансформацию по оси Х с лева на право. Это предаст ей движение.

Li.dws-li:hover a:before{ width: 50%; transform: translateX(100%); }

Тоже самое повторим для псевдоэлементом ::after , только теперь движение зададим с права на лево.

Li.dws-li:hover a:after{ width: 50%; transform: translateX(-100%); }

Li.dws-li a::before{ ... transition: .5s; mix-blend-mode: multiply; } li.dws-li a::after{ ... transition: .5s; mix-blend-mode: multiply; }

Получилось довольно не плохо, давайте теперь ширину поставим в ноль и при наведении ссылке добавим красный цвет.

Li.dws-li a:hover{ color: #e62117; }

Li.dws-li a{ ... padding: 5px; } li.dws-li a::before{ ... top: 90%; } li.dws-li a::after{ ... top: 90%; }

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



Урок подготовил Горелов Денис.

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

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

Гибкие атомарные компоненты

В интерфейсе Tracks реализован подход, рассматривающий каждый фрагмент изолированно на основе принципов Брэда Фроста .

Философию атомарного дизайна можно рассматривать как аналог ЛЕГО-блоков для веб-дизайна. Научные термины такие как организм, молекула, атом используются для того, чтобы дать разработчикам классификацию элементов интерфейса и, соответственно, более глубокое понимание каждого фрагмента как части целого. Этот способ категоризации создает возможность для идентификации этих паттернов и предотвращает влияние на этот процесс внешних факторов, таких как сетки, цвета и расстояния. Построение интерфейса с микроуровня дает возможность более широкого многократного использования его базовых микроэлементов.

Иллюстрация 1. Эти элементы приложения используются для вывода данных на основе принципов атомарного дизайна. Можете ли вы угадать, в каких из них используется Флексбокс? (увеличенная версия)

Иллюстрация 2. Основной интерфейс приложения Tracks, использующий преимущества флексбокса и атомарного дизайна. (увеличенная версия)

Дизайн интерфейса был передан как набор прототипов InVision , с документацией потока и пользовательского интерфейса. В течение первоначального аудита интерфейса, я начал выявлять области, где имеет смысл внедрить флексбокс. Я также решил использовать флексбокс для раскладки страницы, используя традиционные паттерны “боковая колонка слева, основной контент справа”, обычно реализуемые на плавающих блоках.

Html.flexbox ul.flexbox-target, html.no-js ul.flexbox-target { display: flex; flex-direction: row; } html.no-flexbox ul.flexbox-target li, html.no-js ul.flexbox-target li { display: inline-block; /* Could also use a float-positioned-layout system instead */ }

Там где поддержка флексбокса отсутствует, мы будем использовать display: inline-block . К этой же декларации мы добавим класс no-js , на случай отключения в браузере JavaScript. Каскад CSS будет работать даже там, где нет ни флексбокса, ни JavaScript, а также при проблемах с загрузкой. Флексбокс может сосуществовать с float , display: table и position: relative ; браузеры, поддерживающие флексбокс использует его в приоритетном порядке, а браузеры его не поддерживающие ограничатся традиционными механизмами раскладки CSS.

Как и всегда, итоговый выбор технологии будет зависеть от целей проекта, его бюджета и данных аналитики. Мое золотое правило состоит в том, чтобы выбирать всегда самый разумный вариант для проекта.

Строчные паттерны

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

Иллюстрация 3. Эта навигация административной панели использует строчный паттерн с вертикальным центрированием элементов навигации. (увеличенная версия)

Разметка паттерна навигации административной панели состоит из тега nav , оборачивающего ссылки. Вот HTML этого паттерна:

И соответствующие стили:

Nav { display: flex; align-items: center; /* Center navigation items vertically */ } nav a { display: inline-block; /* To avoid layout issues for inline elements with the order property in IE 10 */ } nav a { flex: 1; }

CSS получился такой же минималистичный, как и разметка. Обратите внимание на inline-block , заданный для навигационных ссылок. Эта декларация решает любые возможные будущие проблемы в IE10, в случае, если вы решите поменять последовательность элементов со свойством order . Также мы знаем, что все внешние и внутренние отступы, заданные прямым потомкам флекс-контейнера вызывают проблемы с раскладкой в IE10, во избежание таких вещей имеет смысл всегда кроссбраузерно проверять верстку.

Иллюстрация 4. Паттерн навигации в шапке сайта с центрированным лого часто встречается в вебе и легко адаптируется к флексбоксу. (увеличенная версия)

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

Раскладка состоит из коллекции элементов меню, размещенных по левую и правую сторону от логотипа в центре. Разметка для этого паттерна следующая:

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

До появления флексбокса разработчики использовали подходы display: inline-block и даже float: left , чтобы организовать строчную раскладку. Теперь флексбокс стал жизнеспособным вариантом и разработчиков ничто не вынуждает использовать плохие практики ради красивого дизайна. Требуемый CSS не столь краток, как в предыдущем примере с паттерном на иллюстрации 3, но он проще в реализации, чем старые методы.

Pipeline-header { display: flex; align-items: center; justify-content: space-between; } .pipeline-header > a { display: inline-block; /* IE 10 doesn"t recognize order, so we do this to avoid odd layouts there. */ } .pipeline-logo { flex: 1; order: 2; text-align: center; } .pipeline-nav { flex: 1.25; order: 1; } .pipeline-search { flex: 1; order: 3; } a { order: 4; }

При использования флексбокса в паттерне с иллюстрации 3, помните, что последовательность в разметке может быть изменена. Если логотип требуется сдвинуть, это легко делается с помощью свойства order . Учитывайте, что порядок в разметке важен для доступности и это вызывает противоречия, когда дело доходит до флексбокса, особенно с учетом различной реализации доступности в браузерах . Браузеры (кроме Firefox) и скринридеры используют для навигации с клавиатуры порядок разметки, а не визуальный порядок, созданный средствами CSS.

Иллюстрация 5. Поток, представленный в разметке и его рендеринг в браузере, изменение последовательности с помощью флексбокса без изменений разметки. (увеличенная версия)

Ниже представлен код для такой раскладки. Разметка не используется для изменения порядка вывода элементов.

Здесь CSS используется для изменения порядка вывода элементов диаграмме справа иллюстрации 5.

Container { display: flex; flex-direction: columns; /* row is the default value */ } header { order: 2; } main { order: 3; } footer { order: 1; }

Этот тип раскладки используется не только для навигации. Вы могли видеть его в футере.

Иллюстрация 6. Тот же паттерн, который мы применяли для навигации, используется в футере. (увеличенная версия)

При использовании этого паттерна учитывайте, что контенту может не хватить пространства в контейнере. Должен ли контент распространяться от центра к краям? Как это повлияет на остальные элементы раскладки? Думайте об этих вопросах до того, как к приступать к реализации проекта. И учитывайте, что навигация с клавиатуры важна для пользователей.

Строчные поля ввода

Формы могут быть кошмаром для разработчиков, особенно когда они тесно связаны с замысловатой структурой сетки, сделанной в Photoshop. Паттерн “inline label”, как я его называю, также важен для нашей индустрии как Fender Stratocaster для рок-музыки.

Иллюстрация 7. Строчные лейблы и поля ввода это еще одна область использования флексбокса. Но будьте осторожны с тем, как текст лейбла отталкивает поле ввода в зависимости от количества текста. (увеличенная версия)

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

Иллюстрация 8. Решайте, как ваш контент будет расширяться. Слева display:table с вертикальным выравниванием по середине, справа флексбокс с выравниванием по центру. (увеличенная версия)

Эти скриншоты четко показывают ошибки флексбокса с динамическим или большим содержимым. Эффект на правом изображении я называю “выталкивание от центра”, это означает, что новое содержимое стремится от центра к краям.

Вот разметка для паттерна строчного лейбла на иллюстрации 8.

Решением проблемы будет использование display: table; для длинного текста. Это позволяет контенту идти сверху вниз, а не от центра к краям.

Form-group { display: flex; } .form-group label { display: table; vertical-align: middle; } .form-group input { flex: 1; }

Сочетание флексбокса и display: table это отличная техника, которую имеет смысл изучить глубже. Но при ее использовании важно всегда проверять раскладку в тестовом окружении, чтобы своевременно выявлять баги.

Иллюстрация 9. При использовании полей ввода и кнопок на одной строке, баланс в дизайне создается за счет их равной высоты. (увеличенная версия)

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

Необходимый HTML типичен и включает див-обертку для структуры флексбокса.

А вот и стили:

Form-group { display: flex; } .form-group input { flex: 1; }

Выпадающее меню

Иллюстрация 10. Участок страницы с выпадающим меню выделен при помощи возможностей флексбокс для быстрого позиционирования. (увеличенная версия)

Выпадающее меню состоит из колонки слева, содержащей вертикально центрированные строчные элементы, и списка элементов справа, в котором каждый элемент расположен на своей строке.

Иллюстрация 11. Меню основного интерфейса построено с использованием флексбокса для раскладки. (увеличенная версия)

Разметка для этой навигационного меню использует следующий HTML в качестве основы.

Соответствующий ему CSS прост и понятен, все, как любят разработчики.

Menu { display: flex; } .menu__options { display: flex; align-items: center; } .menu__items { display: flex; flex-direction: column; }

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

Медиа-объекты

Иллюстрация 12. В паттерне медиа-объект используется флексбокс, SVG фиксированной ширины располагается слева, а все остальное содержимое флексбокса располагается рядом. (увеличенная версия)

В этом универсальном паттерне, известном как “медиа-объект”, изображение или видео располагается на одной стороне, а остальное содержимое рядом.

Medi-obj { display: flex; align-items: flex-start; } .media-obj__body { flex: 1; }

Иллюстрация 13. Это крайний случай изменения размера окна браузера, изображению задана максимальная ширина и правой части задан флекс равный 1. Будьте осторожны, когда смешиваете элементы фиксированной ширины и элементы с флексом

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

Решением для этого паттерна будет задание изображениям max-width: 100% для медиа внутри флексбокса или использование фиксированной ширины изображений и медиа-запросов для их регулировки при необходимости.

Календарь на флексбоксе

Календарь это один из самых распространенных виджетов. Вы спросите, а почему бы не использовать таблицу? В нашем случае календарь используется для простого выбора дат, поэтому я решил использовать кнопки для дней, месяцев и годов и ограничить эти кнопки рамками рядов (каждый ряд календаря на неделю обернут отдельным div). Использование этого подхода позволяет уменьшить количество разметки и облегчить создание раскладки (огромная благодарность

В этой публикации я хочу показать один из способов реализации адаптивного горизонтального меню с использованием Flexbox. Данный способ реализации меню используется на сайте Warface Hub , но немного с другой структурой и бо льшим количеством свистелок.

Где-то с год назад, я попал в одну компанию, в которой мне сказали замечательную фразу: «Сначала делаем все с помощью CSS, а потом только добавляем JavaScript». Совет, вроде, хороший, и я ему последовал. Но как бывает, меня понесло. Сейчас мне это аукнулось тем, что не все нужно делать с таким подходом.

И так, ближе к делу. Я приступил к изучению и реализации.

Цели

  1. получить базовые навыки работы с Flexbox свойствами;
  2. разработать горизонтальное адаптивное меню;
  3. полученное решение применить в проекте.

Инструменты и документация

  1. NPM – в качестве менеджера пакетов (теперь активно переезжаем на Yarn)
  2. Grunt – инструмент, который поможет в сборке проекта
  3. Документация по Flexbox (см. Полезные ссылки );
Вы можете использовать свой набор инструментов

Структура

Для организации структуры стилей для меню я пользовался концепцией, которая описана . Автор данной концепции предлагает разбить все описания стилей на несколько частей:

  • layout – описывает положение компонентов и элементов на странице;
  • component – описывает отображение и поведение элементов, которые входят в компонент;
  • element – описывает отображение и поведение единичного элемента;
Таким образом мое понимание концепции привело меня к такой структуре:
  • Base - описание констант, базовых стилей (как в normalize.css)
  • Component - описание компонентов приложения. В нашем случае компонент «Menu»
  • Element - описание стилей для элементов таких как кнопка, ссылка и т.п.
  • Layout - описание расположения блоков на странице
  • style.scss - в этом файле мы соберем все вместе

CSS и HTML теги input & label

Прежде чем начать рисовать HTML разметку, я бы хотел напомнить/показать интересное поведение CSS селекторов, которое нам пригодится.


В данном примере Вы можете заметить, что при нажатии на label Вы получите выбранный input. В этом ничего особенного нет (см. ), но самое интересное происходит со стороны CSS селекторов.

Input:checked { border-color: red; }
Данный CSS селектор будет обработан только тогда, когда будет выбран input (см. :checked)

Второй момент, на который нужно обратить внимание в CSS селекторах - это выбор следующего элемента (см. Adjacent sibling selectors и General sibling selectors). То есть мы можем выбрать следующий элемент после текущего.

Input:checked + .label { color: red; }
В этом примере мы получили следующее поведение: при выбранном элементе с классом input следующий за ним элемент с классом label будет изменен в соответствии с описанными стилями.

Теперь это все можно объединить воедино.

Структура меню с одном элементом



В данном примере я добавил несколько элементов input и label, чтобы получилось следующее поведение:
  1. Каждый элемент name=menu-item-trigger, кроме первого, в состоянии:checked будет изменять видимость и позиции последующих элементов label.menu-item-close и div.menu-sub таким образом, чтобы элемент label.menu-item-close полностью перекрывал элемент label.menu-item-label, а div.menu-sub отображался под элементом label.menu-item-label. То есть мы открываем подменю и меняем поведение при клике на основное меню;
  2. Первый элемент name=menu-item-trigger будет использован только для того, чтобы отменить все примененные изменения в предыдущем пункте, то есть закрыть подменю;
Не выбран ни один пункт меню:


Выбран один пункт меню:

После таких манипуляций остается только скрыть элементы input.

Flexbox

Теперь необходимо добавить стили, чтобы данное меню хорошо отображалось при различных разрешениях и различных браузерах. На текущий момент мы сосредоточили наши усилия на поддержке тех браузеров, которые больше всего используются посетителями нашего ресурса. Получился небольшой список: Chrome, Firefox, IE Edge, IE 11 и их мобильные варианты последних версий.

Поддержка осуществляется путем добавления префиксов (postcss) и отдельного написания стилей для конкретного браузера.

Адаптивность в Flexbox достигается очень просто. Достаточно описать контейнер, но иногда будет необходимо решить проблемы с контентом внутри. Например:

  • элементы меню с длинными словами, как «knowledge base» и его немецкий перевод «Wissensdatenbank». В данном случае добавляется оборачивающий элемент для текста, к которому применяются примерно следующие стили:

    Label-text { // @link: http://htmlbook.ru/css/text-overflow overflow: hidden; text-overflow: ellipsis; width: 100%; display: inline-block; }

  • Картинки, которые нужно растянуть по ширине, но при задании width: 100%; они вылезают за пределы родительского блока. Тут поможет box-sizing: border-box; для этого элемента;
  • Так же могут возникнуть проблемы с тем, что дочерние элементы не занимают всю возможную длину или не распределяются равномерно. Тут возможно поможет flex: 1 1 auto.
В данном примере контейнер для элементов описан так:

Menu { display: flex; align-items: center; flex-wrap: wrap; }
Для каждого элемента в контейнере необходимо задать стили так, чтобы он заполнял все возможное пространство и выравнивали контент внутри себя в центре по вертикали:

Menu-item { flex: 1 1 auto; display: flex; flex-direction: column; align-items: stretch; }

Более красивого отображения меню можно достичь с помощью

В данном выпуске сделаем горизонтальное меню с эффектом при наведении. Подключим с шрифтовые иконки, задействуем режим наложения слоев при помощи mix-blend-mode: multiply , используем псевдоклассы :hover , и познакомимся с desplay:flax , все сделаем на чистом CSS3 .

Каркас меню в HTML

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

Перенесите все в свою среду разработки, в которой вы работаете. Я весь код буду писать в phpstorm . Копирую все папки и файлы в него, открываю index.html и приступим к описанию каркаса меню.

Прописываем body , тег

, в нем пишем div с классом .dws-menu , далее ul с классом .dws-ul ,затем списки li с классом .dws-li в количестве пяти штук. В списки вложим ссылку, затем I с классом .fa и классом fa- куда пропишем название иконок, далее атрибут aria-hidden=”true” , жмем применить.

Div.dws-menu>ul.dws-ul>li.dws-li*5>a>i.fa.fa-

Название иконок:

  • shopping-cart
  • server
  • folder-open
  • newspaper-o
  • Главная
  • Магазин
  • Услуги
  • Портфолио
  • Новости


Оформление CSS стилей

После того как сделали разметку, приступаем к оформлению стилей. Открываем style.css в body задаем задний фон и шрифт Verdana .

Body{ background-image: url("../img/escheresque_ste.png"); font-family: Verdana; }

Блоку с меню задаем фон, с верху делаем отступы в 100 пик. и ширину на весь экран.

Dws-menu{ background-color: white; margin-top: 100px; width: 100%; }

В блоки Ul выстраиваем списки горизонтально с помощью desplay:flax , убираем отступы, и центруем наши элементы при помощи justify-content:center .

Ul.dws-ul{ display: flex; padding: 0; justify-content: center; }

У списков LI убираем маркер и делаем отступ со всех сторон в 10 пик.

Li.dws-li { list-style: none; padding: 10px; }

У ссылок убираем подчеркивание, увеличим текст до 18 пик. и сделаем его черным цветом.

Li.dws-li a{ text-decoration: none; font-size: 18px; color: #000; }

Иконку немного сдвинем правее при помощи margin-right:10px .

Li.dws-li a i{ margin-right: 10px; }

Анимация при наведении

После того как сделали основное оформление приступим к анимированию при наведении.

Создадим дополнительные псевдо элементы, которые будут при наведении подчеркивать название элемента.

Опишем левую часть, отбираем ссылки и присвоим им псевдоэлемент li.dws-li a::before , пишем пустой content:’’; , шириной в 20 пик. и высоту в 3 пик. достаточно. Зададим цвет и для того что бы блок у нас появился присвоим ссылкам position: relative; , и с позиционируем абсолютно ссылкам, спустим его в самый низ, прижмем к левому краю.

Li.dws-li a{ ... position: relative; } li.dws-li a::before{ ... position: absolute; top: 100%; left: 0; }

Дублируем этот блок и присваиваем ему псевдоэлемент ::after . Меняем параметр left на right , цвет выбираем другой #ff2117 .

Li.dws-li a::after{ content: ""; width: 20px; height: 3px; background-color: #ff2117; position: absolute; top: 100%; right: 0; }

Затем делаем анимацию при наведении. Отбираем li и задаем им background чуть темнее.

Li.dws-li:hover{ background-color: #e5eae8; }

Для этого отбираем списки при наведении и добавляем к ним псевдоэлемент с шириной в 50% и задаем трансформацию по оси Х с лева на право. Это предаст ей движение.

Li.dws-li:hover a:before{ width: 50%; transform: translateX(100%); }

Тоже самое повторим для псевдоэлементом ::after , только теперь движение зададим с права на лево.

Li.dws-li:hover a:after{ width: 50%; transform: translateX(-100%); }

Li.dws-li a::before{ ... transition: .5s; mix-blend-mode: multiply; } li.dws-li a::after{ ... transition: .5s; mix-blend-mode: multiply; }

Получилось довольно не плохо, давайте теперь ширину поставим в ноль и при наведении ссылке добавим красный цвет.

Li.dws-li a:hover{ color: #e62117; }

Li.dws-li a{ ... padding: 5px; } li.dws-li a::before{ ... top: 90%; } li.dws-li a::after{ ... top: 90%; }

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



Урок подготовил Горелов Денис.