Centrovaný modální dialog bez JS

Chcete zobrazit modální dialog ve stránce, který je vždy centrovaný do středu obrazovky? To asi budete potřebovat hodně skriptů na jeho otevření, vypočtení velikosti, vycentrování a jeho udržování v obraze (např. při otočení telefonu). Viz demo.

Ale co kdyby tohle všechno šlo udělat jen pomocí HTML a CSS, nebylo by to super?

A představte si, že to jde!

TL;DR

Pokud neradi čtete text a raději se podíváte na demo, můžete prostudovat jeho zdrojový kód, kde je vše popsáno. K dispozici je jednoduchý dialog s pevným umístěním a nebo dialog vždy centrovaný pomocí Flexboxu.

Poznámka: všimněte si drobného rozdílu v tom, že pro pevné umístění je potřeba použít outer a inner DIVy, aby šlo správně nastavit max-height, zatímco u flexboxu je nutno použít jen inner, protože naopak s outer DIVem max-height nefunguje správně!

Otevření dialogu

Přeci na otevření dialogu musí být potřeba onclick handler, ne?

To není úplně pravda: když totiž do odkazu uvedete jen hash (#) znak a ID, přidá se toto ID do URL, ale jinak se stránka nezmění.

Pouze se na stránce označí element s příslušným ID. Označení jednak probíhá nakrolováním na daný prvek a současně označením prvku pro CSS, které pak může použít a pomocí selektoru :target daný prvek zvýraznit.

Pokud tedy necháme dialog skrytý a pomocí :target ho zobrazíme, bude to vypadat, že se dialog zobrazil po kliku na odkaz.

<a href="#dialog">Otevři dialog</a>
#dialog { display: none; }
#dialog:target { display: block; }

Zavření dialogu

Jak udělat zavření dialogu? Stačí přesměrovat stránku na jiný hash, nejlépe prázdný:

<a href="#">Zavři dialog</a>

CSS se pak o vše postará a dialog zase skryje (díky tomu, že ztratí selektor :target).

Pevná pozice

Pokud stačí zobrazit dialog na pevné pozici (nejlépe vlevo nahoře), stačí pomocí position:fixed správně nastavit pozici a rozměry:

    position: fixed;
    transform: translate(0,0);
    width: auto; left: 0; right: 0;
    height: auto; top: 0; bottom: 0;
    z-index: 990;

Pomocí width, height, top, apod. nastavíme rozměr dialogu přes celou stránku. Z-index použijeme k tomu, aby se dialog zobrazil nad stránkou a nic do něj nezasahovalo. Pomocí transform ještě ošetříme chyby v některých webkitech (Safari, Chrome), které mají občas problémy s pevně umístěnými prvky.

Problém ale nastave v případě, že obsah dialogu se nevejde na stránku, protože pak bude prostě vytékat dolu, ale jelikož je pevně umístěn, nepomůže nám skrolování stránky. Kvůli tomu bude potřeba ještě obsah dialogu obalit jedním DIVem, kterému nastavíme maximální výšku a zapneme skrolování:

#modal-inner {
    height: auto;
    max-height: 100%;
    overflow-x: hidden;
    overflow-y: auto;
}

Nejprve nastavíme automatickou výšku, aby se pro menší obsah dialog přizpůsobil. Pak nastavíme max-height na 100%, aby nikdy nemohl přesáhnout oblast obrazovky a následně pomocí overflow umožníme zobrazení svislého posuvníku.

Vždy na středu

Pokud naopak chcete, aby byl dialog vždy uprostřed obrazovky, není potřeba složitě počítat jeho rozměry a neustále ho přemisťovat pomocí JavaScriptu.

Úplně stejně nám k tomu poslouží Flexbox, který umí centrovat prvky v prostoru – zcela automaticky. Nevýhoda je, že jeho zápis je trochu složitější a na IE9 a starších vůbec nefunguje, ale to se dá většinou oželet.

Pokud modální dialog zobrazíme pomocí display:flex místo display:block, všechny vnořené prvky se automaticky začnou chovat jako flex-item, na které můžeme aplikovat některé speciální CSS hodnoty:

#modal:target {
    display: block; /* IE9 and older */
    display: -webkit-box; /* iOS6+, Safari */
    display: -moz-box; /* Firefox 4 - 19 */
    display: box; /* Opera 12 - 14 apod.*/
    display: -ms-flexbox; /* IE10 */
    display: flexbox; /* ostatní starší */
    display: -webkit-flex; /* iOS7.1+ */
    display: flex !important; /* Firefox 22+,
                                 Chrome 21+,
                                 IE11,
                                 Opera 15+
                               */
}

Pro vycentrování obsahu dialogu pak stačí použít:

#modal {
     -webkit-box-align: center;
     -moz-box-align: center;
     box-align: center;
     -ms-flex-align: center;
     flex-align: center;
     -webkit-align-items: center;
     -webkit-align-content: center;
     align-items: center;
     align-content: center;

     -webkit-box-pack: center;
     moz-box-pack: center;
     box-pack: center;
     -ms-flex-pack: center;
     flex-pack: center;
     -webkit-justify-content: center;
     justify-content: center;
}

Díky tomu bude dialog vždy na středu jak vertikálně tak horizontálně (pokud je menší než 100%) nezávisle ne změně velikosti stránky.

Pokud vás zajímá, proč je zápis Flexboxu tak složitý, přečtěte si o historii Flexibilního layoutu.

Pro ošetření vytékání je potřeba provést to samé jako výše, jen není potřeba další obal – stačí max-height a overflow nastavit přímo do flex-item.

Další vylepšení

Další vylepšení, jako je stínované pozadí dialogu, odsazení od okrajů či kulaté rohy si můžete nastudovat ve zdrojových kódech demo ukázek:

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *