Более доступная разметка с display:contents

Более доступная разметка с display:contents

Tolia
Новости Скрипт Шаблон

Перевод статьи More accessible markup with display: contents с сайта hiddedevries.nl для css-live.ru, автор — Хидде де Врис

CSS-гриды (CSS Grid Layout) позволяют превратить элемент в грид (сетку) и располагать по нему непосредственных потомков («детей») этого элемента. С учетом этого бывает соблазн использовать более «плоскую», однородную разметку, но чем менее разметка осмысленна, тем хуже обычно ее доступность. C display:contents можно размещать в гриде «внуков», благодаря чему у нас могут быть и доступная разметка, и красивая верстка. Давайте разберемся в этом подробнее!

Ниже я более подробно поясню, что я имею в виду под «детьми» и «внуками», а затем покажу, как можно улучшить дело с помощью display:contents. Примечание: в браузерах это пока работает неправильно, подробности ниже.

Грид работает для непосредственных «детей»

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

<div class=»container»>
<h1 class=»item»>Пенне с томатным соусом</h1>
<p class=»item»>Для этого простого рецепта нужно немного ингредиентов, но вкус будет восхитительным.</p>
<div class=»item ingredients»>
<h2>Вам понадобятся</h2>
<ul>
<li>консервированные помидоры</li>
<li>лук</li>
<li>чеснок</li>
</ul>
</div>
</div>

CSS может быть таким:

.container {
display: grid; /* элемент будет грид-контейнером */
grid-template-columns: repeat( 4, 1fr ); /* у грида будет 4 колонки */
}
.item:nth-child(1) {
grid-columns: 1 / 2; /* Поместим элемент между грид-линиями 1 и 2 */
}

.item:nth-child(2) {
grid-columns: 2 / 4; /* Поместим элемент между грид-линиями 2 и 4 */
}

.item:nth-child(3) {
grid-columns: 4 / 5; /* Поместим элемент между линиями 4 и 5 */
}

Я назвал классы .container и .item, поскольку это ключевые понятия грид-раскладки: есть грид-контейнеры и грид-элементы. Разумеется, можно использовать любую систему именования, какую требует ваш проект.

Причина, по которой мы можем разместить эти элементы в гриде — то, что они непосредственные дочерние элементы («дети») грид-контейнера. Но посмотрите, что будет, если мы решим добавить список спонсоров, например, так:

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

<div class=»container»>
<h1 class=»item»>Пенне с томатным соусом</h1>
<p class=»item»>Для этого простого рецепта нужно немного ингредиентов, но вкус будет восхитительным.</p>
<div class=»item ingredients»>
<h2>Вам понадобятся</h2>
<ul>
<li>консервированные помидоры</li>
<li>лук</li>
<li>чеснок</li>
</ul>
</div>
<ul class=»item sponsors»>
<li>Супермаркет 1</li>
<li>Супермаркет 2</li>
</ul>
</div>

Но мы не сможем расположить по гриду каждого спонсора. Это из-за того, что непосредственный потомок элемента-контейнера, а значит, и грид-элемент, у нас только <ul>. А элементы <li> в нем — уже нет: они не ближайшие потомки нашего грид-контейнера и не участвуют в его играх с сеткой. Но что если мы во что бы то ни стало хотим выровнять спонсоров по нашей сетке?

Более плоская разметка

Один очевидный способ включить спонсоров в грид-раскладку — убрать <ul> и использовать для каждого спонсора по <div>-у. Но тем самым мы «сплющим» нашу разметку в плоскую структуру. Так мы вместе с водой выплескиваем и ребенка.

От элемента <ul> (неупорядоченного списка) достаточно пользы:

  • он остается списком вне контекста нашей страницы, например, в «режиме чтения» Safari он будет показан как список
  • он будет показан как список при печати с выключенными стилями
  • он будет списком для пользователей скринридеров (скринридеры умеют сообщать информацию наподобие «список, 3 пункта»).

Сделав разметку более плоской, мы лишимся этих преимуществ.

display: contents спешит на помощь

C display: contents можно сохранить и нашу разметку, и наше размещение по гриду. Это свойство заставляет элемент делать вид, будто его нет. Он не генерирует CSS-бокса (прямоугольной области в визуальной структуре страницы), так что фоны, рамки и другие свойства для этой области для него больше не работают. Но все эти свойства работают для потомков этого элемента. Спецификация гласит, что элемент ведет себя «как если бы его заменили … его содержимым». Если это звучит странно, рекомендую подробное объяснение Ире Адеринокун (а также нашу статью тех времен, когда это свойство только-только появилось — прим. перев.).

Фактически, для наших целей в рамках статьи, display: contents делает с элементом следующее: элемент перестает участвовать в грид-раскладке, а его содержимое начинает в ней участвовать. Это позволяет нам привязать к гриду самих спонсоров, а не список, в котором они содержатся.

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

Проблемы с доступностью у теперешних реализаций display: contents в браузерах

Для людей, пользующихся вспомогательными технологиями (англ. assistive technologies, сокращенно AT), браузеры раскрывают специальные свойства доступности, включая роли элементов на странице (атрибут role). Тем самым их AT знают, где что на странице. У многих элементов изначально есть встроенное значение role, например, у списков — роль list (список).

Здесь-то теперешние браузеры с поддержкой display: contents и сплоховали. Они воспринимают display: contents не как что-то чисто для раскладки, а пытаются додумывать смысл по нему. Это проблема и баг, исходя из примечания в спецификации о влиянии display на раскладку:

0
Авторизация
*
*

12 − 11 =

Регистрация
*
*
*
Пароль не введен
*

7 − 3 =

Генерация пароля

10 − четыре =