soy Kseso y esto EsCSS

Dos formas de seleccionar hermanos precedentes y numeración congruente

Cómo emular un selector de precedente en puro Css de dos formas diferentes: con la propiedad float o direction ejemplificado en un sistema de votación con estrellas. Y como guinda una numeración acorde a su visualización.

Dos formas de seleccionar hermanos precedentes y numeración congruente

·Por Kseso ✎ 1
Selector de hermanos precedentes con float o direction y numeración congruente
Las estrellas precedentes a la seleccionada cambian su apariencia

¿Utilizando sólo Css sería posible estilizar los hermanos precedentes a aquel que recibe algún evento, ya sea un :hover o si se trata de inputs hacerlo de forma sencilla e independiente del número de ellos? Esto es, sin necesidad de declarar tantas reglas Css como inputs haya y cada una con su pseuclase checked correspondiente.

La respuesta breve y concisa es Sí. Podemos.

Y antes de seguir, para que tú mismo lo veas en funcionamiento, el pen que lo demuestra. Fíjate que haciendo click sobre una de las estrellas cambia además de la apariencia de ella misma la de las estrellas anteriores a la que recibe el click. Y además que la numeración es ascendente (del 1 al 5).

See the Pen preceding sibling selector by Kseso (@Kseso) on CodePen.

Ver demo a full

Una breve explicación

Todo lo necesario para hacer posible las dos variantes de la demo ya ha sido explicado en detalle en algún artículo del blog, por lo que no entraré a fondo en sus explicaciones. Símplemente comento las particularidades y en las más significativas te enlazo al post correspondiente.

Emulando el selector de hermano precedente

Creo un article para contener las estrellas de votación y su imagen asociada tal que así:

<article> <section class='rating'> <input class='hide' type="radio" id="star-5" name="estrella" /><label for='star-5'> <svg viewBox="0 0 100 100"> <use xlink:href="#str"></use> </svg> </label> <!-- resto de estrellas --> </section> <img src='...' /> </article>

Todo se reduce al input y su label correspondiente. Lo único que cambia de un a otro es el id de cada input y el valor del atributo 'for' de la etiqueta asociada a él.

Como Css de momento no contempla un selector de hermanos precedentes hemos de simularlo. Para ello lo que hago es en el html escribir los inputs (y su etiqueta asociada) en orden descendiente: star-5, star-4... star-1

Para que visualmente se muestren las estrellas (labels de cada input) en el orden inverso al que aparecen en el html hay dos formas de lograrlo:

  1. En el primer article (imagen del Diablo de Tasmania, Taz) altero el orden en el que se "pintan" las estrellas con la declaración direction: rtl; en el section que las contiene: section.direction { direction: rtl; } Los detalles de esta técnica los tienes explicados en el post Propiedad direction: "flotados" a la derecha sin salir del flujo
  2. En el segundo article (imagen del Pirarata Sam) el orden de dibujado está invertido con un float: right para las etiquetas: section.float label { float: right; }

Con esta disposición en el html de las estrellas y su dibujado inverso al crear el documento sólo es cuestión de declarar unos estilos iniciales para las estrellas:

label svg { fill: rgba(21,191,204,.2); stroke: rgba(255,255,255,.4); stroke-width: 1px; width: 80%; max-width: 3rem; cursor: pointer; transition: .5s fill, .5s stroke .3s; }

Y a continuación una sola regla Css para todas y cada una de las estrella prececentes (según se muestran en la página) a la que marquemos input:checked ~ label svg y otra para resaltar la seleccionada input:checked + label svg

input:checked ~ label svg { fill: rgba(21,191,204,0); stroke: rgba(255,255,255,.4); stroke-width: 2px; } input:checked + label svg { fill: rgba(21,191,204,1); stroke: rgba(255,255,255,0); stroke-width: 1px; }

Numeración congruente: del 1 al 5

El segundo detalle es logar una numeración ascendente (del 1 al 5) al dibujarse la página y pese a que las estrellas se muestran en orden inverso (del 5 al 1).

Como puedes ver en el html no hay marcado individual y específico para cada estrella. Para lograr que aparezcan los números del 1 al 5 en cada una hago uso de los contadores Css.

.rating label::after { content: counter(rating); counter-increment: rating; }

Y para que cada grupo de estrellas tengan su numeración del 1 al 5 (sin que el segundo grupo continúe la numeración a partir del primero reseteamos (ponemos a cero) cada grupo de ellas:

.rating { counter-reset: rating; }

Pero de hacerlo sólo así nos encontramos con un pequeño problema: la numeración que se muestra es descendente. Esto es, aparece en primer lugar el número 5 y la última estrella que se muestra en pantalla tendrá asociado el número 1.

Así que hay que corregirlo. Para la demo opté por una de las posibles formas de lograr una numeración inversa. En concreto la que actúa vía css.

Para ello sólo hay que modificar ligeramente los valores de las propiedades relativas a los contadores Css añadiendo el número total de items que cuentan y la cantidad que descuenta cada uno:

.rating { counter-reset: rating 6; } .rating label::after { counter-increment: rating -1; }

Otra forma hubiese sido haciendo uso del atributo reversed="reversed" en cada uno de los dos elementos que crean (y resetean) el contador: los dos section.

avatar del Editor del blog

the obCSServer ᛯ Ramajero Argonauta, Enredique Amanuense de CSS.
#impoCSSible inside
Dicen que, en español, EsCss es el mejor blog de CSS. Posíblemente exageren.
@Kseso EsCss Kseso