Все уже знают про Flexbox. Кто-то испытывает его на продакшене, кто-то только изучает, а кто-то недоумевает, чем он лучше таблиц. Пока вы занимаетесь этим, поделюсь с вами приятной новостью: flexible контейнеры неплохо анимируются с помощью CSS transition.
Расскажу, как это использовать и что с этой радостью можно делать.
Под анимацией я имею в виду изменение размеров контейнеров. Казалось бы, ничего удивительного, ведь есть
Смотреть демо на Codepen.io
Чтобы сделать такое меню с привычными контейнерами, надо синхронно анимировать изменение ширины двух контейнеров. С другой стороны, если отброситьусловности необходимость поддерживать старые браузеры, то можно сделать такую же разметку с помощью Flexbox. Тогда можно использовать следующий код для анимации:
Код для анимирования изменения размеров умещается в одну строку. В качестве CSS-свойства, которое будет анимировано, передаем «flex».
Немного странно здесь выглядит значение flex-grow. Это фактор расширяемости, который указывает, насколько хорошо будет растягиваться контейнер относительно других контейнеров, если родительский элемент имеет свободное место после расчета базовых размеров вложенных элементов. Чем меньше это значение относительно других, тем меньше контейнер будет расширяться. Если использовать значение 0, то ширина (или высота) элемента будет фиксированной. Если же ширина будет фиксированной, то возникает проблема с анимацией: более старая версия Google Chrome напрочь отказалась анимировать изменение размеров при значении flex-grow равным нулю. Есть вероятность, что в некоторых версиях браузеров такая проблема все еще существует.
Давайте пойдем немного дальше: возьмем 5 фотографий, расположим их в одной строке.
При наведении курсора будем показывать выбранную фотографию в увеличенном формате
Для расположения фотографий будем использовать Flexbox, а изображения вставим через background-image:
Все элементы flex-контейнера занимают изначально по 20% от ширины и равноценно расширяются/сжимаются. Чтобы активный элемент увеличивался при наведении курсора, добавим правило, которое устанавливает фиксированную ширину 400 пикселей и уменьшает расширяемость/сжимаемость элемента почти до нуля:
Теперь при наведении курсора все неактивные элементы сожмутся, потому что имеют значение flow-shrink: 1, а активный элемент останется шириной 400 пикселей, потому что он почти несжимаем.
Последний штрих — добавление анимации:
Смотреть демо на Codepen.io
Если пойти еще дальше, то можно сделать несколько рядов фотографий и при наведении курсора увеличивать не только ширину, но и высоту. Для этого надо повторить то же самое, но с
А вот что будет, если навести курсор на фотографию
Смотреть демо на Codepen.io
Редкое обсуждение анимации обходится без разговоров о FPS. Поэтому на моем неторопливом компе я измерял FPS для последней демки. И вот что я получил:
Да, выглядит вполне неплохо. Да и вообще я как-то замерял скорость отрисовки интерфейса сделанного с помощью Flexbox и аналогичного, сделанного на float'ах. Интерфейсы включали в себя по 1500 элементов. Разница в рендеринге составляла около 10 мс на десктопе и около 15-20 мс на мобильном устройстве. Поэтому, если производительность для вас решающий фактор, то вы проиграете немного.
К сожалению, это не кроссбраузерная радость.Поскольку Flexbox работает в IE10+, соответственно, и его анимация будет работать не менее, чем с 10-й версии. Как правильно заметил Reon, приведенный код не будет работать в IE вообще. Остается надеяться, что Microsoft последует примеру других браузеров и со временем начнет поддерживать эту анимацию. С другой стороны, для приведенного примера нетрудно сделать фоллбэк, который будет более-менее прилично отображать фотографии в маленьком размере и увеличивать их с помощью какого-нибудь расширения.
Расскажу, как это использовать и что с этой радостью можно делать.
Под анимацией я имею в виду изменение размеров контейнеров. Казалось бы, ничего удивительного, ведь есть
transition: width 0.3s ease
. Однако анимация flexible-элементов подразумевает, что размеры нескольких контейнеров изменяются одновременно. Это дает просто безграничные просторы для анимирования изменения размеров лэйаута. Например, сейчас очень популярно меню, которое схлопывается, оставляя видимыми только иконки.Смотреть демо на Codepen.io
Чтобы сделать такое меню с привычными контейнерами, надо синхронно анимировать изменение ширины двух контейнеров. С другой стороны, если отбросить
.menu {
flex: 0.0001 1 180px;
transition: flex 0.3s ease;
}
.collapsed .menu {
flex: 0.0001 1 48px;
}
Код для анимирования изменения размеров умещается в одну строку. В качестве CSS-свойства, которое будет анимировано, передаем «flex».
Немного странно здесь выглядит значение flex-grow. Это фактор расширяемости, который указывает, насколько хорошо будет растягиваться контейнер относительно других контейнеров, если родительский элемент имеет свободное место после расчета базовых размеров вложенных элементов. Чем меньше это значение относительно других, тем меньше контейнер будет расширяться. Если использовать значение 0, то ширина (или высота) элемента будет фиксированной. Если же ширина будет фиксированной, то возникает проблема с анимацией: более старая версия Google Chrome напрочь отказалась анимировать изменение размеров при значении flex-grow равным нулю. Есть вероятность, что в некоторых версиях браузеров такая проблема все еще существует.
Фотогалерея
Давайте пойдем немного дальше: возьмем 5 фотографий, расположим их в одной строке.
При наведении курсора будем показывать выбранную фотографию в увеличенном формате
Для расположения фотографий будем использовать Flexbox, а изображения вставим через background-image:
<div class="items-row">
<div class="item img1"></div>
<div class="item img2"></div>
<div class="item img3"></div>
<div class="item img4"></div>
<div class="item img5"></div>
</div>
.items-row {
display: flex;
flex-flow: row nowrap;
}
.item {
flex: 1 1 20%;
}
.img1 {
background-image: url('http://lorempixel.com/400/400/?1');
background-repeat: no-repeat;
}
Все элементы flex-контейнера занимают изначально по 20% от ширины и равноценно расширяются/сжимаются. Чтобы активный элемент увеличивался при наведении курсора, добавим правило, которое устанавливает фиксированную ширину 400 пикселей и уменьшает расширяемость/сжимаемость элемента почти до нуля:
.item:hover {
flex: 0.000000001 0.00000001 400px;
}
Теперь при наведении курсора все неактивные элементы сожмутся, потому что имеют значение flow-shrink: 1, а активный элемент останется шириной 400 пикселей, потому что он почти несжимаем.
Последний штрих — добавление анимации:
.item {
transition: flex 0.4s ease;
}
Смотреть демо на Codepen.io
Если пойти еще дальше, то можно сделать несколько рядов фотографий и при наведении курсора увеличивать не только ширину, но и высоту. Для этого надо повторить то же самое, но с
flex-flow: column nowrap;
.А вот что будет, если навести курсор на фотографию
Смотреть демо на Codepen.io
Производительность
Редкое обсуждение анимации обходится без разговоров о FPS. Поэтому на моем неторопливом компе я измерял FPS для последней демки. И вот что я получил:
Да, выглядит вполне неплохо. Да и вообще я как-то замерял скорость отрисовки интерфейса сделанного с помощью Flexbox и аналогичного, сделанного на float'ах. Интерфейсы включали в себя по 1500 элементов. Разница в рендеринге составляла около 10 мс на десктопе и около 15-20 мс на мобильном устройстве. Поэтому, если производительность для вас решающий фактор, то вы проиграете немного.
Поддержка браузерами
К сожалению, это не кроссбраузерная радость.
Выводы
- Анимировать изменение размеров flexbox-элементов легко:
transition: flex 0.4s ease;
; - Отличные от нуля (0.000001) значения flex-grow и flex-shrink могут все исправить, если анимация не работает;
- По производительности анимация Flexbox контейнеров почти не уступает анимации элементов div с float;
- Это очень свежее решение, поэтому использовать его стоит с осторожностью, а тестировать как можно больше.