Har du någonsin satt z-index: 99999 på ett element i din CSS, och det kommer inte ut ovanpå andra element? Ett värde som är stort bör enkelt placera det elementet visuellt ovanpå allt annat, förutsatt att alla olika element är inställda på antingen ett lägre värde eller inte alls. En webbsida representeras vanligtvis i ett tvådimensionellt utrymme; genom att tillämpa specifika CSS-egenskaper introduceras emellertid ett imaginärt z-axelplan för att förmedla djup. Detta plan är vinkelrätt mot skärmen, och från det uppfattar användaren ordningen på elementen, det ena ovanpå det andra. Tanken bakom den imaginära z-axeln, användarens uppfattning om staplade element, är att CSS-egenskaperna som skapar den kombineras för att bilda vad vi kallar ett staplingskontext. Vi kommer att prata om hur element "staplas" på en webbsida, vad som styr staplingsordningen och praktiska tillvägagångssätt för att "avstapla" element när det behövs. Om Stacking Contexts Föreställ dig din webbsida som ett skrivbord. När du lägger till HTML-element lägger du pappersbitar efter varandra på skrivbordet. Den sista biten papper som placeras motsvarar det senast tillagda HTML-elementet, och den ligger ovanpå alla andra papper som placerats före den. Detta är det normala dokumentflödet, även för kapslade element. Själva skrivbordet representerar rotstackningskontexten, bildad av -elementet, som innehåller alla andra mappar. Nu kommer specifika CSS-egenskaper in i bilden. Egenskaper som position (med z-index), opacitet, transform och contain) fungerar som en mapp. Den här mappen tar ett element och alla dess underordnade element, extraherar dem från huvudstacken och grupperar dem i en separat understack, vilket skapar vad vi kallar en staplingskontext. För positionerade element händer detta när vi deklarerar ett annat z-indexvärde än auto. För egenskaper som opacitet, transformation och filter skapas staplingskontexten automatiskt när specifika värden tillämpas.
Försök att förstå detta: När ett papper (dvs. ett underordnat element) väl finns i en mapp (d.v.s. förälderns staplingskontext), kan det aldrig lämna den mappen eller placeras mellan papper i en annan mapp. Dess z-index är nu bara relevant i sin egen mapp.
I illustrationen nedan är papper B nu i staplingskontexten för mapp B och kan endast beställas med andra papper i mappen.
Föreställ dig, om du vill, att du har två mappar på ditt skrivbord:
.folder-a { z-index: 1; } .folder-b { z-index: 2; }
Låt oss uppdatera markeringen lite. Inuti mapp A finns en specialsida, z-index: 9999. Inuti mapp B finns en vanlig sida, z-index: 5.
.special-page { z-index: 9999; } .plain-page { z-index: 5; }
Vilken sida är överst? Det är .plain-sidan i mapp B. Webbläsaren ignorerar underordnade papper och staplar de två mapparna först. Den ser mapp B (z-index: 2) och placerar den ovanpå mapp A (z-index: 1) eftersom vi vet att två är större än en. Samtidigt är sidan .special-page satt till z-index: 9999 längst ner i stacken även om dess z-index är satt till högsta möjliga värde. Staplingssammanhang kan också kapslas (mappar inuti mappar), vilket skapar ett "släktträd". Samma princip gäller: ett barn kan aldrig fly sina föräldrars pärm. Nu när du förstår hur staplingskontexter beter sig som mappar som grupperar och omordnar lager, är det värt att fråga: varför skapar vissa egenskaper – som transformation och opacitet – nya staplingskontexter? Här är grejen: dessa egenskaper skapar inte staplingssammanhang på grund av hur de ser ut; de gör det på grund av hur webbläsaren fungerar under huven. När du använder transformation, opacitet, filter eller perspektiv säger du till webbläsaren: "Hej, det här elementet kan flytta, rotera eller blekna, så var redo!"
När du använder dessa egenskaper skapar webbläsaren en ny staplingskontext för att hantera renderingen mer effektivt. Detta gör att webbläsaren kan hantera animationer, transformationer och visuella effekter oberoende, vilket minskar behovet av att räkna om hur dessa element interagerar med resten av sidan. Se det som att webbläsaren säger: "Jag kommer att hantera den här mappen separat så att jag inte behöver blanda om hela skrivbordet varje gång något i den ändras." Men det finnsen bieffekt. När webbläsaren väl lyfter ett element till sitt eget lager måste det "platta ut" allt inom det och skapa en ny staplingskontext. Det är som att ta en mapp från skrivbordet för att hantera den separat; allt i den mappen grupperas, och webbläsaren behandlar det nu som en enda enhet när den bestämmer vad som ska placeras ovanpå vad. Så även om egenskaperna för omvandling och opacitet kanske inte verkar påverka hur element staplas visuellt, så gör de det, och det är för prestandaoptimering. Flera andra CSS-egenskaper kan också skapa stackningskontexter av liknande skäl. MDN ger en komplett lista om du vill gräva djupare. Det finns en hel del, vilket bara illustrerar hur lätt det är att oavsiktligt skapa ett staplingssammanhang utan att veta om det. Problemet med "Unstapling". Stackningsproblem kan uppstå av många anledningar, men vissa är vanligare än andra. Modala komponenter är ett klassiskt mönster eftersom de kräver att komponenten "öppnas" på ett toppskikt ovanför alla andra element, och sedan tas bort från det översta lagret när den är "stängd". Jag är ganska säker på att vi alla har hamnat i en situation där vi öppnar en modal och, av vilken anledning som helst, visas den inte. Det är inte så att det inte öppnades ordentligt, utan att det inte syns i ett lägre lager av staplingssammanhanget. Detta får dig att undra "hur kommer det sig?" sedan du ställt in:
.overlay { position: fast; /* skapar staplingskontexten */ z-index: 1; /* lägger elementet på ett lager ovanför allt annat */ infälld: 0; bredd: 100%; höjd: 100vh; overflow: gömd; bakgrundsfärg: #00000080; }
Detta ser korrekt ut, men om det överordnade elementet som innehåller den modala utlösaren är ett underordnat element inom ett annat överordnat element som också är satt till z-index: 1, som tekniskt sett placerar modalen i ett underlager som är skylt av huvudmappen. Låt oss titta på det specifika scenariot och ett par andra vanliga fallgropar i staplingssammanhang. Jag tror att du inte bara kommer att se hur lätt det är att oavsiktligt skapa staplingskontexter, utan också hur man missköter dem. Hur du återgår till ett hanterat tillstånd beror också på situationen. Scenario 1: The Trapped Modal
Du kan omedelbart se din modal fångad i ett lågnivålager och identifiera föräldern. Webbläsartillägg Smarta utvecklare har byggt tillägg för att hjälpa. Verktyg som det här Chrome-tillägget "CSS Stacking Context Inspector" lägger till en extra z-index-flik till dina DevTools för att visa dig information om element som skapar en staplingskontext.
IDE-tillägg Du kan till och med upptäcka problem under utvecklingen med en tillägg som denna för VS Code, som lyfter fram potentiella problem med staplingskontext direkt i din editor.
Avstaplar och återtar kontrollen När vi har identifierat grundorsaken är nästa steg att ta itu med den. Det finns flera tillvägagångssätt du kan ta för att ta itu med det här problemet, och jag kommer att lista dem i ordning. Du kan välja vem som helst på vilken nivå som helst; ingen kan klaga eller hindra en annan. Ändra HTML-strukturen Detta anses vara den optimala lösningen. För att du ska stöta på ett problem med staplingskontext måste du ha placerat några element i roliga positioner i din HTML. Omstrukturering av sidan hjälper dig att omforma DOM och eliminera problemet med staplingskontext. Hitta det problematiska elementet och ta bort det från svällningselementet i HTML-uppmärkningen. Till exempel kan vi lösa det första scenariot, "The Trapped Modal", genom att flytta ut .modal-behållaren från rubriken och placera den i
-elementet själv.Det här innehållet har ett z-index på 2 och kommer fortfarande inte att täcka modal.Rubrik
Huvudinnehåll
När du klickar på knappen "Öppna Modal" placeras modalen framför allt annat som det ska vara. Se Pen Scenario 1: The Trapped Modal (Solution) [kaffed] av Shoyombo Gabriel Ayomide. JusteraFöräldrastaplingskontext I CSS Vad händer om elementet är ett du inte kan flytta utan att bryta layouten? Det är bättre att ta itu med problemet: föräldern skapar sammanhanget. Hitta CSS-egenskapen (eller egenskaperna) som ansvarar för att utlösa sammanhanget och ta bort den. Om det har ett syfte och inte kan tas bort, ge föräldern ett högre z-indexvärde än dess syskonelement för att lyfta hela behållaren. Med ett högre z-indexvärde flyttas den överordnade behållaren till toppen och dess underordnade visas närmare användaren. Baserat på vad vi lärde oss i scenariot "Den nedsänkta rullgardinsmenyn" kan vi inte flytta rullgardinsmenyn från navigeringsfältet; det skulle inte vara vettigt. Vi kan dock öka z-index-värdet för .navbar-behållaren till att vara större än .content-elementets z-index-värde. .navbar { bakgrund: #333; /* z-index: 1; */ z-index: 3; position: relativ; }
Med denna ändring visas nu rullgardinsmenyn framför innehållet utan problem.
Se Pen Scenario 2: The Submerged Dropdown (Solution) [forked] av Shoyombo Gabriel Ayomide.
Prova portaler, om du använder ett ramverk
I ramverk som React eller Vue är en portal en funktion som låter dig rendera en komponent utanför dess normala överordnade hierarki i DOM. Portaler är som en teleporteringsenhet för dina komponenter. De låter dig rendera en komponents HTML var som helst i dokumentet (vanligtvis direkt in i document.body) samtidigt som den håller den logiskt kopplad till sin ursprungliga förälder för rekvisita, tillstånd och händelser. Detta är perfekt för att undvika staplingskontextfällor eftersom den renderade utdata bokstavligen visas utanför den problematiska överordnade behållaren.
ReactDOM.createPortal(
Detta säkerställer att ditt rullgardinsinnehåll inte döljs bakom sin förälder, även om föräldern har översvämning: dolt eller ett lägre z-index. I scenariot "Det klippta verktygstipset" som vi tittade på tidigare använde jag en portal för att rädda verktygstipset från översvämningen: dolt klipp genom att placera det i dokumentets kropp och placera det ovanför avtryckaren i behållaren. Se pennscenario 3: The Clipped Tooltip (Solution) [kaffed] av Shoyombo Gabriel Ayomide. Introduktion av staplingskontext utan biverkningar Alla tillvägagångssätt som förklaras i föregående avsnitt syftar till att "avstapla" element från problematiska staplingssammanhang, men det finns vissa situationer där du faktiskt behöver eller vill skapa ett staplingssammanhang. Att skapa ett nytt staplingskontext är enkelt, men alla tillvägagångssätt kommer med en bieffekt. Det vill säga förutom att använda isolering: isolera. När den tillämpas på ett element bestäms staplingskontexten för det elementets barn i förhållande till varje barn och inom det sammanhanget, snarare än att påverkas av element utanför det. Ett klassiskt exempel är att tilldela det elementet ett negativt värde, till exempel z-index: -1. Föreställ dig att du har en .card-komponent. Du vill lägga till en dekorativ form som sitter bakom .card-texten, men ovanpå kortets bakgrund. Utan en staplingskontext på kortet skickar z-index: -1 formen till botten av rotstaplingskontexten (hela sidan). Detta gör att det försvinner bakom .cards vita bakgrund: Se Pennegativt z-index (problem) [förklädd] av Shoyombo Gabriel Ayomide. För att lösa detta deklarerar vi isolation: isolate på det överordnade .card: Se Pennegativt z-index (lösning) [förklädd] av Shoyombo Gabriel Ayomide. Nu blir själva .card-elementet en staplingskontext. När dess underordnade element - den dekorativa formen som skapas på :before pseudo-elementet - har z-index: -1, går det till botten av förälderns staplingskontext. Den sitter perfekt bakom texten och ovanpå kortets bakgrund, som det är tänkt. Slutsats Kom ihåg: nästa gång ditt z-index verkar utom kontroll är det ett fångat staplingssammanhang. Referenser
Stackningskontext (MDN) Z-index och stackningskontexter (web.dev) "Hur man skapar en ny staplingskontext med isoleringsegenskapen i CSS", Natalie Pina "What the Heck, z-index?", Josh Comeau
Mer läsning på SmashingMag
"Hantera CSS Z-Index i stora projekt", Steven Frieson "Sticky Headers and Full-Height Elements: A Tricky Combination", Philip Braunen "Hantera Z-index i en komponentbaserad webbapplikation", Pavel Pomerantsev "The Z-Index CSS Property: A Comprehensive Look", Louis Lazaris