Введение

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

Статья будет разбита на две части: в первой будут рассмотрены технологии, применяемые в нашей сетке, а во второй части мы, наконец-то, её построим.

Итак, поехали!

Словарь

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

Box-sizing

Теория

Box-sizing - это свойство, позволяющее изменять алгоритм расчёта ширины и высоты элемента.

Это свойство, помимо наследования значения родителя, может принимать ещё три значения:

  • content-box (по умолчанию) - Значение свойств width и height задают размеры контента, при этом не включают в себя отступы, поля и границы.
  • border-box - Значение свойств width и height задают размеры всего блока, при этом включают в себя поля и границы, но не отступы.
  • padding-box - Значение свойств width и height задают размеры всего блока, при этом включает в себя поля, но не отступы и границы.

Практика

Использовать это свойство очень просто - для начала добавьте код, приведённый ниже, после normalize.css (разумеется, если используете его) до начала блока ваших стилей. Да и всё на этом - готово!

*,
*:before,
*:after {
  box-sizing: border-box;
}

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

Кстати, этот способ получил наибольшее распространение благодаря фреймворку Bootstrap. Сейчас же, использование этого свойства - хороший тон вёрстки.

К счастью, вы можете использовать box-sizing без префиксов, конечно, если вы не поддерживаете тот самый браузер. Об этом нам напоминает Can I use.

Но зачем всё это для нашей сетки?

Отличный вопрос!

Как вы могли уже догадаться, использование box-sizing: border-box, даёт нам независимость от полей и границ блока. Именно это нам и понадобится при построении нашей сетки.

Media queries

Теория

Media queries (Медиа-запросы) - часть спецификации CSS3, которая позволяет нам задавать некую область действия селектора.

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

Практика

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

Нам понадобится только лишь параметр ширины окна браузера:

@media (min-width: значение) { ... }
@media (max-width: значение) { ... }
@media (min-width: значение) and (max-width: значение) { ... }

На месте значений вписывается, как бы это банально не звучало, значение (px, em, rem). Например:

@media (min-width: 768px) { background-color: #000 }

Важно учесть, что при использовании свойства min-width имеет место наследование свойств родителя. Это очень важное замечание, так как не стоит заново указывать все свойства - достаточно лишь указать те, что следует изменить.

Графически можно изобразить это так:

Подход "сначала мобильные"

И всё же, давайте рассмотрим пример.

На холсте у нас всего лишь один div:

<div class="demo-block">Demo Text</div>

Зато присутствует простыня стилей:

/* Basic styles */
.demo-block {
    background-color: #ccc;
    color: #fff;
    padding: 25px;
}

/* Screen > 768px */
@media (min-width: 768px) {
    .demo-block {
        text-align: center;
    }
}

/* Screen > 992px */
@media (min-width: 992px) {
    .demo-block {
        text-align: right;
    }
}

/* Screen > 1200px */
@media (min-width: 1200px) {
    .demo-block {
        background-color: #fff;
        color: #000;
        text-align: left;
    }
}

Если не терпится посмотреть результат, то перейдите по ссылке и изменяйте ширину блока с помощью мыши.

Итак, у нас есть базовый стиль поля, цвет текста и фон. При изменении размеров окна браузера, внешний вид блока не будет меняться до тех пор, пока ширина окна меньше 768px. Как только значение перевалит через эту отметку, наш блок получит новое свойство (вернее сказать, получит переопределение стандартного свойства) - выравнивание текста по центру. Мы изменяем ширину окна ещё больше. Достигаем значения 992px и наш текст выравнивается по правому краю. Меняем размер снова. На этот ширина будет больше 1200px. получается, что отрабатывает новый блок, в котором меняется фон, цвет текста и его выравнивание.

Просто же, неправда ли?

Используемый выше подход называется сначала мобильные, то есть сначала мы задаём стиль для мобильных устройств и с увеличением разрешения добавляем или переопределяем какие-то стили.

К сожалению, не всегда можно ограничиться таким подходом и приходится использовать какие-то конечные промежутки. Иначе говоря, использовать сразу два переломных значения.

@media (min-width: значение) and (max-width: значение) { ... }

Допустим, так:

.class {
    background-color: #000;
    color: #fff;
}

@media (min-width: 540px) and (max-width: 767px) {
	.class {
		background-color: #fff;
		color: #000;
	}
}

@media (min-width: 768px) {
	.class {
		color: red;
	}
}

Изначально имеется чёрный фон и белый цвет текста до тех пор, пока ширина окна браузера не преодолеет отметку в 540px . Если это произойдёт, то фон станет белым, а цвет текста чёрным. Но, так как у нас задан чёткий отрезок, то при достижении отметки в 768px фон изменится снова на изначальный (белый), а цвет текста станет красным.

Но зачем всё это для нашей сетки?

И снова в точку!

С помощью медиа-запросов мы сможем менять свойства контейнера, в зависимости от ширины окна браузера, но об этом немного позже.

Плавающие элементы

Теория

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

Давайте рассмотрим такую проблему и её решение.

У нас есть следующая разметка:

<div class="row">
    <div class="col-one">Col #1</div>
    <div class="col-two">Col #2</div>
</div>

И вот такие вот стили:

.row {
    background-color: #cfcfcf;
    padding: 25px;
}

.col-one,
.col-two {
    float: left;
    width: 50%;
    background-color: #fff;
}

В результате имеет вот такое вот поведение:

Но постойте-ка! Почему родительский элемент имеет разный размер поля вокруг дочерних? А ответ прост - особенность float: left и его родительского класса.

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

Посчитаем:

  • Высота - 0px
  • Поле сверху - 25px
  • Поле снизу - 25px

Итого: 50px.

Размеры блока

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

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

.clearfix:before,
.clearfix:after {
	content: " ";
    display: table;
}

.clearfix:after {
	clear: both;
}

Вот теперь другое дело!

Псевдоэлементы :before и :after создают пустую ячейку таблицы и предотвращают вертикальное схлопывание отступов. В то же время, псевдоэлемент :after дополняется объявлением свойства clear: both, которое прерывает обтекание с обеих сторон.

Как-то запутанно? Так и есть, но я уверен, что большинство использует clearfix и даже не знает как он работает. Теперь же, вы не все :)

Внимание!

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

Заключение

В первой части статьи мы разобрались со всем тем, что нам предстоит использовать при построении сетки. Наконец-то узнали, зачем необходимо свойство box-sizing, разобрались с базовой возможностью медиа-запросов @media и в довесок теперь понимаем что такое clearfix.

Продолжение статьи будет находиться тут.