Journey into the heart of the three most known CSS
preprocessors continues, though not in the way I originally planned.
CSS preprocessor is a tool that take code written in their own syntax and
generates the CSS for the browser. The most popular preprocessors are SASS, LESS and
Stylus. We have talked about
installation
and syntax
+ mixins. All three preprocessors have a fundamentally different way of
mixins conception.
Each of them have gallery of finished mixins: For SASS there is a
comprehensive Compass, the LESS has
framework Twitter
Bootstrap or small Elements a Stylus
NIB.
… this was opening sentences of article I started write year and
quarter ago and never finished. I came to the conclusion that all three
preprocessors are useless. They required to do so many compromises that
potential benefits seemed insignificant. Today I will explain it.
…pokračování
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í
FTP deployment is a tool for automated deployment to an FTP
server.
There is nothing worse than uploading web applications to FTP server
manually, using tools like Total Commander. (Although, editing files directly on
the server and then trying to keep some kind of synchronization is even
worse 
Once the process is automated, it costs you a fraction of time and minimizes
the risk of error (didn't I forget to upload some files?). There are lots of
sophisticated deploying techniques available today, but many people are still
using FTP. This tool is designed for them.
FTP Deployment is a script written in PHP (requires PHP 5.4 or newer) and
will automate the entire process. Just say which local folder to upload and
where. This information is stored in a deployment.ini
text file,
which you can associate with deployment
script, so deployment will
become a one click thing.
php deployment deployment.ini
And what does the deployment.ini
file contain? Only the
remote
item is required, all the others are optional:
; log file (defaults to config file with .log extension)
log = ...
; directory for temporary files (defaults to system's temporary directory)
tempDir = /temp/deployment
; enable colored highlights? (defaults to autodetect)
colors = yes
[my site] ; Optional section (there may be more than one section).
; remote FTP server
remote = ftp://user:secretpassword@ftp.example.com/directory
; you can use ftps:// or sftp:// protocols (sftp requires SSH2 extension)
; do not like to specify user & password in 'remote'? Use these options:
user = ...
password = ...
; FTP passive mode
passiveMode = yes
; local path (optional)
local = .
; run in test-mode? (can be enabled by option -t or --test)
test = no
; files and directories to ignore
ignore = "
.git*
project.pp[jx]
/deployment.*
/log
temp/*
!temp/.htaccess
"
; is allowed to delete remote files? (defaults to yes)
allowDelete = yes
; jobs to run before uploading
before[] = local: lessc assets/combined.less assets/combined.css
before[] = http://example.com/deployment.php?before
; jobs to run after uploading and before uploaded files are renamed
afterUpload[] = http://example.com/deployment.php?afterUpload
; directories to purge after uploading
purge[] = temp/cache
; jobs to run after everything (upload, rename, delete, purge) is done
after[] = remote: unzip api.zip
after[] = remote: chmod 0777 temp/cache ; change permissions
after[] = http://example.com/deployment.php?after
; files to preprocess (defaults to *.js *.css)
preprocess = no
; file which contains hashes of all uploaded files (defaults to .htdeployment)
deploymentFile = .deployment
Configuration can also be stored in a PHP file.
In test mode (with -t
option) uploading or deleting files is
skipped, so you can use it to verify your settings.
Item ignore
uses the similar format to .gitignore
:
log - ignore all 'log' files or directories in all subfolders
/log - ignore 'log' file or directory in the root
app/log - ignore 'log' file or directory in the 'app' in the root
data/* - ignore everything inside the 'data' folder, but the folder will be created on FTP
!data/db/file.sdb - make an exception for the previous rule and do not ignore file 'file.sdb'
project.pp[jx] - ignore files or folders 'project.ppj' and 'project.ppx'
Before the upload starts, after it finishes and after all jobs, you can
execute commands or call your scripts on the server (see before
,
afterUpload
, after
), which can, for example, switch
the server to a maintenance mode. If you use php-config – you can run lambda
function with deployment environment.
Syncing a large number of files attempts to run in (something like) a
transaction: all files are uploaded with extension .deploytmp
and
then quickly renamed.
An .htdeployment
file is uploaded to the server, which contains
MD5 hashes of all the files and is used for synchronization. So the next time
you run deployment
, only modified files are uploaded and deleted
files are deleted on server (if it is not forbidden by the
allowDelete
directive).
Uploaded files can be processed by a preprocessor. These rules are
predefined: .css
files are compressed using the Clean-CSS and
.js
minified by Google Closure Compiler via online services.
There is also a rule for expanding mod_include
Apache directives. For example, you can create a file
combined.js
:
<!--#include file="jquery.js" -->
<!--#include file="jquery.fancybox.js" -->
<!--#include file="main.js" -->
This tool will combine scripts together and minify them with the Closure
Compiler to speed-up your website.
In the deployment.ini
, you can create multiple sections, i.e.
you may have separate rules for data and for application.
Installing FTP Deployment
FTP Deployment requires PHP 5.4 or later. It also requires openssl
extensions for ftps:// and SSH2 extension for sftp:// connections.
The easiest way to obtain FTP Deployment is to download a single PHAR file.
Or you can install it using Composer:
composer create-project dg/ftp-deployment
Málokdo má takovou potřebu zdůrazňovat svou domnělou
nadřazenost, jako právě Railisti. Abyste mě nechápali špatně, jde
o dobrou marketingovou strategii. Nepříjemné je, když jí podlehnete do té
míry, že zbytek světa vnímáte jen jako upachtěné kopírovače bez šance
se vám někdy přiblížit. Svět takový totiž není.
Příkladem je Dependency Injection. Zatímco lidé kolem PHP nebo
JavaScriptu objevili DI se zpožděním, Ruby on Rails zůstávají dosud
nepolíbené. Bylo mi záhadou, proč framework s tak pokrokovou image
zůstává kdesi pozadu a začal v tom pátrat. Odpověď mi dala řada zdrojů
na Google nebo karmiq
a zní:
Ruby je tak dobrý jazyk, že vůbec Dependency Injection nepotřebuje.
Fascinující argument, který je navíc v elitářském prostředí
sebepotvrzující. A je skutečně pravdivý? Nebo jde jen o zaslepení
pýchou, stejné zaslepení, jaké způsobilo nedávno přetřásané
bezpečnostní díry v Rails?
Říkal jsem si, že je možné, že Ruby znám natolik málo, aby mi
nějaký klíčový aspekt unikl, a že skutečně jde o jazyk, který DI
nepotřebuje. Jenže primárním smyslem Dependency Injection je zřejmé
předávání závislostí, aby byl kód srozumitelný a předvídatelný (a
je pak i lépe testovatelný). Jenže když se podívám do dokumentace Rails
na tutoriál „blog za pár minut“, vidím
tam třeba:
def index
@posts = Post.all
end
Tedy pro získání blogpostů používají statickou metodu
Post.all
, která odněkud (!) vrátí seznam článků.
Z databáze? Ze souboru? Vyčaruje je? Nevím, protože se tu nepoužívá DI.
Místo toho se tu vaří nějaké statické peklo. Ruby je bezesporu
šikovný jazyk, ale DI nenahrazuje.
V Ruby lze za běhu přepisovat metody (Monkey patch; obdobně jako
v JavaScriptu), což je forma Inversion of control (IoC), která třeba pro
potřeby testů dovolí podstrčit jinou implementaci statické metody
Post.all
. Tohle ale nenahrazuje DI, kód to zřejmější
neudělá, spíše naopak.
Mimochodem, zaujala mě i třída Post tím, že reprezentuje jak jeden
článek na blogu, tak funguje jako repozitář (metoda all), což je porušení
Single
Responsibility Principle jako vyšité.
Jako odůvodnění, proč Ruby nepotřebují DI, se často odkazuje na
článek LEGOs,
Play-Doh, and Programming. Důkladně jsem ho pročetl, sledoval, jak autor
párkrát zaměňuje „DI“ s „DI frameworkem“ (tedy něco jako
zaměňovat „Ruby“ s „Ruby on Rails“) a nakonec zjistil, že
k závěru, že Ruby Dependency Injection nepotřebují, vůbec nepřišel.
Psal, že nepotřebují DI frameworky, jaké zná z Javy.
Jeden mylně interpretovaný závěr, pokud pohladí ego, dokáže zcela
pobláznit obrovskou skupinu inteligentních lidí. Nakonec mýtus, že špenát
obsahuje neobyčejné množství železa, se taky drží od roku 1870.
Ruby je velmi zajímavý jazyk, vyplatí se v něm jako v každém jiném
používat DI a existují pro něj i DI frameworky. Rails je zajímavý
framework, který zatím neobjevil DI. Až ho objeví, půjde o velké téma
některé z příštích verzí.
(Po pokusu diskutovat o DI s Karmim, kterého pokládám za
nejinteligentnějšího Railistu, nechávám komentáře uzavřené,
omlouvám se.)
Viz také: Dependency
injection není pouze o jednoduším testová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