DHTML pro každého - 5. díl: (Ne)viditelnost objektů

Upoutávka

Dnes budeme dynamicky skrývat a zobrazovat prvky na stránce, ukážeme si rozdíly v použití vlastností visibility a display. Do DHTML knihovny přidáme nové funkce a na příkladech ukážeme jejich využití.


Zobrazování a skrývání prvků na stránce je vůbec nejčastějším využitím DHTML. Pomocí této techniky se vytvářejí všechny základní, často používané efekty v interaktivních HTML dokumentech - např. "rozbalování" menu či zobrazování nápovědy a podrobnějších informací po najetí myší. Nikdo by se neměl nechat zmýlit ani velmi efektní dynamičností obsahu stránek a myslet si, že prvky, které se objeví na stránce po nějaké akci, se v tu chvíli nějak vytvářejí či odněkud načítají. Ve většině případů již všechny informace jsou na svém místě již od načtení stránky - jsou pouze neviditelné. Činnost uživatele (najetí myší nad nějaký prvek, kliknutí, stisk klávesy atd.) pouze způsobí zviditelnění příslušné skupiny prvků na stránce a případně jinou skupinu zase skryje.

Při tvorbě dynamických stránek na ně proto nesmíte pohlížet stejnou optikou jako čtenáři, dívejte se na ně vždy jako programátor. Anebo, přesněji řečeno, jako kouzelník-iluzionista, jenž provádí trivální a jednoduché úkony, které však z pohledu diváků vypadají jako kouzla. Dynamické stránky se programují obdobně. Vy, jako jejich tvůrce jen připravíte vše, co na stránce má být, umístíte to na správná místa a patřičně nastylujete - pouze prvky, které mají dělat na stránce ono "kouzlo", skryjete a v pravou chvíli je jednoduchým příkazem odkryjete. Z pohledu diváka to pak ale vypadá, že se z přihrádek vysouvají položky menu a text článku, který tam předtím nebyl, se po kliknutí myší náhle zobrazí. Připravujme své dynamické stránky stejně jako iluzionista vymýšlí své triky - často ty nejefektnější věci uděláme tím nejprostším způsobem.

Nastavení viditelnosti prvků

O událostech (events), jimiž se typicky dynamické akce na stránkách spouštějí, a o jejich vazbách se skripty si povíme příště, dnes si připravíme základní funkce na práci s viditelností objektů a naučíme se s nimi pracovat. Pro zobrazování a skrývání objektů se používají dvě vlastnosti CSS - visibility a display. Ačkoli pomocí obou můžeme objekt na stránce "zneviditelnit", jejich chování se poněkud liší a má také rozdílné následky.

Visibility může mít hodnoty 'visible' [viditelný] nebo 'hidden' [skrytý] (a také 'inherit' - převezme hodnotu z rodičovského prvku - a 'collapse' - používá se pro políčka tabulek). Výchozí hodnotou je typicky visible, tzn. že prvek je viditelný a běžným způsobem umístěný ve stránce. Pokud má hodnotu hidden, stane se neviditelným; ve stránce však zůstane na svém místě a okolní prvky se chovají stejně, jako by tento prvek byl viditelný. Dynamická změna této vlastnosti tedy nemá žádný vliv na formátování stránky - změní-li se visibility prvku na hidden, prvek sice opticky zmizí, ale nezmění se formátování stránky - ve stránce po něm zůstane "díra", stane se pouze zcela průhledným.

Vlastnost display má naproti tomu odlišný význam - definuje, jakým způsobem se má prvek formátovat; zda jako blok (hodnota 'block'), jako úsek textu ('inline'), "plovoucí" titulek ('run-in'), nebo jeden z mnoha dalších typů formátování (viz popis vlastnosti display). Jednou z možných hodnot je hodnota 'none', která způsobí, že prvek se neformátuje nijak: vůbec se nezobrazí, jakoby ani nebyl v kódu stránky uveden. Pokud dynamicky změníme hodnotu display na none, prvek se ze stránky ztratí a celý dokument se znovu přeformátuje - resp. ty jeho části, které tento prvek nějakým způsobem ovlivňoval, se změní tak, jako bychom náš "neviditelný" prvek ze stránky vyjmuli. Pokud tedy tímto způsobem "odstraníme" ze stránky odstavec, zmizí a odstavce za ním následujcí se posunou výš; pokud odstraníme nějaký inline prvek (část textu), odstavec, kde prvek ležel, se znovu zformátuje, jakoby v něm tento úsek nikdy nebyl.

Zde je vidět základní rozdíl mezi chováním display a visibility: když budeme peridicky měnit visibility prvku z visible na hidden a zpět, bude prvek na stránce "blikat", nic víc se dít nebude. Pokud obdobně budeme měnit display např. z block na none, bude prvek ze stránky mizet a zase se v ní vykreslovat, přičemž se pokaždé celá stránka, nebo alespoň její část přeformátuje. Při rychlých změnách by místo "blikání" nejspíš nastala jen nepřehledná změť obsahu stránky - stránka už by se totiž nestíhala přeformátovávat.

Pro srovnání chování visibility a display se podívejte na ukázku.

Kdy použít kterou vlastnost?

V některých situacích může použití display přinášet nevýhody a bude lepší dát přednost visibility, která nenutí stránku k překreslování a změna viditelnosti je tak rychlá. Ve většině případů však výhodnější použití display. Protože různé situace vyžadují různá řešení, ukažme si, kdy je která z obou možností vhodnější a jaké jsou případné výhody i nevýhody:

Je nutné si pamatovat také na pravidla dědičnosti, která se u vlastností visibility a display liší. Pokud má nějaký prvek display:none, nezobrazí se ani on, ani nic z jeho obsahu - bez ohledu na hodnoty display u jeho potomků.

Kdežto u vlastnosti visibility platí, že prvek, který ji má explicitně nastavenu, se řídí jen podle této hodnoty - bez ohledu na viditelnost svého rodičovského prvku. Ukažme si to na příkladu:

<DIV id="obal">
   <P id="prvni">první odstavec uvnitř</P>
   <P id="druhy" style="visibility:visible">druhý odstavec</P>
   <P id="treti">třetí odstavec</P>
</DIV>

Takto definovaný blok se zobrazí přesně tak, jak bychom očekávali - uvnitř vnějšího <DIV> budou zobrazeny tři odstavce. Pokud však tento vnější obal skryjeme, tedy nastavíme mu visibility:hidden, zneviditelní se ("zprůsvitní") vnější blok a prvky uvnitř něj, které nemají definovánu vlastnost visiblity (mají tedy výchozí hodnotu inherit a jejich viditelnost se řídí podle rodičovského prvku). Druhý odstavec však má definováno visibility:visible a bude tak viditelný bez ohledu na viditelnost svého rodičovského prvku - podívejte se na ukázku. Změny vlastnosti display takové chování nemají - pokud "obal" skryjeme pomocí display:none, zmizí tento blok i jeho obsah, bez ohledu na vlastnosti vnitřních prvků.

Funkce pro skrývání a zobrazování objektů

Minule jsme si již ujasnili, že v Netscape 4.x jsou vlastnosti týkající se stylů pro DHTML zcela nepoužitelné (nelze je měnit po načtení stránky, pro dynamické akce se hodí pouze prvek <layer>, který je již "mrtvý"). Proto již můžeme s klidným svědomím opustit původní pokus o zcela univerzální DHTML knihovnu, použitelnou ve všech prohlížečích. Omlouvám se tímto P. T. čtenářům za menší okliku: chtěl jsem se tak vyhnout výtkám, že ignoruji ještě dožívající NN4 - dokud nebude vše náležitě vyjasněno a důvody ozřejmeny.

Nyní již víme, že jakákoli podpora DHTML funkcí pro NN4 by byla jen zdánlivá, skutečného použití by tyto snahy beztak nikdy nemohly dojít. Nadále budeme tedy pokračovat pouze s jedinou knihovnou, některá "neškodná" rozšíření oproti standardu DOM, která nás příliš nezatíží, v ní můžeme klidně ponechat - na podporu "nedynamického" NN4 však již rezignujeme.

Připravíme si funkce pro skrývání a zobrazování objektů pomocí vlastností, které jsme si výše vysvětlili. CSS vlastnosti visibility odpovídá v Javascriptu vlastnost Element.style.visibility, vlastnosti display pak Element.style.display; jejich hodnoty jsou shodné jako v CSS. Funkci pro nastavení hodnot vlastností již máme odminula - teoreticky již teď můžeme použít např.:

objSetStyle (obj,'visibility','visible');
objSetStyle (obj,'visibility','hidden');

Není to však příliš praktické; při přípravě DHTML stránek je zbytečně komplikované používat pro tak časté akce, jako skrývání a zobrazování objektů, tak složité funkce. Bude jednodušší připravit si specializovanou funkci, řekněme objShow, jejímiž parametry bude pouze objekt a booleovská hodnota, zda objekt má být vidět, či nikoli (true=viditelný, false=neviditelný).

function objShow (obj,on) {
return objSetStyle(obj,'visibility',(on) ? 'visible':'hidden');
}

Zavoláme-li tedy např. objShow('jmeno',true), tato funkce pouze spustí objSetStyle pro vlastnost visibility s hodnotou visible (v případě true), resp. hidden (v případě false). Funkce vrací stejnou hodnotu jako objSetStyle - true/false podle toho, zda se viditelnost objektu podařilo přiřadit.

U vlastnosti visibility to bylo jednodušší v tom, že zde máme pouze dvě možné hodnoty (visible/hidden). V případě display to ale bude mírně ztíženo: jednoznačná je pouze hodnota pro skrytí (none), kdežto viditelný objekt může mít mít různou hodnotu display (typicky block nebo inline, ale můžeme potřebovat i mnoho jiných hodnot). Do další funkce (nazveme ji objDisplay) přidáme proto třetí parametr, kterým můžeme tuto "zviditelňovací" hodnotu upřesnit. Ale protože nejčastěji se pracuje s bloky (hodnota block), použijeme tuto hodnotu jako výchozí: pokud typ neupřesníme, použije se block.

function objDisplay (obj,on,type) {
   if (on && !type) type = 'block';
return objSetStyle(obj,'display',(on) ? type:'none');
}

Tuto funkci tedy můžeme použít obdobně funkci první - zavolání objDisplay(objekt,false) nastaví objektu display:none, naopak objDisplay(objekt,true) nastaví display:block. Pokud chceme jinou hodnotu než block, při zobrazování ji můžeme specifikovat - např. objDisplay(objekt,true,'inline').

Pozn.: Bystřejší čtenáři si jistě všimli, že tuto funkci můžeme použít i pro jiné změny vlastnosti display - z bloku uděláme inline pomocí objDisplay(obj,true,'inline') a naopak zase objDisplay(obj,true,'block') (parametr 'block' zde můžeme vynechat, neboť je výchozí).

Pozn. 2: Hodnotou on nemusí být nutně jen false/true; díky automatickému přetypování v Javascriptu můžeme použít i hodnoty jiných typů, které se při testu if(on), resp. (on) ? přetypují na příslušnou booleovskou hodnotu:

Můžeme proto použít i konstrukce např.:

var i = 0;
objShow (obj,i);  // i==0, skrytí objektu
i++;
objShow (obj,i);  // i==1, zobrazení obejktu

objDisplay (objX,0);
objDisplay (objY,1,'inline');

objDisplay (objZ,'');
objDisplay (objZ,'ukaz');

Naše nová (nyní již sloučená knihovna) tedy vypadá takto:

// Webtip.cz - DHTML knihovna
// verze 0.5

function objGet(x) {
	if (typeof x != 'string') return x;
	else if (Boolean(document.getElementById)) return document.getElementById(x);
	else if (Boolean(document.all)) return eval('document.all.'+x);  // pro MSIE 4
	else return null;
}

function objSetStyle (obj,prop,val) {
	var o = objGet(obj);
	if (o && o.style) {
		eval ('o.style.'+prop+'="'+val+'"');
		return true;
		}
	else return false;
	}

function objShow (obj,on) {
	return objSetStyle(obj,'visibility',(on) ? 'visible':'hidden');
	}

function objDisplay (obj,on,type) {
	if (on && !type) type = 'block';
	return objSetStyle(obj,'display',(on) ? type:'none');
	}

// Ceske ekvivalenty funkci:

var objNajdi = objGet;
var objNastavStyl = objSetStyle;
var objZobraz = objShow;

Pro funkci objShow jsme přidali český ekvivalent objZobraz, funkci objDisplay nemá význam překládat.


Ač naše knihovna není zatím příliš obsáhlá a možná se to ani nezdá, nyní již máme základní nástroje pro DHTML. S funkcemi pro nalezení objektů, nastavení jejich CSS vlastností a nástroji pro změnu viditelnosti již uděláme nějakou tu " muziku za málo peněz" - jediné, co ještě potřebujeme, je umět pracovat s událostmi, tedy provést nějakou akci, když uživatel klikne myší či najede kurzorem na nějaký prvek, stiskne klávesu, načte se stránka atd. O nich si povíme příště. Na některé jednoduché příklady se ale můžete podívat už teď.

Důležitá stylotvorná poznámka:

Někteří z vás už se s tím možná setkali, jiní třeba ještě ne - chcete si přečíst nějakou stránku na webu, ale váš prohlížeč zde zahlásí chybu Javascriptu (nebo ani to ne) a nefungují žádné aktivní prvky. Nelze otevřít menu, nefungují odkazy, obsah je skrytý, nedostane se k němu. Stát se to může kdykoli a komukoli - autor udělá ve skriptu chybu a nevšimne si jí, čtenář má "neobvyklý" prohlížeč, nemá podporu Javascriptu nebo si jej (z jakéhokoli důvodu) vypnul atd. Tak jako tak, stránka se stala naprosto nepoužitelnou, její obsah je pro (tohoto) čtenáře nedostupný. I výše uvedená ukázka je (úmyslně!) taková - stačí se na ni podívat pomocí prohlížeče Opera. Uvidíte pouze "zabalené" položky menu a nadpisy, ale k jejich obsahu se nedostanete.

Obsah stránek je přitom to hlavní, co na nich je (až na nepatrné, konkrétně zdůvodnitelné výjimky) - to, co chcete svým čtenářům poskytnout především. Všechno ostatní (vzhled, barvy, dynamika) by už mělo být jen "třešničkami na dortu", které můžete dát jen tomu, kdo je dokáže použít, případně kdo o ně stojí. Stránka by tak měla fungovat dostatečně kdekoli, v každém rozlišení, s jakýmkoli nastavením, s vypnutými CSS, či bez Javascriptu. Dáváte svým čtenářům obsah stránek, proto všechna rozšíření nad jeho rámec udělejte tak, aby byla volitelná či nepovinná. V případě skrývání obsahu např. pomocí display:none je tedy správným postupem skrýt ho pouze tehdy, je-li jisté, že čtenářův prohlížeč má funkční Javascript (JS), který obsah určitě dokáže zase zobrazit. Možností je více, nejčastější postupy jsou:


Ukázky k tomuto dílu:

Ukázka 1 - srovnání použití display a visibility
Ukázka 2 - dědičnost visibility
Ukázka 3 - jednoduché příklady použití skrývání a zobrazování pomocí naší knihovny


Použitelnost prvků zmíněných v tomto díle:

Element.style.visibility
CSS level - 2, DOM level - 2, JavaScript - 1.2, JScript - 3.0, Internet Explorer - 4.0, Netscape - 4.0, Opera - 5.0
Pozn.: v JS 1.2 a v NN4 jen jako layer.visibility
Element.style.display
CSS level - 1, DOM level - 2, JavaScript - 1.5, JScript - 3.0, Internet Explorer - 4.0, Netscape - 6.0

DHTML knihovna ke stažení:

Číslo verze: 0.5 (pro přehlednost číslujeme verze shodně s díly seriálu)
Stažení knihovny: dhtml_0_5.js
Obsah (anglické názvy) objGet(), objSetStyle(), objShow(), objDisplay()
Obsah (české názvy) objNajdi(), objNastavStyl(), objZobraz()

Petr Staníček, pixy.cz © 2002, 2015