Un puro effetto di messa a fuoco della galleria CSS con :not

Nodo di origine: 1723238

Spesso in passato avevo bisogno di capire come aggiungere stili a tutti gli elementi all'interno del contenitore ma non quello sospeso.

Demo dell'effetto di "dissolvenza" previsto sui fratelli per consentire agli utenti di "concentrarsi" su un particolare elemento.

Questo effetto richiede la selezione dei fratelli di un elemento sospeso. Per questo applicavo JavaScript, aggiungendo o rimuovendo la classe che definiva le corrette regole CSS su mouseenter ed mouseleave eventi simili a questo:

Anche se il codice fa il trucco, il mio istinto mi ha sempre detto che ci deve essere un modo puro CSS per ottenere lo stesso risultato. Alcuni anni fa, mentre lavoravo su un certo dispositivo di scorrimento per la mia azienda, ho trovato una soluzione simile a come Chris Geelhoed ha ricreato la famosa animazione della home page di Netflix e ho capito che non avevo più bisogno di JavaScript per questo.

Un paio di mesi fa stavo cercando di implementare lo stesso approccio con un feed basato su griglia sul sito web della mia azienda e, boom, non ha funzionato a causa del divario tra gli elementi!

Fortunatamente per me, sembrava che le cose non dovessero rimanere così e, ancora una volta, non avevo bisogno di JavaScript.

Markup e CSS di base

Iniziamo a scrivere il codice preparando il markup corretto:

  • .grid è basato sulla griglia

      lista;

    • ed .grid__child gli elementi sono
    • bambini con cui vogliamo interagire.

    Il markup è simile al seguente:

    Lo stile dovrebbe assomigliare a questo:

    .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;
    }

    Questo codice di esempio creerà tre elementi dell'elenco che occupano tre colonne in una griglia.

    La potenza dei selettori CSS

    Ora aggiungiamo un po' di interattività. L’approccio che ho applicato inizialmente si basava su due passaggi:

    1. passando il mouse sul contenitore dovrebbero cambiare gli stili di tutti gli elementi all'interno...  
    2. …tranne quello su cui il cursore è sospeso in questo momento.

    Iniziamo afferrando ogni bambino mentre il cursore passa sopra il contenitore:

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

    In secondo luogo, escludiamo l'elemento attualmente sospeso e riduciamo il file opacity di qualsiasi altro bambino:

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

    E questo sarebbe perfettamente sufficiente per contenitori senza spazi tra gli elementi figlio:

    GIF animata di un cursore del mouse che interagisce con elementi che non sono separati da spazi vuoti.
    Demo di una soluzione che funziona senza lacune.

    Tuttavia, nel mio caso, non sono riuscito a rimuovere queste lacune:

    GIF animata del cursore del mouse che passa sopra gli elementi. Tuttavia, quando il mouse entra in uno spazio tra due elementi, l'effetto termina quando il mouse lascia l'elemento.
    Demo del problema riscontrato quando vengono introdotte delle lacune.

    Quando spostavo il mouse tra le tessere tutti gli elementi figli stavano scomparendo.

    Ignorando le lacune

    Possiamo supporre che i gap siano parti del contenitore a cui non vengono sovrapposti i suoi figli. Non vogliamo eseguire l'effetto ogni volta che il cursore entra nel contenitore, ma piuttosto quando passa sopra uno degli elementi al suo interno. Possiamo quindi ignorare il cursore che si sposta sopra gli spazi vuoti? 

    Sì, possiamo, usando pointer-events: none sul .grid contenitore e riportarli indietro pointer-events: auto sui suoi figli:

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

    Aggiungiamo semplicemente qualche interessante transizione sull'opacità e abbiamo un componente pronto:

    Probabilmente è ancora più interessante quando aggiungiamo più tessere e creiamo un layout bidimensionale:

    Il CSS finale è simile al seguente:

    .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;
    }

    Con solo 2 righe di codice aggiuntive abbiamo superato il problema del gap!

    Possibili problemi

    Sebbene sia una soluzione compatta, ci sono alcune situazioni in cui potrebbe richiedere alcune soluzioni alternative.

    Sfortunatamente, questo trucco non funzionerà quando vuoi che il contenitore sia scorrevole, ad esempio, come in una sorta di cursore orizzontale. IL pointer-events: none style ignorerebbe non solo l'evento hover ma anche tutti gli altri. In tali situazioni, puoi avvolgere il .grid in un altro contenitore, in questo modo:

    Sommario

    Ti incoraggio vivamente a sperimentare e provare a trovare un approccio più semplice e nativo per attività che di solito dovrebbero avere un certo livello di complessità. Le tecnologie Web, come i CSS, stanno diventando sempre più potenti e utilizzando soluzioni native pronte all'uso è possibile ottenere ottimi risultati senza la necessità di mantenere il codice e cederlo ai fornitori di browser.

    Spero che questo breve tutorial ti sia piaciuto e che lo abbia trovato utile. Grazie!

    L'autore ha selezionato il Tech Istruzione per ricevere una donazione come parte del Scrivi per DOnations .

    Timestamp:

    Di più da Trucchi CSS