Пару месяцев назад меня кто-то спрашивал, могу ли я подсказать что-либо по переходу с классов «.col» в Bootstrap на Susy или Neat. И этот вопрос поставил меня в тупик: я никогда не говорил на эту тему, хотя сам уже очень долго пользуюсь сетками Susy!

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

Перед тем как продолжить, предполагается, что вы уже понимаете, почему решили перейти с HTML Grid (типа Bootstrap, Foundationи любого фреймворка) систем на CSS Grid (Susy, Neat или даже Flexboxс CSS).Если же вы до конца не осознаете, почему решили сделать это, то перед переходом настоятельно советую прочитать эту статью. В ней описаны все плюсы и минусы обеих систем.

Готовы?

Наши четыре этапа:



  1. Определяем шаблоны макета
  2. Придумываем новую разметку и классы
  3. Создаем шаблоны макета в CSS
  4. Заменяем старую разметку на новую


Пройдемся по каждому этапу отдельно.

Этап 1: Определяем шаблоны макета



Шаблон макета – шаблон, в котором задано, как ваш макет будет изменяться на разных разрешениях экрана. Примером шаблона макета может послужить макет «content-sidebar». В данном макете на мобильных устройствах область контента и сайдбар занимают все 12 колонок (предполагается, что вы используете 12-тиколоночную систему). При ширине экрана в 600px контент занимает 9 колонок, а сайдбар 3.



Код этого макета в Bootstrap относительно прост. (Давайте предположим, что col-md триггеры на 600px. Я забыл точные разрешения в Bootstrap).

<div class="row">
  <div class="col-12 col-md-9">Content</div>
  <div class="col-12 col-md-3">Sidebar</div>
</div>


Еще один пример шаблона макета – трехколоночная сетка. На экранах мобильных устройств каждая ячейка занимает все 12 колонок, а при ширине экрана 600px 4 колонки.



Код трехколоночной сетки в Bootstrap также не отличается сложностью:

<div class="row">
  <div class="col-12 col-md-4">Grid item</div>
  <div class="col-12 col-md-4">Grid item</div>
  <div class="col-12 col-md-4">Grid item</div>
</div>


Иногда приходится работать с более сложными макетами. К примеру, вы хотите вписать два блока в трехколоночную сетку. При ширине экрана 600px и выше каждый блок должен занимать 6 колонок, а не 4.



В Bootstrap код будет выглядеть примерно так:

<div class="row">
  <div class="col-12 col-md-6">Featured Grid Item</div>
  <div class="col-12 col-md-6">Featured Grid Item</div>
  <div class="col-12 col-md-4">Grid item</div>
  <div class="col-12 col-md-4">Grid item</div>
  <div class="col-12 col-md-4">Grid item</div>
</div>


На данный момент мы просмотрели 3 шаблона:

  1. «content-sidebar» шаблон
  2. Шаблон трехколоночной сетки
  3. Шаблон трехколоночной функциональной сетки


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

Этап 2: Придумываем новую разметку и классы



Один из плюсов HTML Grid систем в том, что нам не нужно думать о разметке и классах, все уже решено за нас. А при переходе на CSS Grid системы нам приходится в спешном порядке создавать классы типа «.some-class-name» на замену классам типа «.col-md-6».

Это огромная проблема, и множество людей застревают на этом месте. Когда я первый раз работал с CSS Grid системой, я тоже тут застрял.

Сначала я пытался соблюдать семантику. Я использовал классы типа .content и .sidebar где только мог, а также по максимуму пытался удалить все наследование. Ниже представлена моя первоначальная разметка для шаблона content-sidebar:

<div class="content">Content</div>
<div class="sidebar">Sidebar </div>


Если ваш макет довольно прост, а на сайте есть только область контента .content и сайдбар .sidebar, то данная разметка, в принципе, подойдет. Все становится чуть запутаннее при добавлении других типов шаблонов.

К примеру, самая простая разметка для трехколоночной сетки, которую я создал, выглядит следующим образом:

<div class="grid">
  <div class="grid-item">Grid item</div>
  <div class="grid-item">Grid item</div>
  <div class="grid-item">Grid item</div>
</div>


Если соединить две разметки вместе, то можно заметить, что мой первоначальный метод не работает с трехколоночной сеткой и шаблоном content-sidebar.

<!-- НЕ ДЕЛАЙТЕ ТАК! -->
<div class="content">Content</div>
<div class="sidebar">Sidebar </div>
<div class="grid">
  <div class="grid-item">Grid item</div>
  <div class="grid-item">Grid item</div>
  <div class="grid-item">Grid item</div>
</div>


Лучше добавить контейнер div наподобие класса .row в Bootstrap:

<div class="content-sidebar-container">
  <div class="content">Content</div>
  <div class="sidebar">Sidebar</div>
</div>
<div class="three-column-grid-container">
  <div class="grid-item">Grid item</div>
  <div class="grid-item">Grid item</div>
  <div class="grid-item">Grid item</div>
</div>


Трюк с добавлением div контейнера означает, что для стилизации его прямых наследников можно использовать псевдокласс nth-child:

// Это SCSS
.content-sidebar-container {
  > div:nth-child(1) {
    // Стили контента
  }

  > div:nth-child(2) {
    // Стили сайдбара
  }
}


А значит, больше не нужно задавать классы дочерним элементам контейнера (такие как .content, .sidebar и .grid-item). Разметка становится еще проще:

<div class="content-sidebar-container">
  <div>Content</div>
  <div>Sidebar</div>
</div>


Тут можно внести еще одно исправление — .content-sidebar-container слишком долго набирать. Я ленивый разработчик и не люблю много печатать.

Я выбрал имена классов наподобие системы SMACSS. В SMACSS рекомендуется все правила для макета записывать с приставкой .l. Так как мы пишем только классы контейнеров, а эти классы в свою очередь задают шаблоны макета, то мы можем сократить .content-sidebar-container до .l-content-sidebar.

Класс .content-sidebar тоже довольно длинный. По желанию его можно сократить до .l-cs. (Вроде бы, понятный класс, так ведь? Просто не забудьте его задокументировать где-нибудь.

Как вывод данного этапа, рекомендую создавать имена классов наподобие:

  1. Шаблон content-sidebar => .l-cs
  2. Шаблон трехколоночной сетки => .l-g3
  3. Шаблон функциональной трехколоночной сетки => .l-fg3


После того, как вы придумали новую разметку и классы, необходимо создать макеты в CSS.

Этап 3: Создаем шаблоны макета в CSS



Создавать шаблоны макета в CSS вы можете с помощью любого метода: Susy, Neat, Bootstrap Sass, Flexbox и т.д. Самое главное здесь это уметь пользоваться этим методом.

  • В любом из методов вам нужно научиться писать медиа запросы для техники mobile-first и работать со свойством CSS Box Sizing.
  • Для работы с Susy, Neat и Bootstrap Sass вам нужно изучить float.
  • Для работы с Flexbox придется изучить Flexbox.


Список можно продолжать, но смысл вы поняли.

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

  • .l-cs с помощью обтеканий (в чистом SCSS) и Susy
  • .l-g3 с помощью обтеканий (в чистом SCSS) и Susy
  • .l-fg с помощью Flexbox


Сначала разберем .l-cs.

Как создать макет .l-cs с помощью обычного SCSS



Мы уже знаем, как с помощью предложенной мной разметки создавать макеты – использовать псевдокласс nth-child. Также стоит воспользоваться селектором прямого наследования (>), чтобы исключить случайный выбор других div’ов в макете.

.l-cs {
  > div:nth-child(1) {
    // Стили контента
  }

  > div:nth-child(2) {
    // Стили сайдбара
  }
}


Мы знаем, что div’ы по умолчанию занимают 100% ширины. Это означает, что для создания шаблона макета для маленьких экранов нам стили писать вообще не нужно.

С шириной экрана в 600px мы будем использовать float, чтобы область контента занимала 9 колонок из 12, а сайдбар — оставшиеся 3. При работе с float-ами всем div’ам в макете необходимо указать свойства width и float. Код будет следующий:

.l-cs {
  > div:nth-child(1) {
    @media (min-width: 600px) {
      float: left;
      width: 74.57627%;
    }
  }

  > div:nth-child(2) {
    @media (min-width: 600px) {
      float: right;
      width: 23.72881%;
    }
  }
}


И еще одно. Чтобы контейнер не схлопнулся при работе с float, ему необходимо добавить clearfix:

@mixin clearfix() {
  &:after {
    display: table;
    content: ' ';
    clear: both;
  }
}

.l-cs {
  @include clearfix;

  // ... код выше
}


Вот и все! Не сложно, правда?

Один минус здесь – вычисление width для области контента и сайдбара. Большинство CSS Grid библиотек типа Susy и Neat стараются избавиться от этой головной боли.

Если работать в Susy, то код выше можно упростить, добавив миксин span(), который автоматически создает нужные свойства:

.l-cs {
  @include clearfix

  > div:nth-child(1) {
    @media (min-width: 600px) {
      @include span(9);
    }
  }

  > div:nth-child(2) {
    @media (min-width: 600px) {
      @include span(3 last);
    }
  }
}


Смотреть рабочий код на codepen

Со Susy все гораздо проще, правда?

Продолжим.
.

Как создать макет .l-g3 с помощью Susy



Для создания трехколоночной сетки применяется та же техника: псевдокласс nth-child и селектор прямого наследования >.

Тут вам придется выучить все значения псевдокласса nth-child. На сайте CSS Tricks есть nth-tester, с помощью которого можно наглядно изучить данный псевдокласс.

.l-g3 {
  > div:nth-child(3n+1) { // Крайний левый элемент сетки }
  > div:nth-child(3n+2) { // Центральный элемент сетки}
  > div:nth-child(3n+3) { // Крайний правый элемент сетки }
}


Так как мы создаем трехколоночную сетку с помощью обтеканий, то первым делом нам необходимо добавить clearfix.

.l-g3 {
  @include clearfix;
  > div:nth-child(3n+1) { // Крайний левый элемент сетки }
  > div:nth-child(3n+2) { // Центральный элемент сетки }
  > div:nth-child(3n+3) { // Крайний правый элемент сетки }
}


Как мы уже говорили выше, div по умолчанию занимает 100% ширины. Так что для маленьких экранов нам вообще стили писать не нужно. Также мы помним, что при ширине экрана в 600px необходимо прописать свойства float и width.

Так как колонок более двух, то в данном случае также необходимо добавить свойство margin для элементов сетки.

Код:

.l-g3 {
  @include clearfix;

  @media (min-width: 600px) {
    // Крайний левый элемент сетки
    > div:nth-child(3n+1) {
      width: 32.20339%;
      float: left;
      margin-right: 1.69492%;
    }

    // Центральный элемент сетки
    > div:nth-child(3n+2) {
      width: 32.20339%;
      float: left;
      margin-right: 1.69492%;
    }

    // Крайний правый элемент сетки
    > div:nth-child(3n+3) {
      float:right;
      width: 32.20339%;
      margin-right: 0;
    }
  }
}


Довольно страшный код со свойством nth-child. Выглядит сложно, да еще и нужно вычислять точные значения margin и width.

Писать код в Susy намного проще. Вы можете выбрать один из двух миксинов: span() или gallery().

Если вы создаете сетку, я настоятельно рекомендую использовать gallery(), так как он использует технику изоляции для уменьшения субпиксельных ошибок округления. Код с миксином gallery():

.l-g3 {
  @include clearfix;

  > div {
    @include gallery(4 of 12);
  }
}


Susy сама автоматически генерирует правильные селекторы nth-child и свойства. Милая штуковина!

Поиграйтесь с демо на codepen

Рекомендую ознакомиться со Susy – сильно упрощает создание сеток.

Ну а мы продолжим.
.

Как создать макет .l-fg3 с помощью Flexbox



По сравнению с float-ами во Flexbox сетку создать немного сложнее. Для начала давайте рассмотрим разметку, которую я решил использовать для макета .l-fg3.

<div class="l-fg3">
  <div>Featured Item</div>
  <div>Featured Item</div>
  <div>Grid item</div>
  <div>Grid item</div>
  <div>Grid item</div>
</div>


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

Обратите внимание: для упрощения кода я не стал писал вендорные префиксы. Для генерации префиксов используйте autoprefixer, лучший способ.

.l-fg3 {
  display: flex;
  flex-wrap: wrap;
}


Прописав эти свойства, вы заметите, что элементы сетки занимают только необходимое для них пространство:



Ячейки сетки занимают только необходимое им пространство.

Это значит, что для мобильного макета нам придется их заставить вручную растягиваться на 100% ширины. Можно:

  • Задать свойство flex-flow: column для .l-fg
  • Или задать свойство flex-basis: 100% всем элементам сетки


Зададим flex-basis: 100%, его легче понять.

.l-fg3 > div {
  flex-basis: 100%;
}




Обратите внимание: Чтобы вы видели границы ячеек, я добавил серую рамку в 1px.

С мобильным макетом мы закончили. Теперь создадим функциональную сетку для ширины 600px. Мы знаем, что на одной строке должно быть три элемента, каждый должен занимать ровно треть от размера окна, если нет дополнительных расстояний между элементами сетки. Для этого необходимо изменить значение свойства flex-basis на 33.333%:

.l-fg3 > div {
  flex-basis: 100%;
  @media (min-width: 600px) {
    flex-basis: 33.333%;
  }
}




Трехколоночная функциональная сетка без margin’ов.

Теперь необходимо добавить отступы между ячеек.

При работе с flexbox отступы придется разделить пополам и размещать их по краям элементов сетки. Если расстояние между элементами равно 20px, то каждой ячейке необходимо задать margin-left и margin-right в 10px.

.l-fg3 > div {
  flex-basis: 100%;
  @media (min-width: 600px) {
    margin: 10px;
    flex-basis: 33.333%;
  }
}


Но если вы посмотрите на получившийся макет, то вы, возможно, разочаруетесь и еще больше запутаетесь.



Из-за неправильного значения flex-basis макет поплыл.

Макет поплыл из-за того, что margin’ы прибавляются к значениям flex-basis для каждого элемента. Ширина трех элементов становится равной 100%+60px, что больше 100%. Поэтому браузер просто не может не передвинуть третий блок на следующую строку.

Решение проблемы на удивление простое. Нужно всего лишь удалить margin’ы у всех элементов сетки с помощью calc():

.l-fg3 > div {
  // ...
  @media (min-width: 600px) {
    margin: 10px;
    flex-basis: calc(33.333% - 20px);
  }
}


И вы получите нормальную трехколоночную сетку (но с фиксированным отступом 20px).


Теперь впишем два блока в 3 ячейки.

Мы знаем, что каждый элемент должен занимать половину ширины строки (минус 20px между ними). По точно такой же формуле мы можем просто изменить свойство flex-basis для первых двух элементов и получим функциональную сетку.

.l-fg3 {
  // ...
  > div:nth-child(1),
  > div:nth-child(2) {
    @media (min-width: 600px) {
      flex-basis: calc(50% - 20px);
    }
  }
}




Это еще не все.

Обычно, вам не будут нужны margin’ы в 10px по всем сторонам сетки. Удалить внешние отступы можно с помощью отрицательного значения margin на контейнере .l-fg3.

.l-fg3 {
  margin: -10px;
}


После этого вы обнаружите, что появился скролл вправо, а он нам точно не нужен.



Из-за отрицательного margin’а появляется скролл вправо.

Исправить это можно, создав flex контейнер со свойством overflow-x: hidden и поместив в него контейнер .l-fg:

<div class="l-flex">
  <div class="l-fg">
    <div>Featured Item</div>
    <div>Featured Item</div>
    <div>Grid Item</div>
    <div>Grid Item</div>
    <div>Grid Item</div>
  </div>
</div>


.l-flex {
  overflow-x: hidden;
}


Вот и все! Кто сказал, что во Flexbox тяжело создавать сетки?

Кстати, так как Flexbox – не главная тема статьи, то по созданию сетки с его помощью я пробежался довольно поверхностно. Но надеюсь вам все понятно.

Продолжим.

Этап 4: Заменяем старую разметку на новую



Последний этап – это замена старой разметки на новую. На данном этапе следует внимательно проверить, не допустили ли вы ошибок на 3 этапе.

И все готово.

Заключение



В этой статье мы научились переходить с HTML Grid (в большинстве случаев фреймворки, похожие на Bootstrap) на CSS Grid систему, которую сами и написали.

Обобщая все вышесказанное, можно напомнить, что у нас было 4 этапа:

  1. Определение имеющихся шаблонов макета
  2. Создание новой разметки и классов
  3. Создание шаблона макета в CSS
  4. Замена старой разметки на новую


В заключении статьи хотел сообщить, что на днях мы подготовил для Вас мини-курс «Фреймворк Bootstrap – верстаем адаптивно, просто, быстро».

В этом небольшом курсе мы с вами познакомимся с фреймворком Bootstrap, буквально совсем чуть-чуть прикоснувшись к его возможностям. И в качестве примера сверстаем простой макет сайта-портфолио, нарисованный в минималистичном стиле.
Поэтому, если хотите освоить работу с данным фреймворком, то посмотрите уроки по фреймворку bootstrap.

Помогла ли вам эта статья перейти с HTML Grid на CSS Grid систему? Пишите об этом в комментариях!
Поделиться с друзьями
-->

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


  1. koceg
    10.05.2016 20:17
    +1

    Поясните, пожалуйста, чем плох вариант "НЕ ДЕЛАЙТЕ ТАК" и почему стоит использовать вместо него такие конструкции:

    .l-g3 > div:nth-child(3n+3)
    ?


  1. mayorovp
    11.05.2016 08:45

    Отрицательный margin кажется костылем. Не лучше ли просто не добавлять нежелательные поля для первой и последней колонки?


  1. hermit931
    11.05.2016 09:00
    +1

    Миксины конечно хорошо:

    @mixin clearfix() {
      &:after {
        display: table;
        content: ' ';
        clear: both;
      }
    }
    
    .l-cs {
      @include clearfix;
    
      // ... код выше
    }
    

    но мне почемуто кажеться что лучше добавлять clearfix через класс. Понимаю что это уже не совсем только через стили, но для большой страницы (лендинга какого-то) использование класса может существенно облегчить вес файла стилей.

    И вот так .l-fg3 > div не стоит увлекаться. Используя класс и страница отредериться быстрей, и тег можно при необходимости заменить на другой, да и читать код поприятней будет


    1. stychos
      11.05.2016 09:41

      Всегда делаю clearfix через extend из базового класса, файл стилей не особо увеличивает, так что, только стилей достаточно — но mixin и правда незачем.


      1. hermit931
        11.05.2016 15:15

        Екстенд это не то, екстенд просто пропишет все класы в одном месте с одними правилами… а миксин будет все 3 срочки к кажому класу прописывать


        1. stychos
          11.05.2016 15:46

          Ну и я о том же — лучше класс, и если уж хочется сохранить семантику в шаблоне, то делать экстенды, меньше нагенерирует в итоге.


    1. artemmalko
      11.05.2016 18:00

      gzip уберет повторяющийся код. Так что mixin тут никак на размер не влияет.


  1. wispoz
    11.05.2016 11:30

    Почитал статью, и ту что дана в качестве на подумать, но так и не понял в чем отличие, кроме убранных классов в CSS Grid.


  1. tomgif
    11.05.2016 11:32
    +1

    Почему вы не используете примеси(mixins) того же bootstrap/foundation? Не придется менять фреймворк и останется по 1-2 класса на каждый селектор, либо прямым наследлванием от родителя как в вашем примере.


  1. pepelsbey
    11.05.2016 15:16
    +4

    Что вы делаете с кучей свободного времени, которое экономите на уродливо нечитаемы классах вида l-g3? Ну и променяли шило на мыло: был один оформительский мусор в разметке вместо понятных логичных классов — стал другой. Миксины же! Чем хороши системы, вроде Susy? Тем, что можно сменить систему раскладки, вообще не трогая HTML. А вы себя по рукам связали.


  1. Punk_UnDeaD
    11.05.2016 22:18

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


  1. sashamorozov
    12.05.2016 12:44
    +1

    В примере с flexbox гораздо будет лучше избегать calc, и тем более overflow-x: hidden. Намного лучше будет добавить padding: 10px (не забывая о box-sizing: border-box), а если нужно будет отделить элементы фоном, то просто внутри создать ещё один контейнер.

    Простой пример: https://jsfiddle.net/sashamorozov/ykvkgrb7/