Alternativní styly – změna stylu pomocí JavaScriptu

7. dubna 2004

V předchozím článku jsme si ukázali, jak nadefinovat alternativní styly v XHTML. Také jsem poukázal na některé nedostatky tohoto řešení. V tomto článku se je tedy pokusíme odstranit – podíváme se spolu na techniku výměny stylu stránky pomocí klientského skriptování.

Klientsky skriptujeme

Základem celého mechanismu změny stylů pomocí JavaScriptu je funkce, která v parametru obdrží jméno alternativního stylu (přesněji řečeno řetězec definovaný atributem title elementu link), tento styl zapne a ostatní alternativní styly (respektive i preferovaný styl) vypne. Zároveň nesmí vypnout styl stálý. My si tuto funkci dále vylepšíme tak, že umožní vypnout všechny styly kromě stálého.

Celý skript se pokusíme napsat co nejčistěji s využitím možností, které nám poskytuje standard DOM. Funkce musí nejdříve naplnit pole links všemi uzly tvořenými elementem link:

var links = new Array();
links=document.getElementsByTagName(„link“);

Tím máme v poli obsah všech elementů link. Je ale zřejmé, že ne všechny tvoří odkaz na externí soubor se styly. Tyto odkazy budeme rozpoznávat podle toho, jestli hodnota atributu rel obsahuje slovo stylesheet. K rozpoznání použijeme řetězcovou funkci indexOf(), která vrací polohu podřetězce v řetězci, respektive hodnotu -1 pokud nenalezne podřetězec. Následující příklad navíc rozpozná, jestli jde o alternativní nebo preferovaný styl podle toho, jestli je atributu title přiřazena libovolná neprázdná hodnota:

for (i=0; i<links.length; i++)
{
  if ((links[i].getAttribute(„rel“).indexOf(„stylesheet“)!=-1) && (links[i].getAttribute(„title“)))
  {
    //jde o odkaz na externí stylový soubor
  }
}

Vytvářená funkce setStyle() používá speciální řetězcovou konstantu BASE. Pokud je funkci předána jako argument tato hodnota, znamená to, že po funkci chceme, aby vypnula úplně všechny alternativní styly a nechala aktivní pouze styl stálý. V tomto případě používám znak #, ale vy se samozřejmě můžete rozhodnout pro jiný znak nebo řetězec.

var BASE=“#“
function setStyle(title)
{
  var i, p, links = new Array();
  links=document.getElementsByTagName(„link“);
  for (i=0; i<links.length; i++)
  {
    if ((links[i].getAttribute(„rel“).indexOf(„stylesheet“)!=-1) && (p=links[i].getAttribute(„title“)))
    {
      links[i].disabled=true;
      if ((p==title) && (p!=BASE)) links[i].disabled=false;
    }
  }
}

Možná nebude od věci si tento zdrojový kód krátce okomentovat, i když snad by měl být dostatečně intuitivní. V cyklu for (i=0; i<links.length; i++) funkce prochází všechny uzly link obsažené v poli links. Pokud jde o odkaz na stylový soubor a zároveň jde o preferovaný nebo alternativní styl, kontroluje, zda se jeho hodnota atributu title rovná hodnotě předané parametrem funkce. V pozitivním případě tento soubor aktivuje. K tomu používá atribut disabled definovaný standardem DOM v části Document Object Model (HTML) Level 1 pro uzly, které reprezentují element link. Pokud tento atribut nabude hodnoty true, odkazovaný styl je vypnut, v opačném případě je aplikován.

Integrace do stránky

Nyní ještě musíme volání funkce setStyle() přiřadit jednotlivým odkazům. Na tom není nic složitého, dobře nám poslouží ovladač události onclick. Takto by vypadaly odkazy pro množinu alternativních stylů, kterou jsme si definovali v předchozím článku:

<a href=“#“ onclick=“setStyle(‚preferovaný alternativní styl‘)“>preferovaný alternativní styl</a>
<a href=“#“ onclick=“setStyle(‚1. alternativní styl‘)“>1. styl</a>
<a href=“#“ onclick=“setStyle(‚2. alternativní styl‘)“>2. styl</a>
<a href=“#“ onclick=“setStyle(‚3. alternativní styl‘)“>3. styl</a>
<a href=“#“ onclick=“setStyle(BASE)“>pouze základní styl</a>

Stylové sušenky

Dosud jsme splnili pouze polovinu úkolu, který jsme si vytyčili. Máme funkci, která dokáže změnit daný styl za jiný, ovšem stále pouze v rámci jedné stránky, což nám ale nestačí. Dále se tedy budeme zabývat problémem, jak přinutit prohlížeč, aby si pamatoval naposledy zvolený styl a aby se vybraný styl aplikoval na všechny stránky konkrétního webu.

Ačkoli se zadaný úkol může zdát nesnadným, ve skutečnosti nejde o nic složitého. Pomůže nám cookie, do které uložíme jméno zvolené alternativy. Na začátku každé stránky pak stačí z cookie načíst jméno stylu a ten aktivovat již vytvořenou funkcí. Před zavřením stránky je nutno vybraný styl do cookie zpět uložit.

Další dvě funkce, které budeme potřebovat, musí zabezpečit manipulaci s cookies. O přístupu ke cookie z JavaScriptu toho bylo napsáno již mnoho i zde na Intervalu. Já osobně jsem si zvykl používat funkce, které na svých stránkách uvedl a v článku o cookies popsal Peter-Paul Koch. Následuje pro přehlednost výpis těchto dvou funkcí přesně tak, jak jsou uvedeny v odkazovaném článku:

function createCookie(name,value,days)
{
  if (days)
  {
    var date = new Date();
    date.setTime(date.getTime()+(days*24*60*60*1000));
    var expires = „; expires=“+date.toGMTString();
  }
  else var expires = „“;
  document.cookie = name+“=“+value+expires+“; path=/“;
}
function readCookie(name)
{
  var nameEQ = name + „=“;
  var ca = document.cookie.split(‚;‘);
  for(var i=0;i < ca.length;i++)
  {
    var c = ca[i];
    while (c.charAt(0)==‘ ‚) c = c.substring(1,c.length);
    if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
  }
  return null;
}

Dále potřebujeme funkci, která vrátí jméno právě vybraného alternativního (či preferovaného) stylu. V podstatě jde o modifikaci již vytvořené funkce setStyle(). Tentokrát nebudeme nic nastavovat, ale procházet seznam stylů tak dlouho, dokud nenajdeme ten s nastavenou hodnotou disabled na false. Pokud nenajdeme ani jeden aplikovaný styl (uživatel zvolil pouze stálý styl), funkce vrací hodnotu BASE:

function getStyle()
{
  var i, p, links;
  links=document.getElementsByTagName(„link“);
  for (i=0; i<links.length; i++)
  {
    if ((links[i].getAttribute(„rel“).indexOf(„stylesheet“)!=-1) && (p=links[i].getAttribute(„title“)) && (!links[i].disabled))
    {
      return p;
    }
  }
  return BASE;
}

Nyní již konečně máme vše, co potřebujeme. Zbývá nám jen napsat ovladače událostí load a unload objektu window. Při načtení okna požadujeme, aby se z cookie načetla hodnota naposledy zvoleného stylu. Zde máme tři možnosti. Buď je v cookie uloženo přímo jméno naposledy zvolené alternativy, nebo hodnota BASE značící, že uživatel minule vypnul všechny alternativy, případně cookie vůbec neexistuje (uživatel je na stránce poprvé nebo má cookies zakázané) – v takovém případě se jednoduše neudělá vůbec nic, o načtení základního a preferovaného stylu se postará sám prohlížeč. Uvedený ovladač události load jednoduše řeší všechny tyto varianty:

window.onload=function()
{
  var p;
  if (p=readCookie(„style“))
  {
    setStyle(p);
  }
}

Podobně po přechodu na jinou stránku nebo při zavření okna je nutno do cookie uložit jméno právě zvolené alternativy, respektive hodnotu BASE, pokud není zvolena žádná. Konstanta DAYS slouží k určení, kolik dnů bude daná cookie platná:

var DAYS=10;
window.onunload=function()
{
  createCookie(„style“,getStyle(),DAYS);
}

Nyní si ještě ve zkratce popíšeme, jak bude celý systém fungovat (za předpokladu, že uživatel má povoleny cookies). Při prvním příchodu cookie se jménem stylu neexistuje, proto skript nevykoná vůbec nic a prohlížeč zformátuje dokument podle základního a preferovaného stylu. Uživatel má nyní možnost zvolit si svůj styl pomocí nabídnutých odkazů. Při zavření okna, nebo přechodu na jinou stránku se do cookie uloží jméno vybraného stylu. Pokud uživatel žádný výběr neučinil, uloží se do cookie jméno preferovaného stylu. A pokud všechny alternativy vypnul, uloží se hodnota BASE. Při dalším příchodu již cookie existuje a po načtení okna se dokument naformátuje stylem načteným z cookie, respektive se všechny styly vypnou, pokud je z cookie načtena hodnota BASE.

Hotové řešení si můžete stáhnout a vyzkoušet. Soubor stačí vložit do stránky pomocí elementu script.

Problémy s prohlížeči

Nyní je na čase si říci, jak si s touto technikou výměny stylu rozumí jednotlivé prohlížeče. V předchozím článku jsme si ukázali, že Opera a Mozilla nabízejí i menu pro výběr jednotlivých stylů. Aby tyto dvě možnosti spolu kooperovaly, musí při změně stylu přes menu být změněna i hodnota atributu disabled uzlu, představujícího element link. Mozilla toto zvládá bez problémů, bohužel Opera nikoli. To má za následek, že pokud uživatel změní styl přes menu, hodnoty atributů disabled zůstanou jako před změnou. Microsoft Internet Explorer žádné menu nenabízí, takže kooperace se skriptem se řešit nemusí.

Microsoft Internet Explorer 6.0 ani Mozilla nemají s uvedenou realizací skriptu žádný problém. Bohužel sedmičková Opera mě v tomto ohledu dost zklamala. Problém nastal především v případě načítání jména stylu z cookie. Pokud jméno obsahuje některý z „nestandardních“ znaků (což je bohužel v případě češtiny dost aktuální, protože lze předpokládat, že budeme chtít styly pojmenovat českými názvy), nastává problém při načítání řetězce z cookie. Ten není načten správně, takže následným porovnáváním není nalezena potřebná shoda. Pokud budete chtít tento skript optimalizovat i pro Operu, zkuste vždy nejdříve změnit jméno stylu na ekvivalentní tvar bez diakritiky (nabízí se také použití vhodné hashovací funkce).

A dalším problémem u Opery je spouštění události unload. Ta u Opery nastane pouze v tom případě, že uživatel přejde z dané stránky na jinou. Pokud však uzavře okno, ovladač události se narozdíl od Mozilly a MSIE nespustí. To má za následek, že se v Opeře při opuštění stránky neuloží do cookie hodnota aktuálního jména stylu.

Proč JavaScript?

Pomocí klientského skriptování můžeme uživateli nabídnout větší komfort než při pouhé definici stylů v XHTML. Nabídku na změnu stylu nemusí hledat někde hluboko v menu, ale může ho mít hned po ruce přímo na stránce. Navíc přibývá možnost personalizace stránky, protože zvolený styl je aplikován na stránku i při novém příchodu, respektive přechodu na jinou stránku daného webu.

Zápory tohoto řešení vyplývají ze samotné podstaty JavaScriptu. Hlavně Opera v tomto případě značně zklamala, koordinace mezi menu a hodnotou disabled je podle mého názoru na pováženou. Uvedené řešení samozřejmě nebude fungovat při vypnutém skriptování nebo cookies. To ovšem nepovažuji za závažný problém, protože pokud má uživatel tyto možnosti vypnuté, dává tím najevo, že o interaktivitu a možnost personalizace nestojí, na což má samozřejmě právo.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Předchozí článek J2ME v kostce - jak na zvuk 1.
Další článek euro2004
Štítky: Články

Mohlo by vás také zajímat

Nejnovější

Napsat komentář

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