Отзывчивые блоки одинаковой высоты на основе 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 для дочерних элементов гарантирует одинаковую высоту элементов в строках.

.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 с нуля до результата!

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

Получить

Метки: ,

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

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

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

Ваш 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