Pierwsze kroki z kształtami CSS

Zawijanie treści wokół ścieżek niestandardowych

Razvan Caliman
Razvan Caliman

Przez długi czas projektanci stron internetowych musieli tworzyć w ramach ograniczeń prostokąta. Większość treści w internecie jest nadal zamknięta w prostych ramach, ponieważ większość prób tworzenia układów nieprostokątnych kończy się frustracją. Wprowadziliśmy kształty CSS, które są dostępne od wersji Chrome 37. Kształty CSS umożliwiają projektantom stron internetowych owinięcie treści wokół niestandardowych ścieżek, takich jak koła, elipsy i wielokąty, dzięki czemu mogą oni tworzyć projekty bez ograniczeń związanych z prostokątem.

Kształty można definiować ręcznie lub wyodrębniać z obrazów.

Przyjrzyjmy się bardzo prostemu przykładowi.

Być może jesteś tak naiwny jak ja, gdy po raz pierwszy umieszczasz pływający obraz z przezroczystymi częściami, oczekując, że zawartość zostanie owinięta i wypełni luki, a zamiast tego widzisz prostokątny kształt otaczający element. Aby rozwiązać ten problem, możesz użyć kształtów CSS.

Wyodrębnianie kształtu z obrazu
<img class="element" src="image.png" />
<p>Lorem ipsum…</p>

<style>
.element{
  shape-outside: url(image.png);
  shape-image-threshold: 0.5;
  float: left;
}
</style>

Deklaracja CSS shape-outside: url(image.png) informuje przeglądarkę, aby wyodrębniła kształt z obrazu.

Właściwość shape-image-threshold określa minimalny poziom nieprzezroczystości pikseli, które zostaną użyte do utworzenia kształtu. Wartość musi mieścić się w zakresie od 0.0 (przezroczystość 100%) do 1.0 (przezroczystość 0%). Oznacza to, że shape-image-threshold: 0.5 oznacza, że do utworzenia kształtu zostaną użyte tylko piksele o przezroczystości co najmniej 50%.

Kluczowa jest tutaj właściwość float. Właściwość shape-outside definiuje kształt obszaru, wokół którego ma być zawijana treść. Bez wartości zmiennej typu float nie zobaczysz efektów kształtu.

Elementy mają obszar pływający po przeciwnej stronie wartości float. Jeśli na przykład element z obrazem filiżanki kawy jest przesunięty w lewo, po prawej stronie filiżanki zostanie utworzona obszar pływający. Chociaż możesz utworzyć obraz z lukami po obu stronach, treści zostaną zawinięte tylko po stronie przeciwnej, określonej przez właściwość float, w lewo lub w prawo, ale nigdy po obu stronach.

W przyszłości będzie można używać shape-outside w elementach, które nie są wycentrowane za pomocą CSS Exclusions.

Tworzenie kształtów ręcznie

Oprócz wyodrębniania kształtów z obrazów możesz też kodować je ręcznie. Do tworzenia kształtów możesz wybrać jedną z kilku wartości funkcyjnych: circle(), ellipse(), inset() i polygon(). Każda funkcja kształtu przyjmuje zestaw współrzędnych i jest połączona z polem odniesienia, które określa układ współrzędnych. Więcej informacji o polach referencyjnych znajdziesz za chwilę.

Funkcja circle()

Ilustracja wartości kształtu circle()

Pełna notacja wartości kształtu koła to circle(r at cx cy), gdzie r to promień koła, a cxcy to współrzędne środka koła na osi X i Y. Współrzędne środka okręgu są opcjonalne. Jeśli je pominiesz, domyślnie zostanie użyty środek elementu (punkt przecięcia jego przekątnych).

.element{
  shape-outside: circle(50%);
  width: 300px;
  height: 300px;
  float: left;
}

W przypadku przykładu powyżej treści będą się kończyć na zewnątrz ścieżki okrężnej. Pojedynczy argument 50% określa promień okręgu, który w tym konkretnym przypadku jest równy połowie szerokości lub wysokości elementu. Zmiana wymiarów elementu będzie miała wpływ na promień koła. Oto podstawowy przykład, jak kształty CSS mogą być responsywne.

Zanim przejdziemy dalej, warto pamiętać, że kształty CSS wpływają tylko na kształt obszaru pływającego wokół elementu. Jeśli element ma tło, nie zostanie ono przycięte przez kształt. Aby uzyskać taki efekt, musisz użyć właściwości z maskowania CSSclip-path lub mask-image. Właściwość clip-path jest bardzo przydatna, ponieważ stosuje tę samą notację co kształty CSS, dzięki czemu możesz ponownie używać wartości.

Ilustracja przedstawiająca kształt „circle()” i ścieżkę obcinania

Ilustracje w tym dokumencie wykorzystują wycinki, aby wyróżnić kształt i ułatwić zrozumienie efektów.

Powrót do koła.

Gdy do określenia promienia koła używasz wartości procentowych, wartość jest obliczana za pomocą nieco bardziej złożonej formuły: sqrt(width^2 + height^2) / sqrt(2). Warto to wiedzieć, ponieważ pomoże Ci to wyobrazić sobie kształt koła, który powstanie, jeśli wymiary elementu nie są równe.

W współrzędnych funkcji kształtu można używać wszystkich typów jednostek CSS: px, em, rem, vw, vh itd. Możesz wybrać taki, który jest elastyczny lub wystarczająco sztywny, aby spełniał Twoje potrzeby.

Pozycję koła możesz dostosować, ustawiając dokładne wartości współrzędnych jego środka.

.element{
  shape-outside: circle(50% at 0 0);
}

Umożliwia to umieszczenie środka koła w początku układu współrzędnych. Co to jest układ współrzędnych? Tutaj przedstawiamy pola informacyjne.

Pola referencyjne dla kształtów usługi porównywania cen

Pole odniesienia to wirtualne pole wokół elementu, które określa układ współrzędnych używany do rysowania i umieszczania kształtu. Początek układu współrzędnych znajduje się w lewym górnym rogu, a oś X jest skierowana w prawo, a oś Y w dół.

System współrzędnych dla kształtów w usłudze porównywania cen

Pamiętaj, że shape-outside zmienia kształt obszaru pływającego, wokół którego będzie owijane zawartość. Obszar pływający rozciąga się do zewnętrznych krawędzi pola zdefiniowanego przez właściwość margin. Nazywamy to margin-box i jest to domyślne pole odniesienia dla kształtu, jeśli nie ma żadnego wyraźnego odwołania.

Te 2 deklaracje CSS dają identyczne wyniki:

.element{
  shape-outside: circle(50% at 0 0);
  /* identical to: */
  shape-outside: circle(50% at 0 0) margin-box;
}

Nie ustawiliśmy jeszcze marginesu tego elementu. W tym momencie można założyć, że początek układu współrzędnych i środek okręgu znajdują się w lewym górnym rogu obszaru treści elementu. Gdy ustawisz margines, zmieni się:

.element{
  shape-outside: circle(50% at 0 0) margin-box;
  margin: 100px;
}

Początek układu współrzędnych znajduje się teraz poza obszarem treści elementu (100 pikseli w górę i 100 pikseli w lewo), podobnie jak środek koła. Obliczona wartość promienia koła również rośnie, aby uwzględnić zwiększoną powierzchnię układu współrzędnych określonego przez pole odniesienia margin-box.

System współrzędnych margin-box z marginesem i bez niego
Do wyboru jest kilka opcji pudełka referencyjnego: „margin-box”, „border-box”, „padding-box” i „content-box”. Ich nazwy wskazują ich granice. Już wcześniej wyjaśniliśmy, czym jest pole margin-box. Pole border-box jest ograniczone przez zewnętrzne krawędzie obramowania elementu, pole padding-box jest ograniczone przez wypełnienie elementu, a pole content-box jest identyczne z rzeczywistą powierzchnią używaną przez zawartość w elemencie.
Ilustracja wszystkich pól referencyjnych

W danym momencie można użyć tylko 1 pola odniesienia w ramach deklaracji shape-outside. Każde pole odniesienia wpływa na kształt w różny, czasem subtelny sposób. Istnieje też inny artykuł, który zawiera więcej informacji i pomaga zrozumieć pola referencyjne w przypadku kształtów CSS.

Funkcja Ellipse()

Ilustracja funkcji ellipse()

Elipsy wyglądają jak spłaszczone koła. Są one zdefiniowane jako ellipse(rx ry at cx cy), gdzie rxry to promienie elipsy na osi X i Y, a cxcy to współrzędne środka elipsy.

.element{
  shape-outside: ellipse(150px 300px at 50% 50%);
  width: 300px;
  height: 600px;
}

Wartości procentowe będą obliczane na podstawie wymiarów układu współrzędnych. Nie trzeba tu stosować skomplikowanych obliczeń. Możesz pominąć współrzędne środka elipsy, a będą one wywnioskowane na podstawie środka układu współrzędnych.

Promień osi X i Y można też zdefiniować za pomocą słów kluczowych: farthest-side zwraca promień równy odległości między środkiem elipsy a najdalszym od niego bokiem pola odniesienia, a closest-side oznacza dokładnie odwrotną operację – używa najkrótszej odległości między środkiem a bokiem.

.element{
  shape-outside: ellipse(closest-side farthest-side at 50% 50%);
  /* identical to: */
  shape-outside: ellipse(150px 300px at 50% 50%);
  width: 300px;
  height: 600px;
}

Może to być przydatne, gdy wymiary elementu (lub pole odniesienia) mogą się zmieniać w nieprzewidywalny sposób, ale chcesz, aby kształt elipsy się dostosowywał.

Tych samych słów kluczowych farthest-sideclosest-side można też używać do określenia promienia w funkcji kształtu circle().

Funkcja polygon()

Ilustracja funkcji polygon() z wartością kształtu

Jeśli koła i elipsy są zbyt ograniczające, funkcja kształtu wielokąta otwiera przed Tobą mnóstwo możliwości. Format to polygon(x1 y1, x2 y2, ...), gdzie podajesz pary współrzędnych x y dla każdego wierzchołka (punktu) wielokąta. Minimalna liczba par określających wielokąt to 3, czyli trójkąt.

.element{
  shape-outside: polygon(0 0, 0 300px, 300px 600px);
  width: 300px;
  height: 600px;
}

Wierzchołki są umieszczane w układzie współrzędnych. W przypadku poligonów responsywnych możesz użyć wartości procentowych dla niektórych lub wszystkich współrzędnych.

.element{
  /* polygon responsive to font-size*/
  shape-outside: polygon(0 0, 0 100%, 100% 100%);
  width: 20em;
  height: 40em;
}

Opcjonalny parametr fill-rule importowany z pliku SVG informuje przeglądarkę, jak traktować „wewnętrzną część” wielokąta w przypadku ścieżek przecinających się nawzajem lub zamkniętych kształtów. Joni Trythall bardzo dobrze wyjaśnia, jak działa właściwość fill-rule w SVG. Jeśli nie zdefiniujesz właściwości fill-rule, zostanie użyta wartość domyślna nonzero.

.element{
  shape-outside: polygon(0 0, 0 100%, 100% 100%);
  /* identical to: */
  shape-outside: polygon(nonzero, 0 0, 0 100%, 100% 100%);
}

Funkcja inset()

Funkcja inset() umożliwia tworzenie prostokątnych kształtów, wokół których można zawinąć zawartość. Może to brzmieć nielogicznie, biorąc pod uwagę założenie, że CSS Shapes tworzy proste pudełka dla treści internetowych. Być może. Nie udało mi się jeszcze znaleźć zastosowania dla inset(), które nie byłoby możliwe przy użyciu wartości zmiennoprzecinkowych i marginesów lub przy użyciu polygon(). Jednak inset() zapewnia lepszą czytelność w przypadku kształtów prostokątnych niż polygon().

Pełna notacja funkcji wbudowanej figury to inset(top right bottom left border-radius). Pierwsze 4 argumenty pozycji to przesunięcia do wewnątrz od krawędzi elementu. Ostatni argument to promień obramowania prostokąta. Jest to opcja, więc możesz ją pominąć. Jest ona zgodna z notacją border-radius, której używasz już w usłudze porównywania cen.

.element{
  shape-outside: inset(100px 100px 100px 100px);
  /* yields a rectangular shape which is 100px inset on all sides */
  float: left;
}

Tworzenie kształtów z pól odniesienia

Jeśli nie określisz funkcji kształtu dla właściwości shape-outside, możesz pozwolić przeglądarce wyprowadzić kształt z pola odniesienia elementu. Domyślne pole odniesienia to margin-box. Nie ma tu nic egzotycznego, bo tak już działają liczby zmiennoprzecinkowe. Dzięki zastosowaniu tej techniki możesz ponownie użyć geometrii elementu. Przyjrzyjmy się właściwości border-radius.

Jeśli użyjesz go do zaokrąglenia rogów elementu wyniesionego, uzyskasz efekt przycięcia, ale obszar wyniesienia pozostanie prostokątny. Dodaj shape-outside: border-box, aby owinąć kształt wokół konturu utworzonego przez border-radius.

Wyodrębnianie kształtu z elementu za pomocą właściwości border-radius za pomocą pola referencyjnego border-box
.element{
  border-radius: 50%;
  shape-outside: border-box;
  float: left;
}

Oczywiście w ten sposób możesz używać wszystkich pól referencyjnych. Oto jeszcze jedno zastosowanie kształtów pochodnych – wyodrębnianie cytatów.

Tworzenie cytatu z przesunięciem za pomocą pola odniesienia do treści

Efekt przesunięcia cytatu można uzyskać, korzystając tylko z właściwości float i margin. Wymaga to jednak umieszczenia elementu cytatu w drzewie HTML w miejscu, w którym ma być renderowany.

Oto jak uzyskać ten sam efekt przesunięcia cytatu z dodatkową elastycznością:

.pull-quote{
  shape-outside: content-box;
  margin-top: 200px;
  float: left;
}

W przypadku systemu współrzędnych kształtu ustawiamy wyraźnie pole odniesienia content-box. W tym przypadku ilość treści w cytacie określa kształt, w którym będzie zawijana zawartość zewnętrzna. Właściwość margin-top służy tutaj do pozycjonowania (przesuwania) cytatu, niezależnie od jego położenia w drzewie HTML.

Margines kształtu

Pamiętaj, że owinięcie treści wokół kształtu może spowodować zbyt bliskie przyleganie do elementu. Możesz dodać odstęp wokół kształtu za pomocą właściwości shape-margin.

.element{
  shape-outside: circle(40%);
  shape-margin: 1em;
  float: left;
}

Efekt jest podobny do tego, który znasz z użycia zwykłej właściwości margin, ale shape-margin wpływa tylko na przestrzeń wokół wartości shape-outside. Doda ona odstęp wokół kształtu tylko wtedy, gdy jest na niego miejsce w systemie współrzędnych. Dlatego w tym przykładzie promień koła ma wartość 40%, a nie 50%. Gdyby promień został ustawiony na 50%, okrąg zajmowałby całą przestrzeń w układzie współrzędnych, nie pozostawiając miejsca na efekt shape-margin. Pamiętaj, że kształt jest ograniczony do margin-box elementu (element plus otaczający go margin). Jeśli kształt jest większy i wychodzi poza ten obszar, zostanie przycięty do margin-box, a kształt będzie prostokątny.

Pamiętaj, że shape-margin akceptuje tylko jedną wartość dodatnią. Nie ma zapisu odręcznego. Co to jest margines górny kształtu w przypadku koła?

Animowanie kształtów

Kształty CSS możesz łączyć z wieloma innymi funkcjami CSS, takimi jak przejścia i animacje. Muszę jednak podkreślić, że użytkownicy bardzo nie lubią, gdy podczas czytania zmienia się układ tekstu. Jeśli zdecydujesz się na animację kształtów, zwróć szczególną uwagę na wrażenia użytkowników.

Możesz animować promienie i środki kształtów circle()ellipse(), o ile są one zdefiniowane za pomocą wartości, które przeglądarka może interpolować. Możliwa jest podróż z: circle(30%) do: circle(50%). Jednak animacja między circle(closest-side)circle(farthest-side) spowoduje zablokowanie przeglądarki.

.element{
  shape-outside: circle(30%);
  transition: shape-outside 1s;
  float: left;
}

.element:hover{
  shape-outside: circle(50%);
}
GIF animowanego koła

Bardziej interesujących efektów można dokonać, animując kształty polygon(). Należy jednak pamiętać, że wielokąt musi mieć taką samą liczbę wierzchołków w obu stanach animacji. Jeśli dodasz lub usuniesz wierzchołki, przeglądarka nie będzie mogła interpolować.

Jednym z trików jest dodanie maksymalnej liczby wierzchołków i ustawienie ich w grupach w stanie animacji, w którym chcesz, aby było mniej widocznych krawędzi kształtu.

.element{
  /* four vertices (looks like rectangle) */
  shape-outside: polygon(0 0, 100% 0, 100% 100%, 0 100%);
  transition: shape-outside 1s;
}

.element:hover{
  /* four vertices, but second and third overlap (looks like triangle) */
  shape-outside: polygon(0 0, 100% 50%, 100% 50%, 0 100%);
}
GIF animowanego trójkąta

Zawijanie treści w kształt

Zrzut ekranu pokazujący demo Alicji w Krainie Czarów, w którym do zawijania treści użyto kształtów CSS

Wstępny projekt specyfikacji kształtów CSS zawierał właściwość shape-inside, która umożliwiała zawijanie treści wewnątrz kształtu. Przez pewien czas były nawet implementacje w Chrome i WebKit. Jednak owinięcie dowolnie umieszczonych treści w ścieżce niestandardowej wymaga znacznie więcej wysiłku i badań, aby uwzględnić wszystkie możliwe scenariusze i uniknąć błędów. Dlatego właściwość shape-inside została odroczona do poziomu 2 kształtów CSS, a jej implementacje zostały wycofane.

Jednak przy odrobinie wysiłku i poczynieniu pewnych kompromisów możesz uzyskać efekt owinięcia treści w kształt niestandardowy. Wystarczy użyć 2 elementów z pływającą pozycją i wartością shape-outside umieszczonych po przeciwnych stronach kontenera. Kompromis polega na tym, że musisz użyć 1 lub 2 pustych elementów, które nie mają znaczenia semantycznego, ale służą jako słupki, aby stworzyć iluzję kształtu wewnątrz.

<div>
  <div class='left-shape'></div>
  <div class='right-shape'></div>

  Lorem ipsum...
</div>

Pozycja elementów .left-shape i .right-shape na górze kontenera jest ważna, ponieważ będą one przesuwane w lewo i w prawo, aby otaczać zawartość.

.left-shape{
  shape-outside: polygon(0 0, ...);
  float: left;
  width: 50%;
  height: 100%;
}

.right-shape{
  shape-outside: polygon(50% 0, ...);
  float: right;
  width: 50%;
  height: 100%;
}
Ilustracja obejścia problemu z użyciem kształtu w ramach demonstracji Alice

Dzięki temu stylowi 2 elementy z pływającymi słupkami zajmują całą przestrzeń w elemencie, ale właściwości shape-outside pozostawiają miejsce na pozostałe treści.

Jeśli przeglądarka nie obsługuje kształtów CSS, będzie to powodować nieestetyczne efekty, ponieważ wszystkie treści będą przesuwane w dół. Dlatego ważne jest, aby używać tej funkcji w zwiększający się sposób.

W poprzednich przykładach animacji kształtów zauważysz, że przesuwanie tekstu może być uciążliwe. Nie wszystkie przypadki użycia wymagają animowanej formy. Możesz jednak animować inne właściwości, które współpracują z kształtami CSS, aby dodać efekt w odpowiednich miejscach.

W prezentacji Shapes w CSS na przykładzie Alicji w krainie czarów użyliśmy pozycji przewijania, aby zmienić górny margines treści. Tekst jest ściśnięty między 2 elementami z przesuniętym układem. Gdy przesuwa się w dół, musi ponownie ułożyć elementy zgodnie z wartością shape-outside tych 2 elementów. Daje to wrażenie, że tekst znika w dziurze, co wzbogaca opowiadanie historii. Czy to jest graniczące z nieprzyzwoitością? Być może. Ale wygląda fajnie.

Układ tekstu jest tworzony natywnie przez przeglądarkę, co zapewnia lepszą wydajność niż w przypadku rozwiązania JavaScript. Zmiana marginesu górnego podczas przewijania powoduje jednak wiele zdarzeń ponownego układania i rysowania, co może znacznie obniżyć wydajność. Używaj z zachowaj ostrożności. Jednak używanie kształtów CSS bez ich animowania nie powoduje zauważalnego spadku wydajności.

Stopniowe ulepszanie

Zacznij od założenia, że przeglądarka nie obsługuje kształtów CSS, a później, gdy wykryjesz tę funkcję, użyj jej. Modernizr to dobre rozwiązanie do wykrywania funkcji. W sekcji „Wykrywanie funkcji niebędących funkcjami podstawowymi” znajduje się test dla kształtów CSS.

Niektóre przeglądarki zapewniają wykrywanie funkcji w CSS za pomocą reguły @supports bez potrzeby korzystania z bibliotek zewnętrznych. Google Chrome, który obsługuje również kształty CSS, rozumie regułę @supports. Oto jak go używać, aby stopniowo zwiększać:

.element{
  /* styles for all browsers */
}

@supports (shape-outside: circle(50%)){
  /* styles only for browsers which support CSS Shapes */
  .element{
    shape-outside: circle(50%);
  }
}

Lea Verou napisała więcej o używaniu reguły CSS @supports.

Wykluczenia z usługi porównywania cen

To, co dziś nazywamy kształtami CSS, na początku było nazywane wyłączeniami i kształtami CSS. Zmiana nazwy może wydawać się drobnostką, ale w rzeczywistości jest bardzo ważna. Wykluczenia CSS, które teraz stanowią osobną specyfikację, umożliwiają zawijanie treści wokół elementów umieszczonych dowolnie, bez potrzeby stosowania właściwości float. Wyobraź sobie, że otaczasz treści elementem o pozycji bezwzględnej. To przykład zastosowania wykluczeń CSS. Kształty CSS określają tylko ścieżkę, wokół której będą zawijane treści.

Kształty i wykluczenia to nie to samo, ale uzupełniają się nawzajem. Kształty CSS są obecnie dostępne w przeglądarkach, ale wykluczenia CSS nie są jeszcze stosowane w interakcji z kształtami.

Narzędzia do pracy z formami CSS

Ścieżki możesz tworzyć w klasycznych narzędziach do tworzenia obrazów, ale w momencie pisania tego tekstu żadne z nich nie eksportuje wymaganej składni dla wartości kształtów CSS. Nawet gdyby to było możliwe, praca w taki sposób nie byłaby zbyt praktyczna.

Kształty CSS są przeznaczone do używania w przeglądarce, gdzie reagują na inne elementy na stronie. Bardzo przydatne jest zwizualizowanie efektów edycji kształtu na treściach, które go otaczają. Dostępnych jest kilka narzędzi, które mogą Ci pomóc w tym procesie:

Brackets: rozszerzenie CSS Shapes Editor dla Brackets korzysta z podglądu na żywo w edytorze kodu, aby nakładać interaktywny edytor do edycji wartości kształtów.

Google Chrome: rozszerzenie CSS Shapes Editor dla Google Chrome rozszerza narzędzia deweloperskie przeglądarki o elementy sterujące do tworzenia i edytowania kształtów. Umożliwia umieszczenie interaktywnego edytora na wybranym elemencie.

Inspekcja w Google Chrome ma wbudowane narzędzie do wyróżniania kształtów. Najedź kursorem na element z właściwością shape-outside, a zaświeci się on, aby wskazać kształt.

Kształty z obrazów: jeśli wolisz generować obrazy i chcesz, aby przeglądarka wyodrębniała z nich kształty, Rebecca Hauck napisała przydatny samouczek dla Photoshopa.

Polyfill: przeglądarka Google Chrome jest pierwszą dużą przeglądarką, która obsługuje kształty CSS. Wkrótce udostępnimy tę funkcję w systemie iOS 8 i przeglądarce Safari 8. Inni dostawcy przeglądarek mogą w przyszłości rozważyć jego wdrożenie. Do tego czasu możesz korzystać z polyfilla CSS Shapes, który zapewnia podstawowe wsparcie.

Podsumowanie

W internecie, gdzie treści są głównie zamknięte w prostych polach, kształty CSS umożliwiają tworzenie wyrazistych układów, które zacierają różnice między wiernością projektowania stron internetowych i druku. Oczywiście kształty mogą być niewłaściwie używane i rozpraszać uwagę. Jednak jeśli są używane z dozą smaku i rozsądku, mogą wzbogacać prezentację treści i przyciągać uwagę użytkownika w sposób, który jest unikalny dla danego użytkownika.

Poniżej znajdziesz kolekcję prac innych osób, głównie z druku, które pokazują ciekawe zastosowania niestandardowych układów. Mam nadzieję, że zainspiruje Cię to do wypróbowania kształtów CSS i eksperymentowania z nowymi pomysłami na projekt.

Dziękujemy Pearl Chen, Alanowi Stearnsowi i Zoltanowi Horvathowi za sprawdzenie tego artykułu i podanie cennych informacji.