CSS-only аккордеон: чекбоксы и радио

Аккордеоны (expandable/collapsible UI) часто применяются для меню, изображений, видео, FAQ, списков и выдержек из статей. Их можно реализовать с помощью HTML, CSS и JavaScript. Но в условиях, где JavaScript отключён или ограничен, полезно уметь создавать аккордеоны только на HTML/CSS.
В этом руководстве вы найдёте пошаговый разбор трёх подходов, рекомендации по стилям, доступности и анимации, а также чек-лист для разработки и тестирования.
Базовый аккордеон только на HTML
Если нужна простая и доступная реализация — используйте нативные теги . Браузеры и вспомогательные технологии корректно обрабатывают их: клавиши, фокус и поведение уже реализованы.
Пример структуры (локализовано на русский):
Вопрос 1
Пример ответа: Lorem ipsum dolor, sit amet consectetur adipisicing elit. Ratione adipisci illum error, hic expedita numquam impedit explicabo vitae iure quae vero autem quia quibusdam tempora atque harum perferendis praesentium dolor!
Вопрос 2
Пример ответа: Consequuntur earum pariatur dolorem repellat temporibus ducimus sunt suscipit repudiandae cupiditate in accusantium recusandae tempora sint eligendi...
Вопрос 3
Пример ответа: Tenetur, ex delectus, perferendis aperiam voluptatem consequuntur molestiae ratione rerum vitae ab modi...
Важно:
Стиль для
Можно стилизовать фон, отступы и радиусы:
body {
font-family:'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
max-width: 30rem;
margin: 1.5rem auto;
}
summary {
font-weight: 600;
color: rgb(255, 255, 255);
background-color: rgb(7, 185, 255);
padding: 1.2rem;
margin-bottom: 1.2rem;
border-radius: 0.5rem;
cursor: pointer;
}Вывод:

Ограничение: вы получаете меньше контроля над внутренней разметкой . Если нужно полностью кастомное поведение и визуал, используйте подход с input (checkbox/radio).
Кастомный FAQ: два популярных метода
Два распространённых метода для CSS-only аккордеона: checkbox-метод и radio-метод. Оба используют скрытые input’ы и CSS-селекторы соседей/атрибутов для управления состояниями.
Метод с checkbox (несколько секций могут быть открыты одновременно)
Идея: каждая секция содержит +
HTML (локализовано):
Кастомный аккордеон на CSS (FAQ)
Метод с checkbox
Lorem ipsum dolor sit amet consectetur adipisicing elit. Harum debitis voluptas aliquid tenetur quas suscipit assumenda a...
Temporibus vel dolore nam dolorem similique voluptatum. Aliquam, dolor et!
Общие CSS-настройки (базовые):
body {
color: #502c2c;
background: #f1edec;
padding: 1.2rem;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 45rem;
margin: 0 auto;
font-size: 1.2rem;
} Скрываем input и оформляем лейблы:
/* Скрытие чекбоксов/радио для кастомного UI */
input {
position: absolute;
opacity: 0;
z-index: -1;
}
/* Стили аккордеона */
.faq {
color: #ffe3e3;
margin-bottom: 3rem;
}
.faq-label {
font-size: 1.5rem;
display: flex;
align-items: center;
justify-content: space-between;
padding: 1em;
background: #b61818;
font-weight: bold;
cursor: pointer;
user-select: none;
}
.faq-label::after {
content: '\002B'; /* плюс */
padding: 0.51rem;
transform: scale(1.8);
text-align: center;
transition: all 0.35s;
}
.faq-content {
max-height: 0;
padding: 0 1em;
color: #2c3e50;
background: white;
transition: all 0.35s;
display: none;
}
/* Состояния при открытии */
input:checked + .faq-label {
background: #8f1414;
}
input:checked + .faq-label::after {
content: '\2013'; /* тире */
transform: scale(1.5);
}
input:checked ~ .faq-content {
max-height: 100vh;
padding: 1em;
display: block;
transition: all 0.35s;
}Вывод:
-using-Checkbox-Mehtod.jpg)
Метод с radio (только одна секция открыта)
Вариант похож по структуре, но input[type=”radio”] с общим атрибутом name позволяет открывать только одну секцию одновременно. Проблема: радио нельзя снять (uncheck) через клик, поэтому паттерн “Close all” реализуется отдельным radio без контента.
HTML (локализовано):
Кастомный аккордеон на CSS (FAQ)
Метод с radio
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Voluptatibus maiores quisquam...
Aperiam dolores autem odit, nihil eius sit minima quas laudantium...
Laudantium quibusdam laboriosam hic omnis quas ullam commodi rem...
CSS:
Используйте тот же базовый CSS, что и для checkbox-метода. Для кнопки “Закрыть все” можно добавить позиционирование:
.faq-label {
position: relative;
}
.faq-close {
display: inline-block;
padding: 1rem;
font-size: 1rem;
background: #b61818;
cursor: pointer;
position: absolute;
left: 64rem;
}Вывод:
-using-the-Radio-Method.jpg)
Анимации и плавное раскрытие
Проблема: transition с height: auto не работает напрямую. В этом примере мы использовали max-height: 0 → 100vh, что просто, но не идеально (резервирует большую высоту и может влиять на соседние элементы). Варианты:
- Использовать max-height с аккуратным значением, подходящим по контенту.
- Применять CSS-переменные и вычислять высоту через JavaScript (если JS разрешён).
- Использовать transform и scaleY(0→1) вместе с transform-origin: top; — подходит для простого контента, но может искажать текст.
- Использовать clip-path или mask для сложных эффектов.
Пример плавной анимации через transform:
.faq-content {
transform-origin: top;
transform: scaleY(0);
transition: transform 0.35s ease;
display: block;
height: auto;
overflow: hidden;
}
input:checked ~ .faq-content {
transform: scaleY(1);
}Доступность (A11y) — кратко и по делу
- /
— лучший с точки зрения доступности вариант, если он удовлетворяет требованиям дизайна.
- Для кастомных input-лейблов: не удаляйте визуальные фокусы. Сделайте видимый outline для :focus-visible у label.
- Добавьте aria-expanded=”true/false” на элемент, который управляет видимостью, если вы реализуете полностью кастомное взаимодействие (сценарии без ). В чистом CSS это можно имитировать с помощью атрибутов, но помните, что aria-* рекомендуется обновлять через JS.
- Обеспечьте управление с клавиатуры: таб, Enter и пробел для открытия/закрытия. /
уже поддерживают это.
Пример фокуса:
.faq-label:focus-visible {
outline: 3px solid rgba(255,255,255,0.6);
outline-offset: 3px;
}Когда CSS-only аккордеон не подойдёт
- Нужно сложное динамическое поведение (ленивая загрузка контента при открытии, подсчёт высот, прокрутка к элементу, аналитика кликов) — лучше использовать JavaScript.
- Необходима точная анимация высоты для произвольного содержимого без компромиссов — JS решает это надёжнее.
- Если требуется поддержка устаревших браузеров без полифиллов для CSS-селекторов — учтите совместимость.
Альтернативы и расширения
- Использовать библиотеки UI (Bootstrap Collapse, Headless UI, ARIA patterns) когда проект допускает JS.
- Комбинировать с CSS-переворотами и иконками для простого, доступного решения.
- Для изображений — горизонтальные аккордеоны (side-by-side) с transform и width/translate анимациями.
Чек-лист разработчика перед публикацией
- Проверить поведение без JavaScript (если это критично).
- Протестировать на клавиатуре: Tab, Enter, Space, стрелки (при необходимости).
- Проверить на VoiceOver/NVDA/JAWS для корректного чтения (особенно кастомные элементы).
- Убедиться, что цветовая контрастность заголовков и фона отвечает стандартам.
- Тест: открыть/закрыть несколько раз, проверить на медленных устройствах.
Критерии приёмки
- Все секции корректно открываются/закрываются клавиатурой и мышью.
- Содержимое не обрезается и не перекрывается соседями при раскрытии.
- Контрастность и индикаторы фокуса соответствуют требованиям доступности.
- Нет визуального «дерганья» при анимациях на основных устройствах.
Мини-методология для выбора варианта
- Нужна ли полная доступность «из коробки»? → да → используйте .
- Требуется ли кастомный вид/иконки/несколько открытых секций? → да → checkbox.
- Нужна ли гарантия, что только одна секция открыта? → radio.
- Понадобятся ли дополнительные взаимодействия (AJAX, аналитика)? → добавить JS.
Тестовые сценарии (коротко)
- Открыть одну секцию и проверить видимость контента.
- Открыть несколько секций (для checkbox) и убедиться, что соседние не закрываются.
- Для radio: открыть секцию, затем другую — предыдущая должна закрыться.
- Проверить стили при фокусе и скринридере.
Итог
CSS-only аккордеоны — надёжный инструмент для простых сценариев, особенно когда нужна доступность и отказоустойчивость без JavaScript. Выбор между
Важно: если проект требует динамики, аналитики или сложных анимаций — комбинируйте CSS-решение с лёгким JavaScript-слоем.