Určujte relativní velikost fontů pomocí CSS3

Martin Pešout   9. 2. 2012


Pokud budeme vytvářet kaskádové styly pro nový web, máme v podstatě dvě možnosti, jak zapsat velikosti fontů. Jedna z nich je definovat vše "napevno", například pomocí rozměru v pixelech. Druhou možností je určit velikost relativně vůči nadřazenému HTML elementu. Oba způsoby mají své výhody i nevýhody. CSS3 však rozšiřuje definici relativních rozměrů o novou jednotku, tzv. rem, a snaží se tak vnést do celé problematiky větší zjednodušení zápisu.

Jak již jsem nakousl, máme v kaskádových stylech dvě základní délkové jednotky:

  • absolutní jednotky - především pixel (px)
  • relativní jednotky - em

Bližší definici pixelu a jednotky em naleznete třeba zde na webu CSS-tricks. V tomto článku zmíním jen základní rozdíly.

Absolutní jednotky

Používání absolutních jednotek má jednu velikou výhodu. Je to spolehlivé a konzistentní. Také samotné definice v CSS souborech se velice snadno zapisují. Vše ukážu na následujícím kousku HTML5 kódu:

Ukázková stránka pro blog společnosti IglooNET

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Napsáno v roce 2012

Tento článek je zaměřen na velikosti fontů. Nebudeme se tedy zabývat otázkou, jak nastylovat rozložení prvků na stránce. Definice kaskádových stylů s použitím absolutních jednotek by mohla vypadat následovně:

body {
  font: normal 16px/24px 'Arial CE', 'Helvetica CE', Arial, Helvetica, sans-serif;
}

.main-title {
  font: normal 30px/36px Georgia, 'Times New CE', 'Times CE', 'Times New Roman', Times, serif;
}

.main-title cite {
  font-size: 42px;
  line-height: 50px;
}

.article-body {
  font-size: 18px;
}

.caps,
footer {
  font-size: 14px;
}

Tento zápis má ale jednu nevýhodu. Uživatelé starších prohlížečů Internet Explorer (dokonce i verze 9) jsou znevýhodněni. Nemají možnost měnit velikost textu na webu použitím funkce na zvětšení/zmenšení fontu v prohlížeči. Poslední verze většiny „velkých“ prohlížečů už obsahují funkci přibližování, která zvětšuje naráz rozměry všech prvků stránky.

Relativní jednotky

Problém zvětšování fontů v Internet Exploreru je řešitelný použitím relativních jednotek. Pokud chceme použít tuto techniku, je nutné v prvé řadě upravit základní velikost fontu pro celou stránku. Rozměr zadefinujeme v procentech. Výchozí velikost pro text ve většině moderních prohlížečů je 16 pixelů. Což znamená, že tento zápis:

body { 
  font: normal 16px 'Arial CE', 'Helvetica CE', Arial, Helvetica, sans-serif; 
}

je ekvivalentní tomuto zápisu:

body { 
  font: normal 100% 'Arial CE', 'Helvetica CE', Arial, Helvetica, sans-serif; 
}

Výsledkem této úpravy je flexibilní definice rozměru fontu. A právě na tento rozměr se odkazujeme pomocí relativních jednotek, díky kterým zapíšeme, o kolik bude velikost fontu větší/menší než je velikost nadřazeného HTML elementu.

Velikost 100% tedy odpovídá ve většině prohlížečů velikosti 16px. Někteří vývojáři však preferují zmenšení této velikostí na 62.5%. To totiž odpovídá velikosti textu o rozměru 10 pixelů, která je sice hodně malá pro běžné čtení, ale veškeré další výpočty pomocí relativních jednotek budou následně snazší. Velikost 1em = 10px, 0.8em = 8px, 1.6em = 16px apod. Známý internetový blog A List Apart však doporučuje v článku How to Size Text in CSS používání velikosti 100%, díky které dosáhneme více konzistentního výsledku.

Pokud převádíme velikost v pixelech na jejich ekvivalentní rozměr v em, musíme použít drobný výpočet. Vezmeme velikost v pixelech, kterou chceme převést a vydělíme ji velikostí nadřazeného HTML elementu. Výsledek je náš potřebný relativní rozměr, který můžeme umístit do našeho CSS souboru jako rozměr v em. Dostáváme jednoduchý vzorec:

cílový rozměr (px) ÷ kontext (px) = výsledek (em)

Toto je část definice CSS z předchozího příkladu:

.main-title { 
  font: normal 30px/36px Georgia, 'Times New CE', 'Times CE', 'Times New Roman', Times, serif; 
}

Pokud budeme chtít převést rozměr 30px do rozměru v em, musíme znát velikost nadřazeného HTML elementu. Víme, že máme font-size: 100% a také, že je to ekvivalentní velikosti 16px. Po dosazení do našeho vzorce dostáváme:

30 ÷ 16 = 1.875

30px je 1.875-krát větší než 16px, takže naše velikost fontu pro .main-title je 1.875em.

Další rozměr, který budeme přepisovat, je tento:

.main-title cite { 
     font-size: 42px; 
     line-height: 50px;
}

Pokud budeme chtít přepsat rozměr 42px do rozměru v em, musíme si uvědomit, že došlo ke změně nadřazeného HTML elementu. To by ještě tak nevadilo, jenže nadřazený element .main-title má jiný rozměr. Náš vzorec bude vypadat takto:

42 ÷ 30 = 1.4

42px je 1.4-krát větší než 30px, takže naše velikost fontu pro .main-title cite je 1.4em.

Stále však zůstává výska řádku definovaná v pixelech - 36px pro .main-title a 50px pro cite uvnitř .main_title. To ale znamená, že výška řádku se nebude měnit se zvětšující/zmenšující se velikostí fontu. I na přepočet těchto rozměrů můžeme použít stejný vzorec s jediným rozdílem, že velikost rodičovského HTML elementu bude nahrazena velikostí font-size, ke které se výška řádku vztahuje.

36 ÷ 30 = 1.2
50 ÷ 42 = 1.2

Prvky .main-titlecite mají vypočítanou velikost řádku 1.2em. A protože oba elementy sdílí stejnou velikost, můžeme ji nastavit jen jednou u nadřazeného HTML elementu a zbytek se podědí.

Sečteno a podtrženo. Když to vše přepíšeme do našeho CSS souboru, dostaneme následující zápis:

.main-title {
  font: normal 1.875em/1.2em Georgia, 'Times New CE', 'Times CE', 'Times New Roman', Times, serif;  /* 30 / 18 */
}

.main-title cite {
  font-size: 1.4em;  /* 42 / 30 */
}

Teď si určitě říkáte, že tento způsob zápisu je poměrně pracný. Proč ho tedy vůbec používat? Představte si, že máte na celém webu nadefinované rozměry pomocí pixelů. A najednou si Váš klient vzpomene, že by chtěl zvětšit velikost všech fontů. To, co musíte v této situaci udělat, je přepsat veškeré definice kaskádových stylů. U velikých projektů může být přepsání všech velikostí poměrně pracné. Pokud by však byla velikost fontů definovaná pomocí relativních jednotek, tak jediné co uděláme, je to, že zvýšíme font-size u elementu body v definici kaskádových stylů.

Jednotka rem

Jak jsem již zmínil, jednotka em je relativní vůči font-size nadřazeného HTML elementu. CSS3 přichází s novou jednotkou rem (root em). Ta je relativní vůči kořenovému HTML elementu - což je v našem případě element body. My tak můžeme definovat jednu základní velikost fontu pro celou webovou stránku a všechny rem jednotky budou odvozeny přímo z tohoto rozměru.

body {
  font: normal 100%/1.5rem 'Arial CE', 'Helvetica CE', Arial, Helvetica, sans-serif;
}

.main-title {
  font: normal 1.875rem Georgia, 'Times New CE', 'Times CE', 'Times New Roman', Times, serif; /* 30 / 16 */
}

.main-title cite {
  font-size: 2.625rem;  /* 42 / 16 */
}

.article-body {
  font-size: 1.125rem;  /* 18 / 16 */
}

.caps,
footer {
  font-size: 0.875rem;  /* 14 / 16 */
}

Stále se jedná o relativní určení velikosti fontu. Akorát náš vzorec se trochu změnil:

cílový rozměr (px) ÷ kořenový HTML element (px) = výsledek (rem)

Nemusíme tedy přemýšlet o tom, jak jsou jednotlivé HTML elementy do sebe zanořené. Do celé problematiky zápisu relativních rozměrů v CSS je najednou vnesen větší pořádek. Určitě si říkáte, jak je to skvělé! Bohužel podpora ve webových prohlížečích není až tak ideální, jak by si vývojáři představovali. Protože jednotka rem přišla až s nástupem CSS3, byla do hlavních prohlížečů implementována postupně. Podporovány jsou:

  • Firefox 3.6+
  • Chrome
  • Safari 5+
  • Internet Explorer 9+
  • Opera 11.60+

Nelze ji tedy ještě považovat za univerzální jednotku. Pokud však chceme podporovat i starší prohlížeče, je nutné deklarovat tzv. fallback v pixelech. Pokud prohlížeč nebude umět pracovat s jednotkou rem, použije se alternativní rozměr. Náš příklad by pak mohl vypadat takto:

body {
  font: normal 100%/1.5rem 'Arial CE', 'Helvetica CE', Arial, Helvetica, sans-serif;
}

.main-title {
  font: normal 30px Georgia, 'Times New CE', 'Times CE', 'Times New Roman', Times, serif;
  font-size: 1.875rem;  /* 30 / 16 */
} 

.main-title cite {
  font-size: 42px;
  font-size: 2.625rem;  /* 42 / 16 */
}

.article-body {
  font-size: 18px;
  font-size: 1.125rem;  /* 18 / 16 */
}

.caps,
footer {
  font-size: 14px;
  font-size: 0.875rem;  /* 14 / 16 */
}

Co tedy používat?

Absolutní i relativní jednotky mají své výhody i nevýhody. Definice rozměrů v pixelech nabízí značnou jednoduchost a přesnost při zápisu CSS. Tomuto řešení však chybí potřebná flexibilita. Relativní jednotka em sice tyto nedostatky odstraňuje, ale bohužel i v této malé ukázce bylo vidět, že je nutné při převodu vše „pracně“ přepočítávat.

Osobně si myslím, že používání jednotky rem je elegantním řešením, jak z této situace ven. Ale ještě nějaký čas potrvá, než budou staré prohlížeče vytlačeny ze středu zájmu vývojářů a budeme tak moci zahodit nutné fallbacky.

Zdroje a odkazy na podrobnější informace

Zařazeno v Vývoj

Jsem brněnský UI vývojář pěkného frontendu. Od malička si potrpím na detail, ale přitom kladu důraz na jednoduchost a přehlednost. Zastávám názor, že jednodušší weby jsou ty nejkrásnější.


8 komentáře

  1. Radomír Panna

    Vždycky jsem si myslel, stejně jako je to uvedeno v článku, že px je absolutní jednotka. Eric Meyer ji ovšem řadí mezi relativní jednotky. Ve své knize CSS kompletní průvodce vysvětluje proč (schválně jsem to vyhledal): na různých výstupech je pixel díky přepočtu zobrazován jinak. Pokud by to tak nebylo, písmo o velikosti 18px by na tiskárně s 600dpi bylo vysoké 0,03in

    1. Autor Martin Pešout

      Pokud by to bylo brané v tomto pojetí, tak by šlo podle mého názoru skutečně uvažovat o px jako o relativní jednotce.

      Chtěl bych se zeptat, zmiňuje Eric Mayer nějakou jednotku jako skutečně absolutní? Nebo jsou všechny z jeho pohledu považovány na relativní?

  2. Radomír Panna

    Absolutními jednotkami jsou in, cm, mm, pt, pc. Relativní pak em, ex, px.
    Jinak zmiňovanou knížku velmi doporučuju, myslel jsem si, že o css vím dost, ale při čtení… Je to taková moje „bible“. Je dostání za velmi příznivou cenu 99 kč na intervalu.

  3. Martin Bugner

    Ano, jednotka ‚px‘ sice patří mezi relativní, protože různá výstupní zařízení mohou mít různé rozměry pixelu, ale v rámci výstupního zařízení se chová absolutně. Takže je to s těmi pixely dost zamotané.

    Opravte si prosím nadpis kapitoly na „Relativní jednotky“. Máte tam ‚Realtivní…‘
    A taky mi nehraje ten poslední ukázkový kód u ‚rem‘, resp určení velikosti u tagu ‚body‘. Ať počítám jak počítám, tak 100% je 16px / 16px se rovná 1. Proč je tam uvedeno 1.5rem?

    1. Autor Martin Pešout

      Děkuji za připomínky.

      Co se týče té poslední ukázky, tak při výpočtu se vychází z této definice na začátku:

      font: normal 16px/24px ‚Arial CE‘, ‚Helvetica CE‘, Arial, Helvetica, sans-serif;

      Tento zkrácený zápis Vás asi může trochu zmást. Ale v podstatě je ekvivalentní této definici:

      font-size: 16px; line-heigh: 24px;

      Stejných rozměrů chceme dosáhnout při převodu do rem. 16px je ekvivalentní 100%. A pak už zbývá převést line-height: 24px do rem. A 24px je 1.5násobek 16px.

  4. Martin Bugner

    Děkuji za odpověď.
    Neuvědomil jsem si hned, že ve zkrácené formě font je za lomítkem line-height. Moc to nepoužívám, protože se v tom snadno chybuje 😉

  5. Kristian Feldsam

    pokial pouzivate lesscss tak pouzivat rem aj s fallbackom je tak jednoduche. Staci pouzivat tento mixin (pouzita je funkcia e() ako eval ktoru spracuje php lesscss kompilator. pokial chcete pouzivat JSkovy tak sa pozrite na zapis do dokumentacie)


    .font-size (@size) {
    @rem_size: @size / 16;
    font-size: e("@{size}px");
    font-size: e("@{rem_size}rem");
    }

    potom to uz iba zavolame


    h1 {
    .font-size(18);
    }

    1. Autor Martin Pešout

      Lesscss bych rád použil na dalším projektu u nás v igloonet. Díky za pěknou ukázku. Je vidět, že poté k napsání fallbacku nepotřebujeme dlouhé definice.


Napsat komentář

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