Start arrow Programowanie arrow Szablon arrow Paul O'Brien: 3-kolumny... Objaśnienie
Paul O'Brien: 3-kolumny... Objaśnienie Drukuj Wyślij znajomemu
Redaktor: Stefan Wajda   
01.08.2006.

W kolejnym odcinku zaadoptujemy do potrzeb Joomla! projekt płynnego 3-kolumnowego układu, z nagłówkiem i stopką oraz wyrównanymi do najdłuższej kolumnami zaprezentowany w opracowaniu Paula O’Briena Three Column Layout with Equalizing Header and Footer - objaśnienie technik projektowania 3-kolumnowych układów z nagłówkiem i stopką.

Poniżej zamieszczamy roboczą wersję tłumaczenia artykułu Paula O’Briena (gwoli lepszej czytelności dodaliśmy śródtytuły).

Wprowadzenie

To wstyd, że wiele osób, które chcą zastąpić rozmieszczanie elementów na stronach WWW w tabelach układem opartym na kaskadowych arkuszach stylów, najczęściej chce tworzyć kopię tabeli. Ja uniknąłem tego zupełnie. Używałem szablonów opartych na CSS, ponieważ stwarzają większe możliwości, niż dawniejsze oparte na tabelach.

Tak często jednak byłem pytany o 3-kolumnowe rozmieszczenie, że zdecydowałem się zebrać to, co wiem, i zastosować w praktyce, by przygotować satysfakcjonującą imitację układu 3-kolumnowego. Chociaż takie rozwiązanie ma kilka ograniczeń, to jednak dobrze się prezentuje w większości przeglądarek. Najpierw krótkie wprowadzenie objaśniające, co i w jaki sposób zostanie osiągnięte.

Streszczenie założeń

Najpierw krótkie streszczenie, co chcemy osiągnąć.

Zaprojektujemy 3-kolumnowy układ z wyrównywanymi kolumnami, w którym stopka znajduje się poniżej zawartości, gdy zawartość jest niewielka, albo na dole dokumentu, jeżeli zawartość jest większa niż wysokość ekranu. Każda kolumna może być dowolnie długa. Kolumny mają krawędzie, a kolory wypełniają zawsze całe kolumny.

Można by osiągnąć ten efekt, korzystając z procentowych określeń wysokości. Zastosowalibyśmy wówczas rozwiązanie: 10% dla nagłówka, 80% dla części głównej i 10% dla stopki. Zwykle jednak nie tego chcemy. Najczęściej chcemy niezmiennych wysokości nagłówka i stopki i zawartości automatycznie rozciągającej między nimi.

W CSS nie można zastosować wartości 90%+200px i określić wyniku jako 100%. Takie rozwiązanie nie zadziała. Trzeba więc ustawić pojemność strony na wysokość 100% i upewnić się, że cała zawartość mieści się w granicach tego pojemnika (poza stopką, o czym poniżej).

Dlaczego tworzymy kontener tylko dla kolumny centralnej, skoro chcemy trzech kolumn?

Cierpliwości, już wyjaśniam. Stworzymy kontener z marginesami po lewej i prawej stronie. W tych marginesach umiejscowimy kolumny. Aby jednak uzyskać efekt w postaci 100% wysokości, elementy pływające umieścimy na zewnątrz środkowej kolumny, używając ujemnych marginesów.

Zastosujemy Neat Trick - sztuczkę często używaną w innych okolicznościach. Tajemnica tkwi w tym, że umieszczając elementy pływające na zewnątrz kolumny centralnej, uzyskamy 100% wysokość dzięki temu, że będą one wydłużać środkową kolumnę, gdy ich zawartość będzie większa niż jej wysokość.

W tym momencie wiele osób porzuciłoby ten zamysł i próbowałoby nieco innego rozwiązania. Jeśli jednak nie poddasz się i wytrwasz, to zobaczysz, że elementy pływające - zachodząc tylko 1 pikselem na kolumnę środkową - będą wpływać na jej zachowanie, wymuszając jej wydłużenie tak, jak tego oczekujemy.

Wspaniale! Równocześnie, to, czego chcieliśmy, rozwiąże nam inny kłopot.

Problemów z zachodzeniem itd. można uniknąć przez zastosowanie position:relative, przemieszczając kolumny dokładnie do zamierzonej pozycji, to nie trudne. Pozycjonowanie względne przemieszcza element wizualnie, a nie fizycznie, tak że uzyskamy zamierzony efekt nakładania się warstw.

Ta technika nie tylko pozwala osiągnąć zakładany efekt, ale dodatkowo umożliwia ustawienie kontenerowi krawędzi na prawo i lewo od kolumny centralnej, co będzie dzielić stronę na trzy kolumny (nie będzie więc żadnej potrzeby umieszczania w elemencie pływającym stylu dla obramowania - border).

Widoczne są tam miejsca wstawienia clear:both za elementem pływającym, zobaczysz je w kodzie.

Kolor lewej i prawej kolumny jest faktycznie tym samym, co kolor tła całej strony(elementu body). Tym niemniej w prosty sposób możemy umieścić w tle powtarzający się na osi Y (czyli w pionie) obraz tej samej szerokości co element pływający, by uzyskać tło wypełniające dla trzeciej kolumny.

Dotychczas, mamy 3-kolumnowy układ z nagłówkiem, rozciągający się na dowolną szerokość okna przeglądarki. "Kiedy będzie znów o stopce?" - już słyszę ponownie to pytanie. Strona ma 100% wysokości i jeśli dodamy normalną stopkę poniżej, zobaczymy wypełniony ekran. Sposób polega na tym, że dodajemy kontenerowi ujemny margines dolny, podciągający go od dołu w górę i pozwalamy stopce wskoczyć do okna przeglądarki. Margines musi być wystarczająco duży, kompensować wysokość stopki. Te 2 wymiary muszą ze sobą współgrać. W moim przykładzie nie są one dokładnie takie same, ponieważ uwzględniłem wchłonięcie niektórych marginesów elementu.

Moglibyśmy już zakończyć naszą pracę, ale obawiam się, że przeglądarki mają dla nas inną niespodziankę w zapasie. Mimo że ustawiliśmy ujemny margines dolny dla kontenera, przeglądarki wciąż traktują kontener, jak by miał pełną wysokość i zawartość oraz powodują, że kontener znika pod stopką. Dlaczego?

To rzeczywiście cios, ale nie poddamy się. Wszystko czego potrzebujemy, to zastosowanie podobnej techniki, którą wykorzystaliśmy wcześniej z nagłówkiem. Umieszczamy pusty element czyszczący #clear_footer na dole naszego kontenera i dopasowujemy wysokość ujemnym marginesem (i właściwą wysokością stopki). Ten czyszczący element leży u dołu kontenera i zapobiega zanikaniu zawartości pod stopką. Teraz stopka wyraźnie siedzi na dole kontenera.

Technika umieszczenia stopki wymaga objaśnienia, przedstawionego poniżej:

Obszar dla stopki był problemem i zastosowanie #clear_footer jest działającym sposobem na jego rozwiązanie.

Kontener zewnętrzny - #outer - ma 100% wysokości, ale my zmniejszyliśmy dolny margines - #margin-bottom o 52px, umożliwiając stopce pozostawanie przy dolnej krawędzi ekranu. Jednak przeglądarki wciąż zdają się myśleć, że stopka jest poniżej dołu ekranu. W rezultacie zawartość wpływa pod stopkę o 40px, zanim zacznie się stopka. Ten efekt wydaje się być spowodowany zastosowaniem ujemnego marginesu.

Eksperymentowałem z marginesami i dopełnieniami, ale to tylko komplikowało i tak niełatwe zadanie. Najbardziej skuteczne i najprostsze okazało się zastosowanie pustego obszaru wielkości około 40px powyżej stopki. Zasadniczo stopka wyraźnie siedzi poniżej. 40px to wystarczająca wartość, aby zatrzymać zawartość prawej krawędzi stopki (domyślny margines elementów div dodaje resztę miejsca).

Żeby lepiej zrozumieć problem, skorzystaj z poniższego przykładowego kodu i wprowadź dostatecznie duży tekst wywołujący powiększone okno… Zobaczysz, że tekst wejdzie pod stopkę, a następnie będzie kontynuowany, do końca. To jest ten sam efekt, jaki uzyskuje się z pozycjonowaniem względnym, kiedy przeglądarka wciąż przyjmuje, że element jest w swym oryginalnym miejscu.

 
      <style type="text/css">
        .outer {width:100%;height:200px;background:red;margin-bottom:-50px}
        .footer {width:100%;height:50px;background:yellow}
      </style>
   </head>
   <body>
      <div class="outer">Wprowadź tutaj jak najdłuższy tekst:</div>
      <div class="footer">Stopka</div>
    </body>
</html>

Po eksperymentach z powyższym kodem, rozumiesz dokładnie, na czym polega problem i jak go pokonaliśmy. Dlatego poruszamy tę kwestię odrębnie, poza głównym wątkiem. Teraz, gdy znasz podstawę, możemy przeanalizować i objaśnić kod, w którym zastosowano powyższe rozwiązanie.

Style głównych elementów

Zaczynamy od stylów dla strony (body) i zewnetrznego kontenera - #outer.

html, body {height:100%;
   /* bądźmy mili dla Opery */
   padding:0;
    margin:0;
   }
   body {
   background:pink url(leftcolbg.jpg) repeat-y left top;
   color: #000000;
   }
   #outer{
   height:100%;
   min-height:100%;
   margin-left:130px;
   margin-right:130px;
   background:#F8E7EC;
   border-left:1px solid #000;
   border-right:1px solid #000;
   margin-bottom:-52px;
   color: #000000;
   }
   html > body #outer{height:auto;} /* dla Mozilli, w IE zawsze height = min-height */ 

Style dla elementy <body>

Chcemy mieć stronę o wysokości 100%, wypełniającą ekran w 100%. Uzyskamy to przez ustawienie wartości height na 100% dla elementów html i body. Dla IE wystarczy tylko body{height: 100%}, ale dla przeglądarek Mozilla trzeba również określić wysokość elementu html.

Skoro ustaliliśmy 100% wysokości dla strony, to inne elementy mogą wykorzystywać tę wysokość jako podstawę dla obliczeń. Dlatego teraz tworzymy blok nazywany #outer i ustawiamy jego wysokość również na 100%. To spowoduje, że element #outer będzie miał 100% z elementu html/body.

Wystarczyłoby to dla IE, ponieważ IE interpretuje wysokość (height) jako minimalną wysokość. Jeśli zawartość będzie większa, to spowoduje zwiększenie wysokości. Inne przeglądarki są jednak bardziej restrykcyjne w interpretacji i jeśli zawartość będzie większa niż kontener, to nastąpi przepełnienie - zawartość znajdzie się poza pojemnikiem. Stąd musimy dla pozostałych przeglądarek dodać odrębne reguły.

Zastosowaliśmy w tym celu parametr height-min: 100%, który IE ignoruje, ale inne przeglądarki rozumieją. Pojawia się tu jeszcze jedna przeszkoda do pokonania. Ustawienie height-min: 100% w takich przeglądarkach, jak Mozilla spowoduje, że będzie to nie tylko minimalna, ale i maksymalna wysokość. Aby naprawić ten błąd, użyjemy chwytu, nakazującego innym przeglądarkom dostosować wysokość automatycznie: height:auto i ukryjemy tę regułę przed IE. Idealny jest tutaj selektor potomka (>), którego IE nie interpretuje. Kod jest poniżej:

 
html > body #outer{height:auto;}

Ustawiamy w ten sposób wysokość na automatyczną (zwiększaną, gdy zwiększa się zawartość), a że wcześniej ustawiliśmy min-height: 100%, to zawsze uzyskamy pełne okno i jeśli zawartość będzie większa od okna, to kontener obejmie cały dokument.

Ustawiamy również dopełnienie (padding) i marginesy (margin) na 0, aby pozbyć się wszelkich dopełnień i marginesów w elemencie body i wszystkich elementach potomnych. Jest to konieczne, ponieważ kilka przeglądarek dodaje do krawędzi dopełnienie, kilka używa marginesów, tak że ustawiając te wartości na 0, wyrównujemy wszystko, jak na boisku sportowym. [Uwaga: ponieważ w niektórych wersjach Opery marginesy i odstępy między wierszami są definiowane w elemenciehtml, regułę tę przenieśliśmy do selektora html, body{}].

Dodajemy również do elementu body kolor tła, który będzie również kolorem tła kolumn. Inne kolory dla kolumn możemy uzyskać powtarzającym się obrazem tła (pamiętaj, aby zawsze pod obrazem tła ustawiać odpowiedni kolor - to dobra praktyka programowania).

   padding : 0;
   margin : 0;
   background : pink url(leftcolbg.jpg) repeat-y left top;
   color: #000000;

Style głównego kontenera

Teraz zajmijmy się głównym kontenerem - #outer..

Ten kontener ma ustawione 100% ze 100% elementu body, co już objaśniliśmy wcześniej. Musimy teraz zrobić miejsce dla lewej i prawej kolumny, pamiętając, że #outer ma być kolumną centralną. Oto kod:

margin-left:130px;
   margin-right:130px;
   border-left:1px solid #000;
   border-right:1px solid #000;

W ten sposób tworzymy przestrzeń dla kolumn i ustalamy wygląd ich krawędzi.

Oczywiście rozmiar może być zmieniony odpowiednio do Twoich potrzeb.Następnie tworzymy przestrzeń dla stopki, używając techniki ujemnego marginesu, wyjaśnialiśmy to już wcześniej:

 
margin-bottom:-52px;

Kolor tła ustawiony dla #outer będzie kolorem dla środkowej kolumny.

Pozostałe elementy

Skoro mamy już główne elementy zdefiniowane, to przystępujemy do pozostałej części strony.

Nagłówek

Najpierw przedstawmy kod nagłówka - bloku #header.

#header{
   background:#FF0000;
   border-top:1px solid #000;
   border-bottom:1px solid #000;
   color: #000;
   text-align:center;
   position:relative;
   margin:0 -131px;
   padding-top:56px;
   }
/* Ukryj przed Mac/IE  \*/
* html #header{height:56px;height:10px}  /* height wymusza układ w IE */
/* Koniec ukrywania dla Mac/IE */

Nagłówek #header jest umieszczany przeważnie na zewnątrz, a jego marginesy są rozciągane tak, aby w całości wypełnić ekran. Jest to podobna technika do przemieszczania kolumn przez zastosowanie ujemnych marginesów, ale w przypadku nagłówka musimy zapewnić po obu stronach odpowiednie miejsce [przeciągamy na całe dostępne miejsce]. IE znowu wymaga pomocnej ręki, by zmusić ją do rozmieszczenia na odpowiedniej wysokości… Wysokość będzie zawsze przez IE dostosowywana do zawartości.

Lewa i prawa kolumna

Następne: inteligentne rozwiązania - lewa i prawa kolumna:

#left { 
   position:relative;   /* dla IE, która nie zawsze pokazuje element pływający */
   width:130px;         /* taka sama jak lewy margines w #outer*/
   float:left;
   margin-left:-129px;  /* musi być o 1px mniej niż szer., by zepchnąć stopkę  */
   padding-top:72px;    /* tworzy miejsce na nagłówek */
   left:-2px;           /* ustawia kolumnę w je pozycję */
   }
#left p {padding-left:2px;padding-right:2px}
#right p {padding-left:2px;padding-right:2px}
 
#right {
   position:relative;   /* dla IE, która nie zawsze pokazuje element pływający */
   width:130px;/* taka sama jak prawy margines w #outer*/
   float:right;
   margin-right:-129px; /* musi być o 1px mniej niż szer., aby zepchnąć stopkę */
   padding-top:72px;    /* tworzy miejsce na nagłówek */
   left:2px;            /* ustawia kolumnę w je pozycję */
   }

Lewa kolumna jest pozycjonowanym względnie elementem pływającym (float:left;). Dodanie position:relative; jest konieczne, aby zapobiec błędowi IE, który czasem nie pokazuje elementów pływających (dodanie position:relative dla elementu pływającego i obrazów w IE może rozwiązać dziesiątki problemów związanych z niewidocznością obrazów). Pamiętaj o powiedzeniu: Jeśli coś się nie pokazuje w IE, spróbuj zastosować pozycjonowanie względne (albo wymuś tryb zgodnie z właściwościami umieszczonymi na liście serwisu msdn).

Dodajemy left:-2px, aby - jak wspominałem - zepchnąć kolumnę do wymaganej pozycji.

Element pływający ma szerokość 130px, tę samą, którą ustaliliśmy w #outer. Następnie przemieszczamy ten element w lewo o 129px. To powoduje, że zachodzi on 1 pikselem na kolumnę centralną i zapewnia poprawny układ, jak objaśnialiśmy wcześniej. Na końcu dodajemy 72px dopełnienia do góry elementu, aby zawartość nie znikała pod nagłówkiem - header.

Prawy element pływający jest ustawiony dokładnie tak samo z wyjątkiem parametru float, dla którego ustawiamy wyrównanie do prawej (float: right).

Zwróć uwagę na dwa inne użyte tutaj style (#left p i #right p - dodają one dopełnienie elementowi p (akapitowi) i zapobiegają skutkom innego traktowania elementów blokowych przez IE5/5.5.

Zmieniając rozmiar kolumn, musisz pamiętać o trzech rzeczach:

  1. Ustaw takie marginesy w #outer, jaką szerokość mają mieć pływające kolumny.
  2. Umieść elementy pływające (kolumny) w obszarze marginesów za pomocą float.
  3. Ustaw ujemne marginesy o jeden piksel mniejsze niż szerokości elementów pływających.

To wszystko, co jest niezbędne - nie można tego zrobić prościej jak przypuszczam

Stopka - #footer

Co ze stopką - #footer:

 
#footer {
   width:100%;
   clear:both;
   height:50px;
   border-top:1px solid #000;
   border-bottom:1px solid #000;
   background-color: #FF8080;
   color: #000000;
   text-align:center;
   position:relative;
   }
* html #footer {/* modyfikacje tylko dla IE */
   height:52px;/* dla ie5 */
   height:50px;/* dla ie6 */
   }

Powyższe style dla #footer są po prostu przednie. Nie ma tu niczego, czego nie widziałeś wcześniej (pamiętaj clear:both będzie oczyszczać miejsce dla stopki, jeśli zawartość kolumn z zawartością - lewej, centralnej i prawej - będzie większa).

Co może być nowym tutaj dla Ciebie? Zastosowany tu został selektor uniwersalny * html, którego użyłem już wcześniej. To preferowana przeze mnie metoda rozwiązywania problemu interpretacji modelu blokowego przez IE5/5.5. Selektor dowolnego elementu - gwiazdkę * - można wykorzystać w definicji stylu do zastąpienia dowolnego elementu. Jeśli zostanie umieszczony przed selektorem elementu html, to teoretycznie będzie się odnosił do elementu nadrzędnego wobec html. A według standardu element html stoi najwyżej w hierarchii dokumentu i wszystkie przeglądarki, oprócz IE, omijają taką definicję. Korzystając z chwytu zwanego Star Hack, można zdefiniować kod specjalnie dla przeglądarek IE i ukryć go przed pozostałymi przeglądarkami.

Kolejna sztuczka wykorzystuje znak odwróconego w lewo ukośnika (backslash). Jeśli w nazwie właściwości pojawia się ten znak przed dowolną literą (poza a, b, c, d, e, f), to dana własność zostanie pominięta przez IE 5.x, a poprawnie zostanie zinterpretowana przez IE 6.0. Sztuczka umożliwia zdefiniowanie odmiennych wartości dla IE 5/5.5 oraz dla IE 6.0, a w rezultacie rozwiązanie problemu interpretacji modelu blokowego. Dla IE 5/5.5 ustalamy szerokość i wysokość powiększone o wielkość dopełnienia i grubość ramki.(Więcej na temat selektora gwiazdki i SBMH (Simplified Box Model Hack - uproszczony Box Model Hack) przeczytaj w Kruczki i sztuczki.

Kończymy rozciąganie

 
#clearfooter{clear:both;height:40px;}/*niezbędne, tworzy miejsce dla stopki */
div,p {margin-top:0} /* usuwa górny margines w Mozilli*/
 
* html #centrecontent {height:1%;margin-bottom:12px}/* w IE równoważy 3-pikselową lukę */

Ostatni styl korzysta z selektora gwiazdki (*), aby rozwiązać problem przemieszczania elementów pływających w IE o 3 piksele. To bardzo użyteczny chwyt. Element pływający jest automatycznie rozpychany przez zawartość. Deklarujemy powyżej zwiększenie wysokości o 1% tylko dla IE dzięki selektorowi gwiazdki. Przypomnij sobie, że IE traktuje height jako height-min i rozszerza element automatycznie, jeśli jego zawartość jest większa. Nie ma to więc wpływu na nasz element pływający. W tym miejscu dodajemy do wysokości i szerokości 3 piksele. A ponieważ nie jesteśmy w stanie ustalić szerokości, gdyż naszą szerokość wyznaczają marginesy, dlatego używamy tej samej metody co dla wysokości.

Dodajemy również ujemny margines wewnątrz obu elementów pływających, aby zrekompensować ponownie do 3 pikseli dla poprawności.

Teraz już masz 3-kolumnowy, elastyczny układ, oparty na CSS, z rozwiązaniami różnych problemów. Co jeszcze mogę dla Ciebie zrobić?

Poniżej jest szkic kodu HTML:

<body>
   <div id="outer">
   <div id="header"> <p>Nagłówek - Długa środkowa kolumna
    - stopka u dołu dokumentu.</p></div>
   <div id="left"><p>Tu treść lewej kolumny : </p></div>
   <div id="right"><p>Tu treść prawej kolumny: </p></div>
   <div id="centrecontent"><p>Tu treść środkowej kolumnu</p></div>
   <div id="clearfooter"></div><!-- oczyszczenie dla stopki --> 
   </div><!-- koniec elemenu #outer -->
   <div id="footer"> - Stopka -</div>
   </body>

Wygląda przejrzyście, prawda?

Powyższe techniki dobrze się sprawdzają w układach ze 100% szerokością i wysokością, jeśli używasz obrazka tła dzielącego na trzy kolumny. Zaznaczam, że ten układ nie działa dobrze w IE5 dla MAC, ale jeśli nie zapomnisz o trybie quirks, możesz osiągnąć satysfakcjonującą wersję, która będzie dobrze działać w ie5 mac oraz (ie5 mac oraz (2 column version).

Myślę, że to objaśnienie będzie dla Ciebie wystarczające, ale jeśli masz jakieś pytania, skontaktuj się ze mną na Ten adres email jest ukrywany przed spamerami, włącz obsługę JavaScript w przeglądarce, by go zobaczyć

Inne rozwiązania

Tutaj jest kilka innych rozwiązań (nieprzetestowanych dokładnie).


Uwagi, źródła

Jeżeli masz sugestie odnośnie treści lub chcesz zgłosić poprawki do tego rozdziału, skomentuj go albo umieść wiadomość na forum: Dokumentacja - Propozycje, zmiany, poprawki

Dziękujemy!

Stefan Wajda, Zespół Dokumentacji PCJ

Zmieniony ( 27.05.2009. )
 
« poprzedni artykuł