Les inputs <input type="checkbox"> et <input type="radio"> natifs sont fonctionnels mais visuellement limités et pas toujours simples à styliser de manière cohérente entre navigateurs. Proposition d'un système complet de stylisation qui :
- Respecte l'accessibilité (navigation clavier, lecteurs d'écran)
- S'adapte au dark mode automatiquement
- Gère tous les états (checked, disabled, indeterminate, error)
- Propose plusieurs variantes visuelles (switch, carré classique)
- Est responsive
Usage de base
Pas grand chose à faire. Un input suivi de son label.
<input type="checkbox" id="mon-checkbox">
<label for="mon-checkbox">Checkbox</label>
<input type="checkbox" id="mon-checkbox-2">
<label for="mon-checkbox-2" class="checkbox-square">Checkbox carrée</label>
<input type="radio" id="mon-radio" name="groupe">
<label for="mon-radio">Input radio</label>
<input type="radio" id="mon-radio-2" name="groupe" checked>
<label for="mon-radio-2">Input radio</label>
Ce qui donne ça. Par défaut, les type="checkbox" ont l'apparence de switch. C'est un choix…
Options disponibles
Ajouter ces classes sur le <label> ou le conteneur parent :
.input-tiny: Inputs plus petits (sur conteneur parent).switch-marker: Style interrupteur (checkbox uniquement, sur label).checkbox-square: Style carré classique (checkbox uniquement, sur label).inputs-marker: Active le mode avec symboles (sur conteneur parent)
Les marqueurs visuels switch-marker sont ajoutés automatiquement si :
- Une classe contenant
"contrast"est présente sur:root(à gérer dans votre environnement) - La classe
.use-keyboardest sur:root(navigation clavier détectée avec un JavaScript, voir dans les articles) - La classe
.inputs-markerest sur un conteneur parent
Les différents états
État disabled
<input type="checkbox" id="checkbox-disabled" disabled>
<label for="checkbox-disabled">Checkbox désactivée</label>
<input type="checkbox" id="checkbox-disabled-square" disabled>
<label for="checkbox-disabled-square" class="checkbox-square">Checkbox carrée désactivée</label>
<input type="radio" id="radio-disabled" disabled>
<label for="radio-disabled">Radio désactivée</label>
État error
<input type="checkbox" id="error" class="error">
<label for="error">Checkbox en erreur</label>
<input type="checkbox" id="error-2" class="error">
<label for="error-2" class="checkbox-square">Checkbox en erreur</label>
État default
Les inputs avec l'attribut checked dans le HTML initial sont visuellement marqués (souligné en pointillé) pour indiquer la valeur par défaut.
La classe switch-marker sur le label affiche un interrupteur ON/OFF avec icônes intégrées.
<input type="checkbox" id="switch">
<label for="switch" class="switch-marker">Avec marqueur visuel</label>
Version carrée
Plus traditionnelle.
<input type="checkbox" id="square">
<label for="square" class="checkbox-square">J'accepte les conditions</label>
<!-- class input-right sur input pour visuel à droite -->
<input type="checkbox" id="square-reverse" class="input-right">
<label for="square-reverse" class="checkbox-square">J'accepte les conditions</label>
La classe input-right sur l'élément input permet de placer le visuel sur la… droite ! Oui, bravo !
Checkbox indeterminate
L'état intermédiaire est particulièrement utile pour indiquer qu'un choix délibéré est attendu.
Le statut indeterminate guide visuellement l'utilisateur à effectuer une action.
<input type="checkbox" id="indeterminate-1" data-indeterminate>
<label for="indeterminate-1">Action nécessaire</label>
<input type="checkbox" id="indeterminate-2" data-indeterminate>
<label for="indeterminate-2" class="checkbox-square">Version carrée</label>
Activation via JavaScript
Gestion automatique avec le script utilitaire :
- Initialisation au chargement : Les checkbox avec
data-indeterminatenon cochées passent automatiquement en étatindeterminate - Retrait à l'interaction : Dès que l'utilisateur coche/décoche, l'état
indeterminatedisparaît - Reset des formulaires : L'état
indeterminateest réinitialisé lors d'un reset - Accessibilité : Ajoute automatiquement un
aria-labelsi absent ("Veuillez faire un choix")
La gestion du statut indeterminate nécessite un script car ce n'est pas un statut natif.
Taille brute : 2,79 kilo-octets (~1,07 kilo-octets gzip)
/**
* Source Kortic https://www.kortic.com/le-blog-kortic/2026/01/14/styliser-les-inputs-radio-et-checkbox-uniquement-par-css.html
* licence Creative Commons CC BY-NC-SA 4.0
* https://creativecommons.org/licenses/by-nc-sa/4.0/deed.fr
* Attribution, partage dans les mêmes conditions, pas d'utilisation commerciale
*/
/**
* Initialisation automatique de l'état indeterminate pour les checkbox
* au chargement du DOM et lors du reset des formulaires
*
* Les checkbox avec l'attribut 'data-indeterminate' et qui ne sont pas cochées
* passent automatiquement en état indeterminate pour indiquer visuellement
* qu'un choix est attendu (mais pas obligatoire, contrairement à 'required').
*
* Dès que l'utilisateur coche ou décoche, l'état indeterminate est retiré.
* Lors d'un reset du formulaire, l'état indeterminate est réinitialisé.
*
* Accessibilité :
* - Si l'input n'a pas d'aria-label, un message est ajouté automatiquement
* - Message depuis window.i18n['indeterminate_checkbox'] ou "Veuillez faire un choix"
* - Si l'input a déjà un aria-label, il est conservé tel quel
*
* Configuration i18n (optionnel) :
* window.i18n = {
* 'indeterminate_checkbox' : 'Please make a choice'
* };
*
* Usage :
* <input type="checkbox" id="newsletter" data-indeterminate>
* <label for="newsletter">Je souhaite recevoir la newsletter</label>
*/
(() => {
'use strict';
// Initialise l'état indeterminate pour un checkbox spécifique
function setIndeterminateState(checkbox) {
checkbox.indeterminate = !checkbox.checked && checkbox.hasAttribute('data-indeterminate');
// Accessibilité : ajoute aria-label uniquement si absent et en état indeterminate
if (checkbox.indeterminate && !checkbox.hasAttribute('aria-label')) {
checkbox.setAttribute('aria-label',
window.i18n?.indeterminate_checkbox || 'Veuillez faire un choix'
);
}
}
// Initialise tous les checkbox avec data-indeterminate dans le conteneur spécifié
function initIndeterminateCheckboxes(root = document) {
root.querySelectorAll('input[type="checkbox"][data-indeterminate]').forEach(checkbox => {
// Évite la double-initialisation
if (checkbox._indeterminateInitialized) return;
checkbox._indeterminateInitialized = true;
setIndeterminateState(checkbox);
// Retire l'état indeterminate dès interaction utilisateur
checkbox.addEventListener('change', () => checkbox.indeterminate = false);
});
}
// Réinitialise l'état indeterminate lors du reset des formulaires
document.addEventListener('reset', e => {
setTimeout(() => {
e.target.querySelectorAll('input[type="checkbox"][data-indeterminate]')
.forEach(setIndeterminateState);
}, 0);
});
// Initialisation au chargement du DOM
(document.readyState === 'loading'
? document.addEventListener('DOMContentLoaded', () => initIndeterminateCheckboxes())
: initIndeterminateCheckboxes()
);
// Exposition pour usage manuel (contenu AJAX)
window.initIndeterminateCheckboxes = initIndeterminateCheckboxes;
})();
Télécharger kortic-indeterminate-status-inputs.js
Accessibilité
- Navigation clavier complète (Tab, Espace, Entrée)
- Focus visible avec outline personnalisable
- Support des lecteurs d'écran (inputs natifs masqués visuellement mais accessibles)
- Respect de
prefers-reduced-motion(désactive les animations) - Respect de
prefers-color-scheme(dark mode automatique) - Attributs ARIA non nécessaires (sémantique HTML native)
- États disabled/error/indeterminate bien exposés
Avantages
- Pas de JavaScript : Tout en CSS pur (sauf gestion automatique de
indeterminateoptionnelle) - Pas de dépendances : Fonctionne out-of-the-box
- SVG inline : Les icônes sont encodées en data-URI (pas de requêtes HTTP)
- Transitions conditionnelles : Désactivées si
prefers-reduced-motion: reduce
Les styles
Dimensions proportionnelles :
Toutes les dimensions utilisent em pour hériter de la font-size du label. Résultat : tout reste proportionnel automatiquement.
Variables CSS personnalisables :
- Les couleurs et styles s'adaptent via variables CSS à adapter selon la charte.
- Les valeurs de couleurs sont regroupées en variables CSS au même niveau que les variables SVG.
:root {
--input-bg: var(--background-color-page, white);
--input-bg-reverse: var(--basic-color-reverse, white);
--input-color-primary: var(--primary-color, black);
--input-color-basic: var(--basic-color, black);
--input-color-checked: var(--link-color, blue);
--input-color-heading: var(--heading-color, black);
--input-color-error: var(--error-color, orangered);
--input-color-disabled: var(--lightgray, lightgrey);
}
Support minimum CSS Nesting à partir des versions Chrome 112, Firefox 117, Safari 16.4.
Taille brute : 19,25 kilo-octets (~4,25 kilo-octets gzip)
/**
* Source Kortic https://www.kortic.com/le-blog-kortic/2026/01/14/styliser-les-inputs-radio-et-checkbox-uniquement-par-css.html
* licence Creative Commons CC BY-NC-SA 4.0
* https://creativecommons.org/licenses/by-nc-sa/4.0/deed.fr
* Attribution, partage dans les mêmes conditions, pas d'utilisation commerciale
*/
/*
* ============================================================================
* Custom Radio & Checkbox Inputs (CSS Nesting)
* Description:
* Stylisation moderne, accessible et responsive des inputs radio/checkbox.
* Fonctionne sans dépendances. Nécessite CSS Nesting (Chrome 112+, Firefox 117+, Safari 16.4+).
*
* HTML de base:
* <input type="checkbox" id="mon-checkbox">
* <label for="mon-checkbox">Mon label</label>
*
* Options (classes sur label ou conteneur parent):
* - .input-tiny : Inputs plus petits
* - .switch-marker : Style switch (checkbox uniquement)
* - .checkbox-square : Style carré classique (checkbox uniquement)
* - .inputs-marker : Active le mode contraste (conteneur parent)
*
* Mode contraste/accessibilité:
* Ajoute l'une de ces classes pour des marqueurs visuels renforcés:
* - Classe contenant "contrast" sur :root
* - .use-keyboard sur :root pour le mode navigation clavier
* - .inputs-marker sur un conteneur parent
*
* Toutes les dimensions sont en 'em' (sauf box-shadow/outline) pour que tout
* hérite de la font-size du label et reste proportionnel.
*
* Fonctionnalités:
* - Responsive avec breakpoints mobile/desktop
* - Support prefers-reduced-motion
* - Support prefers-color-scheme (dark mode)
* - Support touch et hover
* - Gestion des états disabled, error, required et indeterminate
* - Focus keyboard accessible
*/
/* ============================================================================
* TAILLES & VARIABLES
* ============================================================================ */
@media (max-width: 63.9375rem) {
:root {
--input-size: 2.5em;
& .input-tiny {
--input-size: 1.8125em;
}
}
}
@media (min-width: 64rem) {
:root {
--input-size: 2.75em;
& .input-tiny {
--input-size: 2.0625em;
}
}
}
:root {
--input-radius: var(--input-size);
}
/* ============================================================================
* INPUTS & LABELS BASE
* ============================================================================ */
input:is([type="radio"], [type="checkbox"]) {
position: absolute;
width: 0 !important;
height: 0 !important;
padding: 0 !important;
overflow: hidden;
outline: none;
box-shadow: none !important;
& + label {
/* Variables de couleurs du composant - à personnaliser selon le design system */
--input-bg: var(--canvas, white);
--input-bg-reverse: var(--basic-color-reverse, white);
--input-color-primary: var(--canvasText, black);
--input-color-basic: var(--basic-color, black);
--input-color-checked: CanvasText;
--input-color-hover: var(--basic-color, black);
--input-color-error: var(--error-color, orangered);
--input-color-disabled: var(--lightgray, lightgrey);
--input-stroke-width: 0.0625rem;
/* Variables SVG scoped au niveau label */
--svg-switch-on: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M16,26.5h0c-.82,0-1.5-.67-1.5-1.5V7c0-.82.67-1.5,1.5-1.5h0c.82,0,1.5.67,1.5,1.5v18c0,.82-.67,1.5-1.5,1.5Z"/></svg>');
--svg-switch-off: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M16,8.5c4.14,0,7.5,3.36,7.5,7.5s-3.36,7.5-7.5,7.5-7.5-3.36-7.5-7.5,3.36-7.5,7.5-7.5M16,5.5c-5.8,0-10.5,4.7-10.5,10.5s4.7,10.5,10.5,10.5,10.5-4.7,10.5-10.5-4.7-10.5-10.5-10.5h0Z"/></svg>');
--svg-switch-on-light: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path fill="%23eee" d="M16,26.5h0c-.82,0-1.5-.67-1.5-1.5V7c0-.82.67-1.5,1.5-1.5h0c.82,0,1.5.67,1.5,1.5v18c0,.82-.67,1.5-1.5,1.5Z"/></svg>');
--svg-switch-off-light: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path fill="%23eee" d="M16,8.5c4.14,0,7.5,3.36,7.5,7.5s-3.36,7.5-7.5,7.5-7.5-3.36-7.5-7.5,3.36-7.5,7.5-7.5M16,5.5c-5.8,0-10.5,4.7-10.5,10.5s4.7,10.5,10.5,10.5,10.5-4.7,10.5-10.5-4.7-10.5-10.5-10.5h0Z"/></svg>');
--image-checked: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="m0,0v32h32V0H0Zm26.45,10.5v.02l-13.38,13.63c-.45.46-1.19.46-1.64,0l-5.89-5.99c-.43-.45-.43-1.16,0-1.61l1.04-1.07c.44-.46,1.18-.46,1.63,0l3.22,3.26c.44.46,1.18.46,1.63,0l10.7-10.91c.45-.45,1.19-.45,1.64,0l1.05,1.07c.43.44.43,1.16,0,1.6Z"/></svg>');
--image-unchecked: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="m0,0v32h32V0H0Zm24.14,24.13h0c-.48.49-1.24.49-1.72.01l-6.42-6.43-6.42,6.42c-.48.48-1.24.47-1.72,0-.48-.47-.47-1.25,0-1.72l6.42-6.41-6.41-6.42c-.48-.48-.48-1.25,0-1.72.48-.48,1.24-.48,1.72,0l6.41,6.42,6.42-6.42c.48-.48,1.24-.47,1.72,0,.48.47.47,1.25,0,1.72l-6.42,6.41,6.42,6.42c.48.48.48,1.25,0,1.72Z"/></svg>');
--svg-ischeck: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M26.91,4.58l-15.35,15.64c-.31.32-.82.32-1.13,0l-5.35-5.43c-.31-.31-.82-.31-1.13,0l-2.42,2.47c-.3.31-.3.8,0,1.11l8.89,9.06c.31.32.82.32,1.13,0L30.46,8.17c.3-.31.3-.8,0-1.1l-2.42-2.49c-.31-.32-.82-.32-1.13,0Z"/></svg>');
--svg-dots: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M8 13.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zm8 0a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zm8 0a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5z"/></svg>');
--svg-error: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M31.3603,23.5634,20.14936,3.48735a4.69431,4.69431,0,0,0-8.28636,0L.64547,23.5634A4.95709,4.95709,0,0,0,4.78865,31h22.389A4.98211,4.98211,0,0,0,31.3603,23.5634ZM15.9996,26.54621a1.84655,1.84655,0,0,1,0-3.691,1.84835,1.84835,0,0,1,0,3.691Zm1.627-11.93122c-.07905,1.43011-.16468,2.85341-.24372,4.28352-.03952.46309-.03952.88531-.03952,1.34158a1.36579,1.36579,0,0,1-1.34374,1.34159A1.33447,1.33447,0,0,1,14.65586,20.281c-.11856-2.22688-.24371-4.41291-.36228-6.6398-.03952-.58567-.079-1.17814-.12515-1.7638a2.00056,2.00056,0,0,1,1.38325-2.01578,1.77528,1.77528,0,0,1,2.07489,1.04875,2.2658,2.2658,0,0,1,.16467.92616C17.75172,12.76946,17.66609,13.69563,17.62657,14.615Z"/></svg>');
position: relative;
display: inline-block;
line-height: calc(var(--input-size) / 1.5);
border-radius: 0.1875em;
@media (any-hover: hover) {
cursor: pointer;
}
&:after {
height: calc(var(--input-size) / 2);
width: calc(var(--input-size) / 2);
content: "\20" / "";
position: absolute;
left: 0.125em;
border-radius: var(--input-radius);
font-family: sans-serif !important;
}
}
/* États checked */
&:checked + label {
color: var(--input-color-checked);
}
/* États disabled */
&:disabled + label {
opacity: .6;
&:after {
background-color: var(--input-color-disabled);
}
}
/* États error */
&.error {
&:not(:checked) {
& + label {
color: var(--input-color-error);
&:before {
box-shadow: 0 0 0 var(--input-stroke-width) currentColor;
}
&:not(.checkbox-square):after {
-webkit-mask-size: 0.75em !important;
mask-size: 0.75em !important;
left: calc(var(--input-size) / 4 + calc(var(--input-stroke-width) * 2));
}
&.checkbox-square:after {
-webkit-mask-size: calc(var(--input-size) / 4) !important;
mask-size: calc(var(--input-size) / 4) !important;
}
&:after {
-webkit-mask-image: var(--svg-error) !important;
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: center center;
mask-image: var(--svg-error) !important;
mask-repeat: no-repeat;
mask-position: center center;
background-color: var(--input-color-error) !important;
opacity: 1;
border-radius: 0 !important;
}
}
}
}
/* État default (valeur par défaut au chargement) */
&:default:not(:checked) + label {
color: var(--input-color-checked);
font-weight: bolder;
text-decoration: underline;
text-underline-position: under;
text-decoration-style: dashed;
}
/* Hover sur non-checked uniquement */
@media (any-hover: hover) {
&:not(:checked) + label:hover {
color: var(--input-color-hover);
text-decoration: underline;
text-underline-position: under;
text-decoration-style: var(--text-decoration-style);
text-decoration-color: currentColor;
text-decoration-thickness: var(--text-decoration-thickness);
}
}
}
/* Focus keyboard */
:root.use-keyboard input:is([type="radio"], [type="checkbox"]) {
&:focus + label {
outline-offset: 0.1875em;
outline: var(--outline);
}
&:not(:checked):focus + label {
color: var(--input-color-hover);
}
}
/* ============================================================================
* CHECKBOX SPÉCIFIQUE - BASE (non square)
* ============================================================================ */
[type="checkbox"] + label:not(.checkbox-square) {
padding-left: calc(var(--input-size) + 0.9375em);
&:before {
border-radius: var(--input-radius);
box-shadow: 0 0 0 0.0625rem var(--input-color-primary);
content: "";
display: inline-block;
font-family: sans-serif !important;
height: calc(var(--input-size) / 2);
left: 0.125em;
position: absolute;
top: 0.1875em;
width: var(--input-size);
}
&:after {
background-color: var(--input-color-basic);
border: solid var(--input-stroke-width) var(--input-bg);
top: 0.1875em;
}
}
/* Mode contraste pour checkbox (non square) */
:is(:root.contrast, :root.use-keyboard, .inputs-marker) [type="checkbox"] + label:not(.switch-marker):not(.checkbox-square):after {
-webkit-mask-size: 90%;
-webkit-mask-image: var(--image-unchecked);
-webkit-mask-position: center center;
mask-size: 90%;
mask-image: var(--image-unchecked);
mask-position: center center;
}
/* Checkbox non-checked (non square) */
[type="checkbox"]:not(:checked) + label:not(.checkbox-square):after {
border-radius: calc(var(--input-radius) + var(--input-stroke-width)) !important;
opacity: .8;
}
/* Checkbox checked (non square) */
[type="checkbox"]:checked + label:not(.checkbox-square) {
&:before {
background-color: currentColor;
box-shadow: 0 0 0 0.0625rem currentColor;
}
&:after {
left: calc(var(--input-size) / 2 + 0.125em) !important;
background-color: var(--input-bg-reverse);
border: solid 0.0625rem currentColor;
opacity: 1;
}
}
/* Mode contraste checkbox checked (non square) */
:is(:root.contrast, :root.use-keyboard, .inputs-marker) [type="checkbox"]:checked + label:not(.switch-marker):not(.checkbox-square):after {
-webkit-mask-image: var(--image-checked);
mask-image: var(--image-checked);
}
/* ============================================================================
* STYLE SWITCH POUR CHECKBOX
* ============================================================================ */
[type="checkbox"] + label.switch-marker {
&:before {
background-image: var(--svg-switch-off);
background-position: 88% 55%;
background-size: 35%;
top: 0.1875em;
@media (prefers-color-scheme: dark) {
background-image: var(--svg-switch-off-light);
}
}
&::after {
top: 0.1875em;
}
}
[type="checkbox"]:checked + label.switch-marker:before {
background-image: var(--svg-switch-on-light);
background-position: 12% center;
background-size: 40%;
@media (prefers-color-scheme: dark) {
background-image: var(--svg-switch-on);
}
}
/* ============================================================================
* RADIO SPÉCIFIQUE
* ============================================================================ */
[type="radio"] + label {
padding-left: calc(var(--input-size) / 2 + 0.9375em);
&:before {
border-radius: var(--input-size);
box-shadow: 0 0 0 var(--input-stroke-width) currentColor;
content: "\20" / "";
display: inline-block;
font-family: sans-serif !important;
height: calc(var(--input-size) / 2);
left: 0.125em;
position: absolute;
top: 0.1875em;
width: calc(var(--input-size) / 2);
}
}
/* Radio checked */
[type="radio"]:checked + label:after {
border-radius: var(--input-size) !important;
top: 0.1875em;
background-color: currentColor;
box-shadow: 0 0 0 var(--input-stroke-width) var(--input-bg) inset;
}
/* Mode contraste radio checked */
:is(:root.contrast, :root.use-keyboard, .inputs-marker) [type="radio"]:checked + label:after {
-webkit-mask-image: var(--image-checked);
-webkit-mask-position: center center;
-webkit-mask-size: 85%;
mask-image: var(--image-checked);
mask-position: center center;
mask-size: 85%;
}
/* ============================================================================
* ÉTAT INDETERMINATE (CHECKBOX non square)
* Appliqué uniquement aux checkbox avec data-indeterminate, excluant .checkbox-square
* ============================================================================ */
/*
[type="checkbox"][data-indeterminate] + label:not(.checkbox-square) {
padding-left: calc(var(--input-size) * 1.5 + 0.9375em);
&:before {
width: calc(var(--input-size) * 1.5);
}
}
*/
/* État indeterminate actif */
[type="checkbox"]:indeterminate + label:not(.checkbox-square) {
&:before {
background-color: transparent;
}
&:after {
background-color: var(--input-color-disabled);
content: "\A0" / "";
font-size: calc(var(--input-size) / 3);
display: flex;
align-items: center;
justify-content: center;
line-height: calc(var(--input-size) / 1.5);
height: calc(var(--input-size) / 2);
font-family: inherit !important;
-webkit-mask-image: none !important;
mask-image: none !important;
top: 0.25em;
left: calc(var(--input-size) / 3 + calc(var(--input-stroke-width) * .5));
box-shadow: 0 0 0 var(--input-stroke-width);
}
}
/* Réinitialisation du masque quand indeterminate non actif */
[type="checkbox"][data-indeterminate]:not(:indeterminate) + label:not(.checkbox-square):after {
content: "\A0" / "";
-webkit-mask-size: contain;
-webkit-mask-image: var(--image-unchecked);
-webkit-mask-position: center center;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
mask-image: var(--image-unchecked);
mask-position: center center;
mask-repeat: no-repeat;
}
/* Réinitialisation du masque quand indeterminate non actif puis checked */
[type="checkbox"][data-indeterminate]:not(:indeterminate):checked + label:not(.checkbox-square):after {
-webkit-mask-image: var(--image-checked);
mask-image: var(--image-checked);
}
/* ============================================================================
* STYLE CHECKBOX CARRÉE CLASSIQUE
* Isolation complète des règles pour .checkbox-square
* ============================================================================ */
[type="checkbox"] + label.checkbox-square {
padding-left: max(calc(var(--input-size) / 2 + 1em), 1.5625rem);
&:before {
border-radius: 0.1875rem;
background-color: var(--input-bg);
box-shadow: 0 0 0 var(--input-stroke-width) var(--input-color-checked) inset;
width: max(calc(var(--input-size) / 2), 1.375rem);
height: max(calc(var(--input-size) / 2), 1.375rem);
top: 50%;
transform: translateY(-50%);
content: "";
display: inline-block;
position: absolute;
left: 0.125em;
background-image: none;
}
&:after {
width: max(calc(var(--input-size) / 2), 1.375rem);
height: max(calc(var(--input-size) / 2), 1.375rem);
top: 50%;
transform: translateY(-50%);
left: 0.125em;
background-color: var(--input-color-checked);
border: solid 0.0625rem transparent;
opacity: 0;
content: "\A0" / "";
-webkit-mask-image: var(--svg-ischeck);
-webkit-mask-position: center center;
-webkit-mask-size: 65%;
-webkit-mask-repeat: no-repeat;
mask-image: var(--svg-ischeck);
mask-position: center center;
mask-size: 65%;
mask-repeat: no-repeat;
}
}
/* Checkbox square checked */
[type="checkbox"]:checked + label.checkbox-square {
&:before {
box-shadow: 0 0 0 var(--input-stroke-width) currentColor inset;
}
&:after {
opacity: 1;
left: 0.125em;
background-color: var(--input-color-checked);
}
}
/* État indeterminate pour checkbox carrée - isolation totale */
[type="checkbox"]:indeterminate + label.checkbox-square {
&:before {
box-shadow: 0 0 0 var(--input-stroke-width) currentColor inset;
background-image: none;
}
&:after {
width: max(calc(var(--input-size) / 2), 1.375rem);
height: max(calc(var(--input-size) / 2), 1.375rem);
left: 0.125em;
background-color: var(--input-color-basic);
content: "\A0" / "";
-webkit-mask-image: var(--svg-dots);
-webkit-mask-position: center center;
-webkit-mask-size: 65%;
-webkit-mask-repeat: no-repeat;
mask-image: var(--svg-dots);
mask-position: center center;
mask-size: 65%;
mask-repeat: no-repeat;
opacity: 1;
border: solid var(--input-stroke-width) transparent;
}
}
/* ============================================================================
* ANIMATIONS ET TRANSITIONS
* ============================================================================ */
@media (prefers-reduced-motion: no-preference) {
[type="radio"] + label:after,
[type="checkbox"] + label:before,
[type="checkbox"] + label:after {
transition: background-color .3s;
}
[type="checkbox"] + label:not(.checkbox-square):after {
transition: left .2s, background-color .3s, border-color .3s;
}
[type="checkbox"] + label.checkbox-square:after {
transition: opacity .3s, background-color .3s;
}
}
/* ============================================================================
* POSITION ALTERNATIVE - INPUT À DROITE
* ============================================================================ */
input:is([type="radio"], [type="checkbox"]).input-right {
& + label {
padding-left: 0;
padding-right: calc(var(--input-size) + 0.9375em);
&:before,
&:after {
left: auto;
right: 0.125em;
}
}
}
/* Ajustements pour checkbox non-square checked */
[type="checkbox"].input-right:checked + label:not(.checkbox-square):after {
left: auto !important;
right: calc(var(--input-size) / 2 + 0.125em) !important;
}
/* Ajustements pour radio avec padding spécifique */
[type="radio"].input-right + label {
padding-right: calc(var(--input-size) / 2 + 0.9375em);
}
/* Ajustements pour checkbox square */
[type="checkbox"].input-right + label.checkbox-square {
padding-right: max(calc(var(--input-size) / 2 + 1em), 1.5625rem);
&:before,
&:after {
right: 0.125em;
left: auto;
}
}
/* Ajustements pour état error */
[type="checkbox"].input-right.error:not(:checked) + label:not(.checkbox-square):after {
left: auto !important;
right: calc(var(--input-size) / 4 + calc(var(--input-stroke-width) * 2));
}
/* Ajustements pour indeterminate */
[type="checkbox"].input-right:indeterminate + label:not(.checkbox-square):after {
left: auto !important;
right: calc(var(--input-size) / 4 + calc(var(--input-stroke-width) * 3));
}
Télécharger kortic-styles-radios-checkboxes.css
En espérant n'avoir rien oublié…
That's all, Folks !