Коротко: изменить внешний вид радиокнопки (input type="radio") напрямую почти нельзя — браузер рисует её сам. Рабочий приём: скрыть нативный input (appearance: none или opacity: 0) и нарисовать свой вид через label или псевдоэлемент ::before. Важно сохранить доступность: связь label + input и фокус с клавиатуры.
Почему нельзя стилизовать напрямую
| Свойство | Результат |
|---|---|
background |
часто игнорируется |
border |
работает нестабильно |
width/height |
ограниченно |
appearance: none |
убирает системный вид — база для своей стилизации |
Вкладки: способы оформления
.radio {
appearance: none;
width: 20px; height: 20px;
border: 2px solid #ccc;
border-radius: 50%;
display: inline-grid;
place-content: center;
}
.radio:checked { border-color: #003F8F; }
.radio:checked::before {
content: "";
width: 10px; height: 10px;
border-radius: 50%;
background: #003F8F;
}Самый чистый способ: input остаётся настоящим (доступность сохраняется), а вид рисуют border и псевдоэлемент.
.opt { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.opt input { accent-color: #003F8F; }Самый быстрый путь: свойство accent-color перекрашивает стандартную радиокнопку в цвет бренда. Ничего скрывать не нужно — минимум кода.
.opt input { position: absolute; opacity: 0; }
.opt span::before {
content: "";
display: inline-block;
width: 18px; height: 18px;
border: 2px solid #bbb;
border-radius: 50%;
margin-right: 8px;
vertical-align: -4px;
}
.opt input:checked + span::before {
background: radial-gradient(#003F8F 45%, #fff 46%);
border-color: #003F8F;
}Нативный input скрыт, но остаётся в разметке: клик по label его переключает. Вид рисует ::before у соседнего элемента.
.tariff input { position: absolute; opacity: 0; }
.tariff span { display: block; border: 2px solid #eee; border-radius: 12px; padding: 16px; }
.tariff input:checked + span { border-color: #003F8F; box-shadow: 0 0 0 3px rgba(0,63,143,.12); }Так делают выбор тарифа «карточками»: выбранный вариант подсвечивается рамкой. Радиокнопка при этом скрыта — клик по всей карточке.
display: none, он пропадёт из навигации с клавиатуры. Скрывайте через opacity: 0 и абсолютное позиционирование — тогда стрелки и Tab работают.Правильная разметка
<label class="opt">
<input type="radio" name="plan" value="base">
<span>Базовый</span>
</label>Важно: label оборачивает input — тогда клик по тексту тоже выбирает вариант. У группы радиокнопок одинаковое name, тогда выбор будет взаимоисключающим.
Частые ошибки: причина → решение
| Симптом | Причина | Решение |
|---|---|---|
| Клик по тексту не работает | нет связи label и input | обернуть или использовать for |
| Не выбирается с клавиатуры | input скрыт через display: none |
скрывать через opacity: 0 |
| Стиль не применяется | правила на ::before у input |
рисовать у соседнего элемента |
| Можно выбрать несколько | разные name |
дать одинаковое name |
Проверьте себя
Вопросы и ответы
Одинаковое name объединяет их в группу: выбрать можно только один вариант. Разные name — независимые переключатели.
Radio — выбор одного из нескольких. Checkbox — независимые галочки, можно отметить несколько. Оформляют их схожими приёмами.
Да, при своей стилизации уберите border-radius: 50%. Но учтите: пользователи привыкли к круглой форме, это снижает узнаваемость.
Через input:focus-visible + span задайте обводку или тень. Это важно для навигации с клавиатуры.
Итоги
- Нативный radio стилизуется плохо; база —
appearance: none. - Быстрый путь —
accent-color, гибкий — свой вид через::before. - Скрывайте input через
opacity: 0, а неdisplay: none. - Связь
label+inputобязательна для клика и доступности.

Комментарии
Пока комментариев нет — будьте первым, кто поделится мнением.