Сверхмощные компоненты сетки с помощью пользовательских свойств CSS

Сверхмощные компоненты сетки с помощью пользовательских свойств CSS

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

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

Построение простого компонента

В этой демо-версии я расскажу о построении компонента с текстом и графикой, который вы часто можете видеть на стандартном сайте. Вот как выглядит наш первый компонент:

Простой компонент с текстом и изображением

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

Тот же компонент с наложением сетки

Вы должны увидеть сетку из 14 столбцов:12 центральных столбцов фиксированной ширины и двух гибких столбцов, по одному с обеих сторон. (Они предназначены для иллюстрации и не будут видны в браузере.) Использование display: grid для элемента позволяет нам расположить прямые дочерних элементы этого элемента в контейнере сетки. Для простоты наш компонент будет иметь только два дочерних элемента — изображение и блок текста. Изображение начинается со строки 2 и охватывает семь треков по оси столбцов. Текстовый блок начинается со строки 9 и охватывает пять столбцов.

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

<article class="grid"> <figure class="grid__media"> <img src="" alt="" width="800px" height="600px" /> </figure> <div class="grid__text"> <h3>Heading</h3> <p>Lorem ipsum...</p> </div>
</article>

Классы .grid__media и .grid__text будут использоваться для позиционирования дочерних элементов. Во-первых, нам нужно определить контейнер сетки. Мы можем использовать следующий CSS для сортировки треков сетки:

.grid { display: grid; grid-template-columns: minmax(20px, 1fr) repeat(12, minmax(0, 100px)) minmax(20px, 1fr); grid-column-gap: 20px;
}

Это даст нам сетку, которую мы проиллюстрировали ранее: 12 центральных столбцов с максимальной шириной 100 пикселей, гибкие столбцы с обеих сторон и зазор в 20 пикселей между каждым столбцом.

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

Теперь нам нужно разместить элементы сетки со следующим CSS. Сетка предлагает нам целый ряд различных способов размещения элементов. В этом случае я использую grid-column, это сокращение от grid-column-start / grid-column-end:

.grid__media { grid-column: 2 / 9; /* Начало со Столбца 2 и конец в начале Столбца 9 */
} .grid__text { grid-column: 10 / 14; /* Начало со Столбца 10 и конец в начале Столбца 14 */
} .grid__media,
.grid__text { grid-row: 1; /* Мы хотим разместить элементы в той же строке */
}

Если вам сложно визуализировать линии сетки при кодировании, можете нарисовать их в ASCII с комментариями CSS. Вот демонстрация нашего компонента в действии — вы можете включать и отключать фон, чтобы отобразить столбцы сетки:

Варианты компонентов

Построить такой компонент достаточно просто, но что, если у нас есть много вариантов одного и того же компонента? Вот несколько примеров различных макетов, которые мы могли бы использовать:

Четыре различных варианта компоновки компонентов одного и того же типа

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

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

Согласованность

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

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

Именование строк сетки

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

.grid { display: grid; grid-template-columns: [start] minmax(20px, 1fr) [wrapper-start] repeat(12, minmax(0, 100px)) [wrapper-end] minmax(20px, 1fr) [end];
}

Предварительная фиксация имен строк сетки с помощью *-start и *-end дает дополнительное преимущество, позволяя нам размещать элементы в областях сетки. Установив для элемента сетки grid-column: wrapper, мы помещаем его между строками wrapper-start и wrapper-end.

Использование для размещения переменных CSS

Переменные CSS (также известные как пользовательские свойства) позволяют нам писать более удобный код. Они дают возможность устанавливать и повторно использовать значения в CSS. Если вы используете препроцессор, такой как Sass или Less, вероятно, вы знакомы с использованием переменных. Переменные CSS отличаются от препроцессорных в нескольких важных аспектах:

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

Они не могут использоваться в именах селекторов, именах свойств или объявлениях медиа-запросов. Они должны использоваться только для значений свойств (поэтому они и известны как пользовательские свойства).

Переменные CSS устанавливаются и используются следующим образом:

.box { --color: orange; /* Определяем переменную и значение по умолчанию */ background-color: var(--color); /* Применяем переменную в качестве значения свойства */
}

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

background-color: var(--color, red);

Итак, в этом случае мы устанавливаем для свойства background-color значение —color, но если эта переменная не будет найдена (например, она еще не объявлена), тогда фон будет красным.

В CSS-коде для размещения элементов сетки мы можем использовать переменную и объявить значение по умолчанию, например, так:

.grid__media { grid-column: var(--mediaStart, wrapper-start) / var(--mediaEnd, 9);
} .grid__text { grid-column: var(--textStart, 10) / span 4;
}

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

.grid--2 { --mediaEnd: end; --textStart: wrapper-start;
} .grid--2,
.grid--4 { --mediaStart: 8;
} .grid--3 { --mediaStart: start;
} .grid--4 { --mediaEnd: wrapper-end; --textStart: 3;
}

Вот результат:

Для сравнения, размещение элементов таким же образом без использования переменных будет выглядеть так:

/* Grid 2 */
.grid--2 .grid__media { grid-column: 8 / end;
} .grid--2 .grid__text { grid-column-start: wrapper-start;
} /* Grid 3 */
.grid--3 .grid__media { grid-column-start: start;
} /* Grid 4 */
.grid--4 .grid__media { grid-column: 8 / wrapper-end;
} .grid--4 .grid__text { grid-column-start: 3;
}

В чем разница? Для меня версия с переменными более читаема и помогает сразу понять, где расположены элементы каждого варианта компонента.

Переменные в медиа-запросах

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

.grid__media { grid-column: var(--mediaStart, wrapper-start) / var(--mediaEnd, 8);
} .grid__text { grid-column: var(--textStart, 8) / span var(--textSpan, 6);
} .grid--2,
.grid--4 { --mediaStart: 8; --mediaEnd: 14; --textStart: wrapper-start;
} /* Move to a more complex layout starting at 960px */
@media(min-width: 960px) { .grid { --mediaStart: wrapper-start; --mediaEnd: 9; --textStart: 10; --textSpan: 4; } .grid--2 { --mediaStart: 9; --mediaEnd: end; --textStart: wrapper-start; } .grid--2, .grid--4 { --mediaStart: 8; } .grid--3 { --mediaStart: start; } .grid--4 { --mediaEnd: wrapper-end; --textStart: 3; }
}

Вот полная демо-версия:

Производительность

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

Заключение

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

Автор: Michelle Barker

Источник: https://css-tricks.com/

Редакция: Команда webformyself.