EpicWEB.pl

webdesign, programowanie, phat lewt!

Ostatni projekt

ddrpl.com

Ostatnie wiadomości

head.js - projektuj z głową

Każdy, kto kiedykolwiek korzystał z internetu doskonale zdaje sobie sprawę, że strony, które ładują się długo odstraszają potencjalnych odwiedzających. Wyszukany w Google link nie ładuje się w ciągu 5 sekund? Pewnie strona nie działa - wracamy na wyniki wyszukiwania i sprawdzamy kolejną.

Często za wolne ładowanie się strony nie odpowiada zły kod silnika na którym stoi, czy też wolne łącze serwera, ale duża ilość ładowanych skryptów JavaScript. W tym miejscu z pomocą przychodzi nam skrypt nazwany head.js. Za pomocą tego prostego skryptu możemy oddelegować ładowanie dziesiątek oddzielnych plików JS w tło i zmniejszyć czas, jaki upłynie do wyświetlenia zawartości strony. head.js ma też kilka innych, przydatnych funkcji, o których wspomnę jeszcze poniżej.

Podstawowa funkcjonalność - równoległe, nie blokujące pobieranie w tle.

Standardowe umieszczanie wywołania skryptów JS w sekcji wiąże się z odczekaniem na pobranie wszystkich dołączonych plików przed rozpoczęciem renderowania strony. Jeżeli ładujemy jeden mały plik może nie stanowić to problemu, jednak kiedy chcemy korzystać z kilku bibliotek, skryptów pomocniczych i innych, które nie daj Bóg znajdują się na wolno odpowiadających serwerach sprawa nieco się komplikuje. Pomocne może być przesunięcie wywołań skryptów na sam koniec części jednak jest to rozwiązanie mało eleganckie i nie intuicyjne.

head.js("http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js", "/assets/scripts.js", function() {
	init();
});

Powyższy kod obrazuje podstawowe i chyba najczęstsze wykorzystanie head.js Wywołanie kodu spowoduje pobranie biblioteki jQuery z serwera GoogleAPI, wczytanie lokalnego pliku JS oraz wywołanie funkcji init kiedy tylko przeglądarka zgłosi zdarzenie DOM.ready (czyli załadowano HTML, ale nie pobrano elementów multimedialnych). Jak już wspominałem, pliki pobierane są w tle, jednak wykonywane w kolejności zdefiniowanej przez nas w wywołaniu. Jeżeli nie zależy nam na kolejności ich wykonywania, możemy zmodyfikować nasz kod:

head.js("/assets/scripts.js", function() {
	init();
});
head.js("http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js");

// jest to równoznaczne z:

head.js("/assets/scripts.js", function() {init();}).js("http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js");

Teraz skrypty wykonane zostaną w kolejności, w której pobierze je przeglądarka.

Jeżeli nie chcemy używać "wywołań zwrotnych" (ang. callback) możemy także nadać każdemu skryptowi unikalny identyfikator i posłużyć się funkcją head.ready jak na poniższym przykładzie:

head.ready("tools", function() {
   init();
});
 
head.js(
   {jquery: "http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"},
   {tools: "/assets/scripts"}
);

Dodatkowe możliwości

Jak już wspomniałem, head.js poza swoim podstawowym zadaniem spełnia także kilka innych funkcji. Jak wiadomo starsze przeglądarki nie w pełni wspierają HTML5 - najbardziej uciążliwy jest brak możliwości używania CSS dla nowo wprowadzonych elementów. By obejść ten problem często używamy HTML5shiv - okazuje się jednak, że autor head.js postanowił umieścić te funkcjonalność w swoim skrypcie, więc nie musimy zawracać sobie tym głowy.

Kolejnym udogodnieniem, którym obdarza nas skrypt jest wykrywanie możliwości przeglądarki w zakresie obsługi CSS, podobnie jak ma to w wypadku zastosowania Modernizr. Samo dodanie wywołania skryptu do strony poskutkuje nadaniem elementowi <html> klas określających wsparcie dla poszczególnych elementów. Klasy, jakie może dodać skrypt to:

borderimage, borderradius, boxshadow, cssreflections, 
csstransforms, csstransitions, fontface, multiplebgs, opacity, rgba, textshadow

Poza wykrywaniem obsługi CSS skrypt pozwoli nam poznać także rodzinę (ie, webkit, opera, mozilla), wersję (tylko dla IE, lt-ie8, ie6), oraz szerokość okna, w którym wyświetlona jest strona dodając odpowiednie klasy z przedrostkiem w- (dla aktualnej rozdzielczości) i lt- (dla rozdzielczości większych od aktualnej). Przykładowo, oglądając stronę w przeglądarce IE7 i rozdzielczości 1400x768 element <html;> otrzyma klasy (pomijając wykrywanie CSS z powyższego akapitu):

<html class="ie ie7 lt-ie8 lt-ie9 w-1400 lt-1440 lt-1680 lt-1920">

Ostatnią funkcjonalnością jest tzw. "CSS routing" czyli dodawanie klasy na podstawie adresu URL. Najłatwiej zobrazować to na przykładzie. Odwiedzając adres

http://example.com/o-firmie/historia/rok-2011

Element <html;> przyjmie postać (dla uproszczenia, bez powyższych funkcjonalności):

<html class="o-firmie-section historia-section rok-2011-section">

Dzięki czemu możemy wpłynąć np. na zaakcentowanie graficzne aktualnie przeglądanej sekcji witryny (chociaż moim zdaniem zawsze lepiej zrobić to po stronie serwera dodając od razu klasy do odpowiednich elementów).

Podsumowując, head.js to doskonałe narzędzie, które poza zmniejszeniem czasu potrzebnego na załadowanie naszej strony oraz usprawnieniem organizacji kodu HTML posiada także dodatkowe, ułatwiające codzienną prace funkcje. Po więcej informacji nt. skryptu, jego możliwości oraz konfiguracji zapraszam na oficjalną stronę projektu.

Stosujesz AJAX? Używaj live.js!

Niedawno, na reddicie, ktoś udostępnił link do projektu Live.js. Czym jest Live.js? To prosty skrypt JavaScript, który można używać jako Bookmarklet, a jego zadaniem jest cykliczne odświeżanie strony - pozwala to na podglądanie zmian w czasie rzeczywistym zaraz po tym, jak zapiszemy je na serwerze (uwaga: skrypt działa tylko z protokołem http - wiec file:// odpada).

Można by pomyśleć, że skrypt po prostu zastępuje zmianę okna i klikanie F5. Takie też było moje pierwsze wrażenie. Okazuje się, że skrypt ma jeszcze jedno - bardzo pożyteczne - zastosowanie. Live.js pozwala na odświeżanie CSS, JS i/lub HTML bez przeładowania dokumentu. Co nam to daje? Możemy np. pobrać dane z pomocą AJAX - a następnie modyfikować plik CSS i sprawdzać jak zmienia się prezentacja danych. Rozwiązanie to przydatne jest w szczególności, kiedy tworzymy rozbudowane, dynamiczne strony, w których dane pobierane za pomocą AJAX znajdują się np. na końcu wypełnianego przez nas formularz.

Przyznam, że nie sprawdzałem jeszcze jak działa odświeżanie HTML i JS - wersja bookmarkletu on-line pozwala tylko na odświeżanie CSS - ale sama możliwość łatwego podglądu zmian w CSS skutkuje umieszczeniem skryptu w widocznym miejscu w przeglądarce :)

Google vs Java Script

Do tej pory byłem przekonany, że Google nie radzi sobie (albo po prostu nie robi tego z wyboru) z elementami Java Script na stronie. Jakież było dziś moje zdziwienie kiedy chciałem znaleźć coś u siebie na blogu za pomocą Google - oto co ujrzałem:

"Ale o co Ci chodzi" - mógłby zapytać ktoś, "przecież masz dokładnie* taki tytuł strony:"

No właśnie nie bardzo - w wynikach Google pojawiło się dodatkowe "null" w tytule. Dodatkowo, z uwagi na sposób, w jaki pociąłem sobie szablon Joggera, tytuł podstrony muszę generować w nieco inny sposób:

Czyli jak widać, strona ma zupełnie inny tytuł nadany w HTML, który następnie w głębi kodu zostaje zmodyfikowany przy pomocy Java Script.

Na początku uznałem, że może być to przyczyna odkrycia linków do strony prowadzących np. z głównej strony Joggera czy innych blogów. Nie może to być jednak wyjaśnienie sytuacji, ponieważ tytuły linków z Joggera wyglądają zgoła inaczej - nie ma w nich głównego sloganu witryny. RSS? Również ma inne tytuły artykułów ...

Zostaje mi tylko jeden wniosek - Google (w jakimś tam stopniu) jest w stanie wywołać skrypty JS i pobrać dane ze zmodyfikowanej strony. Czy ktoś spotkał się może już z tym zjawiskiem i może wskazać jakąś publikację mówiącą o tym w jakim stopniu Google bierze pod uwagę takie - wygenerowane przez JS - treści?

[HTML5] Dodatkowe informacje o elemencie

HTML5 w jednym ze swoich udogodnień wprowadza bardzo przyjazne rozwiązanie pozwalające na przechowywanie informacji o dowolnym tagu. W celu szybszego zrozumienia o co chodzi, posłużmy się przykładem kodu HTML formularza wraz z walidacją danych:

<input type="text" id="email" name="email" class="text required requiredEmail" />

Istnieje wiele bibliotek JavaScript, służących do walidacji formularza po stronie przeglądarki, które w ten właśnie sposób odnajdują pola, które powinny być wypełnione (posiadają klasę required) i sprawdzają, jaką zawartość powinny posiadać (requiredEmail). Rozwiązanie to oczywiście działało, ale powstawały zbędne, nic nie znaczące klasy CSS.

Jak już wspomniałem, HTML5 pomoże nam i w takim przypadku. A to dzięki możliwości stosowania własnych atrybutów z rodziny data-*. Zamysł jest prosty - autor strony może osadzić dowolną informację używając nowego atrybutu - dane te nie są nigdzie wyświetlane, są one dostępne dla JavaScript oraz CSS (za pomocą funkcji attr()).

Jako autorzy strony posiadamy praktycznie pełną dowolność w wyborze nazwy atrybutu - specyfikacja narzuca jedynie, by nie zawierał on dużych liter. Poprawny przykład:

<input type="text" id="email" name="email" data-validate="true" data-validate-type="email" />

Zgodnie ze specyfikacją, wartości powinny być teraz dostępne jako część zbioru dataset z użyciem notacji CamelCase (znanej także jako Notacja Wielbłądzia):

document.getElementById('email').dataset.validate;
document.getElementById('email').dataset.validateType;

Niestety, do czasu implementacji tego rozwiązania przez przeglądarki dane te nie są dostępne i musimy dostać się do nich w inny sposób:

document.getElementById('email').getAttribute('data-validate');
document.getElementById('email').getAttribute('data-validate-type');

Na szczęście powyższe "obejście" problemu działa bez problemu na wszystkich liczących się przeglądarkach.

Poza oczywistym przykładem przechowywania danych na potrzeby walidacji nowy atrybut umożliwia np. sortowanie zestawów danych (tabel) po danych nie widocznych, lub wyświetlanych dla użytkownika w sposób trudny do zrozumienia dla skryptów, np:

<li data-date="2010-07-07T07:58:12"><a href="#">Spis wydarzeń w dniu 7 lipca, roku 2010</a></li>