Cómo aplicar diseño a las casillas de verificación

Usa HTML semántico y accesible con cada casilla de verificación asociada a su etiqueta, ya sea anidando el elemento <input> dentro del elemento <label> o haciendo coincidir el atributo for de la etiqueta con el atributo id de la entrada.

El CSS moderno ofrece dos enfoques para aplicar diseño a las casillas de verificación: personalizar la apariencia nativa con accent-color o anular la presentación predeterminada con appearance: none en el elemento <input type="checkbox">.

Personalización nativa con accent-color

Para un diseño simple y coherente con la marca que conserve la renderización nativa, el comportamiento del teclado, la validación y los indicadores de enfoque del sistema operativo, usa accent-color.

.checkbox-native {
  accent-color: #1a73e8;

  /* Sizing is controlled via relative units */
  inline-size: 1.25em;
  aspect-ratio: 1;
  margin: 0;
  cursor: pointer;
}

Estilo completamente personalizado con appearance: none

Usa appearance: none cuando el diseño requiera control sobre la forma, el tamaño, los estados o los indicadores de la casilla de verificación. Esto quita el diseño visual nativo, pero deja el <input> como el objetivo interactivo.

Establece tamaños relativos explícitos para --checkbox-size y --checkbox-icon-size porque appearance: none quita las dimensiones predeterminadas del navegador. Mantén el ícono más pequeño que la casilla de verificación para dejar espacio para su borde y relleno visual.

/* Reusable SVG assets */
:root {
  --icon-check: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'></polyline></svg>");
  --icon-dash: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='4.5' stroke-linecap='round' stroke-linejoin='round'><line x1='5' y1='12' x2='19' y2='12'></line></svg>");
}

/* Custom checkbox */
.checkbox-custom {
  --checkbox-size: 1.25em;
  --checkbox-icon-size: 0.7em;

  appearance: none;
  display: inline-grid;
  place-content: center;
  inline-size: var(--checkbox-size);
  aspect-ratio: 1;
  margin: 0;
  border: 2px solid currentColor;
  cursor: pointer;

  &::before {
    content: "";
    inline-size: var(--checkbox-icon-size);
    aspect-ratio: 1;
    background-color: currentColor;
    mask: var(--checkbox-icon) no-repeat center / contain;
    scale: 0;

    @media (prefers-reduced-motion: no-preference) {
      transition: scale 150ms ease;
    }

    @media (forced-colors: active) {
      background-color: CanvasText;
    }
  }

  &:checked {
    --checkbox-icon: var(--icon-check);
  }

  &:indeterminate {
    --checkbox-icon: var(--icon-dash);
  }

  &:is(:checked, :indeterminate)::before {
    scale: 1;
  }

  &:focus-visible {
    outline: 2px solid currentColor;
    outline-offset: 2px;
  }

  &:disabled {
    cursor: not-allowed;
    opacity: 0.5;
  }
}

El estado indeterminado

El estado indeterminado no se puede establecer a través de un atributo HTML. Establece la propiedad del DOM indeterminate en JavaScript (checkbox.indeterminate = true) y asegúrate de que la pseudoclase :indeterminate sea visualmente distinta de los estados :checked y no marcado:

  • Nativo (accent-color): El navegador aplica el diseño automáticamente con el accent-color del elemento (no se necesita una regla de CSS :indeterminate adicional).
  • Personalizado (appearance: none): Cambia --checkbox-icon por var(--icon-dash) en .checkbox-custom:indeterminate como se muestra más arriba.
const selectAll = document.querySelector("#select-all");
selectAll.indeterminate = true;

Accesibilidad e interacción

  • SÍ uses :focus-visible en lugar de :focus para aplicar diseño a los indicadores de enfoque en las casillas de verificación personalizadas, de modo que aparezca un contorno distinto para la navegación con el teclado sin que se muestre en los clics del puntero.
  • NO uses outline: none ni ocultes los indicadores de enfoque en las casillas de verificación.
  • SÍ asegúrate de que la casilla de verificación o su <label> de unión proporcione un objetivo de hit interactivo de, al menos, 44px x 44px, mientras mantienes el tamaño de la casilla de verificación visual en unidades relativas:

    label {
      display: inline-flex;
      align-items: center;
      gap: 0.65rem;
      min-block-size: 44px;
      cursor: pointer;
    }
    
  • SÍ proporciona una variante de estilo :disabled que disminuya la opacidad y establezca cursor: not-allowed para transmitir claramente los estados inactivos.

Problemas que debes tener en cuenta cuando usas accent-color

La renderización de accent-color en el navegador varía. En el caso de los indicadores que, por lo general, se pintan sobre un fondo de color de los elementos destacados, como las marcas de las casillas de verificación y los puntos de los botones de selección, los navegadores pueden aplicar diferentes tratamientos:

  • Chromium y Firefox suelen seleccionar un color de indicador que contraste.
  • En cambio, Safari puede conservar un indicador blanco en el modo claro o un indicador negro en el modo oscuro, mientras modifica el color de los elementos destacados detrás de él. Este ajuste no siempre proporciona suficiente contraste para cada color proporcionado, por lo que debes probar las combinaciones importantes en Safari, incluidos los esquemas de colores claros y oscuros. No asumas que Safari elegirá automáticamente el color del indicador que proporcione el mejor contraste.

Estrategias de resguardo

Resguardos y compatibilidad de navegadores con accent-color

La propiedad accent-color es una mejora progresiva. Los navegadores que no admitan esta propiedad la ignorarán y usarán los colores predeterminados de su IU.

Máscaras CSS