Alguna vegada has establert z-index: 99999 en un element del teu CSS i no surt a sobre d'altres elements? Un valor tan gran hauria de col·locar fàcilment aquest element visualment a sobre de qualsevol altra cosa, suposant que tots els diferents elements s'estableixen en un valor inferior o no s'estableixen en absolut. Una pàgina web normalment es representa en un espai bidimensional; tanmateix, aplicant propietats CSS específiques, s'introdueix un pla imaginari de l'eix z per transmetre la profunditat. Aquest pla és perpendicular a la pantalla, i des d'ella, l'usuari percep l'ordre dels elements, uns sobre els altres. La idea darrere de l'eix z imaginari, la percepció de l'usuari dels elements apilats, és que les propietats CSS que el creen es combinen per formar el que anomenem un context d'apilament. Parlarem de com s'"apilen" els elements en una pàgina web, què controla l'ordre d'apilament i enfocaments pràctics per "desapilar" els elements quan sigui necessari. Sobre l'apilament de contextos Imagineu la vostra pàgina web com un escriptori. A mesura que afegiu elements HTML, esteu posant trossos de paper, un darrere l'altre, a l'escriptori. L'últim tros de paper col·locat és equivalent a l'element HTML afegit més recentment i se situa a sobre de tots els altres papers col·locats abans. Aquest és el flux de documents normal, fins i tot per als elements imbricats. El mateix escriptori representa el context d'apilament arrel, format per l'element , que conté totes les altres carpetes. Ara, entren en joc propietats CSS específiques. Propietats com la posició (amb índex z), l'opacitat, la transformació i el contingut) actuen com una carpeta. Aquesta carpeta agafa un element i tots els seus fills, els extreu de la pila principal i els agrupa en una subpila separada, creant el que anomenem un context d'apilament. Per als elements posicionats, això passa quan declarem un valor d'índex z diferent de l'auto. Per a propietats com l'opacitat, la transformació i el filtre, el context d'apilament es crea automàticament quan s'apliquen valors específics.
Proveu d'entendre això: un cop un tros de paper (és a dir, un element secundari) està dins d'una carpeta (és a dir, el context d'apilament dels pares), mai no podrà sortir d'aquesta carpeta ni col·locar-se entre papers en una carpeta diferent. El seu índex z ara només és rellevant dins de la seva pròpia carpeta.
A la il·lustració següent, el paper B es troba ara dins del context d'apilament de la carpeta B i només es pot demanar amb altres papers de la carpeta.
Imagineu, si voleu, que teniu dues carpetes al vostre escriptori:
.folder-a { z-index: 1; } .folder-b { z-index: 2; }
Actualitzem una mica el marcatge. Inside Folder A és una pàgina especial, z-index: 9999. Inside Folder B és una pàgina senzilla, z-index: 5.
.special-page { z-index: 9999; } .plain-page { índex z: 5; }
Quina pàgina és a dalt? És el .plain-page de la carpeta B. El navegador ignora els papers secundaris i apila les dues carpetes primer. Veu la carpeta B (índex z: 2) i la col·loca a sobre de la carpeta A (índex z: 1) perquè sabem que dos és més gran que un. Mentrestant, la pàgina .special-page s'ha establert en z-index: 9999 pàgina es troba a la part inferior de la pila tot i que el seu z-index està configurat amb el valor més alt possible. Els contextos d'apilament també es poden niar (carpetes dins de carpetes), creant un "arbre genealògic". S'aplica el mateix principi: un nen mai pot escapar de la carpeta dels seus pares. Ara que enteneu com es comporten els contextos d'apilament com a carpetes que agrupen i reordenen les capes, val la pena preguntar-vos: per què determinades propietats, com la transformació i l'opacitat, creen nous contextos d'apilament? Aquí hi ha la cosa: aquestes propietats no creen contextos d'apilament per com es veuen; ho fan per com funciona el navegador sota el capó. Quan apliqueu transformació, opacitat, filtre o perspectiva, esteu dient al navegador: "Ei, aquest element es pot moure, girar o esvair, així que estigueu preparat!"
Quan utilitzeu aquestes propietats, el navegador crea un nou context d'apilament per gestionar la representació de manera més eficient. Això permet al navegador gestionar animacions, transformacions i efectes visuals de manera independent, reduint la necessitat de tornar a calcular com interactuen aquests elements amb la resta de la pàgina. Penseu en això com el navegador que diu: "Manejaré aquesta carpeta per separat perquè no hagi de reorganitzar tot l'escriptori cada vegada que canviï alguna cosa". Però hi haun efecte secundari. Una vegada que el navegador aixeca un element a la seva pròpia capa, ha d'"aplanar" tot el que hi ha dins, creant un nou context d'apilament. És com treure una carpeta de l'escriptori per manejar-la per separat; tot dins d'aquesta carpeta s'agrupa i el navegador ara ho tracta com una unitat única a l'hora de decidir què hi ha a sobre de què. Així, tot i que les propietats de transformació i opacitat poden semblar que no afecten la forma en què els elements s'apilen visualment, ho fan, i és per optimitzar el rendiment. Diverses altres propietats CSS també poden crear contextos d'apilament per raons similars. MDN ofereix una llista completa si voleu aprofundir. N'hi ha força, que només il·lustra el fàcil que és crear inadvertidament un context d'apilament sense saber-ho. El problema de "desapilar". Els problemes d'apilament poden sorgir per molts motius, però alguns són més comuns que d'altres. Els components modals són un patró clàssic perquè requereixen alternar el component perquè "obri" a una capa superior per sobre de tots els altres elements i després eliminar-lo de la capa superior quan estigui "tancat". Estic bastant segur que tots ens hem topat amb una situació en què obrim un modal i, pel motiu que sigui, no apareix. No és que no s'hagi obert correctament, sinó que està fora de vista en una capa inferior del context d'apilament. Això us fa preguntar-vos "com és que?" des que has establert:
.overlay { posició: fixa; /* crea el context d'apilament */ índex z: 1; /* posa l'element en una capa per sobre de tota la resta */ inserció: 0; amplada: 100%; alçada: 100vh; desbordament: amagat; color de fons: #00000080; }
Sembla correcte, però si l'element principal que conté l'activador modal és un element fill dins d'un altre element pare que també està establert en z-index: 1, tècnicament col·loca el modal en una subcapa enfosquida per la carpeta principal. Vegem aquest escenari específic i un parell d'altres inconvenients habituals del context d'apilament. Crec que veureu no només com de fàcil és crear contextos d'apilament inadvertits, sinó també com gestionar-los malament. A més, com torneu a un estat gestionat depèn de la situació. Escenari 1: el modal atrapat
Podeu veure immediatament el vostre modal atrapat en una capa de baix nivell i identificar el pare. Extensions del navegador Els desenvolupadors intel·ligents han creat extensions per ajudar. Eines com aquesta extensió de Chrome "CSS Stacking Context Inspector" afegeixen una pestanya d'índex z addicional a les vostres DevTools per mostrar-vos informació sobre els elements que creen un context d'apilament.
Extensions IDE Fins i tot podeu detectar problemes durant el desenvolupament amb una extensió com aquesta per a VS Code, que destaca els possibles problemes de context d'apilament directament al vostre editor.
Desapilar i recuperar el control Un cop hem identificat la causa arrel, el següent pas és tractar-la. Hi ha diversos enfocaments que podeu adoptar per abordar aquest problema, i els enumeraré per ordre. Tanmateix, podeu triar qualsevol persona a qualsevol nivell; ningú no pot queixar-se ni obstruir un altre. Canvia l'estructura HTML Aquesta es considera la solució òptima. Perquè us trobeu amb un problema de context d'apilament, heu d'haver col·locat alguns elements en posicions divertides dins del vostre HTML. La reestructuració de la pàgina us ajudarà a remodelar el DOM i a eliminar el problema del context d'apilament. Cerqueu l'element problemàtic i traieu-lo de l'element de captura del marcatge HTML. Per exemple, podem resoldre el primer escenari, "The Trapped Modal", movent el .modal-container fora de la capçalera i col·locant-lo a l'element
.Aquest contingut té un índex z de 2 i encara no cobrirà el modal.Capçalera
Contingut principal
Quan feu clic al botó "Obrir el modal", el modal es col·loca davant de tota la resta com se suposa que ha de ser. Vegeu el Pen Escenari 1: The Trapped Modal (solució) [forked] de Shoyombo Gabriel Ayomide. Ajustar elContext d'apilament dels pares en CSS Què passa si l'element és un que no es pot moure sense trencar el disseny? És millor abordar el problema: els pares estableixen el context. Cerqueu la propietat (o propietats) CSS responsables d'activar el context i suprimiu-la. Si té un propòsit i no es pot eliminar, doneu al pare un valor d'índex z més alt que els seus elements germans per aixecar tot el contenidor. Amb un valor d'índex z més alt, el contenidor principal es mou a la part superior i els seus fills apareixen més a prop de l'usuari. Segons el que hem après a l'escenari "El menú desplegable submergit", no podem moure el menú desplegable de la barra de navegació; no tindria sentit. Tanmateix, podem augmentar el valor de l'índex z del contenidor .navbar perquè sigui més gran que el valor de l'índex z de l'element .content. .navbar { fons: #333; /* índex z: 1; */ índex z: 3; posició: relatiu; }
Amb aquest canvi, el menú desplegable .apareix ara davant del contingut sense cap problema.
Vegeu el Pen Escenari 2: El desplegable submergit (solució) [forked] de Shoyombo Gabriel Ayomide.
Proveu els portals, si feu servir un marc
En marcs com React o Vue, un portal és una característica que us permet representar un component fora de la seva jerarquia principal normal al DOM. Els portals són com un dispositiu de teletransportació per als vostres components. Us permeten representar l'HTML d'un component a qualsevol part del document (normalment directament a document.body) mentre el mantenen connectat lògicament al seu pare original per a accessoris, estat i esdeveniments. Això és perfecte per escapar de les trampes de context d'apilament, ja que la sortida representada apareix literalment fora del contenidor principal problemàtic.
ReactDOM.createPortal(
Això garanteix que el contingut del menú desplegable no s'amagui darrere del seu pare, fins i tot si el pare té un desbordament: ocult o un índex z inferior. A l'escenari "The Clipped Tooltip" que vam veure anteriorment, vaig fer servir un portal per rescatar la tooltip del desbordament: clip ocult col·locant-lo al cos del document i col·locant-lo per sobre del disparador dins del contenidor. Vegeu l'escenari del llapis 3: la informació sobre eines retallades (solució) [forked] de Shoyombo Gabriel Ayomide. Presentació del context d'apilament sense efectes secundaris Tots els enfocaments explicats a la secció anterior tenen com a objectiu "desapilar" elements de contextos d'apilament problemàtics, però hi ha algunes situacions en què realment necessitareu o voleu crear un context d'apilament. Crear un nou context d'apilament és fàcil, però tots els enfocaments tenen un efecte secundari. És a dir, excepte per utilitzar l'aïllament: aïllar. Quan s'aplica a un element, el context d'apilament dels fills d'aquest element es determina en relació a cada fill i dins d'aquest context, en comptes de ser influenciat per elements fora d'ell. Un exemple clàssic és assignar a aquest element un valor negatiu, com ara l'índex z: -1. Imagineu que teniu un component .card. Voleu afegir una forma decorativa que es trobi darrere del text de la targeta, però a sobre del fons de la targeta. Sense un context d'apilament a la targeta, z-index: -1 envia la forma a la part inferior del context d'apilament arrel (la pàgina sencera). Això fa que desaparegui darrere del fons blanc del .card: Vegeu el Pen Negative z-index (problema) [forked] de Shoyombo Gabriel Ayomide. Per solucionar-ho, declarem aïllament: aïllar a la targeta .maire: Vegeu el Pen Negative z-index (solució) [forked] de Shoyombo Gabriel Ayomide. Ara, el propi element .card es converteix en un context d'apilament. Quan el seu element fill (la forma decorativa creada al pseudoelement :before) té índex z: -1, va a la part inferior del context d'apilament del pare. Es troba perfectament darrere del text i a la part superior del fons de la targeta, tal com es pretén. Conclusió Recordeu: la propera vegada que el vostre índex z sembli fora de control, és un context d'apilament atrapat. Referències
Context d'apilament (MDN) Índex Z i contextos d'apilament (web.dev) "Com crear un nou context d'apilament amb la propietat d'aïllament en CSS", Natalie Pina "Què diablos, índex z?", Josh Comeau
Més lectura sobre SmashingMag
"Gestió de CSS Z-Index en grans projectes", Steven Frieson "Capçaleres adhesives i elements d'alçada completa: una combinació complicada", Philip Braunen "Gestió de l'índex Z en una aplicació web basada en components", Pavel Pomerantsev "La propietat CSS Z-Index: una mirada completa", Louis Lazaris