Cesta do nitra tří nejznámějších CSS preprocesorů
pokračuje, i když ne tak, jak jsem původně plánoval.
CSS preprocesor je nástroj, který vám ze zdrojového kódu zapsaného ve
vlastní syntaxi vygeneruje CSS pro prohlížeč. Mezi nejznámější patří
SASS, LESS
a Stylus. Ukázali jsme si,
jak je nainstalovat a
naťukli téma syntaxe a
mixinů. Všechny tři preprocesory nabízejí fundamentálně rozdílný
způsob, jak programovat s mixiny. Každý je v tom jinak konzistentní a
každý umí být jinak matoucí.
Pro každý preprocesor existuje galerie hotových mixinů, do kterých
nahlédněte přinejmenším k posouzení jejich srozumitelnosti. Pro SASS
existuje komplexní Compass, LESS má
framework Twitter
Bootstrap nebo drobné Elements a
Stylus NIB.
…tak takhle začínal článek, který jsem rozepsal před rokem a
čtvrt a nikdy nedokončil. Přišel jsem totiž k závěru, že všechny tři
preprocesory jsou, alespoň zatím, nepoužitelné. Jejich nasazení by
představovalo tolik ústupků, že by se vedle nich potenciální výhody
dočista ztrácely. Dnes to vysvětlím.
…pokračování
Vyplatí se používat CSS preprocesory? A pokud ano, který
zvolit? Pokračuji v rozboru tří nejznámějších konkurentů.
CSS preprocesor je nástroj, který vám ze zdrojového kódu zapsaného ve
vlastní syntaxi vygeneruje CSS pro prohlížeč. Mezi nejznámější patří
SASS, LESS
a Stylus. Mají řešit
praktické nedostatky samotného CSS.
V předchozí části
jsme si ukázali, jak preprocesory nainstalovat. Dnes se jim podívám na
zoubek.
Syntaxe
Ač jednotlivé nástroje používají odlišnou syntax, všechny rozumí
klasickému CSS. To je nesmírně důležité! Můžete kopírovat
existující CSS fragmenty a budou fungovat. Ačkoliv…
SASS používá dvě různé syntaxe, jedna se nazývá SASS (stejně jako
preprocesor), nepoužívá středníky ani složené závorky {}
a
místo toho odsazuje mezerami či tabulátory:
// SASS
#main
color: blue
font-size: 0.3em
Druhou syntaxí je SCSS, která vypadá jako klasické CSS a měla být
i plně kompatibilní (budu ji pro SASS používat v dalších příkladech).
Stejnou syntax má i LESS:
// SCSS, LESS a CSS
#main {
color: blue;
font-size: 0.3em;
}
Stylus také rozumí CSS syntaxi, nicméně upozorňuje, že nejde o 100%
kompatibilitu, především proto, že hodně bazíruje na odsazování. V jeho
syntaxi lze vynechat složené závorky, středníky a dokonce
i dvojtečky:
// Stylus
#main
color blue
font-size 0.3em
Ale pozor! Důležité je, že tyto znaky můžeme vynechat. Pokud
vám zápis připadá příliš hutný, klidně si dvojtečky doplňte. Nechcete
odsazovat? Vražte tam složené závorky. Velmi podobně funguje NEON. V tomto se zásadně liší od úsporné
SASS syntaxe, kde vynechání závorek a středníků je povinnost. Což
ji činí z praktického hlediska nepoužitelnou a chápu, proč tvůrci
o kompatibilitu s CSS usilovali, ale udělali to nešťastně zavedením
další, nekompatibilní, ukecané syntaxe SCSS.
Když už se totiž rozhodnu preprocesor používat, ocením, když mi
zjednoduší i syntaxi (alespoň nepovinné středníky), což bohužel umí
jen Stylus. Jeho syntax je nejpružnější a nejúspornější.
V kontrastu přísnosti LESS a SASS je zajímavé, že všechny tři
preprocesory podporují // řádkové komentáře
.
Když udělám chybu
Pokud uděláte v dokumentu chibu, preprocesory vás na ni upozorní
chybovou hláškou. A v tomto směru se jednotlivé nástroje zásadně
liší. Pokud třeba zapomenu ve výše uvedeném kódu uzavírací
}
, oznámí SASS:
Syntax error: Invalid CSS after "font-size: 0.3em;": expected "}", was ""
on line 4 of test.scss
Stylus:
if (err) throw err;
^
ParseError: stdin:4
1| #main {
2| color: blue;
3| font-size: 0.3em;
> 4|
unexpected "eos"
a LESS:
ParseError: missing closing `}` in test.less:9:17
8
9 unexpected "eos"undefined
Nutno dodat, že LESS měl šťastnější chvilku. Pokud bych zapomněl
středník, skončí to u obvyklejšího
ParseError: Syntax Error on line 2 in test.less:2:1
1 #main {
2 color: blue
3 font-size: 0.3em
Výmluvné chybové hlášky jsou pro mě důležité a v tomto směru
s přehledem vede SASS. Ačkoliv se to z ukázky tak nejeví, hodně se
snaží i Stylus. Běžně však špatně spočítá číslo řádku a hlásí
chybu o pár řádků výš, než skutečně je. LESS se nejčastěji zmůže
na nicneříkající Syntax Error on line XY
.
Občas jsem narážel na chyby v samotném preprocesoru. Pokud se mi je
podařilo izolovat, snažil jsem se je nahlásit (LESS, Stylus), ale ne vždy
to šlo. Zde se nejvíc projevila vyspělost jednotlivých nástrojů. Zatímco
nejstarší SASS se mi z rovnováhy nepodařilo vyvést nikdy, druhé dva
nástroje obsahují chyb bohužel požehnaně.
Co všechno umí?
Drtivou většinou užitečných vychytávek najdeme u všech tří
nástrojů, byť třeba nemusí být uvedeny v dokumentaci. V množství asi
vede SASS, ale takto se to hodnotit nedá. Třeba nested
properties nepotřebuji, naopak property
lookup a generátor data URI
ve Stylusu vypadá užitečně. Tedy do chvíle, než zjistíte, že převádí
buď všechny obrázky, nebo žádný.
Nechci sepisovat výčet jednotlivých vlastností ani srovnávat jejich
zápis, to najdete v dokumentaci nebo ve srovnávacím
článku na NetTuts. Zaměřím se místo toho na fundamentální rozdíly a
největší z nich se týkají tzv. mixinů.
Mixiny
Mixiny jsou z mého pohledu nejdůležitější vychytávkou preprocesorů,
protože mění způsob, jak píšeme HTML kód. Vysvětlím. Asi
nejznámější „mixin“ je tzv. clearfix, která se stará o to, aby
z bloku nevytékaly plovoucí prvky. Obvykle vypadá nějak takto:
.clearfix:after {
clear: both;
content: ".";
display: block;
height: 0;
visibility: hidden;
font-size: 0;
}
(Poznámka: existují jednodušší i složitější varianty clearfixu.
Kupodivu mně vždycky fungovalo nastavit bloku overflow: auto
a
clearfix jsem nepotřeboval. Ale v tuto chvíli jde jen
o příklad.).
Clearfix pak aktivujeme v HTML:
<div id="content" class="clearfix">
<div style="float: left;">....</div>
...
</div>
Ale to neděláš dobře, Jaromíre. Clearfix by se měl aplikovat na straně
stylů, přímo pro #content
, nikoliv v HTML. Jenže komu by se
chtělo kazit si krásný stylopis kopírováním ošklivého hacku? Mnoho
kodérů raději sáhne do HTML.
S preprocesory však netřeba nic kopírovat a vystačíme si s jedinou
instrukcí. Nejprve si clearfix uložíme jako tzv. mixin a poté ho v definici
#content
zavoláme:
SASS:
// definice mixinu (zkráceno)
@mixin clearfix {
&:after { clear: both; ... }
}
#content {
@include clearfix; // vložení mixinu
}
LESS:
.clearfix() {
&:after { clear: both; ... }
}
#content {
.clearfix;
}
Stylus:
clearfix()
&:after { clear: both; ... }
#content
clearfix()
Zmizí tak nutkání zasahovat do zdrojového kódu. A to je velmi
důležité.
Jak vidno, syntaxe SASS je opět nejukecanější. Za zmínku stojí, že
LESS umožňuje volat jako mixin i jakoukoliv třídu nebo ID.
Parametrické mixiny
Ještě zajímavější je to ve chvíli, kdy mixinům předáme
parametry:
SASS:
@mixin border-radius($arg) {
-webkit-border-radius: $arg;
-moz-border-radius: $arg;
border-radius: $arg;
}
#content {
@include border-radius(2px);
}
LESS:
.border-radius(@arg) {
-webkit-border-radius: @arg;
-moz-border-radius: @arg;
border-radius: @arg;
}
#content {
.border-radius(2px);
}
Stylus:
border-radius(arg)
-webkit-border-radius: arg
-moz-border-radius: arg
border-radius: arg
#content
border-radius(2px)
Ve Stylusu můžeme použít i zapis s dvojtečkou:
#content
border-radius: 2px
Což je velmi zajímavé! Když totiž později vendor prefix odstraníme,
nebo když naopak zjistíme, že určité vlastnosti potřebujeme vendorovou
variantu dodat, nemusíme změnit ani čárku v samotném stylu. Wow.
Jenže… co když mixin zavoláme s více parametry? Například uvedeme
border-radius: 2px 3px
. Překvapivě Stylus bude 3px
v tichosti ignorovat. Proč tomu tak je?
V CSS existují dva způsoby, jak uvést více argumentů, lišící se
v oddělovači:
- oddělené mezerama:
border: 1px solid black
- oddělené čárkama:
rgb(10, 20, 30)
Totéž se rozlišuje i v preprocesorech. Ve Stylusu platí, že volání
mixinu border-radius: 2px 3px
je ekvivalentní k
border-radius(2px, 3px)
(a dává mi to smysl), obojí představuje
předávní dvou argumentů. Naopak border-radius(2px 3px)
bez
čárky předává argument jeden. Náš mixin očekává pouze jeden parametr a
druhý tiše bez jakéhokoliv varování zahodil. Oprava spočívá v použití
užitečného klíčového slova arguments
namísto předaného
argumentu arg
.
SASS a LESS naopak předání více argumentů, než je mixinem očekáváno,
vnímají jako fatální chybu. V případě SASS to v důsledku vede
k podivným blokům $shadow-1, …, $shadow-10 patrným
v galerii Compass, zatímco LESS se s problémem snaží vypořádat
konstrukcí when()
. Nic z toho mi nepřipadá ideální.
Pokračování zase
příště.
Už pár let jsem si pořádně nezakódoval a začalo mi to
chybět. Zachtělo se mi udělat stránky podle nejnovějších trendů.
Responsivní design okořeněný CSS preprocesory. Ale váhal jsem: jsou
preprocesory víc, než jen chvilková móda?
CSS preprocesor je nástroj, který vám ze zdrojového kódu zapsaného ve
vlastní syntaxi vygeneruje CSS pro prohlížeč. Mezi nejznámější patří
SASS, LESS
a Stylus.
Faktem je, že jakmile začne stylopis kynout do větších rozměrů, řada
věcí se řeší dosti nepohodlně. Je třeba vynaložit úsilí, aby zůstal
čitelný a srozumitelný. Aby se z něj nestal write-only soubor plný
magický konstant a hacků. Spoustu těchto nešvarů preprocesory řeší,
nejvíc se těším na vnořené
definice, matematické
výrazy, mixiny
a proměnné.
Vlastně je smutné, že preprocesory musely vzniknout. Ukazuje to na
zanedbanost vývoje CSS. Na druhou stranu, může z nich i těžit.
Preprocesory jsou mladé projekty procházející bouřlivým vývojem, reagují
na potřeby uživatelů a lze u nich, na rozdíl od standardu, tolerovat
i případné nekompatibilní změny. Ve finále tak mohou ukázat směr,
kterým se má vydat příští CSS.
Pokud se kódováním webů bavíte řadu let, máte vybudované
konvence
pomáhající nedostatky obcházet. Preprocesory pak nemusí být úplně
samozřejmou volbou. Nicméně dnes je běžné používat různé CSS generátory a preprocesor nabízí
čistější cestu, než copy&pastovat vygenerovaný kód.
Rád zkouším nové věci, proto jsem dal preprocesorům šanci. Který ale
zvolit? Nejlepší je si všechny osahat.
Instalace
Začneme tedy rovnou instalací. Na webu SASS i LESS rychle najdete
vyčerpávající postup, jak knihovny získat. SASS je napsaný v Ruby, LESS v Node.js, takže prvním krokem bude instalace
překladače, což by neměl být v žádném operačním systému problém.
Preprocesor pak nainstalujete příkazem:
gem install sass
resp.
npm install less
Velmi snadné, PHP může závidět.
Naopak web Stylusu selhává, snaží se mást odkazy na Github, zatímco
informace, jak ho instalovat, je důmyslně skrytá kdesi vespod úvodní
stránky. Vězte tedy, že Stylus je také napsán v Node.js a nainstaluje se
obdobně příkazem npm install stylus
.
Pozor na jednu věc, npm instaluje
balíček do aktuálního adresáře, takže abyste mohli preprocesory pohodlně
spouštět z příkazové řádky, musíte si cestu k lessc.cmd
a
stylus.cmd
přidat do proměnné PATH. Ve Windows se to dělá sparťansky, takže
spíš oceníte možnost nainstalovat balíčky do globálního adresáře
(pomocí přepínače -g
, tj. npm install -g stylus
),
ke kterému už cestu zaregistroval při instalaci překladač.
Příkazová řádka pro SASS a Stylus nabízí spoustu voleb, LESS umí jen
konvertovat vstupní soubor do výstupního CSS. Zmátlo mě, že SASS i Stylus
zavolané bez parametrů se nijak neohlásí a očekávají vstup
z klávesnice. Zavolejte je tedy s parametrem -h
a vypíše se
nápověda všech voleb.
Vývoj a deployment
Preprocesory vyžadují, aby se mezi úpravou stylopisu a zobrazením
v prohlížeči udělat jeden krok navíc: kompilace do CSS.
Tento krůček může mnohé odradit. Pokud jste zvyklí rovnou editovat CSS
soubory na FTP serveru, nad preprocesorem vůbec neuvažujte. Existují sice
možnosti, jak třeba z LESS generovat CSS za běhu přímo v prohlížeči,
ale rozhodně nejsou určeny pro produkční nasazení.
Pokud máte deployment automatizovaný, stačí do procesu zařadit kompilaci
voláním příkazové řádky a je vystaráno.
Jak řešit onen krok navíc během vývoje? Kodéra rozhodně blbnutí
s příkazovou řádkou nezajímá a chce rovnou psát stylopis.
Jak jsem zmínil, LESS umí překládat stylopisy v prohlížeči, stačí
tedy zalinkovat soubor less.js a můžete rovnou připojovat soubory ve formátu
LESS (povšimněte hodnoty atributu rel
):
<link rel="stylesheet/less" type="text/css" href="styles.less">
<script src="less.js" type="text/javascript"></script>
SASS a Stylus zase nabízejí sledovací režim, ve kterém monitorují
adresář se styly ve svém formátu a při každé změně souboru je ihned
překládají do CSS.
// překlad souborů z adresáře /css.sass do /css (včetně podadresářů)
sass --watch css.sass:css
// překlad souborů z adresáře /css.stylus do /css
stylus --watch css.stylus --out css
Do vygenerovaného CSS lze pomocí přepínače --line-numbers
přidat pro lepší orientaci komentáře s číslem řádku zdrojového
souboru. Pokud vyvíjíte ve Firefoxu, ještě užitečnější je nainstalovat
FireStylus
a kompilovat s přepínačem --firebug
. V záložce HTML by se
pak měly objevovat odkazy přímo na zdrojový soubor. Píšu měly, protože
mi to nefunguje.
Všechny tři preprocesory jsou seřazeny na startovní čáře. Který
z nich běží nejlépe? Pokračování příště.
(Doporučuji aktuálnější průvodce CSS preprocesory od Martina
Michálka, první a druhý
díl.)
I found a strange bug in Internet Explorer 9, which appears in the last
version 9.0.8112.16421. If the same cookie is sent twice, once with the
expiration at the end of the session and once with any other expiration, IE9
will remove cookie. Webpage must have a strict doctype.
Example:
<?php
// expire at the end of the session
setcookie('test', 'value', 0);
// expire in 1 hour
setcookie('test', 'value', 3600 + time());
// switch browser and document mode to IE9
?>
<!doctype html>
Is cookie set? <?php echo isset($_COOKIE['test']) ? 'yes' : 'no' ?>
Try to open this example in IE9 and
refresh: cookie will not be set.
Solution is to remove older cookies after sending new one:
$headers = array();
foreach (headers_list() as $header) {
if (preg_match('#^Set-Cookie: .+?=#', $header, $m)) {
$headers[$m[0]] = $header;
header_remove('Set-Cookie'); // requires PHP 5.3 or newer
}
}
foreach ($headers as $header) {
header($header, false);
}
Bug is fixed in Nette Framework.
S pomocí jQuery lze vytvořit HTML element docela jednoduše:
var $el = $('<a href="https://phpfashion.com">blogísek</a>');
Do proměnné $el
se přiřadí objekt jQuery obalující
vytvořený HTML element (proto jsem použil dolar v názvu proměnné),
k nativnímu DOM objektu se dostanete přes $el[0]
.
Co ale v případě, že potřebujeme jako hodnoty použít proměnné?
Přímočaré řešení by vypadalo takto:
// špatně: riziko XSS
var url = 'https://phpfashion.com';
var title = 'blogísek';
var $el = $('<a href="' + url + '">' + title + '</a>');
Jenže, jak uvádí komentář v kódu, koledujeme si tímto o průšvih
jménem Cross-site scripting (XSS). Stačí, aby například proměnná
url
obsahovala uvozovky a výsledek bude nezamýšlený. Proto je
nutné proměnné escapovat, tj.
nahradit znaky mající speciální význam za HTML entity. Na to si můžeme
napsat funkci escapeHtml
:
// správné, ale ne příliš přehledné
var escapeHtml = function(s) {
return s.replace('&', '&').replace('"', '"')
.replace("'", ''').replace('<', '<');
};
var $el = $('<a href="' + escapeHtml(url) + '">' + escapeHtml(title) + '</a>');
Skládání řetězců postrádá onu lehkost a srozumitelnost první
ukázky, nemluvě o riziku, že escapeHtml
zapomeneme zavolat.
Naštěstí jQuery od verze 1.4 nabízí elegantní řešení: proměnné
uvedeme ve druhém parametru (viz dokumentace)
// dokonalé
var $el = $('<a>', {
href: url,
text: title
});
Příjemné je, že takto lze kromě HTML atributů definovat i kaskádové
styly a události:
// <a style="color: red;" onclick="..." href="https://phpfashion.com">blogísek</a>
var $el = $('<a>', {
href: url,
text: title,
click: function(e) {
alert(this.href);
},
css: {
color: 'red'
}
});
Dokonce dovnitř můžeme vložit další element:
// <a href="https://phpfashion.com"><img alt="Logo" src="images/logo.gif"></a>
var $el = $('<a>', {
href: url,
html: $('<img>', {
src: 'images/logo.gif',
alt: 'Logo'
})
});
Fajnové, že?
p.s. pokud se chcete o jQuery dozvědět víc, přijďte na školení jQuery a
AJAX.
„Ty bys měl školit Nette,“ řekl mi Vašek WebExpo Stoupa a já se pak
přes půl roku rozhoupával, než v listopadu 2008 uskutečnil první
školení Vývoj
webových aplikací v Nette Framework. Od té doby prošlo kurzem asi
300 kolegů programátorů.
„Ty bys měl školit jQuery,“ řeklo mi pár účastníků školení
Nette a já se pak přes půl roku rozhoupával, než vypsal první školení jQuery a AJAX, na
které vás tímto zvu. (Než jsem se rozhoupal k napsání tohoto článku,
kurz je z poloviny naplněn. Málo houpu.)
Co vám kurz dá? Vím, že to zní jako otřepaná fráze, ale rád bych
ukázal, že oživování webové stránky pomocí JavaScriptu může být
skutečně zábavné. Seznámím vás s nejpopulárnějším JavaScriptovým
frameworkem jQuery na praktických příkladech.
Přitom budeme dbát na čistý návrh a znovupoužitelnost, protože ve
chvíli, kdy programátor zabředne do bastlení, je se zábavou smyčec. Nebo
šmitec. Celým kurzem se potáhne ústřední motiv user experience,
tj. vysvětlíme si a ukážeme, kterou cestou se vydat, aby výsledek byl pro
uživatele co nejintuitivnější. Protože o nic jiného vlastně nejde.
Bylo by fajn, kdybyste na školení vyrazili se základní znalostí
JavaScriptu (stačí rozumět tomuto
článku bez kapitol Properties a Dědičnost). Pokud zatím neznáte jQuery
a rádi byste to napravili, jsem vám k službám!
Otázka, kterou si klade řada webmasterů: vnímají vyhledávače tyto URL
jako stejné? Jak s nimi naložit?
http://example.com/article
http://example.com/article/
http://example.com/Article
https://example.com/article
http://www.example.com/article
http://example.com/article?a=1&b=2
http://example.com/article?b=2&a=1
Stručná odpověď by byla: „URL jsou odlišné.“ Chce to ale
podrobnější rozbor.
Z pohledu uživatelů se tyto adresy liší v drobnostech, kterým
nepřikládají žádnou váhu. Tedy je vnímají jako stejné, ačkoliv
z technického hlediska jde o adresy různé. Říkejme jim třeba adresy
podobné. V zájmu uživatelského
prožitku proto dodržujte 2 zásady:
- Nedovolte, aby se na podobných adresách nacházel odlišný obsah.
Jak záhy ukážu, nevedlo by to jen ke zmatení uživatelů, ale
i vyhledávačů.
- Umožněte uživatelům přístup i přes podobné adresy.
Pokud se adresy liší v protokolu http
/ https
nebo doméně s www
či bez, považují je vyhledávače za
různé. Nikoliv tak uživatelé. Bylo by tedy fatální chybou na takto
podobné adresy umístit různý obsah. Nicméně chybou by bylo
i znemožnění přístupu přes podobnou adresu. Musí tedy fungovat
adresa s www
i bez www
. Přičemž SEO nabádá
držet se jedné varianty a ostatní na ni přesměrovávat HTTP kódem 301. To
lze u www
subdomény zajistit například souborem
.htaccess
:
# presmerovani na variantu bez www
RewriteCond %{HTTP_HOST} ^www\.
RewriteRule ^.*$ http://example.com/$0 [R=301,NE,L]
# presmerovani na variantu s www
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^.*$ http://www.example.com/$0 [R=301,NE,L]
Schválně si hned vyzkoušejte, jestli vaše servery přesměrovávají a to
včetně celé adresy a správného
předání parametrů. Nezapomeňte i na varianty
www.subdomena.example.cz
. Protože některé prohlížeče umí
chybějící přesměrování obcházet, zkuste raději nízkoúrovňovou
službu jako Web-Sniffer.
Velká a malá písmena se v URL rozlišují všude kromě schéma a
domény. Avšak uživatel je opět nerozlišuje a je tedy nešťastné nabízet
rozdílný obsah na adresách lišících se jen velikostí písmen. Jako
špatný příklad může posloužit Wikipedie:
Kuriózní chybou trpí Bing, který vrací stejné URL, ať už hledáte
kyselinu nebo databázi (ačkoliv textový popis je správný). Google nebo
Yahoo tímto problémem netrpí.
Také některé služby (webmaily, ICQ) převádí velká písmenka v URL na
malá, což jsou všechno důvody, proč se rozlišování velikosti vyhnout a
to nejlépe i v parametrech. Raději dodržujte konvenci, že všechna
písmenka v URL budou malá.
Rozlišit některé podobné adresy je oříšek i pro vyhledávače.
Udělal jsem experiment a na URL lišící se v detailech jako je přítomnost
pravostranného lomítka nebo pořadí parametrů umístil odlišný obsah.
Zaindexovat je byl schopen pouze Google. Ostatní vyhledávače dokázaly
pojmout vždy jen jednu z variant.
Pokud jde o pravostranná lomítka, webový server přesměrovává na
kanonickou podobu obvykle za vás; přistoupíte-li k adresáři bez
pravostranného lomítka, doplní je a přesměruje. Samozřejmě to neplatí,
když URI spravujete ve vlastní režii (Cool URI apod.)
A nakonec: skutečně záleží na pořadí parametrů? Mezi adresou
article?a=1&b=2
a article?b=2&a=1
by neměl
být žádný rozdíl. Jsou ale situace, kdy to neplatí, zejména když
předáváme složitější struktury jako třeba pole. Například
?sort[]=name&sort[]=city
může být něco jiného, než
?sort[]=city&sort[]=name
. Nicméně přesměrovávat, nejsou-li
parametry ve stanoveném pořadí, bych považoval za zbytečnou
hyperkorektnost.
p. s. Nette Framework přesměrování na
kanonické URL provádí zcela automaticky ve své režii
Pracovat s webovým formulářem na straně JavaScriptu se poměrně snadno
může stát očistcem. Nebo jak se nazývá ta věc na čištění záchodové
mísy. Přitom za všechno může jedno nešťastné rozhodnutí.
Mějme jednoduchý formulář
<form id=myform>
<input type=text name=query>
<input type=submit value="Vyhledat">
</form>
K jeho jednotlivým prvkům přistoupíme přes vlastnost
elements
:
var form = document.getElementById('myform');
var query = form.elements.query.value;
// pochopitelně také form.elements['query'].value
A iterovat nad prvky lze cyklem for:
for (var i = 0; i < form.elements.length; i++) {
alert(form.elements[i].value);
}
Z historických důvodů lze vlastnost elements
v příkladech
vynechat, neboť jednotlivé prvky se mapují přímo do objektu
form
. Takže by fungovalo i form.query.value
,
form.length
nebo form[i].value
. Což se záhy ukáže
jako nemilé. Formulářové prvky totiž přepisují nativní
metody a proměnné objektu form. Například metoda submit()
,
která je klíčová pro AJAXové odeslání formuláře, se stane nedostupnou,
pokud formulář obsahuje prvek nazvaný submit
. A uznejte, že to
je zrovinka název pro odesílací tlačítko jako dělaný. Pokud by tedy
formulář vypadal takto
<form id=myform>
<input type=text name=query>
<input type=submit name=submit value="Vyhledat">
</form>
nebude jej možné příkazem form.submit()
odeslat, místo toho
JavaScript zařve „form.submit is not a function“ a má pravdu,
form.submit
není funkce ale objekt HtmlInputElement. Dobrá, dáme
si pozor a nebudeme formulářové prvky nazývat submit
.
(prozradím trik, jak by formulář šlo odeslat i v tomto případě:
document.createElement('form').submit.call(form)
)
Jenže název submit
není tím jediným, kterému se musíme
vyhnout. Prvek pojmenovaný elements
způsobí, že
form.elements
nebude očekávaná kolekce a výše uvedené
příklady skončí chybou. Název length
zase znemožní nad
kolekcí iterovat. A tak by se dalo pokračovat, nativních prvků třeba DOM
Firefoxu definuje hodně přes stovku. Pro zajímavost uvádím seznam jen těch
jednoslovných (tj. vynechávám nodeName
nebo
innerHTML
):
action, attributes, blur, children, dir, draggable, elements, encoding,
enctype, focus, id, lang, length, method, name, normalize, prefix, reset,
spellcheck, style, submit, target, title
Bylo by skvělé, kdyby se HTML5 dokázalo s tímto nešvarem vypořádat.
Zatím jsem ve specifikaci nic takového nenašel.
Podobně mi chybí možnost, jak v obsluze události onsubmit
zjistit, kterým tlačítkem byl formulář odeslán. Triviální a užitečná
věc a jak složitě se musí řešit.
<form id=myform onsubmit="kterým tlačítkem byl odeslán?">
<input type=hidden name=id value="123">
<input type=submit name=save value="Uložit">
<input type=submit name=delete value="Smazat">
</form>
Řeším to tak, že odchytávám událost click
jednotlivých
tlačítek a název prvku ukládám do vlastní proměnné formuláře. O něco
jednodušší je využít bublání a odchytávat click
přímo na
formuláři. Nicméně v HTML5 tohle už nebude fungovat spolehlivě, protože
prvek může být umístěn i mimo strom formuláře a přiřazen k němu
atributem form
. Bylo by tedy fajn, kdyby HTML5 zavedlo vlastnost
například form.submitter
, který by vracela název
odesílajícího tlačítka.
p. s. Nette Framework s těmito
situacemi počítá a snaží se je v rámci možností řešit za
programátora
Poslyšte příběh: klient si přál učinit svůj web hezčím a tak
jsem mu doporučil jednoho z těch mála dobrých tuzemských grafiků. Před
pár dny jsme měli schůzku a on se svěřil, že už dostal od grafika návrh
a není z něj gór šťastný. Že písmo je moc malé a celé je to jakési
kostrbaté. Nějak se mi to nezdálo, poprosil jsem ho, aby návrh otevřel, že
se na to podíváme. Dohledal email, odkliknul obrázek a naběhl mu výchozí
prohlížeč obrázků ve Windows. A protože obrázek měl větší rozměry,
zobrazil se (mírně) zmenšený. A hned bylo jasné, kde je
zakopaný pes.
Pokud klient není expert, nemá šanci zjistit, že se dívá na obrázek
zdeformovaný zmenšením. Prohlížeč obrázků ve Windows XP nebo Vista na to
nijak neupozorní. Ba co víc – i kdyby to zaregistroval, nejspíš se mu
nepodaří obrázek zvětšit na plnou velikost. Alespoň kolečkem myši nebo
klávesami +
-
to nejde. Ty obrázek
zvětšují/zmenšují o 20 % a hranici 100 % bez zastavení přeskočí.
Zobrazit jej v měřítku 1:1 vyžaduje fištróna.
Z příběhu vyplývá velmi cenná a nejspíš překvapivá zkušenost:
neposílejte klientům náhledy webů jako obrázek.
Jak tedy náhledy posílat? Nejvhodnější je klientovi poslat URL. Design
tak uvidí v kontextu webového prohlížeče a bude mít daleko ucelenější
dojem. Ale pozor, pokud byste poslali přímo URL obrázku, prohlížeč by jej
opět zmenšil. Je nad ním potřeba vytvořit HTML obálku. Nahrejte proto na
web kromě obrázku ještě soubor nahled.php
:
<title>Náhled webu</title>
<body style="margin:0; text-align:center">
<img src="<?php echo htmlSpecialChars($_SERVER['QUERY_STRING']) ?>">
</body>
Potom např. obrázek pala.png
bude dostupný pod URL
http://example.com/nahled.php?pala.png
. Tu pošlete klientovi a
učiníte přítrž možným nedorozuměním.
Na závěr ještě tři tipy:
- udělejte obrázek dostatečně široký a výsoký, nebo vhodně nastavte
pozadí, aby nebylo vidět bílé pozadí prohlížeče
- náhled ukládejte zásadně jako 24bitový PNG
- ponechte v kódu element
img
, zobrazením pomocí CSS stylu
background zkomplikujete klientovi tisk
Na posledním školení jsme
narazili na zajímavost HTML, která mě (v tu chvíli nepříjemně)
překvapila.
Podívejte se na následující kus kódu. Vyskočí okénko se zprávou
Barnes & Noble
nebo Barnes & Noble
?
<body>
<h1>Barnes & Noble test</h1>
<script>
alert('Barnes & Noble');
</script>
</body>
Máte tip? Tak si ho ověřte. Zajímavé
přitom je, že pokud bychom entitu nepoužili, bude výsledek nevalidní.