Hvordan man gør det umulige muligt i CSS med lidt kreativitet

Hvis du nogensinde har brugt CSS-søskendevælgere, ved du, at der kun er to. Den +søskende Combinator vælger den første kamp, der kommer umiddelbart efter, og den ~efterfølgende-søskende combinator matcher alle dem, der kommer efter.

Men der er ingen måde at vælge, hvad der kom før. Enten forældrevælgerne eller tidligere søskendeudvælgere er simpelthen ikke noget.

Jeg ved, du vil have det, du ved, at jeg vil have det, men den barske sandhed er, at de ikke eksisterer (og sandsynligvis aldrig vil). Der er en million indlæg om hvorfor. Der er endda forslag til, hvordan de implementeres. Men vi sidder fast i den ensrettet behandling af CSS-regler, sandsynligvis for at beskytte os mod vores "manglende ekspertise", der sætter os fast i genstrømme og endda uendelige sløjfer.

Heldigvis kan vi, som med de fleste CSS-begrænsninger, falske det .

Den første ting at overveje er, hvorfor vi vil have tidligere søskende til at begynde med.

To sager kommer til at tænke på:

  1. Vi er nødt til at vælge alle søskende af et bestemt element, og den ~efterfølgende søskendekombinator vælger kun dem, der kommer efter.
  2. Vi skal kun vælge søskende, der kom før

1. Valg af alle søskende

Nogle gange er vi nødt til at vælge både tidligere og næste søskende. For at gøre det kan vi faktisk vælge forælder og bruge nogle tricks omkring det.

For eksempel, for at vælge alle spændvidder i den følgende struktur, når vi holder markøren over en af ​​dem, kunne vi bare bruge barnevælgeren på forældrenes svævebane. Vi sørger for at deaktivere pointer-eventsforældren og nulstille den tilbage på børnene. Så uanset hvilken handling vi ønsker skal ske, affyrer vi kun, når vi går ind i barnet og ikke forældren selv.

Hvis du har brug for at vælge alle søskende undtagen det, der holdes svævet, kan du kombinere den tidligere teknik med :notvælgeren for at udelukke den.

En typisk brugssag til dette er menuer:

Ovenstående kode vil skrue ned opaciteten af al <li> ele ment s men den ene er svævede.

Desuden kan du bruge filtre som type og nth-vælgerne for at være ekstra præcise på de søskende, som du vil påvirke.

Med lidt styling skal det fungere sådan:

Bemærk : Hvis du vil køre pointer-events:nonefremgangsmåden, skal du huske, at den kan rod med stabling (muligvis giver dig mulighed for at vælge elementer, der er "nedenfor" i stabelfølgende rækkefølge). Det fungerer heller ikke i IE10 og derunder, bortset fra implikationen, at du muligvis har brug for markørbegivenhederne til noget andet. Så vær ekstra forsigtig, når du bruger den.

2. Valg af hvad der kom før

I denne brugssag kan vi vende rækkefølgen på HTML'en, derefter sortere den tilbage i CSS og bruge den ~efterfølgende søskendekombinator eller +tilstødende søskendevælger. På denne måde vælger vi de næste søskende, men det ser ud som om vi vælger de tidligere.

Der er flere måder at gøre dette på. Den enkleste og sandsynligvis ældste ændrer skrivretningen på vores container:

Hvis dine elementer skal vise den faktiske tekst, kan du altid vende den tilbage:

Men det kan komme ud af hånden på mange måder. Heldigvis gør den moderne CSS-værktøjskasse det meget enklere og mere sikkert. Vi kan bare bruge Flexbox på containeren og vende ordren med flex-direction:row-reverse:

Det bedste ved Flexbox-tilgangen er, at vi ikke rod med skriveretningen. Vi har ikke brug for at nulstille børnene, og alt er meget mere forudsigeligt.

Brug af "tidligere søskende" til at oprette et CSS-Only-stjernebedømmelsessystem

Semantisk kan et klassificeringssystem betragtes som blot en simpel liste over radioknapper med deres tilsvarende etiketter. Det er nyttigt, da det giver os mulighed for at bruge :checkedpseudovælgeren til at ændre søskende.

Så lad os starte derfra:

Som vi diskuterede tidligere, er elementerne i omvendt rækkefølge for at give mulighed for en "tidligere søskende" -vælger. Bemærk, at vi bruger unicode "hvid stjerne" karakter (U + 2606) til at repræsentere de tomme stjerner.

Lad os vise dem side om side i den rigtige (omvendte) rækkefølge:

Skjul nu selve radioknapperne, ingen ønsker at se det:

Og anvend nogle styling på stjernekaraktererne:

Den eneste virkelig vigtige linje der er position:relative. Det vil give os mulighed for at placere et fyldt stjerne (U + 2605) pseudo-element på toppen af ​​det, som oprindeligt vil blive skjult.

Når vi svæver over en stjerne, skal det fyldte stjerne-pseudo-element blive synligt for det og alle tidligere søskende.

Samme ting for den valgte vurdering ved at matche alle etiketter, der kommer før den markerede alternativknap:

Husk at bruge det! Vigtige flag er nøjagtigt det modsatte af god praksis. Jeg gør det her, da der ikke er nogen anden måde at opnå den ekstra funktionalitet, der diskuteres i det næste afsnit uden den.

Sidst men ikke mindst er vi nødt til at "huske" den aktuelle vurdering, bare hvis brugeren ønsker at ændre den. For eksempel, hvis de havde valgt fem stjerner og af en eller anden grund vil ændre det til fire, skulle vi vise stjerner 1 til 4 som fyldte og den femte som halvgennemsigtige, når vi svæver over den fjerde.

Dette kan opnås ved at ændre opaciteten hos de tidligere søskende for det kontrollerede input, når du svæver over containeren:

Det var også derfor, vi havde brug for den opacity:1 !importanti den oprindelige svævende erklæring. Ellers ville denne sidste regel have vundet specificitetskonkurrencen og anvendt en semi-transparent fyld på alt.

Og der har vi det, et cross-browser, fuldt funktionelt CSS-kun-stjernesystem, der bruger "tidligere søskende" -vælgere.

Som du kan se, bare fordi "det er umuligt" betyder det ikke, at du ikke skal prøve. Programmering handler om at skubbe grænserne. Så når du rammer væggen, skal du bare skubbe lidt hårdere. Eller antager jeg at finde vej rundt i det kan være en bedre analogi? ... alligevel, ved du hvad jeg mener. Fortsæt med hacking!

En note om tilgængelighed

Det forrige uddrag er en forenkling for at gøre det let at forstå. Det er ikke noget, jeg vil anbefale at bruge til produktion på grund af mange tilgængelighedsbegrænsninger.

For at gøre uddraget lidt mere tilgængeligt, ville den første ting være at skjule radioknapperne med stort set enhver anden teknik end display:noneat gøre dem fokusable. Vi skal også tilføje nogle fokusringe på hele stjernekodestykket, når ethvert element indeni er fokuseret via pseudovælgeren :focus-within.

De identiske “☆” etiketter giver ingen mening for skærmlæsere, så den bedste tilgang er at have en an> inside the label with “n Stars” text, that will be hidden from sighted users .

Also the reverse HTML source + display:row-reverse approach makes keyboard rating awkward, as it doesn’t get reversed back. Flexbox and keyboard accessibility is quite a messy topic, but closest thing to a solution for that one is adding aria-flowtotag to each element, which at least fixes the issue for some screen readers + browser combinations.

For a more accessible snippet (using an alternative technique of modifying next siblings to look empty instead of trying to asses previous ones) check Patrick Cole’s, as we discussed in the answers below.