Tutorial

Piotr Petrus


Zaokrąglone rogi nadają opływowości elementom strony - w odróżnieniu od domyślnych ostrych krawędzi prostokątnych bloków. Pokażę większość sposobów osiągnięcia tego ergonomicznego efektu - ostatnio dość popularnego wśród projektantów internetowych - oraz wskażę najlepsze z nich.

Numer 16 (2/2006) • 31 maja 2006


Nicholas Di Genova : Minigaleria

Piotr Petrus. Zaokrąglone rogi.

Ilustracja: Nicholas Di Genova


Zaokrąglone rogi


W artykule założymy, że potrzeba nam bloku z wszystkimi czterema zaokrąglonymi wierzchołkami. Każde zaokrąglenie będzie równe i wynosiło 10 pikseli, aby ułatwić zrozumienie jak ta cała magia działa.

Najprostsze nie znaczy najlepsze.

Najbardziej trywialną metodą na zaokrąglenie krawędzi jest skorzystanie z właściwości CSS3 jaką jest border-radius. Wystarczy podać wartość, na przykład w pikselach, a przeglądarka zatroszczy się o pożądane krągłości.

Ale żylibyśmy w raju, gdyby mogło to być stosowane powszechnie. Na chwilę obecną żaden agent (agentem nazywamy dowolne urządzenie bądź program umożliwiający dostęp do strony) nie akceptuje tej własności. Jedynym substytutem jakiego można używać jest rozszerzenie CSS dla przeglądarek Mozilla -moz-border-radius.

Rozwiązanie to jednak nie jest nawet w Mozilli najlepsze - oprócz braku wygładzania, tło w postaci obrazka wychodzi poza zaokrąglone rogi oraz jednym akceptowanym stylem linii jest solid. Jeśli chcesz stworzyć coś dla siebie i Twoją ulubioną przeglądarką jest Mozilla - skorzystaj. Jeśli nie, czytaj dalej.

Obrazki tu, obrazki tam.

Zaokrąglenia można dość łatwo wyprodukować w programach graficznych a potem zapisać w postaci plików GIF czy PNG. Nawet najprostszy Paint w Windows ma narzędzie pozwalające uzyskać zaokrąglony prostokąt.

Na początek jednak parę rad ogólnych co do samej grafiki. W zależności od efektu, który chcesz osiągnąć, możesz potrzebować wygładzonych krawędzi rogów, bądź nie. Wygładzone zaokrąglanie jest możliwe tylko za pomocą przygotowanych plików graficznych i nie ma tu miejsca na wielką inwencję. Brak wygładzenia najlepiej sprawdza się w stonowanej kolorystyce bądź małym zakresie zaokrąglenia. Jest prostsze do osiągnięcia i można je wykonać na parę sposobów, o których będzie dalej mowa.

Kolejnym punktem rozważań teoretycznych jest format grafiki. Zalecam stosowanie GIF-ów nie dlatego, że są lepsze, ale dlatego że na pewno nie spowodują żadnych problemów w przeglądarkach. PNG jest wydajniejszy, w wersji ośmiobitowej nawet Internet Explorer 6 potrafi obsłużyć jego przezroczystość, ale wiele aplikacji zapisuje go z profilem gammy monitora, co oznacza że będzie wyglądał trochę inaczej na przykład we wspomnianym Explorerze. Jeśli jednak umiesz używać narzędzi takich jak na przykład pngcrush i potrzebujesz tylko 8bitowego koloru razem z przezroczystością - wybierz PNG.

Następnie wypada się zastanowić jak potraktować nasze obrazki. Zdeterminuje to sposób napisania strony. Bo obrazki możemy przedstawić jako tło elementu bądź wstawić je jako obiekt za pomocą znacznika img. Obydwa rozwiązania mają swoje plusy i minusy, którym przyjrzymy się w dalszej części artykułu.

Zaczynamy

Mamy już przygotowane cztery obrazki - należy także określić na czym będziemy pracowali, czyli co ulegnie zaokrągleniu. Wybrałem zwyczajny pojemnik div, z uwagi na jego uniwersalność. Z większości przypadków jednak będzie można użyć dowolnego blokowego (czyli upraszczając - prostokątnego) elementu, jak akapit p czy cytat blokowy blockquote, a nawet menu w postaci listy wypunktowanej ul. Nasz div zostanie także wypełniony przykładowym tekstem:

  1. <div>
  2. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse vulputate felis ut est. Vivamus congue. Nullam consequat. Etiam elit ipsum, pulvinar in, commodo sed, malesuada et, wisi. Maecenas nunc odio, interdum et, mollis eget, egestas quis, enim. Vestibulum augue leo, molestie ut, sollicitudin sit amet, ultricies eu, diam. Nam vel metus. Donec non ligula at augue dictum mollis. In tristique convallis erat. In pharetra, ligula vitae fringilla ultrices, turpis tellus scelerisque magna, vitae imperdiet nibh quam nec justo. Etiam diam purus, vestibulum id, placerat nec, varius et, augue. Maecenas vitae nulla et est iaculis scelerisque. Mauris tempus sagittis ligula. Nunc consectetuer sem vitae nisl. Praesent sit amet turpis. Sed rutrum blandit tellus. Suspendisse in enim. Ut vel mi.
  3. </div>

Oraz ustawmy od razu prosty CSS, aby przykład nie był kompletnie mdły:

  1. body {
  2. margin: 5%;
  3. font: normal 80% Verdana, Tahoma, sans-serif;
  4. background-color: #2C2C2C;
  5. color: #FFF;
  6. }
  7.  
  8. div {
  9. width: 400px;
  10. background-color: #67C1C7;
  11. }

Ustawiłem tutaj kolory oraz nadałem wymiary i odstępy, żeby przykład był bardziej przejrzysty. No, ale przejdźmy już do najważniejszego.

Stary dobry img

Załóżmy, że postępujemy najbardziej intuicyjnie - chcemy wstawić na stronę, do tego bloku div, cztery obrazki. Wykorzystajmy więc element img, aby je umieścić w kodzie HTML. Nie jest to rozwiązanie doskonałe, ale może być stosowane - o ile będziemy pamiętać o jednej, dość delikatnej sprawie. Mianowicie nie wolno nam wpisać nic w atrybut alt, ponieważ zakładamy, że obrazki te stanowią dekorację, a nie dane. Gdybyśmy wpisali tam, na przykład, „prawy górny róg” to w przeglądarkach tekstowych zobaczylibyśmy zbędny tekst dezorientujący czytelnika. Więc - atrybut alt ma być pusty.

Co dalej? Wyobraźmy sobie efekt naszych działań - zaokrąglony blok. Na górze dwa rogi po prawej i lewej, tak samo jak na dole. Więc jak pomyśleliśmy, tak zróbmy - obrazki top_l.gif oraz top_r.gif umieśćmy powyżej tekstu. Natomiast bot_l.gif oraz bot_r.gif poniżej.

  1. <div>
  2. <img src="top_l.gif" alt="" />
  3. <img src="top_r.gif" alt="" />
  4. Lorem ipsum dolor sit amet, (…) Nunc consectetuer sem vitae nisl. Praesent sit amet turpis. Sed rutrum blandit tellus. Suspendisse in enim. Ut vel mi.
  5. <img src="bot_l.gif" alt="" />
  6. <img src="bot_r.gif" alt="" />
  7. </div>

Efekt tego działania. Obrazki z uwagi, że są elementami liniowymi, czyli zachowują się jak tekst (tak, to prawda - mimo że są prostokątne, nie są elementami blokowymi), zostały umieszczone przed i za fragmentami łaciny. Nie jest to co chcemy osiągnąć. Więc umieśćmy obrazki w rogach dodając im klasy

  1. <div>
  2. <img class="topl" src="top_l.gif" alt="" />
  3. <img class="topr" src="top_r.gif" alt="" />
  4. Lorem ipsum dolor sit amet, (…) Nunc consectetuer sem vitae nisl. Praesent sit amet turpis. Sed rutrum blandit tellus. Suspendisse in enim. Ut vel mi.
  5. <img class="botl" src="bot_l.gif" alt="" />
  6. <img class="botr" src="bot_r.gif" alt="" />
  7. </div>

oraz korzystając z CSS nadajmy im float:

  1. img.topl, img.botl { float: left; }
  2. img.topr, img.botr { float: right; }

O ile góra bloku wygląda wyśmienicie, to dół jest ucięty (w przeglądarkach innych niż Internet Explorer). Dzieje się tak dlatego, że zmuszczając obazki do pływania (float) wyrzuciliśmy je z ciągu dokumentu. Wysokość bloku div jest określona tekstem w nim się znajdującym - jako że dolne obrazki zostały wyrwane z tekstu i umiejscowione na prawo i lewo, więc blok zmniejszył się w pionie, pozostawiając brzydką przerwę, z uwagi że nie ma tam już tła. Rozwiązanie jest dość proste. Należy zmusić blok div, aby zaczął „przejmować się” elementami które z niego wystąją za pomocą własności overflow. Ustawmy ją na auto.

  1. div {
  2. width: 400px;
  3. background-color: #EA2ECD;
  4. oveflow: auto;
  5. }

Efekt, a zarazem nasz upragniony cel, ilustruje przykład. Jeśli chcemy dodać dopełnienie, aby tekst nie sklejał się z krawędzami, musimy dołożyć kolejny element, na przykład akapit p - w innym przypadku utworzy się brzydki różowy odstęp - elementy pływające zostaną odgrodzone od prawdziwych krawędzi diva.

Na tym jednak nie koniec, bo wstawianie obrazków nie jest zgodne z duchem nowoczesności w której wygląd i dekoracje opisujemy CSS-em. Kończąc temat img w dokumencie można jeszcze zerknąć na przykład użycia pozycjonowania.

  1. div {
  2. width: 400px;
  3. background-color: #EA2ECD;
  4. position: relative;
  5. padding: 9px;
  6. }
  7.  
  8. img {
  9. position: absolute;
  10. }
  11.  
  12. img.topl, img.topr { top: 0; }
  13. img.botl, img.botr { bottom: 0; }
  14. img.topl, img.botl { left: 0; }
  15. img.topr, img.botr { right: 0; }

Stosując pozycjonowanie należy pamiętać, aby dodać dopełnienie blokowi, gdyż w odróżnieniu od float, elementy pozycjonowane nie są opływane przez tekst - przykrywają go. Jednak to tylko przykład, do powszechnego zastosowania nadają się inne metody, o których niżej.

Tło?

Pomyślmy sobie teraz co by się stało, gdyby na stronie wykorzystującej poprzedni przykład, było dwadzieścia bloków z zaokrąglonymi rogami i gdybyśmy chcieli zmienić nazwy plików. Albo wyrzucić zaokrąglenie z prawego dolnego rogu. Byłoby to męczące, zwłaszcza gdyby trzeba było zrobić to na całej stronie, a kolory bloków byłyby różne, przez co różne nazwy plików.

Czy nie prościej umieścić takie dekoracje w jednym pliku? Oczywiście, że prościej i od tego mamy CSS. Istnieje własność background-image, która pozwala na zdefiniowanie obrazka tła dla elementu. Zwykle obrazek taki jest powtarzany w pionie i poziomie, ale jest i na to wyjście. Wystarczy zmienić własność background-repeat na no-repeat i voila.

Lecz jest możliwe przyporządkowanie jednemu elementowi tylko jednego obrazka tła. Czyli potrzebujemy większej ilości znaczników w dokumencie, aby sobie poradzić.

  1. <div class="topl">
  2. <div class="topr">
  3. <div class="botl">
  4. <div class="botr">
  5. Lorem ipsum dolor sit amet, (…) Nunc consectetuer sem vitae nisl. Praesent sit amet turpis. Sed rutrum blandit tellus. Suspendisse in enim. Ut vel mi.
  6. <div>
  7. <div>
  8. <div>
  9. <div>

Wygląda to dość masywnie, ale cały czas próbujemy dojść do perfekcji. Co tutaj się stało? Umieściłem cztery divy w sobie nadając każdemu z nich klasę, która będzie potrzebna do napisania reguł CSS. Te same obrazki z przykładu wcześniejszego posłużą za tła, umiejscowione w rogach bloków. Dzięki temu, że tło trzech najwyżej położonych - topr, botl, botr będzie przezroczyste, oprócz tego jednego obrazka narożnika, obraz nałoży się i gotowe. CSS:

  1. div {
  2. color: #FFF;
  3. }
  4.  
  5. div.topl {
  6. width: 400px;
  7. background: #EA2ECD url(top_l.gif) left top no-repeat;
  8. }
  9.  
  10. div.topr { background: transparent url(top_r.gif) right top no-repeat; }
  11. div.botl { background: transparent url(bot_l.gif) left bottom no-repeat; }
  12. div.botr { background: transparent url(bot_r.gif) right bottom no-repeat; }

Tylko na pierwszy rzut oka jest to trudne. Większość już wytłumaczyliśmy sobie. Tutaj po prostu skorzystałem ze skróconego zapisu łączącego kolor tła (background-color), obrazek tła (background-image), pozycję obrazka tła (background-position) oraz jego powtarzania (background-repeat). Tylko pierwszy pojemnik div ma kolorowe tło (oraz określoną szerokość) i dzięki temu, że obrazek narożnika nie jest przezroczysty, nakłada się na różowy prostokąt w lewym górnym rogu. Kolejne bloki mają już przezroczyste tło, ale obrazki też się nakładają, tylko w innych pozycjach. W ten sposób powstał kolejny div z zaokrąglonymi rogami.

Co może przeszkadzać to stykanie się tekstu z pojemnikiem. Można to rozwiązać stosując dopełnienie - padding. A tak wygląda to w całości.

Mała sztuczka z przezroczystością

Przezroczysty róg

Jeśli musisz wygładzić parę bloków pod rząd różniących się kolorem tła oraz wiesz, że kolor tła pod nimi będzie jeden i ten sam - zastosuj uproszczenie. Możesz ułatwić sobie pracę z kolejnym blokami i stworzyć obrazek zakrywający wszystko poza rogiem. Obrazek ten to przezroczysty zaokrąglony róg z tłem w kolorze podkładu na stronie.

Wstawianie obrazków zakrywających część tła, aby nadać krągłości blokowi odbywa się w taki sam sposób jak opisano wyżej. A tutaj parę przykładów użycia.

Optymalizacja

Rzeczą o której musisz pamiętać, to czystość i objętość kodu. O ile efekt zaokrąglenia jest wart paru poświęceń, to nie może on stać się jednym wytłumaczeniem zrezygnowania z poszukiwania lepszej i wydajniejszej drogi rozwiązania problemu.

Dlatego warto zapytać się czy czasem powtarzający się blok na paru stronach nie ma określonej z góry szerokości w pikselach - wtedy można skorzystać z obrazka zaokrąglającego górny lewy i prawy róg. Dwa razy divów mniej. Być może w środku jest jakiś blokowy element - może warto go wykorzystać jako miejsce na umieszczenie tła.

Generowanie treści

Jeśli projektujesz głównie pod nowoczesne przeglądarki, i nie mam na myśli Internet Explorera, to zainteresuje Cię generowanie treści przez CSS. Otóż sztandarowe alternatywne przeglądarki jak Firefox, Opera i Mozilla umożliwiają korzystanie z pseudoelementów :after i :before, aby dodawać treść przed i po elemencie. Gdy wziąć pod uwagę, że treść taka może zostać zamieniona na blok oraz możemy jej zaaplikować obrazek tła - mamy następne optymalne rozwiązanie.

  1. <div class="top">
  2. <div class="bottom">
  3. Lorem ipsum dolor sit amet, (…) Nunc consectetuer sem vitae nisl. Praesent sit amet turpis. Sed rutrum blandit tellus. Suspendisse in enim. Ut vel mi.
  4. <div>
  5. <div>

Jesteśmy w stanie wygenerować element dla diva top oraz dla bottom. Po przekształceniach i dodaniu tła możemy uzyskać tytułowy efekt. Lecz najpierw podstawowe stylowanie:

  1. div.top {
  2. width: 400px;
  3. background: #EA2ECD url(top_r.gif) right top no-repeat;
  4. }
  5.  
  6. div.bottom {
  7. background: transparent url(bot_l.gif) left bottom no-repeat;
  8. }

Zrobiiśmy tutaj dość prostą rzecz, jeśli przyjrzeć się kodowi z przykładu wcześniej - dla pojemnika top nadaliśmy tło z prawej strony, a dla bottom z lewej. Dla top będziemy generować treść za pomocą :before, a dla bottom - :after. Przykład ilustrujący blok z dwoma zaokrąglonymi rogami.

  1. div.top:before {
  2. content: " ";
  3. display: block;
  4. height: 9px;
  5. background: transparent url(top_l.gif) left top no-repeat;
  6. }
  7.  
  8. div.bottom:after {
  9. content: " ";
  10. display: block;
  11. height: 9px;
  12. background: transparent url(bot_r.gif) right bottom no-repeat;
  13. }

Content określa co będzie zawartością nowego elementu - wybrałem spację, po prostu dlatego, że jej nie widać. Nadałem potem temu tekstowi zachowanie blokowe - display: block, przez co stał się jakby divem, określiłem wysokość oraz dodałem obrazek tła. Można jeszcze skrócić CSS, likwidując powtórzenia:

  1. div.top:before, div.bottom:after {
  2. content: " ";
  3. display: block;
  4. height: 9px;
  5. }
  6.  
  7. div.top:before { background: transparent url(top_l.gif) left top no-repeat; }
  8. div.bottom:after { background: transparent url(bot_r.gif) right bottom no-repeat; }

Wygląda tak jak tego oczekiwaliśmy. Jeśli przeszkadza nam odstęp który jest wynikiem obecności spacji w tworzonych elementach bądź chcemy dodać dopełnienie dla bloku, powinniśmy nadać float bądź wypozycjonować tworzone elementy, podobnie jak robiliśmy to wcześniej z obrazkami. Tylko czeka na nas kolejna przeszkoda. Bo o na przykład takie pozycjonowanie generowanej treści działa dobrze tylko w Operze - Firefox aktualnie nie potrafi przenieść tego dolnego elementu. Wybór rozwiązania (może dodatkowy div w środku dla dopełnienia?) zależy od Was.

Kod to poezja

Jak dotąd wszystkie przykłady opierały się na obrazkach, umieszczanych w sprytny sposób na rogach bloku. Obiecałem jednak, że da się to zrobić tylko kodem i nie mówię teraz o tym pokracznym rozwiązaniu z CSS3 tylko dla Firefoksa.

Gdy spojrzeć na obrazek zaokrąglenia, widać że są to poziome linie, którym zabieramy z lewej czy prawej strony piksele na kolor tła strony. Gdyby zapomnieć o pozycjonowaniu, pływaniu i umieszczaniu obrazków teł, a skupić się jeszcze raz na przykładzie generowania treści, to można dojść do wniosku, iż jest jeszcze jeden sposób na zaokrąglenie bloku. W tamtym przykładzie na początku różowego diva znajdował się inny blok długi na 100% szerokości.

A co powiecie na utworzenie jakichś prostych elementów HTML, dodania ich przed tekstem i takiego ostylowania, że tworzyłyby bloki o szerokości 100%, wysokie na jeden piksel i z marginesem z lewej i prawej, tak że po złożeniu paru takich elementów w pionie, powstaje zaokrąglenie z prawej i lewej? Ciekawe? No to dalej, do dzieła!

Zaokrąglenie to parę rzędów pikseli

We wszystkich przykładach używaliśmy zaokrąglenia na 10 pikseli, więc należy teraz utworzyć 9 elementów oraz nadać im klasy. Najlepiej jest skorzystać z elementów span, gdyż nie mówią one nic o znaczeniu kodu - są jakby przezroczyste dla przeglądarki.

Tak więc musimy dostawić 9 elementów u góry różowego bloku i na dole. Oglądając obrazek w powiększeniu widać, że część z „linii” jest takiej samej długości, więc można zastosować taką samą klasę do nich i lekko zwiększyć wysokość. Ogólnie będzie w naszym przypadku 6 klas. Góra pojemnika:

  1. <div>
  2. <span class="r1"></span><span class="r2"></span><span class="r3"></span>
  3. <span class="r4"></span><span class="r5"></span><span class="r6"></span>
  4. <p>Lorem ipsum dolor sit amet, (…) Nunc consectetuer sem vitae nisl. Praesent sit amet turpis. Sed rutrum blandit tellus. Suspendisse in enim. Ut vel mi.</p>
  5. </div>

A teraz CSS. Na początek ogólna reguła dla naszego różowiutkiego bloku i tekstu w środku.

  1. div {
  2. width: 400px;
  3. }
  4.  
  5. p {
  6. margin: 0;
  7. padding: 1em;
  8. background-color: #EA2ECD;
  9. }

Zauważmy, że w tym wypadku blokiem do którego dodajemy zaokrągenia jest akapit p. Następnie ostylujmy elementy span.

  1. span {
  2. display: block;
  3. overflow: hidden;
  4. height: 1px;
  5. background-color: #EA2ECD;
  6. }

Musimy zmienić element span w element blokowy oraz określić jego wysokość na 1 piksel. Dodałem także własność overflow: hidden, aby Internet Explorer ukrył wszystko co wyjdzie poza ten jeden piksel wysokości - gdyż on uważa, że mimo pustych elementów span, powinen zarezerwować miejsce na tekst.

  1. span.r1 { margin: 0 9px; }
  2. span.r2 { margin: 0 6px; }
  3. span.r3 { margin: 0 4px; }
  4. span.r4 { margin: 0 3px; }
  5. span.r5 { margin: 0 2px; height: 2px; }
  6. span.r6 { margin: 0 1px; height: 3px; }

Zastosowałem tutaj także skróconą notację - pierwsza wartość odpowiada za długość marginesu górnego i dolnego, a druga lewego i prawego. W przypadku .r5 i .r6 zwiększyłem także wysokość z 1 piksela do 2 i 3.

W ten sposób otrzymaliśmy górne zaokrąglenie. Teraz odwróćmy kolejność spanów i wstawmy je na dole:

  1. (…) tellus. Suspendisse in enim. Ut vel mi.</p>
  2. <span class="r6"></span><span class="r5"></span><span class="r4"></span>
  3. <span class="r3"></span><span class="r2"></span><span class="r1"></span>
  4. </div>

Efekt jest doskonały, wygląda dokładnie tak samo jak poprzednie przykłady - tylko że nie użyliśmy nawet jednego obrazka!

Jedynym mankamentem tego rozwiązania jest dodatkowy kod, który musimy wstawić do każdego bloku. Podobnie było w przypadku obrazków - w tamtym przykładzie był to minus. Tak jest też tu. Z pewnością jednak brak wykorzystania jakiegokolwiek obrazka zmniejsza ilość danych pobieranych z serwera. Można też zastanowić się czy nie da się ominąć mozolnego wklejania znaczników span.

JavaScript z odsieczą

Zakładając, że dodamy taką samą klasę do bloków, które mają być przekształcone, jesteśmy w stanie wstawić zaokrąglenia za pomocą JavaScriptu. Wróćmy zatem do początku.

  1. <div>
  2. <p class="rounded">Lorem ipsum dolor sit amet, (…) Nunc consectetuer sem vitae nisl. Praesent sit amet turpis. Sed rutrum blandit tellus. Suspendisse in enim. Ut vel mi.</p>
  3. </div>

Potrzebujemy paru funkcji niedostępnych od razu w JavaScript. Jedną z nich będzie funkcja pobierająca do tablicy wszystkie elementy o danej klasie. Wszystkie, ponieważ piszemy kod JavaScript dla strony na której jest więcej niż jeden element do zaokrąglenia. Utwórzmy zatem plik rounded.js.

Jako, że musimy wstawić przed i po elemencie kod HTML, będziemy potrzebować takich dwóch funkcji. O ile istnieje funkcja insertBefore(newElement, targetElement), wstawiająca nowy element przed elementem celowym, tak insertAfter(newElement, targetElement) musimy napisać.

Wygląda ona tak:

  1. function insertAfter(newElement, targetElement) {
  2. var parent = targetElement.parentNode;
  3. if (parent.lastChild == targetElement) {
  4. parent.appendChild(newElement);
  5. } else {
  6. parent.insertBefore(newElement, targetElement.nextSibling);
  7. }
  8. }

W pierwszej linijce widzimy, że do funkcji przekazane są dwa elementy - newElement to element który chcemy wstawić przed elementem określonym za pomocą zmiennej targetElement.

Druga linijka jest przyporządkowaniem do zmiennej parent elementu-rodzica elementu targetElement. Czyli patrząc na kod HTML dostaniemy element div (w którym siedzi p z klasą rounded).

W trzeciej linijce sprawdzamy czy element docelowy - akapit - jest ostatnim elementem rodzica - diva. Porównujemy więc własność lastChild rodzica z elementem do którego dodamy zaokrąglenia. Jeśli warunek jest prawdziwy, to wystarczy skorzystać z własności appendChild, aby dodać newElement - mówi o tym linijka 4.

Gdyby jednak tak nie było - element musi zostać umieszczony pomiędzy elementem docelowym i następnym elementem - kolejnym dzieckiem elementu-rodzica. Używamy do tego kodu w linijce 6. insertBefore wstawia nowy element przed swoim celem za pomocą własności nextSibling.

Funkcja pobierająca do tablicy wszystkie elementy o podanej klasie wygląda tak:

  1. document.getElementsByClassName = function(className) {
  2. var children = document.getElementsByTagName('*') || document.all;
  3. var elements = new Array();
  4.  
  5. for (var i = 0; i < children.length; i++) {
  6. var child = children[i];
  7. var classNames = child.className.split(' ');
  8. for (var j = 0; j < classNames.length; j++) {
  9. if (classNames[j] == className) {
  10. elements.push(child);
  11. break;
  12. }
  13. }
  14. }
  15. return elements;
  16. }

W tym przypadku nie będziemy się w nią bardzo zagłębiać. Starczy powiedzieć, że funkcja działa także na elementach posiadających wiele klas (class="klasa1 klasa2 klasa3"), rozbijając className (nazwę klasy) według spacji (split). Potem następuje pętla (for), w której sprawdzane są klasy elementu z klasą szukaną. Jeśli warunek się zgadza, element ten dorzucany jest na górę tablicy (elements.push).

Posiadamy już funkcje, ułatwiające późniejsze wyszukiwanie i wstawianie elementów. Teraz czas stworzyć zaokrąglenie górne i dolne. Napiszmy zatem funkcję roundBoxes():

  1. function roundBoxes() {
  2.  
  3. }

Pomiędzy nawiasami klamrowymi będziemy pisać kod. Na początek pobierzmy z dokumentu wszystkie elementy posiadające klasę rounded i wstawmy je do zmiennej blocks:

  1. var blocks = document.getElementsByClassName("rounded");

Nie wymaga to większego komentarza - używamy napisanej wcześniej funkcji getElementsByClassName(). Teraz należy użyć pętli, aby przeskoczyć wszystkie elementy w tablicy blocks i zaaplikować im zaokrąglenie.

  1. for (var i = 0; i < blocks.length; i++) {
  2. //(tutaj napiszemy kod)
  3. }

Pierwsza linijka to określenie ile razy pętla ma się wykonywać - dopóki licznik będzie mniejszy od ilości wszystkich elementów w tablicy blocks (blocks.length).

W JavaScript za utworzenie elementu odpowiada własność document.createElement("element"), gdzie element u nas będzie równy span. Jednak jak pamiętamy funkcje insertAfter() i insertBefore() operują na pojedynczych elementach. Musimy takto stworzyć dwa pojemniki i wrzucić w nie po sześć spanów. Stwórzmy zatem dwa divy - kontenery.

  1. var top = document.createElement("div");
  2. var bottom = document.createElement("div");

Teraz do każdego z nich wrzucamy sześć spanów z odpowiednimi klasami. Wykorzystajmy do tego celu pętlę:

  1. for (var j = 1; j < 7; j++) {
  2. var spant = document.createElement("span");
  3. var spanb = document.createElement("span");
  4. spant.className = "r" + j;
  5. top.appendChild(spant);
  6. spanb.className = "r" + (7 - j);
  7. bottom.appendChild(spanb);
  8. }

Wygląda to zawile, ale wcale takie nie jest. Pierwsza linijka to określenie, że będziemy poruszać się w pętli sześć razy. W następnych dwóch tworzymy znowu elementy - span dla krągłości górnych i dolnych. ;) Jako że poruszamy się w pętli, zostanie ogółem stworzonych po sześć spanów.

Następnie przyporządkowujemy klasę. Klasa spanów to "r" plus cyfra. Korzystając z licznika j (nie może być to znowu i) możemy stworzyć odpowiednie nazwy. W czwartej linijce nazwa klasy przy pierwszym wykonaniu pętli będzie równa "r1", przy piątym "r5". Następnie używając właściwości appendChild wrzucamy na koniec pojemnika górnego (top) nowo utworzony span.

Kolejne dwie linijki to ta sama czynność, tylko dla pojemnika dolnego. Musimy pamiętać, że spany na dole są dodawane w odwrotnej kolejności. Osiągamy to tworząc inaczej nazwę klasy - odejmujemy od siódemki licznik j dodajemy do "r". W pierwszym wykonaniu pętli nazwa klasy drugiego spana będzie się równała r6, w trzecim r4 i tak w dół do końca.

Wreszcie zakończmy pętlę dodając utworzone dopiero co elementy różowemu akapitowi:

  1. blocks[i].parentNode.insertBefore(top, blocks[i]);
  2. insertAfter(bottom, blocks[i]);

Korzystamy teraz z funkcji insertBefore i insertAfter. Pierwsza wymaga podania rodzica elementu przed którym chcemy coś wstawić - parentNode wystarczy.

Zapis blocks[i] odnosi się do elementu na pozycji i w tablicy blocks - przy trzecim wykonaniu pętli (jeśli mamy minimum tyle elementów do zaokrąglenia w dokumencie) będzie wskazywać na trzeci element w dokumencie o klasie rounded. W trzeciej linijce korzystamy z napisanej wcześniej funkcji insertAfter.

Kończymy w ten sposób funkcję zaokrąglającą, która ma teraz taką postać:

  1. function roundBoxes() {
  2. var blocks = document.getElementsByClassName("rounded");
  3.  
  4. for (var i = 0; i < blocks.length; i++) {
  5.  
  6. var top = document.createElement("div");
  7. var bottom = document.createElement("div");
  8.  
  9. for (var j = 1; j < 7; j++) {
  10. var spant = document.createElement("span");
  11. var spanb = document.createElement("span");
  12. spant.className = "r" + j;
  13. top.appendChild(spant);
  14. spanb.className = "r" + (7 - j);
  15. bottom.appendChild(spanb);
  16. }
  17.  
  18. blocks[i].parentNode.insertBefore(top, blocks[i]);
  19. insertAfter(bottom, blocks[i]);
  20.  
  21. }
  22. }

Wywołujemy ją na końcu przez dodanie do zdarzenia załadowania się dokumentu:

  1. window.onload = roundBoxes;

Gotowy plik rounded.js wstawiamy do dokumentu HTML w którym chcemy mieć zaokrąglone rogi w ten sposób:

  1. <script src="rounded.js" type="text/javascript"></script>

No i wreszcie upragniony przykład ilustrujący działanie kawałka kodu JavaScript, jaki wspólnie napisaliśmy. Po spojrzeniu w kod źródłowy nie zobaczymy żadnych zbędnych spanów - wszystko jest dodawane dynamicznie po załadowaniu się strony. Wygląd określony jest przez plik CSS w którym znajdują się dokładnie takie same reguły jak wypisałem wcześniej):

  1. <link rel="stylesheet" href="rounded.css" type="text/css" />

Idąc dalej

Podany przykład z kodem JavaScript działa całkiem nieźle, ale jest dość prosty. Nie możemy określić koloru zaokrąglenia, bo odpowiada za to plik CSS aplikujący wygląd do tworzonych elementów. Gdyby zaszła potrzeba szerszego wykorzystania JavaScriptu do tworzenia zaokrągleń, skorzystaj z darmowej biblioteki NiftyCorners. Wykorzystuje ona, tak samo jak nasz skrypt, kod HTML aby stworzyć zaokrąglenie i daje do dyspozycji określenie gdzie krągłości mają się pojawić. Pozwala także określić kolory zaokrąglenia. I wreszcie wykorzystuje selektory CSS w wywołaniu funkcji, aby nie trzeba było zaśmiecać kodu HTML dodatkowymi klasami (u nas rounded).

Podsumowanie

W artykule pokazałem sposoby zmierzenia się z zagadnieniem nowoczesnego designu - aplikowania ergonomicznych i ładnych zaokrągleń do zwykle tak surowych prostokątów na stronach WWW. Wykorzystałem obrazki, tła, później kod HTML przyprawiony JavaScriptem. Wspólnie nauczyliśmy się, żeby wybierać to rozwiązanie, które najlepiej służy osiągnięciu naszego indywidualnego celu. Uzyskaliśmy wymarzone zaokrąglenia, podążając drogą standardów sieciowych i czystego kodu. Poznaliśmy niedogodności przeglądarek, lecz zyskaliśmy nową wiedzę.

I nie powinniśmy nigdy przestać szukać jej więcej. Bo przykłady podane przeze mnie w artykule nie wyczerpują, tak ogromnego przecież, tematu projektowania stron internetowych.

Piotr Petrus


Przykłady przedstawione w artykule


O autorze

Piotr Petrus

Piotr Petrus

Jest projektantem stron internetowych i twórcą artykułów o standardach sieciowych. Freelancer, miłośnik muzyki, pisze także na swoim blogu na tematy pokrywające się z jego pasjami. Uwielbia grzebać do rana w rzeczach, które wszystkim wokoło wydają się stratą czasu - on to jednak kocha.