Visibility
Управление видимостью: display, visibility, overflow по осям, доступность для скринридеров и адаптивное скрытие по брейкпоинтам.
Display-утилиты
| Класс | CSS | Назначение |
|---|---|---|
.gr-hidden | display: none | Полное скрытие элемента |
.gr-block | display: block | Блочный элемент |
.gr-inline | display: inline | Строчный элемент |
.gr-inline-block | display: inline-block | Строчно-блочный элемент |
Изменение в 0.8.0. .gr-flex-display
и .gr-grid-display из этого модуля удалены. Флекс- и
грид-контейнер включает ядро: .gr-flex,
.gr-inline-flex и .gr-grid — вместе с адаптивными
вариантами .gr-flex-md, .gr-grid-lg. Имена
расходились только из-за запрета пересечения классов между пакетами,
а смысл у них был один: .gr-grid в ядре существовал
с самого начала.
Видимость без изъятия из потока
| Класс | CSS | Отличие от .gr-hidden |
|---|---|---|
.gr-invisible | visibility: hidden | Место под элемент сохраняется, вёрстка не сдвигается |
.gr-visible | visibility: visible | Вернуть видимость |
Только для скринридера
.gr-sr-only убирает элемент с экрана, но оставляет его в дереве
доступности: текст озвучивается, хотя визуально его нет. Так подписывают
иконки-кнопки и поясняют ссылки «Подробнее».
<button>
<svg aria-hidden="true">…</svg>
<span class="gr-sr-only">Закрыть диалог</span>
</button>
Генерируемый CSS:
.gr-sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
Изменение в 0.7.0. Вместо устаревшего
clip: rect(0, 0, 0, 0) используется
clip-path: inset(50%) — результат тот же, свойство
действующее. Послабление для clip убрано и из конфигурации
stylelint.
Ссылка «к содержимому»
.gr-sr-only-focusable скрыт ровно до тех пор, пока его
не выбрали с клавиатуры: мышью его не видно, по Tab он появляется. Это
первая ссылка страницы, позволяющая пропустить навигацию.
<a class="gr-sr-only-focusable" href="#main">Перейти к содержимому</a>
Обратная операция — .gr-not-sr-only: возвращает в поток элемент,
скрытый таким образом на узких экранах.
Overflow-утилиты
Пять значений, каждое — по обеим осям сразу и по каждой отдельно.
clip отличается от hidden тем, что запрещает
прокрутку вообще, в том числе программную.
| Обе оси | По горизонтали | По вертикали |
|---|---|---|
.gr-overflow-auto | .gr-overflow-x-auto | .gr-overflow-y-auto |
.gr-overflow-hidden | .gr-overflow-x-hidden | .gr-overflow-y-hidden |
.gr-overflow-clip | .gr-overflow-x-clip | .gr-overflow-y-clip |
.gr-overflow-scroll | .gr-overflow-x-scroll | .gr-overflow-y-scroll |
.gr-overflow-visible | .gr-overflow-x-visible | .gr-overflow-y-visible |
<!-- широкая таблица прокручивается внутри себя, а не тянет страницу вбок -->
<div class="gr-overflow-x-auto">
<table>…</table>
</div>
Прокрутка внутри скруглённого блока
| Класс | CSS |
|---|---|
.gr-scroll-clip | clip-path: inset(0 round var(--gr-r, 0)) |
Полосу прокрутки движок рисует поверх собственного края элемента и по
border-radius не обрезает: у скруглённого блока
с overflow: auto она срезает углы, а если у блока есть рамка —
съедает и её нижнюю сторону. Свойство overflow тут бессильно:
оно обрезает содержимое, а не полосу самого элемента.
Приёма два, и выбор между ними — не вкусовой:
| Что за блок | Приём |
|---|---|
| Фон и скругление, рамки нет | .gr-scroll-clip — один класс, лишний узел не нужен |
| Есть рамка | Прокрутку вложить: рамка и радиус снаружи, overflow внутри |
Полоса срезала углы этого блока
Здесь та же полоса обрезана по радиусу
А здесь прокрутка внутри, и рамка цела
<!-- без рамки: хватает одного класса -->
<div class="gr-radius-4 gr-overflow-x-auto gr-scroll-clip">…</div>
<!-- с рамкой: рамка и радиус снаружи, прокрутка внутри -->
<div class="gr-radius-4 gr-overflow-hidden gr-border">
<p class="gr-overflow-x-auto gr-whitespace-nowrap">…</p>
</div>
Рамку .gr-scroll-clip не спасает. Полоса
рисуется поверх нижней границы своего элемента, и обрезка углов этого
не отменяет: скругление вернётся, а нижняя линия рамки так и останется
закрытой. Свойствами самого блока это не лечится — рамке нужен
отдельный узел снаружи прокрутки. Вложенность заодно обрезает полосу
по радиусу сама, обычным overflow: hidden.
Радиус берётся из --gr-r — той самой
переменной, которую публикуют утилиты со значением:
.gr-radius-4, .gr-radius-full и остальные
из каскада скруглений. У голого
.gr-radius своего значения нет — он читает переменную,
а не задаёт её, поэтому в паре с обрезкой нужен класс с числом.
Без --gr-r утилита не делает ничего: фолбэк 0
оставляет прямые углы прямыми, вместо того чтобы скруглить блок,
который скруглять не просили.
Вторая цена обрезки. clip-path режет всё,
что выходит за коробку элемента, — внешнюю тень и контур фокуса тоже.
Блоку с тенью нужна та же вложенность: тень на внешнем элементе,
прокрутка на внутреннем. Прокручиваемой области
с tabindex="0" контур фокуса возвращают отрицательным
outline-offset.
Адаптивное скрытие
Классы .gr-hidden-{sm,md,lg,xl} скрывают элемент начиная с указанного брейкпоинта.
Полезно для mobile-only / desktop-only элементов.
| Класс | Поведение |
|---|---|
.gr-hidden-sm | Скрыт на экранах ≥ 640px |
.gr-hidden-md | Скрыт на экранах ≥ 768px |
.gr-hidden-lg | Скрыт на экранах ≥ 1024px |
.gr-hidden-xl | Скрыт на экранах ≥ 1280px |
<div class="gr-hidden-sm">Виден только на мобильных</div>
<div class="gr-hidden-md">Скрыт на планшетах и шире</div>
<div class="gr-hidden-lg">Скрыт на десктопах</div>
Адаптивные display-классы
Кроме скрытия, доступны классы для принудительного изменения display на определённом брейкпоинте.
| Класс | Применение |
|---|---|
.gr-block-sm … .gr-block-xl | display: block от брейкпоинта |
.gr-inline-sm … .gr-inline-xl | display: inline от брейкпоинта |
.gr-inline-block-sm … .gr-inline-block-xl | display: inline-block от брейкпоинта |
.gr-flex-sm … .gr-grid-xl | display: flex / grid от брейкпоинта — ядро, не этот модуль |
<div class="gr-hidden gr-block-md">
Скрыт на мобильных, виден от 768px
</div>
Примеры использования
Видимость — это всегда «что и для кого»: элемент прячется от узкого экрана, но не от широкого; от глаз, но не от скринридера; от экрана, но не от принтера. Рецепты ниже — четыре самых частых расклада.
Мобильное меню
<nav>
<button class="gr-hidden-md">Меню (гамбургер)</button>
<div class="gr-hidden gr-block-md">
<ul role="list" class="gr-flex gr-gap">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
</div>
</nav>
Пара «скрыть + показать» собирается из классов этого модуля.
.gr-flex-md и .gr-grid-md живут в ядре, а слой
утилит объявлен позже ядра — рядом с .gr-hidden они
проигрывают, и элемент остаётся скрытым на любой ширине. Поэтому
флекс-ряд, появляющийся от брейкпоинта, оборачивается: снаружи —
.gr-hidden .gr-block-md, внутри — обычный
.gr-flex .gr-gap.
Второстепенное — только широкому экрану
Боковая колонка «Сейчас читают», декоративная иллюстрация, подробности
в строке заказа — то, без чего мобильный экран обойдётся. Пара
.gr-hidden .gr-block-lg (или .gr-flex-lg,
если блок — флекс) прячет элемент через display: до 1024px
он не занимает места вовсе, а не оставляет дыру, как оставила бы
.gr-invisible. Основной контент при этом один для всех
экранов — скрывается только дополнение.
<div class="gr-flex gr-gap">
<article class="gr-flex-1 gr-min-w-0">Статья — видна всем</article>
<aside class="gr-hidden gr-block-lg gr-w-1/4">Сейчас читают — только от 1024px</aside>
</div>
Статья
Видна на любой ширине и занимает всё освободившееся место.
Кнопки-иконки с невидимой подписью
Панель действий из одних пиктограмм экономит место, но кнопка без
текста нема для скринридера. Подпись кладётся внутрь кнопки
с .gr-sr-only: глазами её нет, в дереве доступности —
есть. Сами кнопки — .gr-btn .gr-btn-icon .gr-btn-ghost
из ui, ряд собирает флекс с мелким зазором.
<div class="gr-flex gr-gap-sm">
<button class="gr-btn gr-btn-icon gr-btn-ghost">✎<span class="gr-sr-only">Редактировать</span></button>
<button class="gr-btn gr-btn-icon gr-btn-ghost">⧉<span class="gr-sr-only">Дублировать</span></button>
<button class="gr-btn gr-btn-icon gr-btn-ghost gr-text-danger">✕<span class="gr-sr-only">Удалить</span></button>
</div>
.gr-sr-only-подписи — скринридеруСкрыть при печати
Страница заказа или статья на печати не нуждается в навигации, кнопках
и баннерах. Печатных утилит вроде .gr-print-hidden
в библиотеке нет намеренно — сценарий редкий и решается одним своим
правилом поверх любого класса или контейнера. Тени при печати библиотека
уже глушит сама — токены --gr-shadow-* обнуляются темой.
@media print {
.no-print { display: none; }
}
<nav class="no-print">…</nav>
<button class="gr-btn gr-btn-primary no-print">Оплатить</button>