Реагуючі блоки однакової висоти на основі Flexbox з JavaScript Fallback

31 липня 2014 17:18 comandante 590 1

Чому саме Flexbox? Тому що цей модуль був розроблений для того, щоб вирішити проблеми даного типу. Це гнучкий і ефективний спосіб управління для всіх видів макетів. Цей спосіб не створює майже ніякого часового розриву між правильним та неправильним виглядом макета. В випадку JavaScript рішення потрібен час, щоб скачати документ, а потім завантажити відповідний JS файл і, якщо такий є, завантажити зображення в блок. Flexbox миттєвий і JavaScript займає всього кілька секунд. Цей спосіб з JavaScript ідеально підходить для людей, які використовують старі браузери, які не підтримують Flexbox.

 

Проблема

Код і проблема (макет з ламаною лінією) для вирішення:

<ul class="list">
    <li class="list__item"><!-- content --></li>
    <li class="list__item"><!-- content --></li>
    <!-- other items -->
</ul>
.list
{
    overflow: hidden; /* just clearing floats */
}
    .list__item
    {
        width: 25%; /* 4 items per row */
        float: left;
    }

 

Flex-box

 

Вирішення:

Якщо ви ще не працювали з 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;
    }

 

Flex-box\

 

Це прекрасно працює в останніх версіях 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 Fallback

Ця частина охоплює запасне рішення для таких браузерів, як Internet Explorer 9-, Android 4.3-, IOS Safari 6.1-, і Opera Mini. Я написав невеликий шматочок JQuery-залежного коду, який:

 
  1. Виявляє, якщо браузер не підтримує Flexbox;

  2. Розраховує кількість елементів в рядку, розділивши ширину.list і ..list__item;

  3. Віртуально ділить список в рядках відповідно до цього числа;

  4. Виявляє, який елемент має найбільшу висоту в кожному рядку;

  5. Встановлює цю висоту для інших елементів в кожному рядку відповідно.

;( 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. Тому, використовуючи @support неможливо охопити кожен браузер, який підтримує Flexbox. Але це краще, ніж нічого.

Як можна вирішити цю проблему: “вимкнений JavaScript = немає підтримки Flexbox( скоріше всього - самий вірний спосіб)” і і виправити винятки з допомогою @support. Можна додати ім'я класу .no-JS до <HTML> тега і видалити його за допомогою JavaScript. Так ми будемо знати  відключений він чи ні. Тоді, стилюйте елементи списку і, нарешті, "компенсуйте" це стилювання за допомогою @support.

Блоки відображаються, як рядки в повну ширину в цьому випадку. Якщо є будь-які зображення, вони будуть вирівняні по правому краю рядка на великих екранах.

<html class="no-js">
    <head>
        <!-- your stuff -->
        <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><!-- remove this if you are using Modernizr -->
    </head>
    <!-- your stuff -->
</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;
        }
}

Flex-box

 

 

590 5

Схожі матеріали:

Коментарі:

Taras987

02 Жов 2014 20:07

$list.find( 'img' ).on( 'load', setHeights );
спрацює стільки разів, скільки є картинок, чи я помиляюсь?

Авторизуйтесь, щоб залишити коментар.