Man könnte glauben, der z-index
ist ganz simpel zu verstehen, jedoch versteckt
sich dahinter noch ein komplexeres Thema, welches vielen Webentwicklern nicht
bekannt ist: Der Stacking-Kontext, der beim Stapeln von Elementen durchaus mal
Probleme bereiten kann.
In diesem Artikel erkläre ich ausführlich, worum es sich bei einem Stacking-Kontext genau handelt, wie sie entstehen und welche Auswirkungen sie auf die Stapelung von Elementen haben.
z-index
– ein ganz einfaches Konzept?
Zunächst einmal erscheint einem das Konzept hinter dem z-index
völlig simpel
und selbsterklärend: Ein Element, welches nicht statisch positioniert ist, kann
mithilfe dieses Indexes auf der z-Achse angeordnet werden und somit das
Standard-Verhalten für die Stapelung von Elementen überschreiben. Je höher
dieser Index ist, desto weiter oben im Stapel liegt das Element.
So weit, so gut, dachte ich. Bis sich mir vor einigen Wochen ein seltsamer Fall
darbot: Gegeben war ein Seitenlayout mit 2 Spalten, die rechte Spalte als
Hauptspalte mit dem eigentlichen Inhalt, die linke Spalte als Sidebar mit einem
Filter, welcher Popups öffnen kann. Diese Popups ragen nach rechts in die
Hauptspalte hinein. In diesem Fall wurden die Popups von einigen Inhalten aus
der Hauptspalte überlagert. Ein schneller Blick zeigte, dass die Popups einen
z-index
von 9 hatten, die Inhalte in der Hauptspalte aber 20. Soweit sah noch
alles logisch aus, doch das Erhöhen des z-index
der Popups behob das Problem
nicht. Selbst mit einem Index von 1000 wurden die Popups weiterhin von den
Inhalten der Hauptspalte überlagert, die nur einen Index von 20 hatten.
Der Grund hierfür ist denkbar simpel, jedoch wissen viele Leute nicht darüber Bescheid: Die Popups lagen wegen der Sidebar in einem anderen Stacking-Kontext, welcher weiter unten im Stapel eingeordnet wurde.
Stacking-Kontext
Ein Stacking-Kontext ist eine Art “Ebenengruppe”. Mindestens einen solchen
Kontext gibt es auf jeder Seite: Der Kontext des html
-Tags im DOM.
Verschiedene CSS-Eigenschaften auf einem Element können einen weiteren Kontext
aufmachen. Alle Kinderelemente dieses Elements gehören dann zu diesem neuen
Kontext.
Alle Kontexte ordnen zunächst ihre eigenen Kinder auf der z-Achse an. Nachdem dies geschehen ist, ordnet sich der Kontext selbst relativ zu seinen Geschwister-Kontexten auf der z-Achse ein und nimmt dabei alle seine Kinder mit. Die Kinder eines niedrigeren Kontext liegen also automatisch unter den Kindern eines höheren.
Man kann den z-index
eines Kinderelements auch als eine Art
“Versionsnummer” verstehen, um es sich leichter vorstellen zu können: Ein
Element “A” mit einem z-index
von 5 innerhalb eines Kontexts mit einem
z-index
von 2 hat effektiv einen z-index
von “2.5”, d. h. der z-index
des
Kontexts entspricht der Major-Versionsnummer und der z-index
des enthaltenen
Elements der Minor-Versionsnummer. Ein Element “B” mit z-index
1 innerhalb
eines Kontexts mit z-index
3 entspricht dann einer Version “3.1”. Im Ergebnis
liegt damit “B” über “A”, obwohl “B” allein einen niedrigeren z-index
hat als
“A”. Es liegt jedoch in einem höheren Kontext und wird deshalb weiter oben
angeordnet.
Folgende CSS-Eigenschaften eröffnen einen zusätzlichen Stacking-Kontext (inkl. Doku-Links der weniger verbreiteten Eigenschaften):
position: relative/absolute
in Kombination mit einemz-index
position: fixed
(auch ohne z-index)transform
auf einem anderen Wert alsnone
perspective
auf einem anderen Wert alsnone
isolation: isolate
(Doku)opacity
kleiner als 1filter
auf einem anderen Wert alsnone
mix-blend-mode
auf einem anderen Wert alsnormal
(Doku)-webkit-overflow-scrolling: touch
(Doku)will-change
mit irgendeiner der oben genannten Eigenschaften (Doku)
Um nochmal auf mein konkretes Problem zurückzukommen: Unsere komplette Sidebar
beinhaltete einen div
-Container für den Filter, welcher relativ positioniert
wurde sowie einen z-index
von 3 hatte. Damit lag der Filter unterhalb der
Elemente der Hauptspalte mit z-index
20. Ein Erhöhen des z-index
der Popups
hat nicht geholfen, da diese nur innerhalb des Filter-Kontext mit Index 3
galten, sie konnten also niemals die Elemente mit Index 20 überlagern.
Die Lösung bestand darin, den z-index
und damit den Stacking-Kontext des
Filters als Ganzes anzuheben, sodass er alle Elemente der Hauptspalte
überlagert. Dann funktionieren auch die zugehörigen Popups wieder, wie sie es
sollen. Sie benötigen außerdem keinen irrsinnig hohen z-index
mehr, um alles
zu überlagern, sondern können wieder bei 1 anfangen.
Im folgenden noch ein knappes Beispiel zur Veranschaulichung:
See the Pen Stacking-Context by Linda Grünwald (@lindagruenwald) on CodePen.
Man sieht z. B., dass das achte Element einen z-index
von 1 hat, jedoch das
zweite Element mit einem Index von 2 überlagert. Gleichermaßen überlagert das
erste Element mit einem Index von 8 das siebte Element mit einem Index von 9.
Beides kommt daher, dass das siebte und achte Element innerhalb eines
Stacking-Kontexts mit Index 5 liegen, welcher vom fünften Element geöffnet
wurde.