soy Kseso y esto EsCSS

Donde Css no alcanza se llega con imaginación: Selector de precedentes

Cómo lograr (emular) un falso selector de elementos precedentes con puro Css.

Donde Css no alcanza se llega con imaginación: Selector de precedentes

·Por Kseso ✎ 0

Ya hace unas fechas se mentó por las redes un curioso menú en el que varias opciones previas y otras tantas posteriores al elemento que recibe el :hover sufrían modificaciones: posición, fondo, márgenes...

Fíjate en la imagen. El puntero está en el cuarto item y hay una modificación de los 3 anteriores y los 3 posteriores.

Lógicamente se apoyaba en el uso de js. Recuerda que hoy por hoy Css no define selectores de ancestros (padres) o hermanos precedentes.

Pero... donde no alcanza Css se puede llegar siendo imaginativo

Y este caso en concreto lo resuelve y logra con puro Css @Stu Nicholls en su página cssplay.

Lo que sigue es un pequeño apunte a cómo consigue emular un selector de precedente. Como es normal en estos casos, se trata de una demo. Si pretendes implementarlo en una "producción" evalúa los pros y contras y las alternativas.

Ver demo Original

¿Y cómo lo logra? Pues una vez que ves el marcado html se hace evidente. Fíjate:

<ul class="menu"> <li class="p1"> <a href="index.html"><span>Promotional Items</span></a> </li> <li class="p2"> <a href="index.html"><span>Digital SLR Cameras</span></a> </li> <li class="p3"> <a href="index.html"><span>Zoom Lenses and Filters</span></a> </li> <li class="p4"> <a href="index.html"><span>Tripods and Monopods</span></a></li> <li class="p5"> <a href="index.html"><span>Flashguns and Accessories</span></a> </li> <li class="p6"> <a href="index.html"><span>Photo Framing</span></a> </li> <li class="p7"> <a href="index.html"><span>Wedding Photography</span></a> </li> <li class="p8"> <a href="index.html"><span>Photograph Albums</span></a> </li> <li class="icons"> <b class="m1">Promotional Items</b> <b class="m2">Digital SLR Cameras</b> <b class="m3">Zoom Lenses and Filters</b> <b class="m4">Tripods and Monopods</b> <b class="m5">Flashguns and Accessories</b> <b class="m6">Photo Framing</b> <b class="m7">Wedding Photography</b> <b class="m8">Photograph Albums</b> </li> </ul>

Ahí al final está la solución. Hay un item de la lista (li) a mayores que contiene, repetido, el texto de cada opción del menú con la clase m1, m2, m3...

Con estos elementos repetidos ya no necesitamos un selector de precedentes. Sólo es cuestión de hacer dos cosas.
La primera es posicionar estos últimos elementos convenientemente:

.menu li.icons { position:absolute; left:0; top:0; width:250px; height:240px; z-index:-1; }

Y la segunda un poco de paciencia y ser pelín minucioso a la hora de utilizar los selectores de hermanos ~ para "mover cada m1, m2... al hacer :hover sobre los li primeros:

.menu li:hover {height:48px; margin:-5px 0 0 0; width:276px; position:relative; z-index:100;} .menu li.p2:hover {margin:-3px 0 0 0;} .menu li.p3:hover {margin:-2px 0 0 0;} .menu li.p4:hover {margin:-2px 0 0 0;} .menu li.p5:hover {margin:-2px 0 0 0;} .menu li.p6:hover {margin:-2px 0 0 0;} .menu li.p7:hover {margin:-2px 0 0 0;} .menu li.p8:hover {margin:-2px 0 0 0;} .menu li.icons:hover {position:absolute; left:0; top:0; margin:0; width:250px; height:240px; z-index:-1;} .menu li.p1:hover ~ li.icons b.m1, .menu li.p2:hover ~ li.icons b.m2, .menu li.p3:hover ~ li.icons b.m3, .menu li.p4:hover ~ li.icons b.m4, .menu li.p5:hover ~ li.icons b.m5, .menu li.p6:hover ~ li.icons b.m6, .menu li.p7:hover ~ li.icons b.m7, .menu li.p8:hover ~ li.icons b.m8 {font-size:17px; height:48px; width:240px; line-height:48px; margin:-5px 0 -5px 16px; background-color:#c00; position:relative; z-index:10; box-shadow:0 0 20px rgba(0,0,0,0.6); color:#fff;} .menu li.p1:hover ~ li.icons b.m2, .menu li.p2:hover ~ li.icons b.m1, .menu li.p2:hover ~ li.icons b.m3, .menu li.p3:hover ~ li.icons b.m2, .menu li.p3:hover ~ li.icons b.m4, .menu li.p4:hover ~ li.icons b.m3, .menu li.p4:hover ~ li.icons b.m5, .menu li.p5:hover ~ li.icons b.m4, .menu li.p5:hover ~ li.icons b.m6, .menu li.p6:hover ~ li.icons b.m5, .menu li.p6:hover ~ li.icons b.m7, .menu li.p7:hover ~ li.icons b.m6, .menu li.p7:hover ~ li.icons b.m8, .menu li.p8:hover ~ li.icons b.m7 {font-size:16px; height:46px; width:232px; line-height:46px; margin:-4px 0 -4px 12px; background-color:#b00; position:relative; z-index:9; box-shadow:0 0 15px rgba(0,0,0,0.7); color:#f0f0f0;} .menu li.p1:hover ~ li.icons b.m3, .menu li.p2:hover ~ li.icons b.m4, .menu li.p3:hover ~ li.icons b.m1, .menu li.p3:hover ~ li.icons b.m5, .menu li.p4:hover ~ li.icons b.m2, .menu li.p4:hover ~ li.icons b.m6, .menu li.p5:hover ~ li.icons b.m3, .menu li.p5:hover ~ li.icons b.m7, .menu li.p6:hover ~ li.icons b.m4, .menu li.p6:hover ~ li.icons b.m8, .menu li.p7:hover ~ li.icons b.m5, .menu li.p8:hover ~ li.icons b.m6 {font-size:15px; height:44px; width:226px; line-height:44px; margin:-3px 0 -3px 8px; background-color:#a00; position:relative; z-index:8; box-shadow:0 0 10px rgba(0,0,0,0.8); color:#e8e8e8;} .menu li.p1:hover ~ li.icons b.m4, .menu li.p2:hover ~ li.icons b.m5, .menu li.p3:hover ~ li.icons b.m6, .menu li.p4:hover ~ li.icons b.m1, .menu li.p4:hover ~ li.icons b.m7, .menu li.p5:hover ~ li.icons b.m2, .menu li.p5:hover ~ li.icons b.m8, .menu li.p6:hover ~ li.icons b.m3, .menu li.p7:hover ~ li.icons b.m4, .menu li.p8:hover ~ li.icons b.m5 {font-size:14px; height:42px; width:222px; line-height:42px; margin:-2px 0 -2px 4px; background-color:#900; position:relative; z-index:7; box-shadow:0 0 5px rgba(0,0,0,0.9); color:#e0e0e0;}

Como ves, no hay magia. Sólo un poco de creatividad. Sí, sacrifica algún concepto como la semántica del html (por la repetición) pero logra el objetivo de lograr un comportamiento tal que parece que sí exista el selector de hermanos precedentes. Que era de lo que se trataba.

Créditos y autoria

Una vez más, esta realización es original de @Stu Nicholls y la puedes ver en su página cssplay y es funcional en IE7+, Firefox, Safari, Chrome and Opera (según el autor).

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