Přiřazení skriptu stylem

Tento článek vyšel v internetovém časopisu Interval a zde je pouze jako kopie.

Donedávna šlo CSS stylem ovlivnit jenom vzhled, ale už ne reakci na uživatelské události. V HTML zdroji očištěném od formátovacího balastu tak zůstávaly ještě skripty, které do logické struktury dokumentu nepatří. Nepříliš známá CSS vlastnost BEHAVIOR deklaruje chování HTML prvků a skripty odsouvá do externích souborů.

CSS vlastnost behavior se dá přeložit doslova jako "chování". Přináší nový pohled na implementaci JavaScriptu do HTML stránek. Pokud neumíte JavaScript, nebudete umět zpočátku používat ani behavior. To ovšem neznamená, že to pro začátečníky není užitečné, protože odněkud okopírovaný behavior se do stránek zapracovává snadněji než odněkud okopírovaný javaskript.

Hlavní přínos stylového chování zaznamenají zejména webmasteři, kteří chtějí své úsporné, logické a čisté kódy obohatit o uživatelský komfort bez ztráty kytičky. Je to taková "vyšší dívčí" JavaScriptu a kaskádových stylů. Kdo tedy neovládá základy zápisu kaskádových stylů (CSS), neoceňuje jejich výhody a barvu písma zadává stále tagem <font>, toho behavior rozhodně nenadchne.

Vývoj umístění informací ve webových dokumentech. Před příchodem CSS, využití CSS a důsledné oddělení obsahu pomocí behavior

Vlastnost behavior je podporována v Internet Exploreru od verze 5.0 a v Netscapu 6, tj. v Mozille (o ladění pro Mozillu se zmíním níže). Úspěšně tedy zasáhne asi 95% internetové populace, přičemž skóre se časem bude jenom zlepšovat. V prohlížečích, které behavior nepodporují (čtyřkové verze, Opera), to navíc nebude házet žádné chyby. Technologie patří do standardů W3C a je na ní vidět, že byla vymýšlena pro XML dokumenty, čili výhledy jsou slibné.

Jak behavior zhruba funguje

V klasickém JavaScriptu se do každého HTML prvku, který má něco dělat (například zobrazit hlášku při kliknutí myší), musel připsat ovladač (např. onclick="..." pro kliknutí), jehož hodnotou byl skript. To je nešikovné zejména v případě, že má prvek ovladačů víc (např. onmouseover a onmouseout pro rollover efekty) a na stránce se často opakují ve stejné kombinaci (dynamické menu, obrázková galerie apod.). Navíc informační hodnota skutečnosti, že element má něco udělat např. při najetí myší, je téměř nulová, neměla by tedy patřit do proudu hlavního dokumentu.

Při použití behavior stačí html prvku nějakým způsobem přiřadit styl. V zápisu stylu se potom uvede adresa na externí soubor s příponou *.htc. (Zkratka HTC znamená HTml Component. Doporučuji nezaměňovat s THC, což je TetraHydroCanabinol.) HTC soubor obsahuje popis chování prvku včetně potřebných skriptů. Základní zápis je tedy

selektor {behavior: url('soubor.htc')}

čímž lze ovlivnit mnoho prvků stránky. Samozřejmě fungují všechny klasické zápisy stylů pomocí tříd (class) a identifikátorů (id), styl se může dát do externího souboru. O zápisu CSS stylů už se na Intervalu napsalo mnoho. Chování lze připsat také přímo pro jen jeden prvek (což je poněkud méně elegantní, nicméně funkční).

<tag style="behavior: url('soubor.htc')">

Pokud jste dočetli až sem, rád bych vás nějak povzbudil. Dále budu totiž popisovat techniky použití behavior a syntaxi htc komponent, což nemůže být moc zábavné čtení. Osobně se domnívám, že studium je na pár hodin nebo dnů. Až vás to bude nudit, proklikejte si alespoň příklady, měli byste z nich hodně pochopit. Byl bych rád, kdybyste si odnesli poznatek, že dynamické html se dá dělat úsporně, modulárně a bez prasáren v html kódu.

První příklad

Budu chtít, aby se mi po kliknutí na html element zobrazila výstražná hláška. V praxi to není moc použitelné pro svou přílišnou jednoduchost, jde však o oblíbený příklad v učebnicích JavaScriptu. Pro přehlednost napřed zopakuji, jak se to dělá klasicky v JavaScriptu, a pak stejnou funkčnost rozběhám pomocí behavior.

V JavaScriptu se pro vyvolání hlášky používá metoda alert():

<p onclick="alert('Ukázka události onclick')">Odstavec s atributem onclick.</p>

Odkaz na funkční příklad.

V tomto případě se hláška zobrazí po kliknutí na odstavec (tag <p>).

Pomocí CSS behavior vypadá zápis téže věci jinak:

<p style="behavior: url('alert.htc')">Odstavec se stylem behavior.</p>

Styl se v tomto případě odvolává na soubor alert.htc, ve kterém je teprve napsáno, co to má při jaké události dělat. Výpis celého souboru alert.htc:

<component>
<attach event="onclick" onevent="hlaska()">

<script>
function hlaska()
{
window.alert("Ukázka vazby skriptu pomocí behavior");
}
</script>
</component>

Odkaz na tentýž příklad.

Druhý řádek s textem <attach... říká, že při události kliknutí (event="onclick") se má zavolat funkce hlaska(). Ta je potom klasicky definována ve skriptu. V tomto případě je funkce relativně jednoduchá, pouze jeden alert().

Příklad dvou různých zápisů měl pouze naznačit filosofii techniky behavior a srovnat ji s klasickým javaskriptem. Možná jste si všimli, že zápis a rozběhání konstrukce pomocí behavior je trochu složitější než javaskript. Proč propaguji metodu, která se jeví neefektivní?

Vtip je v tom, že první příklad byl extrémně jednoduchý. Při složitějších skriptech a vazbách na dokument efektivita stylového zápisu výrazně stoupá, kódy se naopak v porovnání s JavaSciptem zjednodušují. To se pokusím dokázat v dalších příkladech. Pravidlo zní: čím je skript složitější a čím častěji se bude používat, tím více se vyplatí napsat htc komponentu a používat behavior.

Příklad: změna pozadí buňky

Častým dotazem začínajících autorů je, jak udělat buňku tabulky, která po najetí myší změní barvu, třeba ze žluté na červenou (u buňky nejde použít :hover jako u odkazu). V JavaScriptu se například dvě takové buňky dají udělat poněkud obšírnějším zápisem (včetně stylu):

<style>
td {background-color: yellow}
</style>
...
<td onmouseover="this.style.backgroundColor = 'red'" onmouseout="this.style.backgroundColor = 'yellow'">Buňka měnící barvu</td>
<td onmouseover="this.style.backgroundColor = 'red'" onmouseout="this.style.backgroundColor = 'yellow'">Druhá buňka měnící barvu</td>

Odkaz na příklad.

Malý výklad: buňka tabulky (td) při přejetí myší (onmouseover) zaznamená, že this (tento objekt, tedy buňka) má nastavit styl, konkrétně barvu pozadí (background-color) na hodnotu červená ("red"). Totéž do žluta při odjetí myši (onmouseout).

Pokud je takových buněk na stránce více, dá se na to napsat funkce, ale i potom je zápis do tagu buňky poněkud neúsporný a nepřehledný. Účelem tohoto článku je zejména ukázat výhody vazby skriptu pomocí behavior. Jednou z předností je úsporný a logický zápis, pokud se aktivního prvku použije na stránce (resp. na celém webu) opakovaně. Stejného efektu přebarvení buněk se tedy dá dosáhnout pomocí behavior:

<style>
td {background-color: yellow; behavior: url('prebarveni.htc')}
</style>
...
<td>Buňka měnící barvu</td>
<td>Druhá buňka měnící barvu</td>

Přebarvovací skript je v tomto případě přenesen do externího souboru prebarveni.htc. Ten vypadá takto:

<component>
<attach event="onmouseover" onevent="prebarvit('red')">
<attach event="onmouseout" onevent="prebarvit('yellow')">

<script>
function prebarvit(barva)
{
element.style.backgroundColor = barva;
}
</script>

</component>

Odkaz na příklad s použitím behavior.

Syntaxe htc

Na tomto příkladu proberu trochu více (třebaže stále velmi povrchně) syntaxi htc souboru. Jistě vidíte, že to je takové skoro XML. Vše je formálně obaleno tagem <component>.

Následuje vazba událostí s funkcemi, to jsou tagy <attach ...>. V tagu attach se říká, při jaké události (event) se spouští jaká funkce (onevent). V tomto případě volám při onmouseover funkci s parametrem prebarvit("red"). Při onmouseout volám tutéž funkci s parametrem "yellow". (Komu vadí, že se barvy zapisují rovnou do skriptu, nechť se podívá na poslední příklad, tam vysvětluji předávání parametrů pomocí property.)

Kromě vazeb (attach) může htc soubor na začátku obsahovat tagy vlastností (property), metod (method) a událostí (event). V tomto článku method a event nezmiňuji.

Následuje vlastní zápis JavaScriptu vymezený klasicky tagy <script> a </script>. Obsahuje pouze deklaraci funkcí (protože nic jiného se prostě nemá jak provést) a má i mnohá další specifika. (Například nemá smysl používat v těchto skriptech metodu document.write(), protože by se vykonávala až při uživatelských událostech, a to je dokument pro zápis již zavřený.)

Objekt element

Dalším specifikem je objekt element. Ve skriptu příkladu je řádek

element.style.backgroundColor = barva;

Co znamená element? Objekt element je obdoba objektu this (zjednodušeně řečeno). Když v zápisu použiji objekt element, ví skript, že tím myslím HTML element v dokumentu, který vyvolal probíhající událost. Přidržím-li se příkladu se změnou barvy buňky, tak element v tomto případě reprezentuje buňku, přes kterou jede myš a které se mění barva pozadí.

Element je velice užitečný objekt. Využije se téměř v každém htc skriptu, těžko by se bez něj dalo obejít. (Když už píšu o objektu element, tak bych měl zmínit, že ve skriptech v htc souboru je element vrcholem objektového modelu; v normálním použití JavaScriptu je tím vrcholem objekt window.)

Příklad: nové okno bez lišt

Zatímco předchozí příklady byly spíše intelektuální hříčky, otevírání odkazu do nového okna bez menu už je věc dosti často používaná, například v galeriích fotografií. První obrázek tam většinou slouží jako odkaz na druhý obrázek, který se má otevřít v novém okně.

Stejně jako v ostatních příkladech proberu napřed klasický zápis JavaScriptem a pak bude následovat zjednodušená verze používající behavior. Javaskriptový zápis odkazu otevírající přesně velké nové okno bez menu, adresy a tlačítek:

<a href="druhy.gif" onclick="window.open('druhy.gif','','menubar=no, width=400, height=300'); return false;"><img src="prvni.gif" border="0"></a>

Odkaz na příklad.

Jak je vidět, při kliknutí na odkaz (onclick) se otevírá nové okno (window.open() ), do kterého se načítá určitý soubor (v tomto případě druhy.gif). Okno není pojmenované a má určité rozměry. Odkaz míří na soubor druhy.gif (atributem href), aby se ten soubor dal dosáhnout i v klientech bez podpory JavaScriptu (např. Google spider). Příkaz return false zabrání tomu, aby odkaz na tento cíl prokliknul. Obsahem odkazu je třeba obrázek (<img>).

Javaskriptový zápis je sice plně funkční, ale pokud je na stránce nebo na webu takových odkazů více, je docela otrava to tam vypisovat. Sice si lze vypomoci javaskriptovou funkcí, ale nejefektivnější bude použít behavior:

<a href="druhy.gif" style="behavior: url('noveokno.htc')"><img src="prvni.gif" border="0"></a>

V tomto případě zapisuji náhodou styl přímo. Míří na soubor noveokno.htc, který vypadá takto:

<public:component>
<public:attach event="onclick" handler="noveokno" />

<script>
function noveokno()
{
window.open( element.href,"_blank","menubar=no, width=400, height=300");
event.returnValue = false; //něco jako return false
}
</script>
</public:component>

Odkaz na souhrnný příklad.

Řádek s attach říká, že při kliknutí (onclick) se použije ovladač (handler) noveokno. Zápis handler="noveokno" je skoro ekvivalentní zápisu event="noveokno()", syntaktický rozdíl je v závorkách. Funkční rozdíl je v tom, že pomocí onevent by se nedala zrušit předdefinovaná událost (prokliknutí odkazu), což pomocí handler jde. (Toto konkrétně se nedělá pomocí primitivního return false, ale přes korektnější zápis event.returnValue = false.) Prostě onevent je jenom navěšení další nezávislé události, kdežto handler je doslova ovladač. V praxi se ale s rozdílem handler a onevent setkáte minimálně, můžete to pustit z hlavy, pamatujte si jenom, že u onevent se píšou ty závorky.

Pozorný čtenář na tomto příkladu jistě vidí i trochu striktnější použití náznaků XML syntaxe, která ale v Internet Exploreru nemá žádný vliv na funkčnost.

Prosím všimněte si, že metoda window.open do nového okna (_blank) načítá soubor, jehož adresa je v proměnné element.href. Co je element.href? Element je to, co událost vyvolalo, v tomto případě tedy odkaz. Odkaz má v JavaScriptu vlastnost href, jejíž hodnotou je cíl odkazu. Takže element.href má hodnotu "druhy.gif" (protože href="druhy.gif").

Na tomto příkladu jsem chtěl ilustrovat, že skripty přiřazené pomocí behavior umějí číst vlastnosti dokumentu (v tomto případě cíl odkazu) a využívat je.

Když není podpora

Kritický čtenář si určitě na předchozích příkladech musel říkat: "je to všechno hezké, ale co se stane v prohlížečích (zejména starších), které behavior nepodporují?" Odpověď je jednoduchá: nestane se nic. Než na základě toho behavior zavrhnete, dovolte mi poznamenat tři věci:

  1. většinou se to dá zapsat tak, aby to i ve starších prohlížečích alespoň nějak fungovalo
  2. nepodpora behavior ve starších prohlížečích je ve skutečnosti výhodou
  3. drtivé většině uživatelů behavior funguje

Právě předchozí příklad s novým oknem byl ukázkou toho, jak to napsat tak, aby i ve starším prohlížeči byla zachována částečná funkce. Zápis byl:

<a href="druhy.gif" style="behavior: url('noveokno.htc')"><img src="prvni.gif" border="0"></a>

Jistě tušíte, že starší prohlížeč vidí pouze normální odkaz s nějakým nesmyslným stylem. Pár procent uživatelů tak po kliknutí sice nebude mít přesně velké nové okno, ale k cíli se dostanou také. Je to to podobné jako u CSS stylů: většinou fungují, ale spolehnout se na ně nelze, takže je stejně nutné dokument strukturovat logicky.

Javaskripty se mají psát tak, aby nehlásily chyby. Jestli mě na skriptech něco fakt štve, tak to, jak musím každou chvíli podmínkovat, jestli mám správný prohlížeč. Podmínky přitom tvoří nezřídka polovinu kódu. V naprosté většině případů podmínka zjišťuje, zda je prohlížeč Internet Explorer verze 4 nebo 5 a vyšší, pak se nechá skript běžet. Pro jiné prohlížeče se to většinou vypíná, alternativy pro Mozillu a Netscape píšou jenom opravdoví profíci, kteří mají spoustu času.

Použití behavior a htc situaci radikálně zjednodušuje. Nemusí se nic podmínkovat. Buď uživatel má moderní prohlížeč a skript běží, nebo ho nemá a skript neběží, což ale znamená, že ani nechybuje.

Jak je to s těmi prohlížeči: css vlastnost behavior podporují Mozilla a Internet Explorer od verze 5. To podle mých statistik (duben 2002) zasáhne přibližně 95% uživatelů, ne-li více. Internet Explorer 4, který behavior nezná, používá něco kolem dvou procent uživatelů. Opera je velmi minoritní a možná se behavior časem naučí. Zůstává tedy jediný opravdový problém: Mozilla podporuje behavior trochu jinak!

Behavior v Mozille

Mozilla nepoužívá soubory *.htc, ale *.xbl. Syntaxe souborů XBL se od HTC trochu liší. Protože teorii zápisu xbl formátu nemám ještě nastudovanou, musím případné zájemce požádat, aby si někde našli nějaký xbl soubor a syntaxi odkoukali. Soubory XBL jsou psány v čistém XML (takže například <script> je označen jako cdata).

Budete-li chtít, aby vaše skripty fungovaly i v Mozille, budete muset HTC soubory zkopírovat a trochu přepsat do XBL. Symbolicky je pak zápis stylu do html trochu delší:

selektor {behavior: url(soubor.htc), url(soubor.xbl)}

Opět je to, co může vypadat jako nevýhoda, ve skutečnosti trochu výhodou. V HTC souborech lze používat obraty specifické pro Explorer a XBL ladit pro Mozillu. Žádné zdlouhavé podmínkování. Tolik nyní k tématu Mozilly, zpět k příkladům pro Explorer.

Příklad: záměna obrázků po přejetí myší

Jde o klasický příklad, který jsem si nemohl dovolit vynechat. Mám odkaz, v něm obrázek a chci, aby se při najetí myší obrázek zaměnil jiným obrázkem (obvykle podobným, ale s nějakou drobnou změnou).

Klasickým javaskriptem:

<img src="prvni.gif" onmouseover="this.src = 'druhy.gif'" onmouseout="this.src = 'prvni.gif'">

Při přejetí myší (onmouseover) se adresa tohoto obrázku (this.src) zamění adresou na druhý obrázek. Při odjetí myši (onmouseout) se to vrátí. V praxi se ještě na konec stránky dává skript, který druhý obrázek přednačítá, aby to neblikalo, to nyní ale není důležité.

Behaviorem je zápis jiný. Přibývá nový atribut (s libovolným jménem) hoverSrc, který obsahuje adresu druhého obrázku:

<img src="prvni.gif" style="behavior: url('menici.htc')" hoverSrc="druhy.gif">

Menšinové prohlížeče, které behavior nepodporují, obrázky nezamění, což opět není žádná tragédie. Výpis souboru menici.htc:

<component>
<property name="hoverSrc" >
<attach event="onmouseover" handler="zamen">
<attach event="onmouseout" handler="zamen">
<attach event="onDocumentReady" handler="prednatahni">
<script>
function zamen()
{
promenna = element.src;
element.src = hoverSrc;
hoverSrc = promenna;
}
function prednatahni()
{
stahuj = new Image();
stahuj.src = hoverSrc;
}
</script>

</component>

Odkaz na příklad.

Jak to funguje: jistě vidíte několik tagů attach, které přiřazují událostem ovladače. Při přejetí a odjetí myší se spouští tatáž funkce zamen(). Je psaná tak, aby třetí pomocnou proměnnou prostě prohodila dvě vlastnosti.

Všimněte si prosím události onDocumentReady:

<attach event="onDocumentReady" handler="prednatahni">

OnDocumentReady je zvláštní událost specifická pro htc skripty. Spouští se ve chvíli, kdy je dokument celý načtený ze serveru. Je to jediná událost, která umožňuje provést něco bez zásahu uživatele. V tomto příkladu se v tuto chvíli spouští funkce prednatahni(), která začne načítat druhý obrázek, aby byl dříve k dispozici.

Property, předávání parametrů

Nejdůležitější rys předchozího příkladu je tag property.

<property name="hoverSrc" >

Zaručuje, že v proměnné hoverSrc (totéž, co element.hoverSrc) bude hodnota, kterou skript nalezne v html kódu jako hodnotu atributu téhož jména. V příkladu to bude jméno hoverSrc s hodnotou "druhy.gif", ta se bere z html kódu

<img src="prvni.gif" style="behavior: url('menici.htc')" hoverSrc="druhy.gif">

Toto je způsob, kterému můžete htc skriptům předávat parametry. Do htc přidáte tag property a k html tagu prostě přidáte další atribut libovolného jména (ale raději nepoužívejte klíčová slova). Toto jméno pak můžete rovnou použít ve skriptu jako jméno proměnné.

Na tomto místě je dobré na chvíli se zarazit. Přidáváním nestandardních atributů (např. hoverSrc) do html dokumentů vznikají invalidní dokumenty. Může to tedy být dobrá cesta do pekla. Naštěstí se všechny prohlížeče k neznámým atributům chovají neutrálně, prostě je ignorují. Pravdou ovšem zůstává, že dokument potom není validní. Pokud to chcete řešit, tak buďto property nepoužívejte, nebo pište dokumenty v XML a nový atribut zapracujte do DTD. To je mimochodem cesta, kterou se asi bude ubírat vývoj.

Vize knihovny komponent

Ve čtyřech příkladech jsem se snažil použít všechny postupy, které je třeba znát pro psaní vlastních plnohodnotných htc souborů. Nyní si můžete pro běžné skripty, které ve stránkách budete používat, napsat svoje vlastní komponenty. Postupně by vám tak měla vzniknout knihovna komponent. Komponentu, kterou si dnes napíšete, můžete používat navždy. Potom jediné, co bude při psaní další stránky potřeba, bude přiřadit prvkům styly.

Domnívám se, behavior bude užitečný zejména na větších webech (jeden htc se bude načítat do všech stránek). Opravdový význam bude mít pro projekty, na kterých pracuje více lidí, z nichž někdo neovládá JavaScript (nebo dokonce nikdo). Dobře zdokumentovaná knihovna může sloužit mnoha autorům, aniž by jí museli rozumět. Nemusíte svoje kolegy učit JavaScript, stačí, když je naučíte CSS.

Určitě znáte z netu knihovny již hotových javaskriptů. Jejich kvalita je různá (nezřídka záporná), protože implementace cizího skriptu nebývá úplně triviální. Předpokládám, že podobně časem vzniknou knihovny htc komponent. Jejich význam bude v jednoduchosti použití. Pokud budou dobře dokumentované, tak jediné, co bude muset autor stránky udělat, bude zkopírování htc souboru, přiřazení stylu a občas přidání případných dalších atributů (property) podle dokumentace.

Další informace, odkazy

Problematika stylu behavior je velmi široká. Úplně jsem například pominul autorem definované události (event) a metody (method), protože je nepovažuji za moc užitečné. Také ještě musím zmínit, že Internet Explorer má v prohlížeči zabudovaná tzv. defaultní chování, což jsou chování, která programátorům Exploreru připadla užitečná (mně třeba ne).

Zpočátku jsem se domníval, že bude problém obejít se bez metody document.write(), která je v htc nepoužitelná. Dá se ale dobře nahradit vlastnostmi innerHTML a outerHTM či metodou insertAdjacentHTML(), např.

element.insertAdjacentHTML(beforeEnd, "text přidaný před konec elementu");

Když se to naváže na událost onDocumentReady, dá se dosahovat dobrých výsledků, maximálně to při natahování trošku poskočí.

Věřím, že pokud vás problematika zaujala, najdete si další zdroje sami. V češtině jsem nic nenašel. Rád bych upozornil na anglické stránky:

http://msdn.microsoft.com/library/default.asp?url=/workshop/author/behaviors/overview.asp Úvod do behaviors na stránkách Microsoftu.

http://www.w3.org/TR/xbl/ XBL binding language, specifikace W3C.

http://www.w3.org/TR/becss Behavioral Extensions to CSS, starší návrh specifikace W3C, který pravděpodobně implementoval Internet Explorer.

Doplňující informace hledejte v diskusi pod článkem.

 

Reklama

www.webhosting-c4.cz, extra rychlý SSD webhosting s doménou v ceně
o tvorbě, údržbě a zlepšování internetových stránek

Návody HTML CSS JavaScript Články Ostatní

CSS kurz Přehled hodnot Vlastnosti CSS příklady

Jak psát web píše Yuhů, Dušan Janovský. Kontakt.