• Главная»
  • Уроки»
  • CSS»
  • 4 простых способа реализации адаптивной сеточной разметки

4 простых способа реализации адаптивной сеточной разметки

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

Давайте вернемся на шаг назад, сделаем глубокий вздох, и спросим себя: действительно ли мы собираемся использовать все 24 варианта, и миллион их комбинаций, которые нам предоставляет “Этот Наикрутейший Фреймворк”? Зачастую нам нужно простое, гибкое решение, с ограниченным количеством вариаций, с кодовой базой, которую мы можем в любой момент расширить. Я хочу рассказать о четырех техниках реализации CSS сеток, каждая из которых легко расширяется. Вот эти четыре способа:

  1. Адаптивная сеточная разметка №1 (с использованием отрицательных отступов)
  2. Адаптивная сеточная разметка №2 (с использованием box-sizing: border-box)
  3. Адаптивная сеточная разметка на основе табличного отображения
  4. Адаптивная сеточная разметка на основе flexbox

Я упрощу описание этих способов, и буду использовать минимальное количество простого и понятного CSS. Для каждого способа будет представлена демонстрация на CodePen.

Общий CSS

Перед тем, как углубиться в описание каждого метода, давайте взглянем на общие стили, которыми мы будем использовать во всех примерах. Я буду использовать объявление box-sizing: border-box для всех элементов документа, а также добавлю класс .clearfix для очистки плавающих блоков. Вот наш базовый CSS:

/* сбрасываем свойства */
*,
*:before,
*:after {
  box-sizing: border-box;
}
.clearfix:after {
  content: "";
  display: table;
  clear: both;
}

Способ 1: используем отрицательные отступы

Данный способ основан на использовании отрицательных отступов для создания блоков сетки с фиксированным отступом между блоками. Размер отрицательного отступа варьируется от позиции блока в сетке, а расстояние между блоками остается постоянным. Давайте посмотрим на разметку:

<div class="row-2 clearfix">
  <div class="col-1-2"></div>
  <div class="col-1-2"></div>
</div><!-- /.row -->

<div class="row-4 clearfix">
  <div class="col-1-4"></div>
  <div class="col-1-4"></div>
  <div class="col-1-4"></div>
  <div class="col-1-4"></div>
</div><!-- /.row -->

<div class="row-8 clearfix">
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
</div><!-- /.row -->

И стили:

/* сетка */
[class*="row-"] {
  margin-bottom: 20px;
}
[class*="row-"]:last-child {
  margin-bottom: 0;
}
[class*="col-"] {
}

@media all and ( min-width: 768px ) {

  /* all cols margin */
  [class*="col-"] {
    margin-right: 20px;
  }
  [class*="col-"]:last-child {
    margin-right: 0;
  }

  /* делаем колонки адаптивными */
  .col-1-2 {
    float: left;
    width: 50%;
  }
  .col-1-4 {
    float: left;
    width: 25%;
  }
  .col-1-8 {
    float: left;
    width: 25%;
  }

  /* 2 span rows */
  .row-2 {
    padding-left: 20px;
  }
  .row-2 [class*="col-"]:first-child {
    margin-left: -20px;
  }

  /* 4 span rows */
  .row-4 {
    padding-left: 60px;
  }
  .row-4 [class*="col-"]:first-child {
    margin-left: -60px;
  }

  /* 8 span rows */
  .row-8 {
    padding-left: 60px;
  }
  .row-8 [class*="col-"]:nth-child(4n+1) {
    margin-left: -60px;
  }
  .row-8 [class*="col-"]:nth-child(5n-1) {
    margin-right: 0;
  }
  .row-8 [class*="col-"]:nth-child(6n-1) {
    clear: both;
  }

}

@media all and ( min-width: 1200px ) {

  /* adjust width */
  .col-1-8 {
    float: left;
    width: 12.5%;
  }

  /* 8 span rows */
  .row-8 {
    padding-left: 140px;
  }
  /* reset these... */
  .row-8 [class*="col-"]:nth-child(4n+1) {
    margin-left: 0;
  }
  .row-8 [class*="col-"]:nth-child(5n-1) {
    margin-right: 20px;
  }
  .row-8 [class*="col-"]:nth-child(6n-1) {
    clear: none;
  }
  /* and add this */
  .row-8 [class*="col-"]:nth-child(1) {
    margin-left: -140px;
  }
}

А вот и демонстрация на CodePen:

Как видно, в рамках условий медиазапросов фиксированное значение отступа (назовем его x) умножается на количество колонок в строке минус 1 (n-1), и такой отступ применяется к строке слева. У каждой колонки, кроме последней, задан фиксированный отступ справа (x). А первой колонки в строке задан отрицательный отступ (n-1)*x

Недостатки и ошибки

Необходимость в некоторых расчетах, к тому же способ становится непрактичен при увеличении количества колонок. К тому же при увеличении количества шагов (количество градаций медиазапросов, например на 1 колонку на строку, 4, 8…), нам необходимо сбрасывать CSS, и приходится использовать множество математических вычислений.

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

Преимущества и использование на практике

Настоящая прелесть этого способа заключается в создании комбинаций сетки фиксированного/переменного размера. В качестве примера давайте представим область основного содержимого переменной ширины, и дополнительную боковую область фиксированной ширины. Наш HTML-код может выглядеть примерно так:

<div class="container clearfix">
  <div class="primary">
    <h2>Primary</h2>
    Lorem ipsum dolor...
  </div>
  <div class="secondary">
    <h2>Secondary</h2>
    Lorem ipsum dolor...
  </div>
</div><!-- /.container -->

А CSS - так:

/* разметка */
.primary {
  margin-bottom: 20px;
}

@media all and ( min-width: 600px ) {

  .container {
    padding-right: 300px;
  }
  .primary {
    float: left;
    padding-right: 60px;
    width: 100%;
  }
  .secondary {
    float: right;
    margin-right: -300px;
    width: 300px;
  }
}

А вот и демонстрация кода в действии на CodePen:

Способ 2: используем box-sizing: border-box

Этот способ использует всю силу box-sizing: border-box. Так как это свойство позволяет добавлять элементу поля без того, чтобы их значение влияло на общую ширину элемента, мы все еще можем добиться гибкой сетки с фиксированными “отступами”. Но здесь вместо использования свойства margin, мы будем использовать внутренние поля, которые будут играть роль отступов между элементами сетки.

Разметка:

<div class="row clearfix">
  <div class="col-1-2"></div>
  <div class="col-1-2"></div>
</div><!-- /.row -->

<div class="row clearfix">
  <div class="col-1-4"></div>
  <div class="col-1-4"></div>
  <div class="col-1-4"></div>
  <div class="col-1-4"></div>
</div><!-- /.row -->

<div class="row clearfix">
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
</div><!-- /.row -->

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

/* сетка */
.row {
  margin: 0 -10px;
  margin-bottom: 20px;
}
.row:last-child {
  margin-bottom: 0;
}
[class*="col-"] {
  padding: 10px;
}

@media all and ( min-width: 600px ) {

  .col-2-3 {
    float: left;
    width: 66.66%;
  }
  .col-1-2 {
    float: left;
    width: 50%;
  }
  .col-1-3 {
    float: left;
    width: 33.33%;
  }
  .col-1-4 {
    float: left;
    width: 25%;
  }
  .col-1-8 {
    float: left;
    width: 12.5%;
  }
}

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

Демонстрация:

Расширяем этот способ:

Скажем, вы бы хотели, чтобы элементы .col-8 сначала разбивались по 4 в строку, а затем по 8. Это довольно просто реализовать, если немного подумать. Для вышеприведенной разметки наш CSS будет выглядеть следующим образом:

@media all and ( min-width: 600px ) {

  .col-1-8 {
    float: left;
    width: 25%;
  }
  .col-1-8:nth-child(4n+1) {
    clear: both;
  }

}

@media all and ( min-width: 960px ) {

  .col-1-8 {
    width: 12.5%;
  }
  .col-1-8:nth-child(4n+1) {
    clear: none;
  }

}

Демонстрация:

Способ 3: используем табличное отображение

Этот способ реализует старое-доброе табличное поведение, но не ломая семантику или структуру. В этом методе видимые элементы отображаются по-умолчанию как блоки. Но при определенных размерах строки сетки становятся таблицами, а столбцы становятся ячейками таблицы. Давайте взглянем на разметку - она похожа на аналогичную из второго способа, но тут нам не нужен .clearfix:

<div class="row">
  <div class="col-1-2"></div>
  <div class="col-1-2"></div>
</div><!-- /.row -->

<div class="row">
  <div class="col-1-4"></div>
  <div class="col-1-4"></div>
  <div class="col-1-4"></div>
  <div class="col-1-4"></div>
</div><!-- /.row -->

<div class="row">
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
</div><!-- /.row -->

И, соответственно, CSS:

/* сетка */
.row {
  margin: 0 -10px;
  margin-bottom: 10px;
}
.row:last-child {
  margin-bottom: 0;
}
[class*="col-"] {
  padding: 10px;
}

@media all and ( min-width: 600px ) {

  .row {
    display: table;
    table-layout: fixed;
    width: 100%;
  }
  [class*="col-"] {
    display: table-cell;
  }

  /* set col widths */
  .col-2-3 {
    width: 66.66%;
  }
  .col-1-2 {
    width: 50%;
  }
  .col-1-3 {
    width: 33.33%;
  }
  .col-1-4 {
    width: 25%;
  }
  .col-1-8 {
    width: 12.5%;
  }
}

Демонстрация:

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

Способ 4: Flexbox

Последний способ, который я опишу, использует модуль flexbox. Согласно MDN:

CSS3 Flexible Box, или flexbox - режим макета, предоставляющий возможность размещать элементы на странице так, что они ведут себя предсказуемо на различных размерах экрана и различных устройствах.

Flexbox предлагает множество различных возможностей, дающих нам мощный арсенал различных вариантов компоновки элементов. Сделать модуль flexbox адаптивным проще простого. Как и ранее, наша разметка выглядит так:

<div class="row">
  <div class="col-1-2"></div>
  <div class="col-1-2"></div>
</div><!-- /.row -->

<div class="row">
  <div class="col-2-3"></div>
  <div class="col-1-3"></div>
</div><!-- /.row -->

<div class="row">
  <div class="col-1-4"></div>
  <div class="col-1-4"></div>
  <div class="col-1-4"></div>
  <div class="col-1-4"></div>
</div><!-- /.row -->

<div class="row">
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
  <div class="col-1-8"></div>
</div><!-- /.row -->

А теперь посмотрим на наш новый CSS:

/* grid */
.row {
  display: flex;
  flex-flow: row wrap;
  margin: 0 -10px;
  margin-bottom: 10px;
}
.row:last-child {
  margin-bottom: 0;
}
[class*="col-"] {
  padding: 10px;
  width: 100%;
}

@media all and ( min-width: 600px ) {

  /* set col widths */
  .col-2-3 {
    width: 66.66%;
  }
  .col-1-2 {
    width: 50%;
  }
  .col-1-3 {
    width: 33.33%;
  }
  .col-1-4 {
    width: 25%;
  }
  .col-1-8 {
    width: 12.5%;
  }
}

И демонстрация на CodePen:

В данном случае для строк необходимо выставить свойство display в значение flex, а также указать свойство flex-flow. Полное определение и описание этих свойств доступно в документации MDN к flexbox. Для медиа-запроса мы просто меняем ширину колонок, а flexbox делает за нас остальное.

Заключение

Мы рассмотрели 4 способа создания адаптивных сеток на CSS, каждая со своими достоинствами и недостатками. Не существует абсолютного способа реализации того или иного действия, и я часто ловлю себя на том, что возникают ситуации, когда один способ подходит лучше другого, или мне нужно комбинировать несколько вариантов. Способы 1 и 2 - мои любимые, и я частенько использую их в своих проектах (основная разметка по методу 1, а адаптивные сетки по методу 2).

Как упоминалось ранее, третий способ имеет свои преимущества, но я предпочитаю использовать табличные макеты только тогда, когда это строго необходимо. Способ 4 прекрасен, и я жду не дождусь дня, когда я смогу перенести его на все свои проекты. Flexbox набирает обороты, но он поддерживается только в IE10 и выше. Для него есть полифиллы, но я предпочитаю обходиться без них. Хотя и сегодня есть сценарии, в которых flexbox будет превосходным решением (например, в мобильных браузерах, где нет IE).

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

Данный урок подготовлен для вас командой сайта ruseller.com
Источник урока: http://www.sitepoint.com/easy-responsive-css-grid-layouts/
Перевел: Станислав Протасевич
Урок создан: 2 Июля 2014
Просмотров: 51327
Правила перепечатки


5 последних уроков рубрики "CSS"

или авторизуйтесь, чтобы добавлять комментарии, оценивать уроки и сохранять их в личном кабинете
  • 3 Июля 2014 00:42
    coderphp_info
    нет демонстраций)
    • 5 Июля 2014 21:32
      deonisii185
      нету ??? а это что http://codepen.io/stanislas-prime/pen/ydjqm
  • 3 Июля 2014 08:33
    userseal
    Согласен. Примеры бы.
    • 5 Июля 2014 21:32
      deonisii185
      http://codepen.io/stanislas-prime/pen/ydjqm
      • 14 Августа 2014 08:01
        dennypodemirov
        Пример в окошке размером 10 на 80 пикселей, грубо говоря. Это неудобно.
        • 14 Сентября 2014 22:23
          verstal
          Ну там же ссылка сверху над окошком 10 на 80 пикселей. Ну чего вы такие невнимательные?
  • 3 Мая 2015 13:43
    deathdrummmer
    Отличный материал, хотя он для тех, кто более-менее хорошо разбирается в css и может обойтись без примеров... Автору благодарность!
  • 3 Мая 2015 16:16
    deathdrummmer
    Вот пример простого и рабочего варианта использования с гибким указанием длины блоков, глаавное, чтобы в сумме всегда было 20 (или сколько вы сами зададите)
    .row{ display: flexbox; flex-flow: row wrap; margin: 0 -10px; margin-bottom: 10px;
    }
    .row:last-child{ margin-bottom: 0;
    }
    .row:after{ content: ""; display: table; clear: both;
    }
    [class*="col-"]{ padding: 10px; float: left;
    }
    .col-1-20 {width: 5%;}
    {...}
    .col-19-20 {width: 95%;}
    пример разметки:
    <div class="row"> <div class="col-6-20"></div> <div class="col-14-20"></div>
    </div>
    <div class="row"> <div class="col-8-20"></div> <div class="col-12-20"></div>
    </div>
    
^ Наверх ^