CSS псевдокласс :indeterminate
Псевдокласс CSS :indeterminate выбирает элементы в неопределённом состоянии. Узнайте о псевдоклассе и попрактикуйтесь на примерах.
Псевдокласс CSS :indeterminate соответствует элементам управления формой, находящимся в неопределённом состоянии — третьем состоянии, которое не является ни «включённым», ни «выключённым». В этой главе объясняется, какие элементы могут переходить в это состояние, как его вызвать и как стилизовать, с работающими примерами для чекбоксов, групп радиокнопок и полос прогресса.
Что означает «indeterminate»
Некоторые элементы управления формой обычно имеют два состояния (отмечено / не отмечено или известное значение прогресса). Неопределённое состояние представляет собой третье «нерешённое» условие. Псевдокласс :indeterminate применяется к трём видам элементов:
- Чекбоксы (
<input type="checkbox">), у которых DOM-свойствоindeterminateустановлено вtrue. Это классический трёхсостояний чекбокс «некоторые, но не все дочерние элементы выбраны». - Радиокнопки (
<input type="radio">) — каждая кнопка в группе с одним именем совпадает, пока ни одна опция в этой группе не выбрана. - Полосы прогресса (
<progress>), у которых отсутствует атрибутvalue, что означает неизвестную длину задачи, поэтому полоса анимируется без фиксированного заполнения.
Неопределённое состояние устанавливается через JavaScript, а не CSS — войти в него с помощью CSS-правила невозможно. Для чекбоксов устанавливается element.indeterminate = true через JavaScript. Установка этого свойства не изменяет checked; эти два свойства независимы. Визуальный вид неопределённого состояния (обычно тире вместо галочки) и совпадение с :checked — это разные вещи. Сброс формы через form.reset() очищает флаг indeterminate чекбокса обратно в false.
Псевдокласс :checked стилизует отмеченное состояние, тогда как :indeterminate стилизует нерешённое состояние. Элемент управления может находиться в одном, другом или ни в каком состоянии, но никогда в обоих одновременно. Можно комбинировать :indeterminate с другими псевдоклассами, например :hover, чтобы стилизовать неопределённый элемент только при наведении указателя, или с :focus, чтобы выделить его при получении фокуса с клавиатуры.
Синтаксис
:indeterminate {
/* css declarations */
}Ограничьте селектор конкретным типом элемента, чтобы избежать нежелательных совпадений:
/* Only checkboxes */
input[type="checkbox"]:indeterminate { outline: 2px dashed orange; }
/* Only radio buttons */
input[type="radio"]:indeterminate { opacity: 0.7; }
/* Only progress bars */
progress:indeterminate { opacity: 0.5; }Также можно инвертировать совпадение с помощью :not, чтобы нацелиться на элементы управления, покинувшие неопределённое состояние:
/* Style a progress bar once it has a known value */
progress:not(:indeterminate) { border: 2px solid green; }Пример: стилизация неопределённого чекбокса
Чекбокс становится неопределённым только тогда, когда JavaScript устанавливает свойство indeterminate в true. CSS-правило срабатывает в момент установки этого свойства и снимается в момент, когда оно устанавливается обратно в false. В этом примере элемент управления выделяется цветной тенью box-shadow.
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
input:indeterminate {
box-shadow: 0 0 2px 2px #666;
}
</style>
</head>
<body>
<h2>Indeterminate selector example</h2>
<form>
<input type="checkbox" id="box" /> Checkbox
<script>
var checkbox = document.getElementById("box");
checkbox.indeterminate = true;
</script>
</form>
</body>
</html>Распространённый случай использования: трёхсостояний чекбокс «выбрать всё»
Наиболее практичное применение :indeterminate — главный чекбокс, суммирующий список опций: отмечен, когда выбраны все дочерние элементы, снят, когда не выбран ни один, и в неопределённом состоянии, когда выбраны некоторые. Этот паттерн распространён в файловых менеджерах, почтовых клиентах и таблицах данных.
Логика JavaScript синхронизирует свойства indeterminate и checked главного чекбокса с дочерними чекбоксами. CSS берёт на себя всё остальное.
<!DOCTYPE html>
<html>
<head>
<title>Tri-state checkbox</title>
<style>
/* Highlight master while in partial-selection state */
#all:indeterminate {
outline: 2px solid #8ebf42;
}
</style>
</head>
<body>
<label><input type="checkbox" id="all" /> Select all</label>
<ul>
<li><label><input type="checkbox" class="child" /> Apples</label></li>
<li><label><input type="checkbox" class="child" /> Bananas</label></li>
<li><label><input type="checkbox" class="child" /> Cherries</label></li>
</ul>
<script>
var all = document.getElementById("all");
var children = document.querySelectorAll(".child");
function syncParent() {
var checked = [...children].filter(function (c) { return c.checked; }).length;
all.checked = checked === children.length;
all.indeterminate = checked > 0 && checked < children.length;
}
all.addEventListener("change", function () {
children.forEach(function (c) { c.checked = all.checked; });
});
children.forEach(function (c) {
c.addEventListener("change", syncParent);
});
syncParent();
</script>
</body>
</html>Отметьте один из дочерних чекбоксов: чекбокс «Select all» переходит в неопределённое состояние и появляется зелёная рамка. Отметьте все три: рамка исчезает, и он переключается в полностью отмеченное состояние.
Пример: неопределённая группа радиокнопок
Группа радиокнопок находится в неопределённом состоянии, пока ни одна из её опций не выбрана. Псевдокласс :indeterminate соответствует каждому <input type="radio"> в группе, пока пользователь не выберет ответ. Как только выбрана любая опция, вся группа покидает неопределённое состояние и стилизация снимается.
Это полезно для побуждения пользователей сделать выбор — например, можно использовать это в валидации формы вместе с :invalid и :valid, чтобы визуально направлять пользователей к неотвеченным обязательным вопросам.
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
label {
margin-right: .5em;
position: relative;
top: 1px;
}
input[type="radio"]:indeterminate + label {
color: #8ebf42;
}
</style>
</head>
<body>
<h2>:indeterminate selector example</h2>
<form>
<input type="radio" name="option" value="yes" id="yes" />
<label for="yes">Yes</label>
<input type="radio" name="option" value="no" id="no" />
<label for="no">No</label>
<input type="radio" name="option" value="dont-know" id="dont-know" />
<label for="dont-know">Don’t know</label>
</form>
</body>
</html>Пример: неопределённая полоса прогресса
Элемент <progress> без атрибута value не имеет известного процента завершения, поэтому он соответствует :indeterminate. Браузеры по умолчанию отображают анимированную полосу «выполняется». Добавление атрибута value (и, опционально, max) переводит элемент в определённое состояние, и CSS-правило больше не применяется.
<!DOCTYPE html>
<html>
<head>
<title>Indeterminate progress</title>
<style>
progress:indeterminate {
opacity: 0.6;
width: 200px;
}
/* Once a value is set, show a green accent */
progress:not(:indeterminate) {
accent-color: #2a9d8f;
width: 200px;
}
</style>
</head>
<body>
<p>Indeterminate (no value): <progress></progress></p>
<p>Determinate (value set): <progress value="60" max="100"></progress></p>
</body>
</html>Свойство accent-color управляет цветом заливки <progress> в браузерах, которые его поддерживают (Chrome 93+, Firefox 92+, Safari 15.4+). Для поддержки старых браузеров может потребоваться использование псевдоэлементов с вендорными префиксами, таких как ::-webkit-progress-bar и ::-moz-progress-bar, однако они не являются частью стандартной спецификации CSS.
Комбинирование с другими псевдоклассами
:indeterminate можно объединять с другими псевдоклассами состояния для построения точных селекторов:
/* Indeterminate checkbox that is also focused */
input[type="checkbox"]:indeterminate:focus {
outline: 3px solid royalblue;
}
/* Indeterminate and disabled checkbox — show a muted style */
input[type="checkbox"]:indeterminate:disabled {
opacity: 0.4;
cursor: not-allowed;
}Подробнее о псевдоклассах :focus, :disabled и :enabled читайте в соответствующих разделах.
Доступность
Флаг неопределённого состояния является чисто визуальным на уровне CSS; он не изменяет значение, отправляемое вместе с формой. Трёхсостояний чекбокс по-прежнему отправляется как отмеченный или неотмеченный, в зависимости от текущего состояния checked.
Для вспомогательных технологий необходимо явно сообщать о третьем состоянии с помощью атрибута aria-checked="mixed" на главном элементе управления. Без него программы чтения с экрана объявляют элемент управления просто как отмеченный или неотмеченный, и пользователи, полагающиеся на вспомогательные технологии, не узнают о значении частичного выбора.
<!-- Accessible tri-state master checkbox -->
<input
type="checkbox"
id="all"
aria-checked="mixed"
aria-label="Select all items"
/>Держите aria-checked в синхронизации со свойством indeterminate в вашем JavaScript:
function syncParent() {
var checked = [...children].filter(function (c) { return c.checked; }).length;
if (checked === 0) {
all.indeterminate = false;
all.checked = false;
all.setAttribute("aria-checked", "false");
} else if (checked === children.length) {
all.indeterminate = false;
all.checked = true;
all.setAttribute("aria-checked", "true");
} else {
all.indeterminate = true;
all.checked = false;
all.setAttribute("aria-checked", "mixed");
}
}Для групп радиокнопок :required, в которых ни одна опция не выбрана, рассмотрите также использование aria-required="true" на каждом элементе input, чтобы вспомогательные технологии могли идентифицировать неотвеченную группу.
Поддержка браузеров
Псевдокласс :indeterminate поддерживается во всех современных браузерах (Chrome, Edge, Firefox, Safari). Все три типа элементов — чекбоксы, группы радиокнопок и полосы прогресса — поддерживаются в актуальных версиях браузеров.
| Элемент | Примечания |
|---|---|
input[type="checkbox"]:indeterminate | Поддерживается во всех современных браузерах. Требует JavaScript для установки свойства indeterminate. |
input[type="radio"]:indeterminate | Поддерживается во всех современных браузерах. Применяется автоматически, пока пользователь не выберет опцию. |
progress:indeterminate | Поддерживается во всех современных браузерах. Применяется автоматически при отсутствии атрибута value. |