Подсетки в Grid Layout жизненно важны

Перевод статьи Subgrids Considered Essential с сайта meyerweb.com для css-live.ru. Автор — Эрик Мейер.

Модуль Grid layout — невероятно фантастическая штука. Я познакомился с ним подробно во время написания главы про грид-раскладку в четвёртом издании своей книги «CSS: полное руководство», и он позволяет вытворять с раскладками такое, что нам даже не снилось. И, кажется, я понял одну недостающую деталь — мощь и необходимость подсеток.

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

<form method="post" action="script.cgi">
  <ul>
    <li><label for=name>Name:</label>
        <input id=name name=name></li>
    <li><label for=email>Email:</label>
        <input id=email name=email type=email></li>
    <li><label for=tel>Telephone:</label> 
        <input id=tel name=tel type=tel></li>
    <li><label for=url>Homepage:</label>
        <input id=url name=url type=url></li>
    <li><label for=bday>Birthday:</label>
        <input id=bday name=bday type=date></li>
  </ul>
</form>

grid-vs-subgrid-fig1

Обычная форма без сеток.

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

Этот пример отлично подходит для грид-раскладки, правда, есть загвоздка. Поскольку грид-элементы — всегда дочерние элементы грид-контейнера, нельзя просто применить грид к элементу ul и плясать от него. Поэтому приходится делать каждый элемент li грид-контейнером, чтобы элементы label и input из каждой пары стали грид-элементами. А это значит, что грид каждого элемента списка влияет на своих потомков, не обращая внимания на гриды других элементов списка. Можно написать нужный шаблон, например, такой:

form ul li {display: grid;
  grid-template-columns: [start label] max-content [input] 1fr [end];}

grid-vs-subgrid-fig2

Каждый элемент списка грид, но что нам это даст?

Результат почти такой же, как если бы мы не использовали гриды вовсе. Единственная разница — ширина всех элементов input соответствует ширине их колонок, согласно спецификации CSS Grid. Chrome не справился с этим последним пунктом, а в Firefox Nightly всё хорошо, но в целом суть та же. Можно посмотреть пример #form1 на тестовой странице. (Помните, чтобы вам было понятнее, о чём я, у вас должен быть браузер с поддержкой текущей спецификации гридов).

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

form ul li {display: grid;
  grid-template-columns: [start label] 7em [input] 1fr [end];}

grid-vs-subgrid-fig3

Использование колонки фиксированной ширины для имитации одной колонки.

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

Но что, если сначала сделать гридом элемент ul, а после сделать гридами все элементы li, которые будут использовать грид родительского элемента для раскладки своих потомков? Именно это и делают подсетки. Это решение мы и искали.

form ul {display: grid;
  grid-template-columns: [start label] max-content [input] 1fr [end];}
form ul li {display: grid; grid: subgrid; grid-column: start / end;}

Тут элементы списка устанавливают грид-контейнеры, делая таким образом элементы label and input грид-элементами, как и прежде, но растягиваются на ширину двух колонок ul, используя те же грид-линии для выкладывания своих дочерних элементов, плюс эти элементы влияют на размещение грид-линий своего прародителя. Поэтому можно указать что-то вроде max-content для размера колонки с меткой — и дело в шляпе.

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

Наверняка подсетки могут еще много где пригодиться. Допустим, нам надо создать грид для целой страницы, такой, в котором грид-линии во множестве повторялись бы через равные промежутки, и к ним можно было бы привязывать разные элементы — вроде этого или этого. Если бы при этом можно было бы назначить каждому разделу страницы подсетку, внутренние элементы каждого раздела могли бы участвовать в общем гриде страницы и располагаться относительно него же. Без подсеток вам остается либо делать каждый размещаемый элемент непосредственным потомком body (или на чем там у вас сделан главный грид), либо заново воспроизводить структуру внешнего грида в каждом из вложенных гридов — и тогда прощай колонки, подстраивающие ширину под содержимое из разных разделов. Ни то, ни другое решение не радует.

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

Как правило, мы привыкли усваивать технологию по первой (ещё сырой) реализации, изучая ее от и до и находя хаки на каждое ее ограничение, а затем игнорировать любые улучшения, если нас не ткнут в них носом. Если в реализации грид-раскладки не найдётся места для подсеток, мы рискуем надолго запихнуть их глубоко в дальний чулан для разработческого инвентаря. А вместе с ними, не исключено, и сами гриды. Разработчики быстро разочаруются, попытавшись выстроить мало-мальски сложную раскладку без подсеток, в результате чего они забросят гриды после первых же проб, не увидев в них серьезного инструмента.

Первое впечатление крайне важно. У дизайнеров и так годами складывалось не лучшее впечатление о CSS из-за «скучных, угловатых» раскладок времен его молодости, и его до сих пор сковывает то, что он остается системой оформления без встроенного механизма раскладки. За последние два десятилетия Grid layout — первый серьёзный кандидат на эту роль, и мне не хочется, чтобы он с самого начала оказался калекой. Подсетки — обязательный атрибут гридов. Надеюсь, что их реализуют как можно скорее, и прежде чем поддержка гридов перестанет быть экспериментальной.

P.S. Это тоже может быть интересно:

2 Комментарии

  1. Артём

    К счастью, display: contents; решает проблему в Firefox.
    Пример

    1. SelenIT

      В этой задаче — да (display: contents вообще полезная штука:). Но всё-таки бывают ситуации, где его недостаточно (пример с магазином отсюда).

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Получать новые комментарии по электронной почте. Вы можете подписаться без комментирования.