En ren CSS Gallery Focus Effect med :not

Källnod: 1723238

Förr i tiden behövde jag ofta ta reda på hur man lägger till stilar till alla element i behållaren men inte den svävande.

Demo av den förväntade "fade-out"-effekten på syskon för att låta användare "fokusera" på ett visst element.

Denna effekt kräver att man väljer syskon till ett svävande element. Jag brukade använda JavaScript för detta, lägga till eller ta bort klassen som definierade de korrekta CSS-reglerna för mouseenter och mouseleave händelser, liknande detta:

Även om koden gör susen, sa min magkänsla mig alltid att det måste finnas något rent CSS-sätt för att uppnå samma resultat. För några år sedan, när jag arbetade på en viss reglage för mitt företag, kom jag på en lösning som liknar hur Chris Geelhoed återskapade den berömda animationen på Netflix hemsida och jag förstod att jag inte behövde JavaScript för detta längre.

För ett par månader sedan försökte jag implementera samma tillvägagångssätt för ett rutnätsbaserat flöde på min företagswebbplats och — boom — det fungerade inte på grund av gapet mellan elementen!

Lyckligtvis för mig såg det ut som att det inte behöver vara så här, och återigen behövde jag inte JavaScript för det.

Markup och bas CSS

Låt oss börja koda genom att förbereda rätt uppmärkning:

  • .grid är ett rutnätsbaserat

      lista;

    • och .grid__child element är
    • barn som vi vill umgås med.

    Markeringen ser ut så här:

    Stilen ska se ut så här:

    .grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, 15rem);
      grid-gap: 1rem;
    }
    
    .grid__child {
      background: rgba(0, 0, 0, .1);
      border-radius: .5rem;
      aspect-ratio: 1/1;
    }

    Denna exempelkod kommer att skapa tre listobjekt som upptar tre kolumner i ett rutnät.

    Kraften hos CSS-väljare

    Låt oss nu lägga till lite interaktivitet. Tillvägagångssättet som jag först tillämpade baserades på två steg:

    1. att sväva på behållaren bör ändra stilen för alla element inuti ...  
    2. …förutom den som markören svävar för tillfället.

    Låt oss börja med att ta tag i varje barn medan markören svävar över behållaren:

    .grid:hover .grid__child {
      /* ... */
    }

    För det andra, låt oss utesluta objektet som för närvarande svävar och minska opacity av något annat barn:

    .grid:hover .grid__child:not(:hover) {
      opacity: 0.3;
    }

    Och det här skulle räcka perfekt för behållare utan mellanrum mellan de underordnade elementen:

    Animerad GIF av en muspekare som interagerar med element som inte är åtskilda av några luckor.
    Demo av en lösning som fungerar utan luckor.

    Men i mitt fall kunde jag inte ta bort dessa luckor:

    Animerad GIF av en muspekare som svävar över element. Men när musen går in i ett mellanrum mellan två element, upphör effekten när musen lämnar elementet.
    Demo av problemet som uppstår när luckor införs.

    När jag flyttade musen mellan brickorna höll alla barnelement på att tona ut.

    Att ignorera luckorna

    Vi kan anta att luckor är delar av behållaren som inte är överlagrade av dess barn. Vi vill inte köra effekten varje gång markören går in i behållaren, utan snarare när den svävar över ett av elementen inuti. Kan vi ignorera att markören rör sig ovanför luckorna då? 

    Ja, vi kan, med hjälp av pointer-events: none.grid behållare och ta med dem tillbaka pointer-events: auto på sina barn:

    .grid {
      /* ... */
      pointer-events: none;
    }
    
    /* ... */
    
    .grid__child {
      /* ... */
      pointer-events: auto;
    }

    Låt oss bara lägga till en cool övergång på opacitet och vi har en färdig komponent:

    Det är förmodligen ännu coolare när vi lägger till fler brickor och skapar en 2-dimensionell layout:

    Den slutliga CSS ser ut så här:

    .grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, 15rem);
      grid-gap: 3rem;
      pointer-events: none;
    }
    
    .grid:hover .grid__child:not(:hover) {
      opacity: 0.3;
    }
    
    .grid__child {
      background: rgba(0, 0, 0, .1);
      border-radius: .5rem;
      aspect-ratio: 1/1;
      pointer-events: auto;
      transition: opacity 300ms;
    }

    Med endast 2 extra rader kod övervann vi gapproblemet!

    Möjliga problem

    Även om det är en kompakt lösning, finns det vissa situationer där det kan kräva vissa lösningar.

    Tyvärr kommer det här tricket inte att fungera när du vill att behållaren ska vara rullbar, t.ex. som i någon form av horisontell reglage. De pointer-events: none stil ignorerar inte bara hover-händelsen utan alla andra också. I sådana situationer kan du linda in .grid i en annan behållare, så här:

    Sammanfattning

    Jag uppmuntrar dig starkt att experimentera och försöka hitta ett enklare och mer naturligt tillvägagångssätt för uppgifter som vanligtvis förväntas ha en viss nivå av komplexitet. Webbteknik, som CSS, blir mer och mer kraftfull och genom att använda out-of-the-box inbyggda lösningar kan du uppnå fantastiska resultat utan att behöva underhålla din kod och överlåta den till webbläsarleverantörer.

    Jag hoppas att du gillade den här korta handledningen och tyckte att den var användbar. Tack!

    Författaren valde Tech Utbildning att ta emot en donation som en del av Skriv för donationer programmet.

    Tidsstämpel:

    Mer från CSS-tricks