Стилизация пустых ячеек с помощью сгенерированного содержимого и макета сетки CSS

Опубликовано: 2022-03-10
Краткое резюме ↬ Вы когда-нибудь задумывались, как добиться стиля пустых ячеек сетки, не добавляя лишних пустых элементов? Что ж, сгенерированный с помощью CSS контент может помочь вам в этом.

Распространенная ошибка Grid Layout — это когда новичок в методе макета задается вопросом, как оформить ячейку сетки, которая не содержит никакого содержимого. В текущей спецификации уровня 1 это невозможно, так как нет способа настроить таргетинг на пустую ячейку или область сетки и применить стиль. Это означает, что для применения стиля вам нужно вставить элемент.

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

Пристальный взгляд на BFC

Если вы когда-либо делали макет с помощью CSS, вы, вероятно, знаете, что такое BFC. Понимание того, почему это работает и как его создать, полезно и может помочь вам понять, как макет работает в CSS. Читать статью по теме →

Почему мы уже не можем стилизовать пустые области?

В первом абзаце Спецификации сети говорится:

«Этот модуль CSS определяет двухмерную систему компоновки на основе сетки, оптимизированную для дизайна пользовательского интерфейса. В модели компоновки сетки дочерние элементы контейнера сетки могут быть расположены в произвольных слотах в предопределенной гибкой сетке макета или сетке фиксированного размера».

Ключевая фраза здесь — «потомки грид-контейнера». Спецификация определяет создание сетки на родительском элементе, в которую могут быть помещены дочерние элементы. Он не определяет какой-либо стиль этой сетки, даже не реализуя что-то вроде свойства column-rule которое у нас есть в многоколоночном макете. Мы стилизуем дочерние элементы, а не саму сетку, поэтому нам нужно иметь какой-то элемент, к которому можно применить этот стиль.

Еще после прыжка! Продолжить чтение ниже ↓

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

Один из способов вставить что-то в стиль — вставить в документ лишний элемент, например, span или div. Разработчикам, как правило, не нравится эта идея, несмотря на то, что они годами добавляли дополнительные избыточные «обертки строк», чтобы добиться макетов сетки с использованием плавающих элементов. Возможно, этот очевидно пустой элемент более неприятный, чем несколько скрытая избыточность элемента-обертки!

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

Посмотрите, как пустые элементы пера становятся элементами сетки от Рэйчел Эндрю (@rachelandrew) на CodePen.

Посмотрите, как пустые элементы пера становятся элементами сетки от Рэйчел Эндрю (@rachelandrew) на CodePen.

Эрик Мейер в своей статье A List Apart Faux Grid Tracks выступает за использование элемента b в качестве избыточного элемента выбора, поскольку он не имеет семантического значения, является коротким, а также довольно очевидным в разметке в качестве крючка.

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

Использование сгенерированного контента в качестве крючка для стиля

Генерируемый CSS контент использует псевдоклассы CSS ::before и ::after вместе со свойством content для вставки контента в документ. Идея вставки содержимого может привести вас к мысли, что это для вставки текста, и хотя это возможно, для наших целей мы заинтересованы во вставке пустого элемента в качестве прямого дочернего элемента нашего контейнера сетки. Вставив элемент, мы можем стилизовать его.

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

 <div class="grid"> <div class="item"></div> </div>
 .grid { display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; grid-gap: 10px; } .grid > * { border: 2px solid rgb(137,153,175); } .item { grid-column: 2; grid-row: 2; }

Если мы посмотрим на этот пример, используя Инспектор сетки Firefox для наложения линий сетки, мы увидим, как существуют другие пустые ячейки сетки, однако, чтобы добавить к ним фон или границу, нам потребуется добавить дополнительные дочерние элементы. элементы. Это именно то, что позволяет сгенерированный контент.

Один элемент в центральной ячейке сетки
Один элемент сетки с дорожками, выделенными с помощью инспектора сетки Firefox.

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

 .grid::before { content: ""; background-color: rgb(214,232,182); grid-column: 3; grid-row: 1; } .grid::after { content: ""; background-color: rgb(214,232,182); grid-column: 1; grid-row: 3; } 
Один элемент в центральной ячейке сетки с двумя зелеными элементами по углам.
Один элемент сетки и два элемента, которые генерируют контент

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

Ограничения подхода сгенерированного контента

Очевидная проблема с этим подходом станет очевидной, если вы решите также стилизовать верхнюю правую и нижнюю левую ячейки сетки. Вы можете применить только одну часть сгенерированного содержимого к верхней части и одну к нижней части контейнера, несколько ::before и ::after не допускаются. Этот метод не сработает, если вы хотите создать шахматную доску CSS Grid! Если вы обнаружите, что вам нужно много стилизовать пустые ячейки, то в обозримом будущем подход «Filler B», описанный выше, вероятно, будет вашим лучшим выбором.

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

Необычные заголовки

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

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

Заголовок со строками по бокам, за которым следует текст
Стиль заголовка, которого мы хотим добиться

Наша разметка — это простой h1 .

 <h1>My heading</h1>

В правилах для h1 я создаю сетку из трех столбцов. Значение grid-template-columns дает дорожку 1fr затем одну дорожку auto и конечную дорожку 1fr . Две дорожки 1fr разделят доступное пространство, оставшееся после того, как заголовок занял место, необходимое для размещения внутри дорожки auto размера.

Я добавил свойство text-align со значением center , чтобы мой заголовок вводился в браузерах без сетки.

 h1 { text-align: center; display: grid; grid-template-columns: 1fr auto 1fr; grid-gap: 20px; }

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

Сама линия является границей сгенерированного элемента.

 @supports (display: grid) { h1:before, h1:after { content: ""; align-self: center; border-top: 1px solid #999; } }

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

См. пример заголовка Pen Generated Content от Rachel Andrew (@rachelandrew) на CodePen.

См. пример заголовка Pen Generated Content от Rachel Andrew (@rachelandrew) на CodePen.

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

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

Добавление фона и границ к областям вашего дизайна

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

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

Макет в один столбец с изображением во всю ширину
Планировка, к которой мы стремимся

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

 <article class="grid"> <section class="section1"> <p>…</p> </section> <div class="full-width"> <img src=“placeholder.jpg” alt=“Placeholder”> </div> <section class="section2"> <p>…</p> </section> </article>
 .grid { display: grid; grid-template-columns: 1fr 20px 4fr 20px 1fr; grid-template-rows: auto 300px auto; grid-row-gap: 1em; } .section1 { grid-column: 3; grid-row: 1; } .section2 { grid-column: 3; grid-row: 3; } .full-width { grid-column: 1 / -1; grid-row: 2; background-color: rgba(214,232,182,.5); padding: 20px 0; }

Это дает мне макет с полноразмерным изображением и двумя размещенными секциями контента; однако, если я добавлю фон к разделам, он остановится над промежутком между row-gap между section и полноразмерным изображением.

 .section { background-color: rgba(214,232,182,.3); border: 5px solid rgb(214,232,182); } 
Макет в один столбец с изображением во всю ширину, цвет фона за областями содержимого
Фон теперь находится за областями содержимого

Если бы мы удалили grid-row-gap и использовали padding для создания пространства, это все равно не включило бы эффект фона, бегущего под панелью во всю ширину.

Здесь мы можем использовать сгенерированный контент. Я добавляю сгенерированный контент ::before контейнером сетки и задаю ему цвет фона. Если я ничего не сделаю, это поместит содержимое в первую ячейку сетки.

 .grid::before { content: ""; background-color: rgba(214,232,182,.3); border: 5px solid rgb(214,232,182); } 
Квадрат цвета в верхнем левом углу макета
Сгенерированный контент помещается в первую пустую ячейку сетки.

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

 .grid::before { content: ""; background-color: rgba(214,232,182,.3); border: 5px solid rgb(214,232,182); grid-column: 2 / 5; grid-row: 1 / 4; }

Вы можете увидеть полный пример в этом CodePen.

См. пример фона Pen Generated Content от Рэйчел Эндрю (@rachelandrew) на CodePen.

См. пример фона Pen Generated Content от Рэйчел Эндрю (@rachelandrew) на CodePen.

Управление стеком с помощью z-index

В приведенном выше примере сгенерированное содержимое вставляется с помощью ::before . Это означает, что другие элементы следуют за ним, он находится внизу стека и поэтому будет отображаться за остальным контентом, где я этого хочу. Вы также можете использовать z-index для управления стеком. Попробуйте изменить селектор ::before на ::after . Сгенерированный фон контента теперь находится поверх всего, как вы можете видеть по тому, как граница проходит по изображению. Это потому, что теперь он стал последним в контейнере сетки, он рисуется последним и поэтому отображается «сверху».

Чтобы изменить это, вам нужно присвоить этому элементу более низкое свойство z-index чем всему остальному. Если ничто другое не имеет значения z-index , самое простое, что можно сделать, это присвоить сгенерированному контенту z-index -1 . Это приведет к тому, что он будет первым в стеке, как элемент с наименьшим z-index .

 .grid::after { z-index: -1; content: ""; background-color: rgba(214,232,182,.3); border: 5px solid rgb(214,232,182); grid-column: 2 / 5; grid-row: 1 / 4; }

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

Это что-то, что спецификация может решить в будущем?

Добавление фона и границ кажется отсутствующей функцией спецификации CSS Grid, которую рабочая группа обсуждала вместе со многими членами сообщества (тема обсуждения находится на GitHub).

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

Больше примеров, пожалуйста!

Если эта статья побуждает вас экспериментировать со сгенерированным контентом или, если у вас уже есть пример, добавьте его в комментарии. Все новичок в использовании Grid в продакшене, так что есть много: « Я никогда не думал об этом! моментов, когда мы комбинируем Grid с другими методами компоновки.