Отзывчивые блоки одинаковой высоты на основе Flexbox

Отзывчивые блоки одинаковой высоты на основе Flexbox

От автора: После публикации поста о том, как я создал отзывчивые блоки одинаковой высоты на сайте Readerrr, я получил несколько полезных отзывов от сообщества веб-разработчиков. Дэниел Стёрм (Daniel Sturm) предложил мне использовать модуль Flexbox из CSS3 вместо JavaScript, а Вирли Питерс (Veerle Pieters) оставил твит «… вы можете сделать это с помощью Flexbox, а JavaScript использовать для подстраховки». Точно! И почему я сам об этом не додумался?! Я читал до этого несколько статей про Flexbox, но сам никогда его не применял, поэтому он совершенно вылетел у меня из головы.

Почему Flexbox? Если вкратце, то модуль Flexbox Layout был создан для решения именно таких задач. Он является эффективным и гибким инструментом для управления, возможно, всеми разновидностями макетов. Благодаря ему практически не возникает задержки по времени между неправильной и правильной отрисовкой внешнего вида макета. При использовании решения на JavaScript тратится время на загрузку документа, затем на загрузку соответствующего JS-файла и, если таковые имеются, на загрузку изображений в блоках. Решение с Flexbox срабатывает мгновенно, а решению на JavaScript потребуются секунды. Но даже в этом случае, решение на JavaScript прекрасно подойдет для людей, использующих старые версии браузеров, которые не поддерживают Flexbox.

Проблема

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

<ul class="list">
 <li class="list__item"><!-- контент --></li>
 <li class="list__item"><!-- контент --></li>
 <!-- остальные элементы -->
</ul>
.list
{
 overflow: hidden; /* отменяем обтекание */
}
 .list__item
 {
 width: 25%; /* 4 элемента на одной строке */
 float: left;
}

Решение

Если вы никогда раньше не сталкивались с Flexbox, то вы будете удивлены, насколько он потрясающий. Свойство display: flex активирует сам Flexbox для контейнера и свойство flex-wrap: wrap говорит о том, что нужно обернуть дочерние элементы, а нет уместить их на одной строке. Повторное написание свойства display: flex для дочерних элементов гарантирует одинаковую высоту элементов в строках.

Практический курс по верстке адаптивного лендинга с нуля!

Научитесь с нуля верстать адаптивные лендинги на HTML5 и CSS3 за ближайшие 6 дней

Узнать подробнее
.list
{
 display: -webkit-flex;
 display: -ms-flexbox;
 display: flex;
 
 -webkit-flex-wrap: wrap;
 -ms-flex-wrap: wrap;
 flex-wrap: wrap;
}
 .list__item
 {
 display: -webkit-flex;
 display: -ms-flexbox;
 display: flex;
 }

Это решение отлично работает в последних версиях браузеров Chrome, Android, Safari, Opera, Firefox и Internet Explorer 10+. Для всех остальных браузеров у меня есть «лекарство» на JavaScript.

Я не включил это в предыдущий CSS-код, но некоторые старые версии браузеров на движке WebKit поддерживают устаревший синтаксис для Flexbox (display: -webkit-box). Однако, свойство -webkit-box-lines: multiple просто не работает ни в браузере iOS Safari 6.1-, ни в Android 4.3-.

Запасной вариант на JavaScript

Здесь я рассматриваю альтернативное решение для таких браузеров, как Internet Explorer 9-, Android 4.3-, iOS Safari 6.1-, and Opera Mini. Я написал крошечный кусочек кода на jQuery, который:

Определяет браузер, не поддерживающий Flexbox;

Вычисляет число элементов на одной строке, разделив для этого значения ширины у элементов .list и .list__item;

Фактически делит список на строки в соответствии с этим числом;

Находит элемент с наибольшим значением высоты в каждой строке;

Устанавливает соответственно такое же значение высоты для всех остальных элементов в каждой строке.

;( function( $, window, document, undefined )
{
 'use strict';
 
 var s = document.body || document.documentElement, s = s.style;
 if( s.webkitFlexWrap == '' || s.msFlexWrap == '' || s.flexWrap == '' ) return true;
 
 var $list = $( '.list' ),
 $items = $list.find( '.list__item' ),
 setHeights  = function()
 {
 $items.css( 'height', 'auto' );
 
 var perRow = Math.floor( $list.width() / $items.width() );
 if( perRow == null || perRow < 2 ) return true;
 
 for( var i = 0, j = $items.length; i < j; i += perRow )
 {
 var maxHeight = 0,
 $row = $items.slice( i, i + perRow );
 
 $row.each( function()
 {
 var itemHeight = parseInt( $( this ).outerHeight() );
 if ( itemHeight > maxHeight ) maxHeight = itemHeight;
 });
 $row.css( 'height', maxHeight );
 }
 };
 
 setHeights();
 $( window ).on( 'resize', setHeights );
 $list.find( 'img' ).on( 'load', setHeights );
 
})( jQuery, window, document );

А что если в браузере отключен JavaScript? Проблема заключается в том, что встроенный механизм CSS для распознавания возможностей имеет более слабую поддержку, чем сам модуль Flexbox. Таким образом, использование CSS-правила @support не подойдет для определения всех браузеров, поддерживающих Flexbox. Но это лучше, чем ничего.

Я предлагаю рассуждать следующим образом: отключен JavaScript = нет поддержки Flexbox (я считаю, что данное равенство является практически верным), а для исключений будем использовать @support. На деле вам нужно добавить класс .no-js для тега html и удалить его с помощью JavaScript. Именно так мы узнаем, отключен JavaScript или нет. Затем добавьте соответствующие стили для элементов списка и, наконец, «компенсируйте» данное оформление с помощью правила @supports.

В данном случае я решил представить блоки в виде строк, растянутых на всю ширину. Если в них будут вставлены какие-нибудь изображения, то на больших экранах они выровняются по правому краю.

<html class="no-js">
 <head>
 <!-- ваш код -->
 <script>(function(e,t,n){var r=e.querySelectorAll("html")[0];r.className=r.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")})(document,window,0);</script><!-- удалите этот код, если вы используете Modernizr -->
 </head>
 <!-- ваш код -->
</html>
html.no-js .list__item
{
 width: 100%;
 float: none;
}
 html.no-js .list__item img
 {
 max-width: 9.375rem; /* 150 */
 float: right;
 margin-left: 1.25rem; /* 20 */
 }
 
@supports ( display: -webkit-flex ) or ( display: -ms-flex ) or ( display: flex )
{
 html.no-js .list__item
 {
 width: 25%;
 float: left;
 }
 html.no-js .list__item img
 {
 max-width: none;
 float: none;
 margin-left: 0;
 }
}

Демо-пример

Автор: Osvaldas Valutis

Источник: http://osvaldas.info/

Редакция: Команда webformyself.

Практический курс по верстке адаптивного лендинга с нуля!

Научитесь с нуля верстать адаптивные лендинги на HTML5 и CSS3 за ближайшие 6 дней

Узнать подробнее
Самые свежие новости IT и веб-разработки на нашем Telegram-канале

Практика HTML5 и CSS3 с нуля до результата!

Получите бесплатный пошаговый видеокурс по основам адаптивной верстки с полного нуля на HTML5 и CSS3

Получить

Метки: ,

Похожие статьи:

Комментарии Вконтакте:

Комментарии Facebook:

Комментарии (2)

  1. Цифровой

    Че-то у меня не выравнивает по высоте блоки. Наверное чего-то не хватает

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

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

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree