Autor: Paweł Rajewski

Co jakiś czas zgłaszane są na forum dyskusyjnym problemy związane z pozycjonowaniem elementów na stronie. To temat szeroki i dość delikatny, bo pozycjonowanie wymaga pewnej wprawy i praktyki.

Pozornie sprowadza się do podawania i odczytywania współrzędnych, ale te współrzędne często okazują się nie tym, czego oczekujemy…

Temat obejmuje trzy zagadnienia – pozycjonowanie obiektów (ich „ustawianie”), odczytywanie współrzędnych obiektów (pomiary) i odczytywanie współrzędnych kursora (kliknięcia itp.). Ponieważ uzyskiwane wyniki mogą różnić się w zależności od modelu przeglądarki (a nawet trybu pracy w przypadku Explorera 6), polecam dodatkowo artykuł „Internet Explorer a CSS”. Natomiast sprawy związane z odczytywaniem współrzędnych kliknięcia (kursora) poruszyłem w artykule „Ulotny obiekt event”.

Pozycjonowanie zwykłe

W jakim miejscu strony wyrysowany zostanie obiekt? W normalnych warunkach zależy to od konstrukcji i zawartości strony. Oto prosty przykład:

<HTML> 
<BODY> 
<H1> 
Ala <SPAN STYLE="color:#FF0000;">ma</SPAN> kota 
</H1> 
</BODY> 
</HTML> 

Obiekt SPAN (zawierający czerwony tekst „ma”) zostanie ustawiony w miejscu, które zależy od poprzedzających go elementów strony (w tym przypadku tekstu). To oczywiste, że gdyby litery tekstu były szersze, obiekt przesunąłby się bardziej w prawo. To jest pozycjonowanie zwykłe.

STYLE="position:relative; top:wartość; left:wartość;" 
obiekt.style.position='relative'; 
obiekt.style.top=sWartość; 
obiekt.style.left=sWartość; 

Pozycjonowanie względne (relative) pozwala przesunąć obiekt na określoną odległość względem miejsca, w którym znalazłby się normalnie. Przeglądarka wylicza „zwykłą” pozycję, a następnie koryguje ją o podane współrzędne. Zmień linię 4 poprzedniego przykładu:

Ala <SPAN STYLE="color:#FF0000; position:relative; top:10px; 
left:20px;">ma</SPAN> kota 

Czerwony tekst przesunął się o 10px w dół i 20px w prawo. Sposób pozycjonowania i odległości przesunięcia podane zostały jako właściwości CSS: position, top i left. Nazwy kierunków mogą być mylące, bo top odpowiada tu przesunięciu w dół, a left – w prawo. Aby uzyskać przesunięcie w przeciwnym kierunku należy użyć liczb ujemnych (można też używać określeń right i bottom, aby przesuwać obiekt w lewo i w górę, ale potrafią one płatać figle w starszych Explorerach, lepiej więc ograniczyć się do top i left).

top i left to nie liczby, lecz łańcuchy (string) zawierające także jednostkę – można więc używać różnych miar – px, cm czy pt. Nie należy podawać samych liczb, bez jednostki.

Istotną właściwością pozycjonowania relative jest to, że na stronie pozostaje przestrzeń po przesuniętym obiekcie. Działa więc ono tak, jakby obiekt został wrysowany w swoim naturalnym położeniu, a dopiero potem „wycięty” ze strony i przesunięty w nowe miejsce. Ten sposób pozycjonowania nie nadaje się więc do większych zmian w układzie strony, bo miejsca po „wyjętych” obiektach nie zostaną zapełnione przez obiekty następne (chyba, że je także przesuniemy sposobem relative, ale z kolei pozostaną miejsca po tych przesuniętych itd.). Jeśli natomiast chcemy dokonać drobnej korekty położenia obiektu nie wpływającej na położenie innych elementów, to position:relative jest metodą znakomitą.

Pozycjonowanie bezwzględne

STYLE="position:absolute; top:wartość; left:wartość;" 
obiekt.style.position='absolute'; 
obiekt.style.top=sWartość; 
obiekt.style.left=sWartość; 

Drugi rodzaj pozycjonowania to absolute – pozycjonowanie bezwzględne. Tutaj właściwości top i left określają wprost współrzędne górnego i lewego brzegu obiektu. Zmień linię 4 pierwszego przykładu na:

Ala <SPAN STYLE="color:#FF0000; position:absolute; top:10px; 
left:20px;">ma</SPAN> kota 

Czerwony tekst jest teraz przesunięty o 10px w dół i 20px w prawo względem lewego górnego rogu obszaru roboczego okna (względem czego tak naprawdę jest on ustawiony, napiszę w dalszej części artykułu!). Jak widać, zniknęło też miejsce zajmowane dotychczas przez czerwony tekst – został on wyjęty z normalnego układu strony, strona została wygenerowana bez niego, a wyjęty fragment został następnie umieszczony w wybranej lokalizacji. To ważna cecha pozycjonowania bezwzględnego, bo umożliwia tworzenie przeróżnych konstrukcji w rodzaju wyskakujących menu, które nie zabierają miejsca na stronie i nie wpływają na jej układ.

Podobnie jak w poprzednim przykładzie, top i left to łańcuchy zawierające także jednostkę.

Pozycjonowanie automatyczne

STYLE="position:absolute;" 
obiekt.style.position='absolute'; 

To pewna odmiana pozycjonowania bezwzględnego. Jeśli razem z zapisem position:absolute nie podamy właściwości top i left, miejsce wyświetlenia obiektu będzie wynikać z jego położenia w kodzie strony. Czyli przyjęte zostaną takie współrzędne, jakie miałby obiekt, gdyby był normalnie wyświetlony w danym miejscu. Zmień linię 4 pierwszego przykładu:

Ala <SPAN STYLE="color:#FF0000; 
position:absolute;">ma</SPAN> kota 

Czerwony tekst został wyjęty z normalnego układu strony, strona została wygenerowana bez niego, a następnie tekst został wyświetlony w miejscu, w którym byłby wyświetlony normalnie. Czasami taka „automatyzacja” może być przydatna do ustalania poziomego lub pionowego położenia obiektu (można podać tylko jedną współrzędną: top lub left, a druga zostanie przejęta z miejsca położenia obiektu w kodzie strony).

Przestrzeń współrzędnych

Dotychczas przyjmowaliśmy, że współrzędne top i left przy pozycjonowaniu bezwzględnym określają położenie obiektu względem obszaru roboczego okna (left:0px powodowało przecież dosunięcie obiektu do lewej krawędzi okna). W rzeczywistości są to współrzędne względem nadrzędnego obiektu zapewniającego tzw. przestrzeń współrzędnych. Czyli po prostu będącego obiektem odniesienia dla danego, pozycjonowanego elementu. Najczęściej jest to obiekt BODY, ale nie zawsze. W nowszych Explorerach może to być obiekt HTML (przeczytaj artykuł „Internet Explorer a CSS”).

Najistotniejsze jest jednak to, że każdy element posiadający pozycjonowanie relative lub absolute tworzy w swoim wnętrzu własną, lokalną przestrzeń współrzędnych. We wnętrzu takiego obiektu współrzędne top i left kalkulowane są względem tego obiektu, a nie względem obiektu BODY. To bardzo ważna cecha, bo pozwala zachować pozycjonowanie bezwzględne, a jednocześnie przesuwać obiekt wraz z innym fragmentem strony. Oto przykład:

 
<HTML> 
<BODY> 
<H1 STYLE="margin:100px;"> 
Ala ma kota<SPAN STYLE="color:#FF0000; position:absolute; top:-2px; 
left:-2px;">Ala ma kota</SPAN> 
</H1> 
</BODY> 
</HTML> 

No cóż, to po prostu dwa napisy – jeden odsunięty od brzegów okna o 100px (margines), drugi na samym brzegu okna (a nawet nieco poza). Zmień jednak trzecią linię powyższego przykładu na:

<H1 STYLE="margin:100px; position:relative;"> 

Co się wydarzyło? Powstał ładny napis z cieniem. Po dodaniu pozycjonowania relative dla znacznika H1 jego pozycja nie zmieniła się, bo nie zostały podane żadne wartości top ani left (co w tym przypadku jest równoznaczne z top:0px i left:0px). Tytuł H1 jest więc wyświetlany identycznie, ale w jego wnętrzu powstała lokalna przestrzeń współrzędnych. Obiekt SPAN (czerwony tekst) wyświetlany jest teraz z dwupikselowym przesunięciem względem obiektu H1 (zawierającego czarny tekst) co daje efekt cienia. Ponieważ współrzędne top i left liczone są względem H1, napis i cień będą przesuwały się razem – możesz dowolnie zmieniać położenie tytułu (np. zmieniając jego marginesy), zmieniać czcionkę, a napis zawsze będzie przesunięty o 2px w stosunku do cienia. W ten sposób można „zaczepiać” obiekty pozycjonowane bezwzględnie o inne elementy strony.

Pozycjonowanie w pionie

STYLE="z-index:iLiczba;" 
obiekt.style.zIndex=iLiczba; 

Poza ustalaniem pozycji w poziomie (prawo-lewo, góra-dół), możemy także ustawiać obiekty w pionie (nad lub pod innymi obiektami). Służy do tego współrzędna pionowa z-index.

Normalnie obiekty układane są w kolejności wynikającej z logicznej struktury strony – elementy nadrzędne położone są niżej, podrzędne – wyżej. W poprzednim przykładzie najniżej rysowany jest obiekt BODY, nad nim H1, a jeszcze wyżej – SPAN. Analogicznie, w przypadku tabelki najniżej znajdzie się tabelka „jako taka” (TABLE), wyżej TBODY, wyżej TR, wyżej TD, a jeszcze wyżej zawartość TD. Strona ma więc swoje góry i doliny – punkty „wyższe” i „niższe” i przypomina nieco miasto widziane pionowo z góry.

Sytuacja ta ulega zaburzeniu, gdy pojawiają się elementy o pozycjonowaniu relative lub absolute, czyli obiekty wyświetlane w innym miejscu strony niż wynika to z ich położenia w kodzie. Problem rozwiązano następująco:

— najpierw rysowane są wszystkie „normalne” elementy strony, a ich pionowa kolejność i przysłanianie się wynikają z układu i konstrukcji strony;
— powyżej rysowane są elementy o pozycjonowaniu relative i absolute. Ich pionowa kolejność odpowiada kolejności w kodzie strony (ostatni będzie najwyżej);
— na samym szczycie stosu rysowane są obiekty „okienkowe” (np. SELECT, a do IE5.5 także IFRAME).

Jak widać, nadanie elementowi specjalnego pozycjonowania automatycznie przenosi go niemal na sam wierzch „rysunku” strony. Jeśli trzeba dodatkowo zmienić kolejność tych obiektów – niektóre podnieść, a inne opuścić – można albo zamienić je miejscami w kodzie strony, albo skorzystać z właściwości CSS z-index (z-index dotyczy tylko elementów mających ustawiony atrybut position). Osobiście wolę ten pierwszy sposób, bo tak zbudowana strona jest logiczniejsza. Zaletą z-index jest natomiast możliwość manipulowania „głębokością” położenia obiektu przy pomocy skryptów.

Wartością z-index jest liczba całkowita (integer) odpowiadająca poziomowi, na jaki obiekt zostanie przesunięty: w dół (wartość ujemna) lub w górę (wartość dodatnia). Elementy nie posiadające ustawionego atrybutu z-index, oraz ustawiane automatycznie podczas generowania strony, zachowują się tak, jakby ich z-index wynosił 0 (zero). A zatem element o STYLE=”z-index:1;” znajdzie się ponad wszystkimi takimi elementami, a o z-index:-1; – pod nimi. Elementy mające taki sam z-index będą układane w kolejności wynikającej z kolejności w kodzie strony.

Użycie właściwości z-index wymaga pewnej wprawy – trzeba poeksperymentować. W pierwszej chwili wydaje się nielogiczne, że mimo, iż elementy układane w pionie automatycznie ewidentnie zajmują różne poziomy (zasłaniają się wzajemnie), to ich z-index jest taki sam i wynosi zero dla wszystkich. Jeśli mamy np. 3 DIV-y pozycjonowane bezwzględnie i umieszczone w kodzie jeden po drugim, to pierwszy będzie najniżej, a trzeci najwyżej. Jeżeli teraz nadamy pierwszemu z nich z-index:1; to nie przesunie się on o jedno „piętro” w górę, ale od razu na sam szczyt stosu – z parteru na dach (bo wszystkie pozostałe mają z-index:0. Do takiego zachowania trzeba się przyzwyczaić.

Inną konsekwencją tego stanu jest niemożność „wsunięcia” obiektu pomiędzy elementy nie mające ustawionego atrybutu position. Ponieważ z-index ich wszystkich wynosi zero, element pozycjonowany w sposób specjalny można ustawić jedynie pod lub ponad nimi wszystkimi.

Innego rodzaju problem powstaje gdy pozycjonowane w sposób specjalny elementy zagnieżdżamy jeden w drugim (jak w poprzednim przykładzie, gdzie SPAN o pozycjonowaniu bezwzględnym zagnieżdżony był w H1 o pozycjonowaniu względnym). W takiej sytuacji nadając z-index obiektowi „zewnętrznemu” przesuwamy go w górę lub w dół wraz z całą jego zawartością, a więc także i z obiektem „wewnętrznym”. W takiej sytuacji „zetindeksy” obiektów wewnętrznych określają pionową kolejność we wnętrzu takiego kontenera, ale cały kontener ma pozycję wskazaną przez z-index obiektu „zewnętrznego”. Wymaga to nieco skupienia, ale da się zrozumieć (to zachowanie analogiczne do lokalnej przestrzeni współrzędnych, tylko w pionie).

Jeśli wydaje Ci się, że pozycjonowanie w pionie jest skomplikowane, na „pocieszenie” powiem, że to dopiero przedsmak problemów, z jakimi będziemy mieli do czynienia przy pomiarach położenia obiektów – co przedstawię w drugiej części artykułu.

Na zakończenie prosty skrypt z wykorzystaniem omówionych właściwości. Oto kwadracik, który bardzo lubi kursor i zawsze chce być blisko niego. Wykorzystałem tu pozycjonowanie bezwzględne z właściwościami top, left i z-index.

<HTML> 
<HEAD> 
<META HTTP-EQUIV="Content-type" CONTENT="text/html; 
charset=iso-8859-2"> 
<SCRIPT TYPE="text/Jscript" LANGUAGE="JScript" DEFER> 
var iKX=0, iKY=0, iPX=0, iPY=0; 
var oPilkaS=idPilka.style; 
function fGon(){ 
iPX+=Math.round((iKX-iPX)/15); 
iPY+=Math.round((iKY-iPY)/15); 
oPilkaS.top=iPY-5+'px'; 
oPilkaS.left=iPX-5+'px'; 
}; 
timer1=setInterval('fGon()',100); 
</SCRIPT> 
</HEAD> 
<BODY SCROLL="no" onmousemove="iKX=event.clientX; 
iKY=event.clientY;" onclick="oPilkaS.zIndex*=-1;"> 
<DIV ID="idPilka" STYLE="width:10px; height:10px; 
font-size:1px; background:#FF0000; position:absolute; 
z-index:1;"></DIV> 
<H1>Czerwony kwadracik<BR>nie ma wpływu<BR>na inne elementy 
strony<BR>i porusza się niezależnie.<BR>Klikaj, aby przenosić 
go<BR>poniżej albo powyżej tekstu.</H1> 
</BODY> 
</HTML> 

cdn.

Paweł Rajewski