Encore une fois sur la visualisation des types d'entrées checkbox et radio. Pour ceux qui ont oublié comment

Le sujet est vieux et déjà, il s'est avéré, oublié.



Récemment, j'ai eu un petit travail sur le développement de spécifications techniques pour la modernisation d'un projet existant de longue date. Et, en particulier, l'affaire concernait le style de la célèbre <input type = "checkbox">. Il s'est avéré que l'interprète, un programmeur «de tous les métiers» n'avait même pas compris que je lui expliquais avec des mots comment le faire. J'ai dû faire des exemples et, par conséquent, ce texte est apparu.



Permettez-moi de vous rappeler que maintenant la case à cocher et la radiobox sont affichées différemment selon les sites. Il arrive qu'une entrée non marquée ne puisse pas être immédiatement discernée - elle est tellement "designly beautiful", et dans les dernières versions de Chrome, les cases à cocher sélectionnées sont devenues une vile couleur cyan.



Donc la situation



Il existe trois entreprises qui utilisent un certain produit logiciel lié aux commandes, à la comptabilité, à l'entrepôt, etc. Travailler avec les clients, les partenaires, les exécuteurs, etc.



Les spécialistes du marketing et les annonceurs l'utilisent également. Ce que fait ce système - peu importe ce qu'il dit - peu importe.



Et il est important que le site de ce produit comporte de nombreuses pages avec des formulaires, sur lesquels il y a de nombreuses cases à cocher d'entrée et radio.



Plaintes des employés



Réalisateur : Sur grand écran, les "kryzhiki" sont difficiles à voir et pas perceptibles.

Chef comptable : Sur mon ordinateur, le «kryzhiki» ressemble à ça, sur les employés c'est différent, à la maison c'est aussi différent, mais sur la tablette c'est complètement différent.

Marketer : Est-ce possible, de sorte que certaines positions non sélectionnées soient rouges et d'autres sélectionnées vertes?

Etc.



Donc la tâche



  1. Corrigez l'apparence de la case à cocher et de la radio-boîte avec des coûts minimes et des changements minimes.
  2. Créez une case à cocher et un style de radiobox pour différents utilisateurs. Important: c'est un site fermé, il y a «tout à nous», la «beauté» n'est pas nécessaire, mais l'efficacité de la perception est nécessaire.


Ce qui n'est pas autorisé



1. Le côté serveur ne doit pas être touché.

2. Vous ne pouvez pas toucher les fichiers javascript, vous ne pouvez pas insérer votre propre javascript.

3. Les fichiers css ne peuvent pas être touchés.



Ce qui est autorisé



1. Modifiez les modèles html.

2. Créez un fichier de style pour tous les utilisateurs.

4. Créez un fichier de style pour un utilisateur ou un groupe d'utilisateurs spécifique.

Et ce que vous avez fait, vous pouvez immédiatement consulter codepen.io , mais il vaut mieux lire plus loin.



Une étude préliminaire a montré



1. Presque tous les <input type = "checkbox"> ont un champ de nom, et ceux qui n'ont pas d'identifiant.

2. Tous les <input type = "radio"> ont un champ de nom, certains ont un identifiant.

3. En conséquence, en css, la case à cocher est accessible à la fois par identifiant et par nom. À la radio - soit par identifiant, soit par le numéro de l'enfant du parent.



Extraits de code source:



/*  1 */
<tag><input type="checkbox">  </tag>

/*  2 */
<tag><input type="checkbox">  <br>
<input type="checkbox">  </tag>

/*  3 */
...<label><input type="checkbox">  </label>...

/*  4 */
<td><input id="idxxx" type="checkbox"></td>
<td><label for="idxxx"> </label></td>


Corrigeons le code:



/*  1 */
<tag><label class="new-input"><input type="checkbox"><s></s><span> </span></label></tag>

/*  2 */
<tag><label class="new-input"><input type="checkbox"><s></s><span> </span></label><br>...</tag>

/*  3 */
...<label class="new-input"><input type="checkbox"><s></s><span> </span></label>...

/*  4 */
<td><label class="new-input new-input-one"><input id="idxxx" type="checkbox"><s></s></label></td>
<td><label for="idxxx"> </label></td>


Tout est pareil pour <input type = "radio">, la classe de LABEL est la même.



Qu'avez-vous exactement fait?



  1. Chaque entrée (stern de l'option 3) a été enveloppée d'une balise LABEL avec notre classe. L'option 3 vient d'ajouter une classe.
  2. Immédiatement après l'entrée, nous avons inséré une balise S vide. Puisque l'entrée elle-même ne sera pas visible, cette balise rendra cette entrée.
  3. Le texte d'accompagnement était entouré de la balise SPAN (sauf pour l'option 4). Cette balise sera nécessaire lorsque nous déciderons de l'alignement de l'entrée visuelle par rapport à ce texte.
  4. L'option 4 a été ajoutée une autre classe pour éviter cet alignement, puisque le texte d'accompagnement se trouve dans une autre cellule du tableau. À proprement parler, il serait nécessaire de faire le contraire - ajouter une classe responsable de l'alignement aux options 1 à 3. Mais, il y a beaucoup plus d'options 1 à 3 que la 4ème, et pour ne pas gonfler le html, c'est fait comme ça.


Questions rhétoriques et réponses rhétoriques
1. S? , S – . , input.



2. S SPAN ? , html? , , «» .



  .new-input > S { }
  .new-input > .new-input-S {}


3. , , «» html . – mni mnio. :-))



Quelques considérations préliminaires et ajustements css concernant le dimensionnement des boîtes: border-box, normalisation LABEL, sélecteurs A + B, A ~ B et [attr] ,: coché ,: désactivé et :: avant les pseudo-classes. Quiconque n'est pas sûr de ce qu'il sait ou veut rafraîchir ses connaissances regarde sous la coupe.



Considérations préliminaires
1. , «» css (box-sizing:content-box) width height , padding border . box-sizing:border-box , padding border width height.



2. , , «» . «» LABEL , . LABEL.



LABEL {
    box-sizing:border-box; cursor:pointer; user-select:none;
}
LABEL *,
LABEL *::before,
LABEL *::after {
    box-sizing:inherit;
}


.., box-sizing:border-box LABEL, . ( ).



3. «A + B» , B, A, .. B. , «A ~ B» , B A, .. .

, «».



?



<label class="new-input"><input type="checkbox"><s></s><span> </span></label>
<label class="new-input"><input type="radio"><s></s><span> </span></label>


/* 1 */
.new-input > INPUT + S {}
.new-input > INPUT ~ SPAN {}

/* 2 */
.new-input > INPUT:not(:checked) + S {}
.new-input > INPUT:not(:checked) ~ SPAN {}

/* 3 */
.new-input > INPUT:checked + S {}
.new-input > INPUT:checked ~ SPAN {}

/* 4 */
.new-input > INPUT:disabled + S {}
.new-input > INPUT:disabled ~ SPAN {}

/* 5 */
.new-input > INPUT[type="radio"] + S {}


– S SPAN.

– INPUT .

– INPUT .

– INPUT .



, , – S , input radio.

, S SPAN input.



4. S input, input display:none, , LABEL , S . html hidden input? , hidden input «» , html .



Alors, commençons le rendu de l'entrée



Exemple N 1. Le plus simple - nous utilisons des caractères alphabétiques. Le

code html est le même, et le css sera comme ceci:



/* s1 */
.new-input > INPUT + S::before {
  content: "c";
}
/* s2 */
.new-input > INPUT:checked + S::before {
  content: "V";
}
/* s3 */
.new-input > INPUT[type="radio"] + S::before {
  content: "r";
}
/* s4 */
.new-input > INPUT[type="radio"]:checked + S::before {
  content: "X";
}
/* s5 */
.new-input > INPUT:disabled + S::before {
  opacity: 0.5;
}
/* s6 */
.new-input > S {
  text-decoration: none;
  margin-left: 3px;
  margin-right: 6px;
}
/* s7 */
.new-input > S::before {
  display: inline-block;
  width: 1.25em;
  text-align: center;
  color: #fafafa;
  background-color: #37474f;
}
/* s8 */
.new-input > INPUT[type="radio"] + S::before {
  border-radius: 50%;
}


La balise S rendra l'entrée. Mais nous allons le «diviser» par fonctionnalité: la balise S elle - même sera responsable du placement dans LABEL et de l'alignement par rapport au prochain SPAN.



Et le pseudo-élément S :: before sera placé à l'intérieur de la balise S et servira d'entrée.



La ligne s1 définit le caractère qui sera placé dans S :: avant lorsque l'entrée n'est pas sélectionnée. En principe, il faudrait écrire ".new-input> INPUT: not (: checked) + S :: before", mais certains navigateurs (par exemple, IE) peuvent ne pas exécuter une telle construction.

La chaîne s2 spécifie le caractère lorsque l'entrée est sélectionnée.

Les lignes s3 et s4 font de même pour la radio d'entrée.

Chaîne s5décrit ce qui se passe si l'entrée est bloquée - dans ce cas, la balise S sera à moitié transparente.

La ligne s6 définit l'alignement, dans ce cas, elle donne un remplissage à gauche et à droite (uniquement dans cet exemple). De plus, il supprime le barré régulier.

La ligne s7 forme un carré, s8 le transforme en cercle pour l'entrée radio.



L'exemple # 1 peut être consulté sur codepen.io . Il existe des entrées natives et de nouvelles. Le premier peut être supprimé.



Plus de détails sur l'affichage: inline-block, font-size, line-height
font-size, line-height. line-height – font-size, line-height – , line-height – . line-height:1.25, S::before width:1.25em.



S::before display: inline-block – S::before «» ( , , .), «» . .





Question:



Pouvez-vous utiliser des caractères spéciaux? Comme ceux-ci:

□ ■ ▢ ▣ ○ ● ◎ ◉

Donnez-leur la bonne taille et c'est tout. Non?



Réponse:



vous pouvez. Mais vous n'en avez pas besoin. Car il y aura de grandes hémorroïdes et des danses avec des tambourins sur l'attribution de la taille souhaitée, l'alignement vertical, la coupe, etc. De plus, différents navigateurs fonctionnent différemment avec ces symboles.

Nous sommes allés dans l'autre sens. Bien que le dernier exemple contienne une mise en œuvre de cette idée.



Exemple N 2. Les éléments d'entrée "Dessiner" en utilisant le



code html css sont identiques, mais css sera comme ceci:



/* s1 */
.new-input > S::before {
  content: "";
  display: inline-block;
  width: 0.75em;
  height: 0.75em;
  border: 1px solid currentColor;
  padding: 2px;
  background-clip: content-box;
  border-radius: 20%;
}
/* s2 */
.new-input > INPUT[type="radio"] + S::before {
  border-radius: 50%;
}
/* s3 */
.new-input > INPUT:checked + S::before {
  background-color: currentColor;
}
/* s4 */
.new-input > INPUT:disabled + S::before {
  opacity: 0.5;
}
/* s5 */
.new-input > S {
  text-decoration: none;
  margin-left: 3px;
  margin-right: 6px;
}


La ligne s1 définit S :: avant de rendre l'entrée. Ce sera un bloc en ligne dont la largeur et la hauteur sont définies sur 0,75em, ce qui correspond à peu près à la hauteur de la lettre majuscule et dépend de la taille de la police du parent. Une fine bordure est définie avec la couleur actuelle, un rembourrage intérieur, un petit arrondi des coins. Et le plus important! - propriété background-clip: content-box est défini. C'est une propriété très intéressante - si la couleur d'arrière-plan est définie, elle ne peindra que la partie du contenu et n'affectera pas le remplissage. Ce dont nous avons besoin.



La ligne s2 pour une entrée radio fait S :: avant le tour.

La ligne s3 pour l'entrée marquée définit S :: avant background-color sur la couleur courante. Autrement dit, il "dessine" un carré ou un cercle à l'intérieur.

Lignes4 déverrouille l'entrée, la ligne s5 donne un remplissage à gauche et à droite.



Les avantages de cette méthode



  1. Tout est très simple. Fonctionne sur tous les navigateurs. Même IE10 (en émulation du 11e).
  2. Vous pouvez colorier comme vous le souhaitez.
  3. Puisque S :: before est un bloc en ligne, alors il se trouve exactement au bas de la ligne de base et ne s'en va nulle part. S'il est plus grand que le texte, il augmentera simplement la hauteur de la ligne et restera sur la ligne de base.
  4. Étant donné que la visualisation d'entrée se trouve à l'intérieur d'une balise S, elle peut être positionnée et alignée facilement.
  5. Les dimensions de S :: avant dans em permettent de définir sa taille par rapport à la taille du texte de la légende. Vous pouvez, par exemple, définir des limites pour la hauteur et la largeur.


Inconvénients de cette méthode



Principalement dans les tailles em. Le fait est qu'une situation peut survenir lorsque la largeur et la hauteur lors du calcul (de em à px) auront une valeur fractionnaire. Sur les ordinateurs ordinaires avec un écran normal, l'arrondi peut ne pas se produire correctement. Par exemple, les dimensions 12.8px par 12.8px dans le même Mozila peuvent devenir 13px par 12px. Ensuite, vous devez définir des tailles fixes. Bien que sur les moniteurs et les cartes vidéo modernes, les ordinateurs portables, les tablettes et les smartphones, cela ne se produit pas du fait que le point (pixel) du navigateur se compose de plusieurs pixels d'écran.



L'exemple # 2 peut être consulté sur codepen.io . Il existe des entrées natives et de nouvelles. Le premier peut être supprimé.

Ainsi, la première tâche - rendre l'entrée - est terminée. Nous passons à la "coloration" sélectionnée.



Entrée de coloration



html par exemple:



<label class="new-input"><input name="chb1" type="checkbox" ...><s></s><span> </span></label>
<label class="new-input"><input id="rb1" type="radio" ...><s></s><span> </span></label>


Nous ferons référence à une entrée du type de case à cocher par nom, à radio par id.



Nous peignons tout en bleu



/*  input */
.new-input > INPUT[name="chb1"] + S,
.new-input > INPUT#rb1 + S {
  color: #0091ea;
}
/*  text */
.new-input > INPUT[name="chb1"] ~ SPAN,
.new-input > INPUT#rb1 ~ SPAN {
  color: #0091ea;
}
/*   */
.new-input > INPUT[name="chb1"] ~ *,
.new-input > INPUT#rb1 ~ * {
  color: #0091ea;
}


N'oubliez pas la spécificité du CSS, ces styles seront plus spécifiques que les styles de base et fonctionneront certainement. En quoi diffèrent-ils de ceux décrits ci-dessus? Celles qui s'appliquent uniquement aux entrées sélectionnées - celles qui ont le nom et la valeur d'identifiant spécifiés.



Tout va bien ici, sauf que les entrées non sélectionnées n'auront pas l'air très bonnes - la fine bordure bleue est à peine perceptible.



Colorez-le en vert lorsque l'entrée est sélectionnée



/*  input */
.new-input > INPUT[name="chb1"]:checked + S,
.new-input > INPUT#rb1:checked + S {
  color: #00c853;
}
/*  text */
.new-input > INPUT[name="chb1"]:checked ~ SPAN,
.new-input > INPUT#rb1:checked ~ SPAN {
  color: #00c853;
}
/*   */
.new-input > INPUT[name="chb1"]:checked ~ *,
.new-input > INPUT#rb1:checked ~ * {
  color: #00c853;
}


La première option, à mon avis, n'est pas très bonne - le cadre et le carré / cercle intérieur seront verts. Vous ne pouvez que le colorier.



/*  input    */
.new-input > INPUT[name="chb1"]:checked + S::before,
.new-input > INPUT#rb1:checked + S::before {
  background-color: #00c853;
}


Couleur en rouge lorsque l'entrée n'est PAS sélectionnée



/*  input */
.new-input > INPUT[name="chb1"]:not(:checked) + S,
.new-input > INPUT#rb1:not(:checked) + S {
  color: #d50000;
}
/*  text */
.new-input > INPUT[name="chb1"]:not(:checked) ~ SPAN,
.new-input > INPUT#rb1:not(:checked) ~ SPAN {
  color: #d50000;
}
/*   */
.new-input > INPUT[name="chb1"]:not(:checked) ~ *,
.new-input > INPUT#rb1:not(:checked) ~ * {
  color: #d50000;
}


La logique est-elle claire? Vous pouvez continuer à créer des conceptions plus complexes.



Par exemple, si l'entrée n'est pas sélectionnée, le texte doit être rouge et gras, et si l'élément d'entrée interne et le texte sont sélectionnés, il doit être vert. Élémentaire!



/* ,    */
.new-input > INPUT[name="chb1"]:not(:checked) ~ SPAN,
.new-input > INPUT#rb1:not(:checked) ~ SPAN {
  color: #d50000;
  font-weight: bold;
}
/*   input,   */ 
.new-input > INPUT[name="chb1"]:checked + S::before,
.new-input > INPUT#rb1:checked + S::before {
  background-color: #00c853;
}
/* ,   */ 
.new-input > INPUT[name="chb1"]:checked ~ SPAN,
.new-input > INPUT#rb1:checked ~ SPAN {
  color: #00c853;
}


Et, par exemple, vous devez traiter tout un groupe d'entrées (10 à 15 pièces). Afin de ne pas écrire un tas de lignes, vous pouvez trouver leur parent commun (.parent_element) et raccourcir la condition.



.parent_element > .new-input > INPUT:not(:checked) ~ SPAN {
  color: #d50000;
  font-weight: bold;
}
.parent_element > .new-input > INPUT:checked + S::before {
  background-color: #00c853;
}
.parent_element > .new-input > INPUT:checked ~ SPAN {
  color: #00c853;
}


Vous pouvez tout voir dans l'exemple final sur codepen.io



C'est, semble-t-il, et c'est tout. Il ne reste plus qu'à «gratter les taches de naissance» du perfectionniste - les problèmes d'alignement.



Aligner l'entrée visuelle et le texte d'accompagnement



Pour commencer, permettez-moi de vous rappeler des choses bien connues concernant le placement du texte, la mise en forme, etc. Tout est sous la coupe.



Choses communément connues
, , css . .



1. font-size , . (baseline), «» . «» – g – «» . (cap height) – «» () . «» – – «» . , , . «» 75% . , font-size:16px, Arial 12px. , «» .



2. line-height . , font-size, , . , .



3. , S SPAN font-size line-height - . font-size:16px line-height:1.25. N1 S::before 1.25em, . N2 ( ) – S::before 0.75em, . font-size . , .



4. - «», , . . , , 50%. , , 150%. -, / – -! , -.



? , , input — , , , . !



Que se passe-t-il si le texte d'accompagnement dans SPAN est affiché sur deux ou trois lignes? De toute évidence, il "s'adaptera" sous l'entrée. Ce n'est pas joli, il faut le réparer.



Une méthode ancienne est la suivante: la balise S est float: left, et la balise SPAN est display: block et overflow: hidden.



Cela créera une colonne de texte. On suppose que certains d'entre eux auront une marge appropriée, ce qui donnera un saut entre eux. Eh bien, il y a aussi des hémorroïdes ajoutées avec l'arrêt du flotteur après SPAN. Nous allons prendre la voie moderne - utilisez flexbox. Il est complètement hors de propos ici.



.new-input {
  display: flex;
  flex-direction: row;
  align-items: start;
}
.new-input > S {
  margin-right: 4px;
  flex: 0 0 auto;
}
.new-input > SPAN {
  flex: 0 1 auto;
}


Dans ce cas, la balise LABEL (qui est .new-input) sera flex, S et SPAN seront des blocs, placés en haut de LABEL. Le texte dans SPAN sera en plusieurs lignes si nécessaire. Pour cette raison, l'entrée visuelle a été décrite dans S :: avant. Quelle que soit la hauteur, SPAN S :: before sera aligné sur la première ligne SPAN. Alternativement, vous pouvez spécifier align-items: center - puis avec un SPAN sur une seule ligne, l'entrée visuelle serait en haut et avec deux lignes - au milieu et avec trois lignes - sur la deuxième ligne. Dans le dernier exemple, vous pouvez changer l'emplacement de l'entrée.



C'est tout



J'espère que c'était intéressant et utile pour quelqu'un. S'il vous plaît ne me grondez pas beaucoup - c'est ma première expérience sur Habr.



L'exemple # 1 est juste une démonstration de l'interaction entre le changement d'entrée et un élément voisin.



Exemple N 2 - visualisation de l'entrée en utilisant css, comme base de la solution.



Le dernier exemple est tout décrit ensemble.



À propos d'une implémentation spécifique



Il y avait des formulaires étendus, où les blocs de champ qui pouvaient être modifiés par des utilisateurs spécifiques étaient mis en évidence avec un arrière-plan pâle, et le reste de l'entrée avait la propriété désactivée et servait uniquement à titre d'information. Par conséquent, le style ".new-input> INPUT: disabled + S :: before" n'était pas appliqué.



UPD



En réponse aux commentaires Exemple N 3 .

Il existe une prise en charge clé et ciblée pour les entrées cachées au travail.



All Articles