O webu
Jednotné odsazení v CSS

U rozsáhlejší webové stránky nebo aplikace je typicky na stránce několik bloků, mezi kterými je odsazení. Zajistit, aby jednotlivé mezery nebyly náhodné, ale měly nějaký řád, dá docela práci.

Problém je kvůli:

  1. Slučování CSS vlastnosti margin.
  2. Neprojevení se marginu, nemá-li rodič padding, border apod.

Příklad

Typicky je obsah stránky v nějakém obalu:

<div class="obal">
</div>

Běžný text se potom píše do odstavce:

<div class="obal">
  <p>Text</p>
  <p>Text</p>
</div>

Odstavce mají ve výchozích stylech horní a dolní margin. Hodnoty marginu mezi odstavci se potom slučují – rozestup se rovná vyššímu z odsazení. V případě stejného odsazení se vezme jen jedna hodnota.

Text

Text

Aby obsah nebyl nalepený na .obal, přidá se mu nějaký padding, stejný pro všechny strany:

Text

Text

To najednou způsobí, že se projeví horní a dolní odsazení marginem, který mají odstavce. Ve výsledku je tedy odsazení zdola a shora dvojnásobné oproti krajům.

Co teď s tím? Vynulovat horní a dolní padding obalu?

.obal {
  padding: 0 1em;
}

Potom se přece zase přestane margin vnořených odstavců nahoře a dole projevovat.

Text

Text

Oříznutí overflow: hidden

Docílit projevu marginu na okrajích jde třeba pomocí overflow: hidden. To je ale problematické v případě, že by bylo potřeba, aby něco z obalu vylézalo ven.

Text

Text

Rámeček a záporný margin

Odsazení se projeví i při použití rámečku. Jde tedy přidat tenký border v barvě okolí nahoru a dolu a následně jeho rozměry odečíst záporným marginem:

Text

Text

Tento postup ale spoléhá na to, že je pozadí za obalem jednobarevné. V případě použití průhledného rámečku by za ním bylo pozadí obalu – tedy by odsazení bylo visuálně větší o šířku rámečku.

První/poslední element

Mohlo by se nabízet řešení, kdy se prvnímu a poslednímu elementu zruší horní, respektive dolní marign. Se selektory :first-child/last-child to není problém:

.obal :first-child {margin-top: 0}
.obal :last-child {margin-bottom: 0}

Na první pohled to vypadá dobře:

Text

Text

Bohužel nastane problém v případě, že obsah s marginem nebude přímo v .obalu, ale bude v ještě nějakém jiném elementu:

Text

Text

Text odstavce v dalším obalu

Pouze horní/dolní margin

Pokud by byla šance, že se uhlídá, aby margin-top prvního elementu (:first-child) byl nulový, jde používat dále jen margin-top).

V klasickém případě, kdy se pod sebou sejde vrchní element se spodním odsazením a spodní element s horním – rozměr se stejně sloučí – mezera bude rovna vyššímu z marginů.

Text

Text

Další obal s marginem

Docela prosté řešení je použít vnořený element, který u obalu rozměr horního a spodního paddingu odečte záporným marginem:

Text

Text

Zobrazení jako tabulka

Margin vnitřních elementů se projeví i v případě, že bude .obal zobrazen jako tabulka – display: table:

Text

Text

Element jako odsazení

V případě, že odsazení od krajů u obalu bude větší než odsazení používané u jeho potomků, docela spolehlivé řešení je odsazení nahoře a dole uvnitř obalu vytvořit prázdnými elementy.

Nižší marginy potomků .obalu se sloučí s vyššími hodnotami odsazovacích elementů. Pro projevení odsazení se malinká část marginu odsazovacích elementů přidá do jejich paddingu:

Text

Text

Sežrání marginu

Protože není jisté, jaký spodní margin posledního elementu bude. Jde pomocí dalšího elementu vytvořit margino-žrouta – <div>, který má velký margin, aby spolehlivě stanovil hodnotu po sloučení. Tato známá hodnota může být potom odečtena záporným marginem na opačné straně.

Text

Text

Nepoužívat margin

Možné řešení je margin vůbec nepoužívat a rozestupy řešit všude paddingem.

Není potom nutné přemýšlet nad slučováním a neprojevením se marginu, ale počítat s tím, že se odsazení sčítá.

Živá ukázka

V řadě případů to ale znamená komplikovanější HTML kód – používat zvláštní obaly jen pro odsazení.

Závěr

Při psaní článku jsem zkoumal řadu webů, jestli jednotné odsazení nějak řeší. Zpravidla neřeší a odsazení jsou svým způsobem náhodná dle hesla „jak to vyjde“.

Zamysleli jste se někdy nad tímto problémem a oblíbili si nějaké řešení? Napište mi to, prosím.