Implementační chyby v prohlížečích – plovoucí prvky a obtékající text

30. června 2004

Chybný plovoucí model a třípixelové vyklenutí obtékajícího textu jsou dvě závažné implementační chyby plovoucích boxů ve všech aktuálních verzích Microsoft Internet Exploreru. Řešení tohoto problému, který se může mnohdy ukázat jako životně důležitý, si klade za cíl tento článek.

Představme si dva blokové prvky A a B, umístěné v rodičovském prvku X. Deklarujeme-li pro prvek A CSS vlastnost float na hodnotu left nebo right, necháváme tak vzniknout plovoucí box A. Podle specifikace by měl být tento plovoucí box A odsunut k levému nebo pravému okraji obsahu rodičovského boxu X a vyjmut z toku dokumentu. Box B by se tedy měl chovat zcela nezávisle na předchozím plovoucím boxu A. Pouze obsah boxu B (pokud B nemá deklarovanou vlastnost clear) by měl plovoucí box A obtékat.

Pokud u druhého prvku B nedeklarujeme šířku ani výšku (CSS vlastnosi width nebo height), potýkáme se s problémem „vyklenutého textu“. Pokud jednu nebo obě výše uvedené vlastnosti u prvku B nastavíme, projeví se pro změnu „chyba implementace plovoucího modelu“ v Microsoft Internet Exploreru.

V tomto článku vám představím dvě implementační chyby, které jsou vzájemně provázané. Snaha vyhnut se jedné je příčinou vzniku té druhé. Z důvodu snadnějšího pochopení si ovšem chování obou chyb popíšeme odděleně na několika příkladech. Ošetření chyb si necháme až na závěr článku, kdy se vrátíme k zmíněným příkladům.

Chyba plovoucího modelu

Příklad 1

Toto je základní podoba problému s chybou plovoucího modelu:

<html>
<head>
  <title>Float model 1</title>
  <style type=“text/css“>
    #aa {
      float: left;
      width: 40px;
      height: 40px;
      border: 5px solid black;
    }
    #bb {
      width : 200px; /* podmínka vzniku chyby */
      border: 2px solid gray;
      background-color: #dadada;
    }
  </style>
</head>
<body>
  <div id=“xx“>
    <div id=“aa“> </div>
    <div id=“bb“>
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
      Maecenas pharetra ultrices tellus. Maecenas rhoncus elementum sapien.
    </div>
  </div>
</body>
</html>

Podívejme se na správné vykreslení příkladu a vykreslení v Microsoft Internet Exploreru:

Správné vykreslení příkladu
Správné vykreslení příkladu

Vykreslení příkladu v MSIE
Vykreslení příkladu v MSIE

Jak vidíte, v příkladu nebyl z toku dokumentu vyjmut plovoucí box aa. Normálně řazený box bb se za plovoucí zařadil stejně, jako kdyby byl i on sám plovoucí. Bez zajímavosti není ani zcela nelogická mezera 3 px mezi plovoucím aa a normálně řazeným bb boxem.

Pozn. aut.: Chybných rozměrů plovoucího boxu aa si nevšímejte, jsou zapříčiněny chybným boxmodelem, který jsme se naučili řešit v článku Implementační chyby v prohlížečích – chybné rozměry boxů.

Příklad 2

Zkusme nyní u normálně řazeného prvku bb deklarovat velikost levého okraje 60 px (ke stylovém předpisu přidejme řádek #bb { margin-left: 60px; }). Microsoft Internet Explorer aplikuje vlastnost okraje správně od okraje obsahu rodičovského boxu xx, leč zcela nelogicky ji zvětšuje o 3 px:

Správné vykreslení příkladu
Správné vykreslení příkladu

Levý okraj zvětšený o 3 px v MSIE
Levý okraj zvětšený o 3 px v MSIE

Možná vás napadlo nedeklarovat u prvku bb šířku. Tím bychom se sice chybě vyhnuli, ovšem projevila by se chyba „vyklenutého textu“, kterou budeme řešit v druhé polovině článku.

MSIE 5 a 6 se liší!

První příklad (s vlastností width deklarovanou v px), by měl být v MSIE 5+ i 6 zobrazen shodně. Pokud deklarujeme rozměry v procentech, situace se komplikuje. MSIE 5+ a 6 v kompatibilním quirk režimu vypočítávají rozměry normálně řazeného boxu bb z šířky rodičovského boxu xx, zmenšené o celkovou šířku plovoucího boxu aa (včetně šířky okrajů, rámečku a výplně), což je špatný postup. MSIE6 ve standardním režimu již vypočítává rozměry normálně řazeného boxu bb správně z plné šířky obsahu rodičovského boxu xx.

Příklad 3

Vraťme se k příkladu 1. Na začátek dokumentu přidejme definici DTD <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"> a nastavme šířku normálně řazeného boxu bb na 50 % (ke stylovém předpisu přidejme řádek #bb {width:50%}).

Správné vykreslení příkladu
Správné vykreslení příkladu

Vykreslení příkladu v MSIE6 (standardní režim)
Vykreslení příkladu v MSIE6 (standardní režim)

Vykreslení příkladu v MSIE 5, 5.5 a 6 (kompatibilní režim)
Vykreslení příkladu v MSIE 5, 5.5 a 6 (kompatibilní režim)

Tímto příkladem jsme vyčerpali popis projevů chybné implementace plovoucího modelu v Microsoft Internet Exploreru. V dalších dvou příkladech si vysvětlíme problém vyklenutého textu a v poté už se budeme věnovat ošetření obou chyb.

Problém vyklenutí obtékajícího textu

Příklad 4

Toto je základní podoba problému s vyklenutím obtékajícího textu:

<html>
<head>
  <title>Float model 1</title>
  <style type=“text/css“>
    #xx { width: 200px; }
    #aa {
      float: left;
      width: 30px;
      height: 30px;
      background-color: gray;
    }
    #bb {
      font-size: 10px;
      font-family: Verdana, sans-serif;
      border: 1px solid black;
      background-color: #dadada;
    }
  </style>
</head>
<body>
  <div id=“xx“>
    <div id=“aa“> </div>
    <div id=“bb“>
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
      Maecenas pharetra ultrices tellus. Maecenas rhoncus elementum sapien.
    </div>
  </div>
</body>
</html>

Správné vykreslení příkladu Detail správného vykreslení
Správné vykreslení příkladu a náhled detailu

Chybné vykreslení v MSIE Detail chybného vykreslení v MSIE
Chybné vykreslení v MSIE a náhled detailu

Mezi plovoucím boxem aa a textem vznikla mezera, jako kdyby měl plovoucí box nastavený pravý okraj 3 px. Ve skutečnosti však mezera vzniká na levém okraji anonymních prvků jednotlivých řádků.

Přidejme k prvku xx levý okraj 3 px (#xx { margin-left: 30px; }). Výsledek:

Vykreslení upraveného příkladu v MSIE Detail vykreslení upraveného příkladu v MSIE
Vykreslení upraveného příkladu v MSIE a náhled detailu

Vzpomeňme na problematickou třípixelovou mezeru mezi plovoucím a normálně řazeným boxem u prvního příkladu. Zjevně spolu obě chyby souvisí, třípixelová mezera zde vzniká na obsahu normálně řazeného boxu bb (na rozdíl od prvního příkladu, kde vznikala vně normálně řazeného boxu bb).

Příklad 5 – obtékaný obrázek

Je zajímavé, jak se chování chyby změní, zachováme-li všechny konstrukce z předchozího příkladu až na blokový prvek aa, který nahradíme obrázkem či jiným generovaným řádkovým prvkem. Třípixelová mezera se pak přesouvá z obsahu normálně řazeného boxu bb na plovoucí box aa, přičemž ovlivňuje vykreslení po obou svých stranách (vlevo i vpravo).

<html>
<head>
  <title>Float model 1</title>
  <style type=“text/css“>
    #xx {
      width: 200px;
      border: 1px solid gray;
    }
    #aa {
      float: left;
      width: 32px;
      height: 32px;
      background-color: gray;
    }
    #bb {
      font-size: 10px;
      font-family: Verdana, sans-serif;
      border: 1px solid black;
      background-color: #dadada;
      margin-left: 32px;
    }
  </style>
</head>
<body>
  <div id=“xx“>
    <img src=“ie-ico.png“ id=“aa“ alt=“ikona“ />
    <div id=“bb“>
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
      Maecenas pharetra ultrices tellus. Maecenas rhoncus elementum sapien.
    </div>
  </div>
</body>
</html>

Správné vykreslení příkladu 3
Správné vykreslení příkladu 3

Vykreslení příkladu 3 v MSIE
Vykreslení příkladu 3 v MSIE

Řešení problémů

Nyní, když známe projevy obou implementačních chyb a vidíme jejich vzájemnou spojitost, můžeme přikročit k řešení všech výše uvedených příkladů tak, abychom předešli projevům obou chyb.

Řešení příkladu 1

U příkladu 1 stačí přesunout deklaraci šířky width: 200px z normálně řazeného boxu (bb) na rodičovský (xx). A pro vyloučení vzniku vyklenutého textu deklarujeme pro MSIE u plovoucího boxu pravý okraj -3 px, k čemuž využijeme známý CSS trik, kde deklaraci začínající podtržítkem MSIE normálně zpracuje, ač by ji měl ignorovat.

<html>
<head>
  <title>Float model 1</title>
  <style type=“text/css“>
    #xx { width: 200px; }
    #aa {
      float: left;
      width: 40px;
      _width: 50px; /* řešení boxmodelu */
      height: 40px;
      _height: 50px; /* řešení boxmodelu */
      border: 5px solid black;
      _margin-right: -3 px; /* eliminace vyklenutého textu */
    }
    #bb {
      /* width : 200px; není deklarována width ani height */
      border: 2px solid gray;
      background-color: #dadada;
    }
  </style>
</head>
<body>
  <div id=“xx“>
    <div id=“aa“> </div>
    <div id=“bb“>
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
      Maecenas pharetra ultrices tellus. Maecenas rhoncus elementum sapien.
    </div>
  </div>
</body>
</html>

Řešení příkladu 2

Řešení druhého příkladu spočívá v podstrčení o 3 px zmenšeného levého okraje Microsoft Internet Exploreru. Opět využijeme CSS triku s podtržítkem.

<html>
<head>
  <title>Float model 1</title>
  <style type=“text/css“>
    #aa {
      float: left;
      width: 40px;
      _width: 50px; /* pouze pro MSIE */
      height: 40px;
      _height: 50px; /* pouze pro MSIE */
      border: 5px solid black;
    }
    #bb {
      width : 200px;
      border: 2px solid gray;
      background-color: #dadada;
      margin-left: 60px;
      _margin-left: 57px; /* pouze pro MSIE o 3 px méně*/
    }
  </style>
</head>
<body>
  <div id=“xx“>
    <div id=“aa“> </div>
    <div id=“bb“>
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
      Maecenas pharetra ultrices tellus. Maecenas rhoncus elementum sapien.
    </div>
  </div>
</body>
</html>

Řešení příkladu 3

Řešení třetího příkladu tkví v přesunutí deklarace šířky width: 50%; z boxu bb do xx a použití záporného okraje plovoucího boxu aa.

<html>
<head>
  <title>Float model 1</title>
  <style type=“text/css“>
     #xx {width: 50%; }
    #aa {
      float: left;
      width: 40px;
      _width: 50px; /* pouze pro MSIE */
      height: 40px;
      _height: 50px; /* pouze pro MSIE */
      border: 5px solid black;
      _margin-right: -3 px; /* pouze pro MSIE */
    }
    #bb {
      /* width: 50%; */
      border: 2px solid gray;
      background-color: #dadada;
    }
  </style>
</head>
<body>
  <div id=“zz“>
    <div id=“aa“> </div>
    <div id=“bb“>
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
      Maecenas pharetra ultrices tellus. Maecenas rhoncus elementum sapien.
    </div>
  </div>
</body>
</html>

Řešení příkladu 4

Na řešení čtvrtého příkladu určitě přijdete i sami. Stačí jen podstrčit Microsoft Internet Exploreru již několikrát použitým CSS trikem záporný (-3 px) pravý okraj.

<html>
<head>
  <title>Float model 1</title>
  <style type=“text/css“>
    #xx { width: 200px; }
    #aa {
      float: left;
      width: 30px;
      height: 30px;
      background-color: gray;
      _margin-right: -3 px; /* pouze pro MSIE */
    }
    #bb {
      font-size: 10px;
      font-family: Verdana, sans-serif;
      border: 1px solid black;
      background-color: #dadada;
    }
  </style>
</head>
<body>
  <div id=“xx“>
    <div id=“aa“> </div>
    <div id=“bb“>
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
      Maecenas pharetra ultrices tellus. Maecenas rhoncus elementum sapien.
    </div>
  </div>
</body>
</html>

Řešení příkladu 5

Řešení pátého příkladu je analogické řešení příkladu 4. CSS trikem zajistíme, aby měl MSIE pro plovoucí obrázek levý i pravý okraj -3 px.

<html>
<head>
  <title>Float model 1</title>
  <style type=“text/css“>
    #xx {
      width: 200px;
      border: 1px solid gray;
    }
    #aa {
      float: left;
      width: 32px;
      height: 32px;
      background-color: gray;
      _margin-left: -3 px;
      _margin-right: -3 px;
    }
    #bb {
      font-size: 10px;
      font-family: Verdana, sans-serif;
      border: 1px solid black;
      background-color: #dadada;
      margin-left: 32px;
    }
  </style>
</head>
<body>
  <div id=“xx“>
    <img src=“ie-ico.png“ id=“aa“ alt=“ikona“ />
    <div id=“bb“>
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
      Maecenas pharetra ultrices tellus. Maecenas rhoncus elementum sapien.
    </div>
  </div>
</body>
</html>

Myslím, že implementační chyby popsané v tomto článku jsou nejvíce na obtíž ze všech implementačních chyb vůbec, neboť se prakticky neobejdete bez CSS triků. Často v praxi zapříčiňují paradoxní situaci, kdy se u určitých typů plovoucích dvou a třísloupcových layoutů nechává plovat obsah dokumentu a menu zůstává normálně řazené, pročež řešení klade hlavní důraz na fantazii kodéra (X)HTML.

Odkazy, zdroje

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

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

Š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 *