Spousta webů využívá zobrazení informací v malých pop up oknech. V takovém případě vždy chceme vypsat uživateli zprávu na jasném a viditelném místě. Zarovnání absolutně napozicovaného divu na střed obrazovky může znít jako poměrně jednoduchý úkol, ovšem pokud chceme docílit univerzálního řešení, situace se může trochu zkomplikovat. V dnešním článku bych rád ukázal jednoduchý návod jak na to. 

Využijeme k tomu knihovny jQuery. Máme stránku, kde chceme po kliknutí na nějaký odkaz zobrazit box, který překryje obsah a vycentruje se na střed viditelné oblasti. Jak horizontálně, tak vertikálně. Takových elementů může být na stránce více: formulář pro přihlášení, jiný formulář, o pár polí větší, nějaké textové oznámení a vlastně cokoli, co klient zadá. Proto je dobré dopředu počítat s tím, že box nebude mít ani jeden rozměr pevný.

Prosím berte v potaz, že článek je z roku 2014. Což není zase tolik, nicméně dnes už žádný JavaScript nepotřebujete. Ne, když existuje krásná věc jménem flexbox, majoritou prohlížečů podporovaný transform či jednotky vw (viweport width) a vh (viewport height).

Než začneme

V prvé řadě se musíme zamyslet, zda-li použijeme pozici absolutní nebo fixní. Fixní má tu výhodu, že nemusíme dopočítávat výšku odscrollované oblasti a prvek také nebude reagovat na posun okna. Tato výhoda je ale i nevýhoda: v případě, že element bude obsahovat nějaké sáhodlouhé vyprávění, které se uživateli nevejde na monitor, jeho konec si už nepřečte.

Dohledání funkcí na detekci šířky okna je otázkou chvíle strávené na Googlu, musíme ale vědět, kdy přesně daný výpočet spustit. Skrytému prvku (display:none) se totiž špatně dopočítávají rozměry. Už z hlavy nevím, který prohlížeč v jaké verzi mi na tom selhával, ale naučil jsem se nepočítat výšku (respektive šířku) skrytého prvku. Kaskádové styly naštěstí umí vlastnost visibility, která perfektně poslouží našemu účelu.

  1. Nejdříve nastavíme visibility:hidden; a display:block;
  2. Spočítáme rozměry okna a rozměru boxu
  3. Vrátíme visibility zpět na visible
  4. Přidáme výpočet i na resize okna

Totiž v případě, že bychom chtěli daný prvek zobrazit nějakým fade efektem, uživateli by to poněkud poskakovalo před očima. Prvně tedy spočítáme pozici, pak až zobrazíme.

Rozměry divu a rozměry okna

Knihovna jQuery naštěstí obsahuje vlastní chytré metody, které vrátí ta správná čísla aniž bychom museli řešit dostupnost některých objektů v různých prohlížečích.

// rozměry divu včetně odsazení a rámečku
$('.element').outerHeight();
$('.element').outerWidth();

// velikost okna prohlížeče 
$(window).height();
$(window).width();

Teorii už známe, tak je na čase uvést celý kód. Styly by mohly vypadat nějak takto:

.popupdiv {
	display:none;
	border:1px solid #222;
	min-width:500px;
	min-height:300px;
	padding:20px;
	position:absolute;
	top:0;
	left:50%;
	z-index:1000;
}

Funkce na vycentrování spolu s ošetřením záporné pozice a její zavolání bude následující. Celé by to samozřejmě mělo být obalené v $(document).ready().

function alignPopupDiv(elem){
	elem.css({ visibility: 'hidden', display: 'block' });
	
	var elemTop = Math.round($(window).height() / 2) - Math.round(elem.outerHeight() / 2);
	var elemLeft = Math.round($(window).width() / 2) - Math.round(elem.outerWidth() / 2);
	
	if(elemTop < 0){
		elemTop = 0;
	}
	
	if(elemLeft < 0){
		elemLeft = 0;
	}

	if(elem.css('position') != 'fixed'){
		elemTop+= $(window).scrollTop();
	}
	
	elem.css({ top: elemTop, left: elemLeft });
	elem.css({ visibility: 'visible' });
}

$('.showpopupdiv').click(function(){
	alignPopupDiv($('.popupdiv'));
});

Na závěr ještě přepočet na resize okna a máme hotovo.

$(window).resize(function(){
	$('.popupdiv').each(function(){
		if($(this).is(':visible')){
			alignPopupDiv($(this));
		}
	});
})

Ukázkový HTML dokument si můžete prohlédnout zde: JS Vertical Align

Edit 28. 4. 2020: Jak jsem doplnil v úvodu, tohle řešení už rozhodně nepoužívejte. Článek tu ale nechávám jako vzpomínku na řešení problémů z dob minulých.