Maison >interface Web >tutoriel CSS >Un composant d'évaluation d'étoile uniquement CSS et plus encore! (Partie 1)

Un composant d'évaluation d'étoile uniquement CSS et plus encore! (Partie 1)

William Shakespeare
William Shakespeareoriginal
2025-03-07 16:38:11299parcourir

A CSS-Only Star Rating Component and More! (Part 1)

Construire un composant d'évaluation des étoiles est un exercice classique du développement Web et a été implémenté à plusieurs reprises en utilisant une variété de techniques. Habituellement, une petite quantité de code JavaScript est requise, mais qu'en est-il des implémentations à l'aide de CSS? Oui, oui!

Il s'agit d'une démonstration de la composante de notation d'étoile implémentée à l'aide de CSS uniquement. Vous pouvez cliquer sur la note de mise à jour.

C'est cool, non? En plus d'utiliser CSS uniquement, le code HTML n'est qu'un seul élément:

<input type="range">

L'élément d'entrée de plage est idéal car il permet à l'utilisateur de sélectionner une valeur numérique entre deux limites (minimum et maximum). Notre objectif est de concevoir cet élément natif, de le convertir en un composant d'évaluation d'étoile, sans marquage supplémentaire ni aucun script! Nous créerons également plus de composants à la fin, alors restez à l'écoute.

Remarque: Cet article ne se concentre que sur la partie CSS. Alors que j'ai fait de mon mieux pour réfléchir aux aspects de l'interface utilisateur, de l'UX et de l'accessibilité, mes composants n'étaient pas parfaits. Il peut avoir certains inconvénients (erreurs, problèmes d'accessibilité, etc.), alors utilisez avec prudence.

<input type="range"> élément

Vous savez peut-être que la conception d'éléments indigènes, comme les éléments d'entrée, est un peu délicat en raison de tous les styles de navigateur par défaut et différentes structures internes. Par exemple, si vous vérifiez le code pour un élément d'entrée de plage, vous verrez différents HTML entre Chrome (ou Safari, Edge) et Firefox.

Heureusement, nous avons des pièces en commun sur lesquelles je compterai. Je vais localiser deux éléments différents: élément principal (entrée lui-même) et élément de curseur (cet élément que vous utilisez la souris pour glisser pour mettre à jour la valeur).

Notre CSS est principalement le suivant:

input[type="range"] {
  /* 主元素样式 */
}

input[type="range"][i]::-webkit-slider-thumb {
  /* Chrome、Safari和Edge的滑块样式 */
}

input[type="range"]::-moz-range-thumb {
  /* Firefox的滑块样式 */
}

Le seul inconvénient est que nous devons répéter deux fois le style de l'élément curseur. N'essayez pas de faire ce qui suit:

input[type="range"][i]::-webkit-slider-thumb,
input[type="range"]::-moz-range-thumb {
  /* 滑块样式 */
}

Cela ne fonctionne pas car l'ensemble du sélecteur n'est pas valide. Chrome etc. ne comprennent pas la partie ::-moz-*, tandis que Firefox ne comprend pas la partie ::-webkit-*. Pour plus de simplicité, dans cet article, j'utiliserai le sélecteur suivant:

input[type="range"]::thumb {
  /* 滑块样式 */
}

mais la démo contient de vrais sélecteurs avec des styles répétitifs. L'introduction est suffisante, commençons à coder!

style élément principal (étoile)

Nous définissons d'abord la taille:

input[type="range"] {
  --s: 100px; /* 控制大小 */

  height: var(--s);
  aspect-ratio: 5;

  appearance: none; /* 删除默认浏览器样式 */
}

Si nous pensons que chaque étoile est dans une zone carrée, pour une note 5 étoiles, nous avons besoin de largeur égale à cinq fois la hauteur, alors utilisez aspect-ratio: 5.

Les 5 valeurs sont également définies comme la valeur de l'attribut max de l'élément d'entrée.

<input type="range" max="5">

afin que nous puissions compter sur la fonction attr() nouvellement améliorée (actuellement chrome uniquement) pour lire la valeur au lieu de la définir manuellement!

input[type="range"] {
  --s: 100px; /* 控制大小 */

  height: var(--s);
  aspect-ratio: attr(max type(<number>));

  appearance: none; /* 删除默认浏览器样式 */
}</number>

Maintenant, vous pouvez contrôler le nombre d'étoiles en ajustant simplement l'attribut max. C'est génial car l'attribut max est également utilisé en interne par le navigateur, donc la mise à jour de la valeur contrôlera notre implémentation et le comportement du navigateur.

Cette version améliorée de attr() est actuellement disponible uniquement dans Chrome, donc toutes mes démos incluent un schéma de secours pour aider les navigateurs non pris en charge.

L'étape suivante consiste à utiliser un masque CSS pour créer des étoiles. Nous avons besoin que la forme soit répétée cinq fois (ou plus de fois, selon la valeur max), de sorte que la taille du masque doit être égale à var(--s) var(--s) ou var(--s) 100% ou simplifié à var(--s) car la hauteur sera égale à 100% par défaut.

&lt;input type=&quot;range&quot;&gt;

Vous pouvez demander quel est l'attribut? Je pense qu'il n'est pas surprenant que je vous dirai qu'il a besoin d'un gradient, mais cela peut aussi être un SVG. Cet article concerne la création d'un composant d'évaluation des étoiles, mais je veux que la partie étoile reste polyvalente afin que vous puissiez facilement la remplacer par n'importe quelle forme que vous souhaitez. C'est pourquoi j'ai dit "plus" dans le titre de ce post. Nous verrons plus tard comment obtenir différentes variantes différentes en utilisant la même structure de code. mask-image

Voici une démonstration montrant deux façons différentes de mettre en œuvre des formes d'étoiles. L'un consiste à utiliser des gradients, l'autre consiste à utiliser SVG.

Dans ce cas, l'implémentation SVG semble plus propre et le code est plus court, mais n'oubliez pas les deux méthodes, car les implémentations de gradient peuvent parfois faire mieux.

style curseur (valeur sélectionnée)

Concentrons-nous maintenant sur l'élément curseur. Utilisez la dernière démo, puis cliquez sur les étoiles et remarquez la position du curseur.

La bonne nouvelle est que pour toutes les valeurs (du minimum au maximum), le curseur est toujours dans la région d'une étoile donnée, mais chaque étoile a une position différente. Il serait encore mieux si la position est toujours la même quelle que soit la valeur. Idéalement, pour la cohérence, le curseur doit toujours être au centre de l'étoile.

Il s'agit d'une image qui illustre l'emplacement et comment la mettre à jour.

Ces lignes sont les positions de curseur pour chaque valeur. À gauche, nous avons la position par défaut où le curseur se déplace du bord gauche de l'élément principal vers le bord droit. À droite, si nous limitons la position du curseur à la petite zone en ajoutant de l'espace des deux côtés, nous obtiendrons un meilleur alignement. Cet espace est égal à la moitié de la taille d'une étoile, ou

. Nous pouvons utiliser un rembourrage pour ceci: var(--s)/2

input[type="range"] {
  /* 主元素样式 */
}

input[type="range"][i]::-webkit-slider-thumb {
  /* Chrome、Safari和Edge的滑块样式 */
}

input[type="range"]::-moz-range-thumb {
  /* Firefox的滑块样式 */
}
C'est mieux, mais pas parfait, parce que je ne pensais pas à la taille du curseur, ce qui signifie que nous ne centrivons pas vraiment. Ce n'est pas un problème, car j'utiliserai une largeur égale à 1px pour rendre la taille du curseur très petite.

input[type="range"][i]::-webkit-slider-thumb,
input[type="range"]::-moz-range-thumb {
  /* 滑块样式 */
}
Le curseur est maintenant une ligne mince, située au centre de l'étoile. J'utilise du rouge pour mettre en évidence la position, mais en réalité je n'ai pas besoin de couleur car elle sera transparente.

Vous pouvez penser que nous sommes encore loin du résultat final, mais nous avons presque terminé! Une propriété est manquante pour compléter ce puzzle:

. border-image L'attribut

nous permet de dessiner des décorations à l'extérieur de l'élément en utilisant sa fonction border-image. Pour ce faire, je rends le curseur plus petit et transparent. La coloration sera effectuée en utilisant outset. Je vais utiliser un dégradé avec deux couleurs solides comme source: border-image

input[type="range"]::thumb {
  /* 滑块样式 */
}
Nous écrivons le contenu suivant:

&lt;input type=&quot;range&quot;&gt;

Ce qui précède signifie que nous élargissons la zone de border-image par 100px de chaque côté de l'élément, et le gradient remplira cette zone. En d'autres termes, chaque couleur du gradient couvrira la moitié de la zone, c'est-à-dire 100px.

comprenez-vous la logique? Nous avons créé un ombrage débordant de chaque côté du curseur - un ombrage qui suivra logiquement le curseur afin que chaque fois qu'une étoile soit cliquée, elle se glisse en place!

Utilisons maintenant une très grande valeur au lieu de 100px:

Nous avons presque terminé! La coloration remplit toutes les étoiles, mais nous ne voulons pas qu'elle soit au milieu, mais sur toute l'étoile sélectionnée. Pour ce faire, nous mettons un peu le dégradé un peu, au lieu d'utiliser 50%, nous utilisons 50% var(--s)/2. Nous ajoutons un décalage égal à la moitié de la largeur de l'étoile, ce qui signifie que la première couleur prendra plus d'espace et que notre composant d'évaluation de l'étoile est parfait!

Nous pouvons toujours optimiser légèrement le code au lieu de définir la hauteur du curseur, nous le gardons à 0 et considérons la verticale border-image de outset pour étendre l'ombrage.

input[type="range"] {
  /* 主元素样式 */
}

input[type="range"][i]::-webkit-slider-thumb {
  /* Chrome、Safari和Edge的滑块样式 */
}

input[type="range"]::-moz-range-thumb {
  /* Firefox的滑块样式 */
}

Nous pouvons également utiliser des gradients coniques pour écrire des gradients différemment:

input[type="range"][i]::-webkit-slider-thumb,
input[type="range"]::-moz-range-thumb {
  /* 滑块样式 */
}

Je sais que la syntaxe de border-image n'est pas facile à comprendre, et je suis un peu rapide à expliquer. Mais j'ai un article très détaillé publié sur Smashing Magazine où je disséque cette propriété avec de nombreux exemples et je vous invite à le lire pour une compréhension plus approfondie de son fonctionnement.

Le code complet de notre composant est le suivant:

input[type="range"]::thumb {
  /* 滑块样式 */
}
input[type="range"] {
  --s: 100px; /* 控制大小 */

  height: var(--s);
  aspect-ratio: 5;

  appearance: none; /* 删除默认浏览器样式 */
}

c'est tout! Avec quelques lignes de code CSS, nous obtenons une belle composante de notation d'étoile!

cote de semi-star

Comment définir la granularité du score en demi-étoile? Ceci est très courant et nous pouvons compléter le code précédent en faisant quelques ajustements.

Tout d'abord, nous mettons à jour l'élément d'entrée pour incrémenter en demi-étape au lieu d'une étape complète:

<input type="range" max="5">

Par défaut, la taille de l'étape est égale à 1, mais nous pouvons la mettre à jour à 0,5 (ou toute valeur), puis à mettre à jour la valeur minimale à 0,5. Du côté CSS, nous changeons le rembourrage de var(--s)/2 à var(--s)/4 et faisons de même pour les compensations dans le gradient.

input[type="range"] {
  --s: 100px; /* 控制大小 */

  height: var(--s);
  aspect-ratio: attr(max type(<number>));

  appearance: none; /* 删除默认浏览器样式 */
}</number>

La différence entre les deux implémentations est un facteur de la moitié, qui est également la valeur de taille de pas. Cela signifie que nous pouvons utiliser attr() et créer du code commun qui fonctionne pour les deux cas.

input[type="range"] {
  --s: 100px; /* 控制大小 */

  height: var(--s);
  aspect-ratio: attr(max type(<number>));

  appearance: none; /* 删除默认浏览器样式 */

  mask-image: /* ... */;
  mask-size: var(--s);
}</number>

Il s'agit d'une démo où la modification de la taille de l'étape est tout ce que vous devez faire pour contrôler la granularité. N'oubliez pas que vous pouvez également utiliser l'attribut max pour contrôler le nombre d'étoiles.

Utilisez le clavier pour ajuster le score

Comme vous le savez, nous pouvons utiliser le clavier pour ajuster la valeur saisie par le curseur de plage, afin que nous puissions également utiliser le clavier pour contrôler le score. C'est une bonne chose, mais il y a un avertissement. En raison de l'utilisation de la propriété mask, nous n'avons plus de contour par défaut indiquant le foyer du clavier, qui est un problème d'accessibilité pour les utilisateurs qui comptent sur la saisie du clavier.

Pour une meilleure expérience utilisateur et rendre les composants plus accessibles, il est préférable d'afficher le plan de mise au point. La solution la plus simple consiste à ajouter un emballage supplémentaire:

&lt;input type=&quot;range&quot;&gt;

Cela aura un contour lorsque l'entrée à l'intérieur aura une mise au point:

input[type="range"] {
  /* 主元素样式 */
}

input[type="range"][i]::-webkit-slider-thumb {
  /* Chrome、Safari和Edge的滑块样式 */
}

input[type="range"]::-moz-range-thumb {
  /* Firefox的滑块样式 */
}

Essayez d'utiliser le clavier pour ajuster ces deux notes dans l'exemple suivant:

Une autre idée est de considérer une configuration de masque plus complexe qui maintient les petites zones autour de l'élément visible pour montrer le contour:

input[type="range"][i]::-webkit-slider-thumb,
input[type="range"]::-moz-range-thumb {
  /* 滑块样式 */
}

Je préfère utiliser la dernière méthode car elle maintient la mise en œuvre de l'élément unique, mais peut-être que votre structure HTML vous permet d'ajouter une mise au point sur l'élément parent, et vous pouvez garder la configuration du masque simple. Tout dépend de vous!

Plus d'exemples!

Comme je l'ai déjà dit, nous avons fait plus qu'un simple composant d'évaluation des étoiles. Vous pouvez facilement mettre à jour la valeur du masque pour utiliser toute forme souhaitée.

Voici un exemple, j'utilise le SVG du cœur au lieu de l'étoile.

Pourquoi n'est-ce pas un papillon?

Cette fois, j'utilise des images PNG comme masque. Si vous n'êtes pas habitué à utiliser SVG ou les gradients, vous pouvez utiliser des images transparentes. Tant que vous avez du SVG, de la PNG ou des gradients, vous pouvez faire n'importe quoi en forme avec cette méthode.

Nous pouvons encore personnaliser et créer un composant de contrôle de volume comme ce qui suit:

Dans le dernier exemple, au lieu de répéter la forme spécifique, j'ai utilisé une configuration de masque complexe pour créer la forme du signal.

Conclusion

Nous avons commencé avec un composant d'évaluation des étoiles et nous nous sommes retrouvés avec de nombreux exemples sympas. Le titre aurait pu être «comment concevoir des éléments d'entrée de la plage» parce que c'est ce que nous faisons. Nous avons mis à niveau un composant natif sans scripts ni balises supplémentaires et utilisé seulement quelques lignes de code CSS.

où êtes-vous? Pouvez-vous penser à un autre beau composant qui utilise la même structure de code? Partagez vos exemples dans la section des commentaires!

série d'articles

  1. Composants d'évaluation des étoiles uniquement CSS et plus encore! (Partie 1)
  2. Composants d'évaluation des étoiles uniquement CSS et plus encore! (Partie 2) - publié le 7 mars!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn