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ů 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, který 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í,
jako by 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, jako by v něm tento úsek nikdy nebyl.
Zde je vidět základní rozdíl mezi chováním display a visibility: když budeme periodicky 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ů je 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:
- Při zobrazování a skrývání odstavců a úseků textu je vhodnější použití
display. Skrytý úsek "zmizí"
ze stránky a po zobrazení se opět "vsune" na původní místo. Display tedy použijeme na objekty,
které ovlivňují formátování okolních prvků - použili-li bychom visibility:hidden, ve stránce by vznikla
"díra". Nepoužívejme však display tehdy, je-li pro nás změna formátování stránky časově kritická
(především v animacích).
- I absolutně pozicované prvky je lepší skrývat pomocí
display - řešení s visibility si můžeme
dovolit jen při dobrém rozmyslu. Umístění absolutně pozicovaných prvků ve stránce je sice nezávislé na okolí a po
skrytí objektu po prvku nemusí vzniknout žádná "díra" - je zde ale jeden háček: prvky ve stránce, i když
jsou neviditelné (visibility:hidden), stále mohou reagovat na činnost uživatele. Stane se tak, že prvky
umístěné "pod" těmito skrytými objekty nezaregistrují pohyb či kliknutí myši, neboť tyto události
si přivlastní "výše" umístěné neviditelné objekty. Objekty skryté pomocí display:none už ale
ve stránce vlastně nejsou a tento problém nezpůsobují. Skrývání pomocí visibility tedy používáme jen
tehdy, pokud nebude vadit, když prvkům pod skrývanými objekty budou hůře přístupné události myši.
Objekty vkládané do stránky pomocí <object> / <embed> (především flash animace)
a prvky iframe je nutné vždy skrývat pomocí display:none. Obsah těchto prvků (i když jsou "neviditelné")
bude vždy ve stránkách tropit neplechu: flash animace zůstanou aktivní, některé prvky ze stránek načtených do iframu
zůstanou viditelné atd. Zde se visibility nedoporučuje používat vůbec.
- Řešení pomocí
visibility tak oceníme především v animacích - změna je rychlá (stránka se nemusí přeformátovat)
a zobrazení a skrytí prvků tak bude plynulejší a rychlejší. I zde je ale vhodné celou animaci skrýt pomocí display:none,
aby nerušila chování stránky. Příkladem může být menu se složitou strukturou - skrývání a zobrazování nabídek a podnabídek
se z důvodů rychlosti může vytvořit pomocí visibility, celé menu se však zobrazí a skryje pomocí display
- skryté nabídky tak nebudou rušit a ve stránce se objeví, až když se menu aktivuje. Po výběru položky se ze stránky
zase "ztratí".
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í proti
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 je 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:
- číslo: nenulové číslo => true, 0 => false
- řetězec: neprázdný řetězec => true, prázdný řetězec => false
- objekt: neprázdný objekt => true, null => false
- atd.
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:
- Vložit potřebné definice CSS až pomocí JS - když jsme si předem otestovali, že prohlížeč umí příslušné funkce. Ten,
kdo má JS vypnutý, nemá jej vůbec nebo jeho verze nepodporuje funkci, kterou ke skrývání/zobrazování objektů potřebujeme,
tyto definice nedostane a objekty skryté nebudou.
- Stránku naformátovat "rozbalenou" a objekty skrýt pomocí JS až po načtení stránky. Objekty tak skryje jen
prohlížeč, který umí měnit příslušnou CSS vlastnost (např.
display), a tudíž je bude moci zase zobrazit.
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() |
Staníček Petr
|