Cinco métodos para las calificaciones de cinco estrellas | Programar Plus

En el mundo de los Me gusta y las estadísticas sociales, las reseñas son un método muy importante para dejar comentarios. A los usuarios a menudo les gusta conocer las opiniones de los demás antes de decidir qué artículos comprar ellos mismos, o incluso artículos para leer películas o restaurantes para cenar.

Los desarrolladores a menudo tienen dificultades con las revisiones: es común ver implementaciones inaccesibles y demasiado complicadas. Oye, Programar Plustiene un fragmento de uno que ahora está al borde de una década.

Analicemos enfoques nuevos, accesibles y fáciles de mantener para este patrón de diseño clásico. Nuestro objetivo será definir los requisitos y luego emprender un viaje sobre el proceso de pensamiento y las consideraciones sobre cómo implementarlos.

Alcance del trabajo

¿Sabía que el uso de estrellas como calificación se remonta a 1844, cuando se usaron por primera vez para calificar restaurantes en los manuales para viajeros de Murray, y luego las guías Michelin las popularizaron en 1931 como un sistema de tres estrellas? Hay mucha historia allí, ¡así que no es de extrañar que sea algo a lo que estamos acostumbrados!

Hay un par de buenas razones por las que han resistido la prueba del tiempo:

  1. Imágenes claras (en forma de cinco estrellas huecas o rellenas seguidas)
  2. Una etiqueta sencilla (que proporciona una descripción accesible, como aria-label)

Cuando lo implementamos en la web, es importante que nos concentremos en lograr ambos resultados.

También es importante implementar características como esta de la manera más versátil posible. Eso significa que deberíamos utilizar HTML y CSS tanto como sea posible y tratar de evitar JavaScript donde podamos. Y eso es porque:

  1. Las soluciones de JavaScript siempre serán diferentes según el marco. Los patrones que son típicos en JavaScript vanilla pueden ser anti-patrones en marcos (por ejemplo, React prohíbe la manipulación directa de documentos).
  2. Los lenguajes como JavaScript evolucionan rápidamente, lo que es genial para la comunidad, pero no tan buenos artículos como este. Queremos una solución que se pueda mantener y que sea relevante a largo plazo, por lo que debemos basar nuestras decisiones en herramientas consistentes y estables.

Métodos para crear las imágenes

Una de las muchas cosas maravillosas de CSS es que a menudo hay muchas formas de escribir lo mismo. Bueno, lo mismo ocurre con la forma en que podemos abordar el dibujo de estrellas. Hay cinco opciones que veo:

  • Usando un archivo de imagen
  • Usando una imagen de fondo
  • Usando SVG para dibujar la forma
  • Usando CSS para dibujar la forma
  • Usar símbolos Unicode

¿Cuál elegir? Depende. Vamos a verlos todos.

Método 1: usar un archivo de imagen

Usar imágenes significa crear elementos, al menos 5 de ellos para ser exactos. Incluso si llamamos al mismo archivo de imagen para cada estrella en una calificación de cinco estrellas, son cinco solicitudes en total. ¿Cuáles son las consecuencias de eso?

  1. Más nodos DOM hacen que la estructura del documento sea más compleja, lo que podría provocar una pintura de página más lenta. Los elementos en sí mismos también deben renderizarse, lo que significa que el tiempo de respuesta del servidor (si es SSR) o la generación del hilo principal (si estamos trabajando en un SPA) tiene que aumentar. Eso ni siquiera tiene en cuenta la lógica de representación que debe implementarse.
  2. No maneja calificaciones fraccionarias, digamos 2.3 estrellas de 5. Eso requeriría un segundo grupo de elementos duplicados enmascarados con clip-path encima de ellos. Esto aumenta la complejidad del documento en un mínimo de siete nodos DOM más y, potencialmente, decenas de declaraciones de propiedades CSS adicionales.
  3. El rendimiento optimizado debe considerar cómo se cargan las imágenes e implementar algo como la carga diferida) para imágenes fuera de la pantalla se vuelve cada vez más difícil cuando se agregan elementos repetidos como este a la mezcla.
  4. Realiza una solicitud, lo que significa que el almacenamiento en caché de TTL debe configurarse para lograr una segunda carga de imagen instantánea. Sin embargo, incluso si está configurado correctamente, la primera carga seguirá sufriendo porque TTFB espera del servidor. Se deben considerar las técnicas de captación previa, de conexión previa o el trabajador del servicio para optimizar la primera carga de la imagen.
  5. Crea un mínimo de cinco elementos no significativos para un lector de pantalla. Como comentamos anteriormente, la etiqueta es más importante que la imagen en sí. No hay razón para dejarlos en el DOM porque no agregan significado a la calificación, son solo un objeto visual común.
  6. Las imágenes pueden ser parte de medios manejables, lo que significa que los administradores de contenido podrán cambiar la apariencia de la estrella en cualquier momento, incluso si es incorrecta.
  7. Permite una apariencia versátil de la estrella, sin embargo el estado activo solo puede ser similar al estado inicial. No es posible cambiar la imagen. src atributo sin JavaScript y eso es algo que estamos tratando de evitar.

¿Se pregunta cómo se vería la estructura HTML? Probablemente algo como esto:

<div class="Rating" aria-label="Rating of this item is 3 out of 5">
  <img src="https://css-tricks.com/static/assets/star.png" class="Rating--Star Rating--Star__active">
  <img src="https://css-tricks.com/static/assets/star.png" class="Rating--Star Rating--Star__active">
  <img src="https://css-tricks.com/static/assets/star.png" class="Rating--Star Rating--Star__active">
  <img src="https://css-tricks.com/static/assets/star.png" class="Rating--Star">
  <img src="https://css-tricks.com/static/assets/star.png" class="Rating--Star">
</div>

Para cambiar la apariencia de esas estrellas, podemos usar múltiples propiedades CSS. Por ejemplo:

.Rating--Star {
  filter: grayscale(100%); // maybe we want stars to become grey if inactive
  opacity: .3; // maybe we want stars to become opaque
}

Un beneficio adicional de este método es que <img> el elemento está configurado en inline-block de forma predeterminada, por lo que se necesita un poco menos de estilo para colocarlos en una sola línea.

Accesibilidad: ★★ ☆☆☆
Gestión: ★★★★ ☆
Rendimiento: ★ ☆☆☆☆
Mantenimiento: ★★★★ ☆
En general: ★★ ☆☆☆

Método 2: usar una imagen de fondo

Esta fue una vez una implementación bastante común. Dicho esto, todavía tiene sus pros y sus contras.

Por ejemplo:

  1. Claro, es solo una solicitud de servidor que alivia muchas necesidades de almacenamiento en caché. Al mismo tiempo, ahora tenemos que esperar tres eventos adicionales antes de mostrar las estrellas: eso sería (1) el CSS para descargar, (2) el CSSOM para analizar y (3) la imagen en sí para descargar.
  2. Es muy fácil cambiar el estado de una estrella de vacía a llena, ya que todo lo que realmente estamos haciendo es cambiar la posición de una imagen de fondo. Sin embargo, tener que abrir un editor de imágenes y volver a cargar el archivo cada vez que se necesita un cambio en la apariencia real de las estrellas no es lo más ideal en lo que respecta al mantenimiento.
  3. Podemos usar propiedades CSS como background-repeat propiedad y clip-path para reducir el número de nodos DOM. En cierto sentido, podríamos usar un solo elemento para que esto funcione. Por otro lado, no es genial que técnicamente no tengamos un buen marcado accesible para identificar las imágenes a los lectores de pantalla y que las estrellas sean reconocidas como entradas. Bueno, no fácilmente.

En mi opinión, las imágenes de fondo son probablemente las apariciones de estrellas complejas más utilizadas en las que ni CSS ni SVG son suficientes para obtener el estilo exacto. De lo contrario, el uso de imágenes de fondo todavía presenta muchos compromisos.

Accesibilidad: ★★★ ☆☆
Gestión: ★★★★ ☆
Rendimiento: ★★ ☆☆☆
Mantenimiento: ★★★ ☆☆
En general: ★★★ ☆☆

Método 3: usar SVG para dibujar la forma

¡SVG es genial! Tiene muchos de los mismos beneficios de dibujo personalizado que las imágenes ráster, pero no requiere una llamada al servidor si está integrado porque, bueno, ¡es simplemente código!

Podríamos incorporar cinco estrellas en HTML, pero podemos hacerlo mejor, ¿verdad? Chris nos ha mostrado un buen enfoque que nos permite proporcionar el marcado SVG para una sola forma como <symbol></symbol> y llámalo varias veces con con <use></use>.

<!-- Draw the star as a symbol and remove it from view -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="star" viewBox="214.7 0 182.6 792">
    <!-- <path>s and whatever other shapes in here -->  
  </symbol>
</svg>
    
<!-- Then use anywhere and as many times as we want! -->
<svg class="icon">
  <use xlink:href="https://css-tricks.com/five-methods-for-five-star-ratings/#star"></use>
</svg>

<svg class="icon">
  <use xlink:href="https://css-tricks.com/five-methods-for-five-star-ratings/#star"></use>
</svg>

<svg class="icon">
  <use xlink:href="https://css-tricks.com/five-methods-for-five-star-ratings/#star"></use>
</svg>

<svg class="icon">
  <use xlink:href="https://css-tricks.com/five-methods-for-five-star-ratings/#star"></use>
</svg>

<svg class="icon">
  <use xlink:href="https://css-tricks.com/five-methods-for-five-star-ratings/#star"></use>
</svg>

¿Cuales son los beneficios? Bueno, estamos hablando de cero solicitudes, HTML más limpio, sin preocupaciones por la pixelación y atributos accesibles desde el primer momento. Además, tenemos la flexibilidad de usar las estrellas en cualquier lugar y la escala para usarlas tantas veces como queramos sin penalizaciones adicionales en el rendimiento. ¡Puntaje!

El beneficio final es que esto tampoco requiere gastos generales adicionales. Por ejemplo, no necesitamos un proceso de compilación para que esto suceda y no se depende de un software de edición de imágenes adicional para realizar más cambios en el futuro (aunque, seamos honestos, ayuda).

Accesibilidad: ★★★★★
Gestión: ★★ ☆☆☆
Rendimiento: ★★★★★
Mantenimiento: ★★★★ ☆
En general: ★★★★ ☆

Método 4: usar CSS para dibujar la forma

Este método es muy similar a background-image , aunque lo mejora optimizando el dibujo de la forma con propiedades CSS en lugar de hacer una llamada para una imagen. Podríamos pensar en CSS como elementos de estilo con bordes, fuentes y otras cosas, pero también es capaz de producir ilustraciones bastante complejas. Basta con mirar el ahora famoso retrato de “Francine” de Diana Smith.

Francine, una réplica CSS de una pintura al óleo realizada en CSS por Diana Smith (Fuente)

No nos vamos a volver tan locos, pero puedes ver a dónde vamos con esto. De hecho, ya hay una buena demostración de una forma de estrella CSS aquí en CSS-Tricks.

Ver la pluma
¡Cinco estrellas! por Geoff Graham (@geoffgraham)
en CodePen.

O, oye, podemos ser un poco más astutos usando el clip-path propiedad para dibujar un polígono de cinco puntos. ¡Incluso menos CSS! Pero tenga cuidado con el comprador, porque el kilometraje de la compatibilidad con varios navegadores puede variar.

Ver la pluma
¡5 estrellas recortadas! por Geoff Graham (@geoffgraham)
en CodePen.

Accesibilidad: ★★★★★
Gestión: ★★ ☆☆☆
Rendimiento: ★★★★★
Mantenimiento: ★★ ☆☆☆
En general: ★★★ ☆☆

Método 5: usar símbolos Unicode

Este método es muy agradable, pero muy limitado en términos de apariencia. ¿Por qué? Porque la apariencia de la estrella está grabada en piedra como un carácter Unicode. Pero, bueno, hay variaciones para una estrella llena (★) y una estrella vacía (☆) ¡que es exactamente lo que necesitamos!

Los caracteres Unicode son algo que puede copiar y pegar directamente en el HTML:

Ver la pluma
Estrellas Unicode! por Geoff Graham (@geoffgraham)
en CodePen.

Podemos usar fuente, color, ancho, alto y otras propiedades para cambiar el tamaño y estilo de las cosas un poco, pero no mucha flexibilidad aquí. Pero este es quizás el enfoque HTML más básico del grupo que casi parece demasiado obvio.

En cambio, podemos mover el contenido al CSS como un pseudoelemento. Eso da rienda suelta a capacidades de estilo adicionales, incluido el uso de propiedades personalizadas para rellenar las estrellas fraccionadamente:

Ver la pluma
Pequeña pero accesible calificación de 5 estrellas por Fred Genkin (@FredGenkin)
en CodePen.

Analicemos un poco más este último ejemplo porque termina obteniendo los mejores beneficios de otros métodos y los empalma en una única solución con muy pocos inconvenientes y, al mismo tiempo, cumple con todos nuestros requisitos.

Comencemos con HTML. hay un solo elemento que no realiza llamadas al servidor mientras mantiene la accesibilidad:

<div class="stars" style="--rating: 2.3;" aria-label="Rating of this product is 2.3 out of 5."></div>

Como puede ver, el valor de calificación se pasa como una propiedad CSS personalizada en línea (--rating). Esto significa que no se requiere una lógica de representación adicional, excepto para mostrar el mismo valor de calificación en la etiqueta para una mejor accesibilidad.

Echemos un vistazo a esa propiedad personalizada. En realidad, es una conversión de un valor a un porcentaje que se maneja en el CSS usando el calc() función:

--percent: calc(var(--rating) / 5 * 100%);

Elegí seguir esta ruta porque las propiedades de CSS, como width y linear-gradient – No acepto <number></number> valores. Aceptan <length></length> y <percentage></percentage> en su lugar y tienen unidades específicas en ellos, como % y px, em. Inicialmente, el valor de calificación es flotante, que es un <number></number> escribe. El uso de esta conversión ayuda a garantizar que podamos usar los valores de varias maneras.

Llenar las estrellas puede parecer difícil, pero resulta bastante simple. Necesitamos una linear-gradient background para crear paradas de color duro donde debe terminar el relleno de color dorado:

background: linear-gradient(90deg,
  var(--star-background) var(--percent), 
  var(--star-color) var(--percent)
);

Tenga en cuenta que estoy usando variables personalizadas para los colores porque quiero que los estilos se puedan ajustar fácilmente. Dado que las propiedades personalizadas se heredan de los estilos de los elementos principales, puede definirlas una vez en el :root element y luego anular en un contenedor de elementos. Esto es lo que puse en la raíz:

:root {
  --star-size: 60px;
  --star-color: #fff;
  --star-background: #fc0;
}

Lo último que hice fue recortar el fondo a la forma del texto para que el degradado del fondo tome la forma de las estrellas. Piense en las estrellas Unicode como plantillas que usamos para recortar la forma de las estrellas del color de fondo. O como cortadores de galletas en forma de estrellas que se machacan directamente en la masa:

-webkit-background-clip: text;
-webkit-text-fill-color: transparent;

La compatibilidad del navegador con el recorte de fondo y los rellenos de texto es bastante buena. IE11 es el único que se resiste.

Accesibilidad: ★★★★★
Gestión: ★★ ☆☆☆
Rendimiento: ★★★★★
Mantenimiento: ★★★★★
En general: ★★★★★

Pensamientos finales

Archivos de imagen Imagen de fondo SVG Formas CSS Símbolos Unicode
Accesibilidad ★★ ☆☆☆ ★★★ ☆☆ ★★★★★ ★★★★★ ★★★★★
Gestión ★★★★ ☆ ★★★★ ☆ ★★ ☆☆☆ ★★ ☆☆☆ ★★ ☆☆☆
Rendimiento ★ ☆☆☆☆ ★★ ☆☆☆ ★★★★★ ★★★★★ ★★★★★
Mantenimiento ★★★★ ☆ ★★★ ☆☆ ★★★★ ☆ ★★ ☆☆☆ ★★★★★
General ★★ ☆☆☆ ★★★ ☆☆ ★★★★ ☆ ★★★ ☆☆ ★★★★★

De los cinco métodos que cubrimos, dos son mis favoritos: usar SVG (método 3) y usar caracteres Unicode en pseudoelementos (método 5). Definitivamente hay casos de uso en los que una imagen de fondo tiene mucho sentido, pero parece que se evalúa mejor caso por caso en lugar de una solución de referencia.

Siempre debe considerar todos los beneficios y desventajas de un método específico. Esta es, en mi opinión, la belleza del desarrollo front-end. Hay varias formas de hacerlo y se requiere la experiencia adecuada para implementar funciones de manera eficiente.