Hai mai impostato z-index: 99999 su un elemento nel tuo CSS e non viene visualizzato sopra gli altri elementi? Un valore così grande dovrebbe facilmente posizionare visivamente quell'elemento sopra qualsiasi altra cosa, presupponendo che tutti i diversi elementi siano impostati su un valore inferiore o non impostati affatto. Una pagina web è solitamente rappresentata in uno spazio bidimensionale; tuttavia, applicando proprietà CSS specifiche, viene introdotto un piano immaginario dell'asse z per trasmettere la profondità. Questo piano è perpendicolare allo schermo e da esso l'utente percepisce l'ordine degli elementi, uno sopra l'altro. L’idea dietro l’immaginario asse z, la percezione dell’utente degli elementi impilati, è che le proprietà CSS che lo creano si combinano per formare quello che chiamiamo contesto di impilamento. Parleremo di come gli elementi vengono "impilati" su una pagina Web, di cosa controlla l'ordine di impilamento e di approcci pratici per "disimpilare" gli elementi quando necessario. Informazioni sull'impilamento dei contesti Immagina la tua pagina web come una scrivania. Man mano che aggiungi elementi HTML, disponi i pezzi di carta, uno dopo l'altro, sulla scrivania. L'ultimo pezzo di carta posizionato equivale all'elemento HTML aggiunto più recentemente e si trova sopra tutti gli altri fogli posizionati prima di esso. Questo è il normale flusso di documenti, anche per gli elementi nidificati. La scrivania stessa rappresenta il contesto di stacking root, formato dall'elemento , che contiene tutte le altre cartelle. Ora entrano in gioco proprietà CSS specifiche. Proprietà come posizione (con z-index), opacità, trasformazione e contenuto) funzionano come una cartella. Questa cartella prende un elemento e tutti i suoi figli, li estrae dallo stack principale e li raggruppa in un sottostack separato, creando quello che chiamiamo contesto di stacking. Per gli elementi posizionati, ciò accade quando dichiariamo un valore z-index diverso da auto. Per proprietà come opacità, trasformazione e filtro, il contesto di impilamento viene creato automaticamente quando vengono applicati valori specifici.
Cerca di capire questo: una volta che un pezzo di carta (cioè un elemento figlio) si trova all'interno di una cartella (cioè il contesto di impilamento del genitore), non potrà mai uscire da quella cartella o essere posizionato tra i fogli in una cartella diversa. Il suo z-index ora è rilevante solo all'interno della propria cartella.
Nell'illustrazione seguente, la carta B si trova ora nel contesto di impilatura della cartella B e può essere ordinata solo con altre carte nella cartella.
Immagina, se vuoi, di avere due cartelle sulla tua scrivania:
.cartella-a { z-indice: 1; } .cartella-b { z-indice: 2; }
Aggiorniamo un po' il markup. La cartella interna A è una pagina speciale, z-index: 9999. La cartella interna B è una pagina semplice, z-index: 5.
.pagina-speciale { z-index: 9999; } .plain-pagina { z-index: 5; }
Quale pagina è in alto? È la pagina .plain nella cartella B. Il browser ignora i documenti secondari e impila prima le due cartelle. Vede la cartella B (z-index: 2) e la posiziona sopra la cartella A (z-index: 1) perché sappiamo che due è maggiore di uno. Nel frattempo, la pagina .special-page impostata su z-index: 9999 è in fondo allo stack anche se il suo z-index è impostato sul valore più alto possibile. È anche possibile annidare i contesti sovrapposti (cartelle all'interno di cartelle), creando un "albero genealogico". Vale lo stesso principio: un bambino non potrà mai sfuggire alla cartella dei suoi genitori. Ora che hai capito come i contesti di impilamento si comportano come cartelle che raggruppano e riordinano i livelli, vale la pena chiedersi: perché alcune proprietà, come trasformazione e opacità, creano nuovi contesti di impilamento? Il punto è questo: queste proprietà non creano contesti di impilamento a causa del loro aspetto; lo fanno a causa di come funziona il browser dietro le quinte. Quando applichi trasformazione, opacità, filtro o prospettiva, stai dicendo al browser: "Ehi, questo elemento potrebbe spostarsi, ruotare o sbiadire, quindi preparati!"
Quando utilizzi queste proprietà, il browser crea un nuovo contesto di impilamento per gestire il rendering in modo più efficiente. Ciò consente al browser di gestire animazioni, trasformazioni ed effetti visivi in modo indipendente, riducendo la necessità di ricalcolare il modo in cui questi elementi interagiscono con il resto della pagina. Immaginatelo come se il browser dicesse: "Gestirò questa cartella separatamente in modo da non dover rimescolare l'intera scrivania ogni volta che cambia qualcosa al suo interno". Ma c'èun effetto collaterale. Una volta che il browser solleva un elemento nel proprio livello, deve “appiattire” tutto al suo interno, creando un nuovo contesto di sovrapposizione. È come prendere una cartella dalla scrivania per gestirla separatamente; tutto all'interno di quella cartella viene raggruppato e il browser ora lo tratta come una singola unità quando decide cosa si trova sopra cosa. Quindi, anche se le proprietà di trasformazione e opacità potrebbero non sembrare influenzare il modo in cui gli elementi si impilano visivamente, lo fanno, e serve per l'ottimizzazione delle prestazioni. Molte altre proprietà CSS possono anche creare contesti di stacking per ragioni simili. MDN fornisce un elenco completo se vuoi scavare più a fondo. Ce ne sono parecchi, il che illustra solo quanto sia facile creare inavvertitamente un contesto di stacking senza saperlo. Il problema del “disimpilamento”. I problemi di impilamento possono sorgere per molte ragioni, ma alcune sono più comuni di altre. I componenti modali sono uno schema classico perché richiedono di attivare o disattivare l'"apertura" del componente su uno strato superiore sopra tutti gli altri elementi, quindi di rimuoverlo dallo strato superiore quando è "chiuso". Sono abbastanza fiducioso che tutti noi ci siamo imbattuti in una situazione in cui apriamo un modal e, per qualsiasi motivo, non appare. Non è che non si sia aperto correttamente, ma che non è visibile in uno strato inferiore del contesto di impilamento. Questo ti lascia chiederti "come mai?" dato che hai impostato:
.sovrapposizione { posizione: fissa; /* crea il contesto di stacking */ indice z: 1; /* mette l'elemento su un livello sopra ogni altra cosa */ inserto: 0; larghezza: 100%; altezza: 100vh; overflow: nascosto; colore di sfondo: #00000080; }
Sembra corretto, ma se l'elemento genitore contenente il trigger modale è un elemento figlio all'interno di un altro elemento genitore anch'esso impostato su z-index: 1, tecnicamente posiziona il modale in un sottolivello oscurato dalla cartella principale. Diamo un'occhiata a quello scenario specifico e ad un paio di altre trappole comuni legate al contesto dello stacking. Penso che vedrai non solo quanto sia facile creare inavvertitamente contesti di stacking, ma anche come gestirli male. Inoltre, il modo in cui si ritorna a uno stato gestito dipende dalla situazione. Scenario 1: Il modale intrappolato
Puoi immediatamente vedere il tuo modale intrappolato in un livello di basso livello e identificare il genitore. Estensioni del browser Gli sviluppatori intelligenti hanno creato estensioni per aiutare. Strumenti come questa estensione Chrome "CSS Stacking Context Inspector" aggiungono una scheda z-index aggiuntiva ai tuoi DevTools per mostrarti informazioni sugli elementi che creano un contesto di stacking.
Estensioni dell'IDE Puoi anche individuare i problemi durante lo sviluppo con un'estensione come questa per VS Code, che evidenzia potenziali problemi di contesto di impilamento direttamente nel tuo editor.
Disimpilarsi e riprendere il controllo Dopo aver identificato la causa principale, il passo successivo è affrontarla. Esistono diversi approcci che puoi adottare per affrontare questo problema e li elencherò in ordine. Puoi scegliere chiunque a qualsiasi livello, però; nessuno può lamentarsi o ostacolare un altro. Cambia la struttura HTML Questa è considerata la soluzione ottimale. Per incorrere in un problema di contesto di stacking, devi aver inserito alcuni elementi in posizioni divertenti all'interno del tuo HTML. La ristrutturazione della pagina ti aiuterà a rimodellare il DOM ed eliminare il problema del contesto di stacking. Trova l'elemento problematico e rimuovilo dall'elemento di trapping nel markup HTML. Ad esempio, possiamo risolvere il primo scenario, "The Trapped Modal", spostando il .modal-container fuori dall'intestazione e posizionandolo da solo nell'elemento
.Questo contenuto ha uno z-index pari a 2 e non coprirà comunque il modale.Intestazione
Contenuto principale
Titolo modale
Ora, non sono dietro a nulla. Ho ottenuto una posizione migliore a seguito della ristrutturazione del DOM.
Quando fai clic sul pulsante “Apri modale”, la modale viene posizionata davanti a tutto il resto come dovrebbe essere. Guarda lo Scenario Pen 1: The Trapped Modal (Soluzione) [biforcato] di Shoyombo Gabriel Ayomide. Regola ilContesto di impilamento genitore nei CSS Cosa succede se l'elemento è uno che non puoi spostare senza interrompere il layout? È meglio affrontare la questione: il genitore stabilisce il contesto. Trova la proprietà (o le proprietà) CSS responsabile dell'attivazione del contesto e rimuovila. Se ha uno scopo e non può essere rimosso, assegna al genitore un valore z-index più alto rispetto agli elementi fratelli per sollevare l'intero contenitore. Con un valore z-index più alto, il contenitore principale si sposta in alto e i suoi figli appaiono più vicini all'utente. In base a quanto appreso nello scenario "Il menu a discesa sommerso", non possiamo spostare il menu a discesa fuori dalla barra di navigazione; non avrebbe senso. Tuttavia, possiamo aumentare il valore z-index del contenitore .navbar in modo che sia maggiore del valore z-index dell'elemento .content. barra di navigazione { sfondo: #333; /* indice z: 1; */ indice z: 3; posizione: relativa; }
Con questa modifica, il menu .dropdown ora appare davanti al contenuto senza alcun problema.
Guarda lo Scenario Pen 2: The Submerged Dropdown (Solution) [biforcato] di Shoyombo Gabriel Ayomide.
Prova i portali, se utilizzi un framework
In framework come React o Vue, un Portal è una funzionalità che ti consente di eseguire il rendering di un componente al di fuori della sua normale gerarchia principale nel DOM. I portali sono come un dispositivo di teletrasporto per i tuoi componenti. Ti consentono di eseguire il rendering dell'HTML di un componente in qualsiasi punto del documento (in genere direttamente in document.body) mantenendolo logicamente connesso al suo genitore originale per oggetti di scena, stato ed eventi. Questo è perfetto per sfuggire alle trappole del contesto di impilamento poiché l'output renderizzato appare letteralmente all'esterno del contenitore genitore problematico.
ReactDOM.createPortal(
Ciò garantisce che il contenuto del menu a discesa non sia nascosto dietro il suo genitore, anche se il genitore ha un overflow: nascosto o uno z-index inferiore. Nello scenario "Il tooltip ritagliato" che abbiamo esaminato in precedenza, ho utilizzato un portale per salvare il tooltip dall'overflow: clip nascosta inserendolo nel corpo del documento e posizionandolo sopra il trigger all'interno del contenitore. Guarda lo Scenario Pen 3: Il tooltip ritagliato (Soluzione) [biforcato] di Shoyombo Gabriel Ayomide. Presentazione del contesto di impilamento senza effetti collaterali Tutti gli approcci spiegati nella sezione precedente mirano a "disimpilare" elementi da contesti di stacking problematici, ma ci sono alcune situazioni in cui avrai effettivamente bisogno o vorrai creare un contesto di stacking. Creare un nuovo contesto di stacking è facile, ma tutti gli approcci hanno un effetto collaterale. Cioè, tranne che per l'uso dell'isolamento: isolare. Quando applicato a un elemento, il contesto di impilamento dei figli di quell'elemento è determinato rispetto a ciascun figlio e all'interno di quel contesto, anziché essere influenzato da elementi esterni ad esso. Un classico esempio è assegnare a quell'elemento un valore negativo, come z-index: -1. Immagina di avere un componente .card. Vuoi aggiungere una forma decorativa che si trova dietro il testo della carta .card, ma sopra lo sfondo della carta. Senza un contesto di stacking sulla carta, z-index: -1 invia la forma alla fine del contesto di stacking root (l'intera pagina). Questo lo fa scomparire dietro lo sfondo bianco del .card: Vedi Pen Negative z-index (problema) [biforcato] di Shoyombo Gabriel Ayomide. Per risolvere questo problema, dichiariamo l'isolamento: isolate sul genitore .card: Vedi Pen Negative z-index (soluzione) [biforcuta] di Shoyombo Gabriel Ayomide. Ora, l'elemento .card stesso diventa un contesto di impilamento. Quando il suo elemento figlio - la forma decorativa creata sullo pseudo-elemento :before - ha z-index: -1, va fino in fondo al contesto di stacking del genitore. Si posiziona perfettamente dietro il testo e sopra lo sfondo della carta, come previsto. Conclusione Ricorda: la prossima volta che il tuo z-index sembra fuori controllo, è un contesto di stacking intrappolato. Riferimenti
Contesto di impilamento (MDN) Contesti Z-index e stacking (web.dev) "Come creare un nuovo contesto di stacking con la proprietà di isolamento nei CSS", Natalie Pina "Che diavolo, z-index??", Josh Comeau
Ulteriori letture su SmashingMag
"Gestione dell'indice Z CSS in progetti di grandi dimensioni", Steven Frieson "Intestazioni appiccicose ed elementi a tutta altezza: una combinazione complicata", Philip Braunen "Gestione dell'indice Z in un'applicazione Web basata su componenti", Pavel Pomerantsev "La proprietà CSS dell'indice Z: uno sguardo completo", Louis Lazaris