Стилизация чекбоксов на CSS: кастомный checkbox своими руками

Стилизация чекбоксов на CSS: кастомный checkbox своими руками Полезное

Чекбокс (checkbox, флажок) — это элемент формы <input type="checkbox">, который хранит одно из двух состояний, отмечен или нет, и позволяет выбирать любое число опций из набора независимо друг от друга. Внешне это квадратное поле с галочкой; браузер рисует его по-своему, и чтобы вписать флажок в дизайн, вид переопределяют средствами CSS.

Ниже разберем, как связать чекбокс с подписью, быстро покрасить стандартный флажок свойством accent-color, полностью нарисовать свой через appearance: none, обработать состояния :checked, :hover, :focus и :disabled и не потерять при этом доступность. Все примеры — готовый HTML и CSS, который можно вставить в страницу и увидеть результат.

Чекбокс, радиокнопка и переключатель: не путать

Эти элементы легко смешать, но задачи у них разные. Разведем их до того, как перейдем к стилям.

Элемент Что делает Разметка Когда брать
Чекбокс независимый выбор, каждый флажок сам по себе <input type="checkbox"> согласия, фильтры с множественным выбором
Радиокнопка ровно один вариант из группы с общим name <input type="radio" name="size"> выбрать один из нескольких
Переключатель (switch) включить/выключить одну настройку тот же чекбокс, оформленный как тумблер быстрое вкл/выкл опции
Выпадающий список один или несколько вариантов, свернутых компактно <select> много однородных вариантов, мало места

Важная оговорка: отдельного HTML-элемента «переключатель» нет. Визуальный тумблер — это тот же <input type="checkbox">, которому CSS придали форму ползунка; для доступности такому элементу добавляют role="switch".

Разметка: input и подпись через label

Голый <input> без подписи неудобен: по тексту рядом нельзя кликнуть. Подпись задают тегом <label>, и связать их можно двумя способами.

<!-- Способ 1: label ссылается на input по for/id -->
<input type="checkbox" id="agree">
<label for="agree">Соглашаюсь с условиями</label>

<!-- Способ 2: input вложен внутрь label -->
<label>
  <input type="checkbox"> Подписаться на рассылку
</label>

Оба варианта расширяют кликабельную зону на текст подписи: клик по слову «Соглашаюсь» переключает флажок. При первом способе значение for должно совпадать с id поля — это и есть их связь.

Простой путь: покрасить флажок через accent-color

Если нужно лишь привести цвет стандартного флажка к фирменному, полная перерисовка не требуется. Свойство accent-color красит нативный чекбокс, сохраняя его поведение и доступность.

input[type="checkbox"] {
  accent-color: #2f80ed;
  width: 1.1em;
  height: 1.1em;
}

Флажок станет синим в отмеченном состоянии, галочку и фокус браузер отрисует сам. Это самый дешевый способ, и он работает в актуальных Chrome, Firefox, Safari и Edge (свойство доступно во всех основных браузерах примерно с 2021-2022 годов).

Граница приема: accent-color меняет только цвет. Задать другую форму, толщину рамки, скругление или анимацию появления галочки так нельзя — для этого нужен следующий подход.

Полная кастомизация: appearance: none

Чтобы нарисовать флажок с нуля, сначала снимают стандартный вид свойством appearance: none, а потом оформляют сам элемент как обычный блок. Галочку удобно рисовать псевдоэлементом ::before без картинок и SVG-файлов.

Минимальный рабочий пример целиком — его можно вставить в страницу:

<label class="check">
  <input type="checkbox" checked>
  <span>Помидоры</span>
</label>
.check {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-size: 1.1rem;
  cursor: pointer;
}

.check input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  margin: 0;
  width: 1.2em;
  height: 1.2em;
  border: 2px solid #9aa0a6;
  border-radius: 0.3em;
  display: inline-grid;
  place-content: center;
  transition: background-color .15s, border-color .15s;
}

.check input[type="checkbox"]::before {
  content: "";
  width: 0.65em;
  height: 0.65em;
  transform: scale(0);
  transition: transform .12s ease-in-out;
  background-color: #fff;
  clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0, 43% 62%);
}

.check input[type="checkbox"]:checked {
  background-color: #2f80ed;
  border-color: #2f80ed;
}

.check input[type="checkbox"]:checked::before {
  transform: scale(1);
}

Что отрисуется: серый квадрат со скругленными углами; когда флажок отмечен, фон становится синим, а внутри плавно, за счет transform, проступает белая галочка. Так как в примере стоит checked, при загрузке галочка видна сразу.

Разберем ключевые строки:

  • appearance: none убирает нативный вид, после чего рамку, фон и размеры задаем сами. Префикс -webkit-appearance оставлен для старых версий Safari.
  • display: inline-grid вместе с place-content: center центрирует псевдоэлемент-галочку внутри квадрата.
  • ::before рисует галочку: квадратный блок обрезается по контуру «птички» через clip-path: polygon(...), а background-color задает ее цвет.
  • :checked меняет фон рамки на синий, а :checked::before увеличивает галочку с scale(0) до scale(1) — отсюда эффект появления.

Состояния и доступность

Кастомный флажок должен отзываться на наведение, фокус и блокировку, иначе он ощущается сломанным. Добавим состояния к тому же элементу.

.check input[type="checkbox"]:hover {
  border-color: #2f80ed;
}

.check input[type="checkbox"]:focus-visible {
  outline: 2px solid #2f80ed;
  outline-offset: 2px;
}

.check input[type="checkbox"]:disabled {
  border-color: #d0d0d0;
  background-color: #f1f1f1;
  cursor: not-allowed;
}

:focus-visible рисует контур только при навигации с клавиатуры (Tab), а не при клике мышью — так фокус виден тем, кому он нужен, и не мешает остальным.

Здесь же главная оговорка о доступности. Нативный чекбокс нельзя прятать через display: none или visibility: hidden: тогда он выпадает из потока, перестает получать фокус и не переключается с клавиатуры. Подход с appearance: none этим и хорош — элемент остается на месте и фокусируемым, стилизуется сам <input>.

Раньше, до широкой поддержки appearance, флажок скрывали иначе: input уводили за экран (position: absolute; opacity: 0), а рисовали на соседнем <span> или <label> через комбинатор +. Прием рабочий и встречается в старом коде, но в 2026 году стилизация самого input через appearance: none проще и меньше рискует доступностью.

Промежуточное состояние: indeterminate

У чекбокса есть третий визуальный вид — частично отмечен. Его применяют для флажка «выбрать все», когда часть вложенных пунктов отмечена, а часть нет. В CSS для этого есть псевдокласс :indeterminate.

.check input[type="checkbox"]:indeterminate {
  background-color: #2f80ed;
  border-color: #2f80ed;
}

Граница приема: HTML-атрибута indeterminate не существует, только checked. Само состояние выставляется из скрипта — checkbox.indeterminate = true, — а CSS лишь дает зацепку для стиля. Чистой разметкой промежуточный флажок не задать.

Сводка приемов

Инструмент Что дает
accent-color быстро красит нативный флажок, форму не меняет
appearance: none сбрасывает нативный вид для полной перерисовки
:checked стили отмеченного состояния
:hover отклик на наведение
:focus-visible контур фокуса при навигации с клавиатуры
:disabled вид заблокированного поля
:indeterminate промежуточный вид (состояние ставится из JS)

Выводы

  • Чекбокс — независимый выбор из набора; его не путают с радиокнопкой (один из группы) и переключателем (тот же <input type="checkbox">, оформленный тумблером, с role="switch").
  • Подпись связывают с полем через <label> (по for/id или вложением), это расширяет кликабельную зону на текст.
  • Если нужен только фирменный цвет, хватает accent-color: он красит нативный флажок, сохраняя поведение и доступность, но не меняет форму, рамку и анимацию.
  • Полная перерисовка — через appearance: none плюс галочка псевдоэлементом ::before; нативный input при этом не прячут display: none, иначе теряется фокус и управление с клавиатуры.
  • Состояния задают псевдоклассами :checked, :hover, :focus-visible, :disabled; промежуточный вид :indeterminate цепляют стилем, но само состояние ставится из JS.

Где применяется и что учить дальше

Чекбоксы — базовый элемент любой формы: согласие с условиями перед отправкой, фильтры с множественным выбором в каталогах, списки задач, настройки-переключатели. Умение аккуратно переопределить их вид, не потеряв доступность, — обычная задача верстальщика, и те же приемы (appearance: none, псевдоэлементы, состояния через псевдоклассы) переносятся на радиокнопки, select и другие поля.

Освойте тему на практике

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

FAQ

Почему галочку рисуют через clip-path или ::before, а не картинкой? Псевдоэлемент не требует лишнего запроса к серверу, масштабируется без потери четкости и перекрашивается одним свойством цвета. Картинку-иконку пришлось бы держать отдельным файлом и менять на второй вариант для отмеченного состояния.

Можно ли стилизовать чекбокс без appearance: none? Частично. Цвет нативного флажка задает accent-color, и для многих задач этого хватает. Но чтобы поменять форму, рамку, скругление или анимацию, нужен либо appearance: none на самом поле, либо старый прием со скрытием input и отрисовкой на соседнем элементе.

Как сделать флажок крупнее? Задайте width и height в единицах em и увеличьте font-size у контейнера — размер флажка привяжется к тексту. Свойство transform: scale() тоже увеличивает элемент, но может размыть рамку и контур фокуса, поэтому для чекбокса надежнее явные размеры.

OTUS Журнал
Скидка 5% 14-20 сентября на курсы (popup)