Sizzle – Twój przyjaciel

Podczas czytania książki na temat CSS3 (w sumie tylko częściowo na ten temat, ale o tym w recenzji), naszło mnie pytanie – jak się ma kompatybilność przeglądarek z CSS3 do obsługi takich selektorów przez silnik Sizzle?

Chwila, moment, stop! „Co to jest Sizzle?” zapyta niejeden z Was. To te musujące cukierki? Nie, te cukierki nazywają się inaczej. Sizzle to silnik stosowany we frameworkach JS do znajdowania elementów w drzewie DOM. Wiele osób, nawet korzystających z niego regularnie, nie ma pojęcia o jego istnieniu – i nic w tym złego, dopóki potrafią się nim właściwie posługiwać. Jeśli jednak chcecie się dowiedzieć trochę więcej – dobrze trafiliście. Natomiast jeśli wolicie od razu poznać odpowiedź na pytanie ze wstępu – przewińcie na koniec artykułu.

Sizzle jest dzieckiem Johna Resiga, twórcy jQuery. Nie jest to przypadek – silnik stał się  odgałęzieniem projektu tego frameworka. Za pomocą przekazanych mu selektorów CSS3 odnajduje żądane przez nas elementy i zwraca je do dalszej obróbki. Tylko tyle i aż tyle. Każdy, kto pamięta kodowanie za pomocą getElementById, getElementsByClassName czy getElementsByTagName z wielką ulgą powitał to rozwiązanie, które pojawiło się w 2006 roku (czyt. prehistoria). Od tego czasu nad krainą manipulacji DOMem zawitało słońce.

Sizzle jest bardzo elastycznym narzędziem. Dostęp do poszczególnych węzłów lub ich kolekcji możemy zwykle uzyskać na wiele różnych sposobów. To jego wielka siła, ale i wielka bolączka. Ponieważ wszyscy zawsze najbardziej oglądają się za przykładami, oto on:

<nav>
	<ul>
		<li id="translate">Tłumaczenie</li>
		<li>Pierwsza strona</lli>
		<li>Druga strona</li>
	</ul>
</nav>
<article>
	<header>Nagłówek 1</header>
	Treść 1
	<div class="translation">
		Przetłumaczona treść 1
	</div>
</article>
<article>
	<header>Nagłówek 2</header>
	Treść 2
	<div class="translation">
		Przetłumaczona treść 2
	</div>
</article>

Mamy kawałek kodu HTML (nie pastwmy się teraz na usability etc.), więc spróbujmy dobrać się do elementu listy, który jak możemy się domyślać, przełącza tłumaczenia oraz do pojemników zawierających te tłumaczenia. Jak można to zrobić? Dobrze i źle, jak zawsze. Spróbujmy źle:

Sizzle('nav ul li:first');

Jestem świadomym użytkownikiem Sizzle’a i po prostu współczuję mu, gdy musi wykonywać takie zapytania. A ponieważ jest moim dobrym i wiernym przyjacielem, staram się ułatwiać mu życie, np. tak:

Sizzle('#translate');

W rzeczywistości ułatwiłem życie nie tylko jemu, ale i sobie, na wypadek, gdyby przycisk powędrował gdzie indziej. Podobnie zamiast pisać:

Sizzle('article div.translation');

napiszę – to w zupełności wystarczy:

Sizzle('div.translation');

Gdy już wiemy, jak właściwie dostać się do odpowiednich elementów, możemy wykorzystać to w użytecznym kodzie. Sizzle schodzi do podziemi, żeby odwalać swoją robotę na użytek jQuery, które będzie potrafiło obsłużyć otrzymane od niego elementy:

$(function($){
	$('div.translation').hide();
	$('#translate').click(function(){
		$('div.translation').show();
	});
})

Jeśli nie wiecie, dlaczego ukrywam tłumaczenia dopiero w kodzie JavaScript, zamiast w arkuszu CSS lub stylu inline, zajrzyjcie do artykułu o stopniowym ulepszaniu – motywacje się trochę pozmieniały, ale nadal warto przygotować strony tak, żeby JavaScript dodawał, a nie ograniczał ich funkcjonalność.

Przykład nie jest jakoś wielce wyrafinowany, ale porusza ważny temat. Selektory dla Sizzle (a więc np. te używane w jQuery czy Prototype) można tworzyć na wiele różnych sposobów, ale warto zadbać o to, żeby były jak najprostsze – dla dobra własnego (łatwiejsze utrzymanie i rozwój takiego kodu) i Sizzle’owego – o ile w tej chwili kilka kolejnych operacji wykonanych przez taki silnik w przeglądarce użytkownika nie robi wielkiej różnicy, to przemnożenie ich przez skalę zjawiska pokazuje, że możemy tu już mieć wpływ na user-experience.

Ale o czym to ja? A tak – kompatybilność przeglądarki z CSS3 a Sizzle. Otóż okazuje się, że jedno z drugim nie ma nic wspólnego. Sizzle implementuje swoją obsługę podzbioru selektorów CSS3 tak, aby działać we wszystkich ważnych przeglądarkach. Podzbioru, ponieważ kilka selektorów nie jest dostępnych – są to :root, :target, :nth-last-child, :nth-of-type / :nth-last-of-type / :first-of-type / :last-of-type / :only-of-type i :lang(). Wpisujcie w komentarzach miasta, które tęsknią za ich obsługą z poziomu jQuery.

Mam nadzieję, że ten wpis skłoni Was do chwili przemyśleń nad kwestią używania selektorów w kodzie JS. A dodatkowo, że skrótowe i powierzchowne potraktowanie tematu rozbudzi Wasz głód wiedzy i zaprowadzi do ciekawych materiałów:

Zapraszam do zapoznania się z tymi stronami. Zaprzyjaźnijcie się z Sizzle’m, a jeśli macie jakieś uwagi i pytania – nie wahajcie się, tylko piszcie w komentarzach.

2 myśli nt. „Sizzle – Twój przyjaciel

  1. Obecnie chyba nie przejmowałbym się tak bardzo wydajnością selektorów, w szczególności w przeglądarkach „klasy” IE8 i nowszych. Złożoność zapytania typu ‚nav ul li’ jest chyba liniowa, więc przy natywnie wykonywanym kodzie JS jak np. w Chromie nie powinno mieć to większego znaczenia nawet dla setek takich „odpytywań”. Z tego, co doświadczyłem dużo większym obciążeniem dla silnika przeglądarki są wielokrotne zmiany wyglądu lub pozycji elementów (manipulacja DOM wymuszająca odświeżenie strony) niż wykonywanie jakiegokolwiek kodu JS. Dzięki za jQuery cheatsheet!

    • Można zrobić sobie proste porównanie szybkości – zarówno różnych frameworków, jak i selektorów w poszczególnych frameworkach: http://mootools.net/slickspeed/ – klikamy start tests i obserwujemy wyniki. Do szybkości jQuery i Prototype na tych przykładach trudno się przyczepić i rzeczywiście nadmierna optymalizacja wydaje się zbędna. Przy jakiejś okazji spróbuję przygotować benchmark dla rzeczywistej aplikacji.
      Jednak nadal uważam, że nie warto sobie folgować w sprawie selektorów, a należy trzymać się możliwej prostoty. Tam, gdzie mamy dostępny identyfikator – aż żal go nie wykorzystać.
      Ale już dwa identyfikatory w selektorze to chyba żart – według zestawienia na blogu Johna Resiga stanowią 0,43% wywołań na całkiem poważnych stronach: http://ejohn.org/files/selectors.html