Wprowadzenie
Tworzenie stron na urządzenia mobilne to obecnie bardzo popularny temat. W tym roku po raz pierwszy sprzedaż smartfonów przewyższyła sprzedaż komputerów. Coraz więcej użytkowników korzysta z urządzeń mobilnych do przeglądania internetu, co oznacza, że optymalizacja witryn pod kątem przeglądarek mobilnych staje się dla deweloperów kluczowa.
Dla wielu deweloperów rynek „mobilny” to wciąż niezbadane wody. Wiele osób ma starsze witryny, które w ogóle nie uwzględniają użytkowników urządzeń mobilnych. Zamiast tego witryna została zaprojektowana głównie do przeglądania na komputerach i źle się wyświetla w przeglądarkach mobilnych. Ta witryna (html5rocks.com) nie jest wyjątkiem. Na początku nie przywiązywaliśmy dużej wagi do wersji mobilnej.
Tworzenie witryny html5rocks.com dostosowanej do komórek
W ramach ćwiczenia postanowiłem wziąć html5rocks (istniejącą witrynę HTML5) i uzupełnić ją o wersję dostosowaną do komórek. Zależało mi głównie na tym, aby przy minimalnym nakładzie pracy dostosować grę do smartfonów. Moim celem nie było utworzenie zupełnie nowej witryny mobilnej i utrzymywanie 2 baz kodu. Zajęłoby to mnóstwo czasu. Zdefiniowaliśmy już strukturę witryny (znaczniki). Mieliśmy wygląd i styl (CSS). Główna funkcjonalność (JS) była dostępna. Chodzi o to, że wiele witryn jest w podobnej sytuacji.
W tym artykule opisujemy, jak utworzyliśmy mobilną wersję html5rocks zoptymalizowaną pod kątem urządzeń z Androidem i iOS. Aby zobaczyć różnicę, wystarczy wczytać stronę html5rocks.com na urządzeniu z jednym z tych systemów operacyjnych. Nie ma przekierowań do m.html5rocks.com ani innych tego typu sztuczek. Otrzymujesz html5rocks w niezmienionej postaci, ale z dodatkową korzyścią w postaci świetnego wyglądu i działania na urządzeniu mobilnym.
Zapytania o media CSS
HTML4 i CSS2 od pewnego czasu obsługują arkusze stylów zależne od multimediów. Na przykład:
<link rel="stylesheet" media="print" href="printer.css">
będzie kierować na urządzenia drukujące i zapewniać określony styl zawartości strony podczas jej drukowania. CSS3 idzie o krok dalej i rozszerza funkcjonalność typów mediów o zapytania o media. Zapytania o media zwiększają użyteczność typów multimediów, umożliwiając dokładniejsze oznaczanie arkuszy stylów. Dzięki temu można dostosować prezentację treści do określonego zakresu urządzeń wyjściowych bez konieczności zmiany samych treści. Brzmi idealnie w przypadku istniejącego układu, który wymaga modyfikacji.
Możesz używać zapytań o media w atrybucie media zewnętrznych arkuszy stylów, aby kierować reklamy na szerokość ekranu, szerokość urządzenia, orientację itp. Pełną listę znajdziesz w specyfikacji zapytań o media W3C.
Kierowanie na rozmiary ekranu
W poniższym przykładzie phone.css będzie dotyczyć urządzeń, które przeglądarka uznaje za „urządzenia przenośne”, lub urządzeń z ekranem o szerokości mniejszej niż 320 pikseli.
<link rel='stylesheet'
media='handheld, only screen and (max-device-width: 320px)' href='phone.css'>
Dodanie przed zapytaniem o media słowa kluczowego „only” spowoduje, że przeglądarki niezgodne ze standardem CSS3 będą ignorować tę regułę.
Poniższy kod będzie kierować reklamy na ekrany o rozmiarze od 641 do 800 pikseli:
<link rel='stylesheet'
media='only screen and (min-width: 641px) and (max-width: 800px)' href='ipad.css'>
Zapytania o media mogą też występować w tagach <style> umieszczonych w tekście. Poniższy kod jest kierowany na all typów multimediów w orientacji pionowej:
<style>
@media only all and (orientation: portrait) { ... }
</style>
media="handheld"
Musimy się na chwilę zatrzymać i omówić media="handheld".
Faktem jest, że Android i iOS ignorują media="handheld". Użytkownicy nie będą mieli dostępu do wysokiej jakości treści dostarczanych przez arkusze stylów kierowane na media="screen", a deweloperzy będą mniej skłonni do utrzymywania wersji media="handheld" o niższej jakości. Dlatego w ramach hasła „pełny internet” większość nowoczesnych przeglądarek na smartfony po prostu ignoruje arkusze stylów dla urządzeń przenośnych.
Idealnie byłoby używać tej funkcji do kierowania na urządzenia mobilne, ale różne przeglądarki implementują ją na różne sposoby:
- Niektóre odczytują tylko arkusz stylów dla urządzeń przenośnych.
- Niektóre odczytują tylko arkusz stylów dla urządzeń przenośnych, jeśli jest dostępny, a w przeciwnym razie domyślnie używają arkusza stylów dla ekranu.
- Niektóre odczytują zarówno arkusz stylów dla urządzeń przenośnych, jak i arkusz stylów dla ekranów.
- Niektóre czytają tylko arkusz stylów ekranu.
Opera Mini nie ignoruje media="handheld". Aby system Windows Mobile rozpoznał media="handheld", należy użyć wielkich liter w wartości atrybutu media dla arkusza stylów ekranu:
<!-- media="handheld" trick for Windows Mobile -->
<link rel="stylesheet" href="screen.css" media="Screen">
<link rel="stylesheet" href="mobile.css" media="handheld">
Jak html5rocks używa zapytań o media
Zapytania o media są często używane w mobilnej wersji html5rocks. Dzięki nim mogliśmy dostosować układ bez konieczności wprowadzania znaczących zmian w znacznikach szablonu Django… To było prawdziwe wybawienie! Ponadto obsługa w różnych przeglądarkach jest całkiem dobra.
W sekcji <head> każdej strony zobaczysz te arkusze stylów:
<link rel='stylesheet'
media='all' href='/static/css/base.min.css' />
<link rel='stylesheet'
media='only screen and (max-width: 800px)' href='/static/css/mobile.min.css' />
base.css zawsze definiował główny wygląd i styl html5rocks.com, ale teraz stosujemy nowe style (mobile.css) dla ekranów o szerokości poniżej 800 pikseli. Zapytanie o media obejmuje smartfony (~320 pikseli) i iPady (~768 pikseli).
Efekt: stopniowo zastępujemy style w pliku base.css (tylko w razie potrzeby), aby poprawić wygląd strony na urządzeniach mobilnych.
Niektóre zmiany stylu wymuszane przez mobile.css:
- Zmniejsza dodatkowe odstępy i dopełnienia w witrynie. Małe ekrany oznaczają, że miejsce jest na wagę złota.
- Usuwa
:hoverstany. Nigdy nie będą widoczne na urządzeniach dotykowych. - Dostosowuje układ do jednej kolumny. Omówimy to dokładniej w dalszej części szkolenia.
- Usuwa
box-shadowwokół głównego kontenera div witryny. Duże cienie pól obniżają wydajność strony. - Użyto modelu CSS flex box
box-ordinal-group, aby zmienić kolejność poszczególnych sekcji na stronie głównej. Zauważysz, że sekcja „LEARN BY MAJOR HTML5 FEATURE GROUPS” znajduje się przed sekcją „TUTORIALS” na stronie głównej, ale po niej w wersji mobilnej. Taka kolejność była bardziej odpowiednia dla urządzeń mobilnych i nie wymagała zmian w znacznikach. CSS flexbox FTW! - Usuwa
opacityzmiany. Zmiana wartości alfa wpływa na wydajność na urządzeniach mobilnych.
Metatagi mobilne
Mobilny WebKit obsługuje kilka funkcji, które zapewniają użytkownikom lepsze wrażenia podczas przeglądania na niektórych urządzeniach.
Ustawienia widocznego obszaru
Pierwszym ustawieniem meta (i tym, którego będziesz używać najczęściej) jest właściwość viewport. Ustawienie widocznego obszaru informuje przeglądarkę, jak zawartość powinna być dopasowana do ekranu urządzenia, oraz że witryna jest zoptymalizowana pod kątem urządzeń mobilnych. Na przykład:
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
informuje przeglądarkę, że ma ustawić widoczny obszar na szerokość urządzenia ze skalą początkową 1. Ten przykład umożliwia też powiększanie, co może być pożądane w przypadku witryny, ale nie aplikacji internetowej. Możemy uniemożliwić powiększanie za pomocą user-scalable=no lub ograniczyć skalowanie do określonego poziomu:
<meta name=viewport
content="width=device-width, initial-scale=1.0, minimum-scale=0.5 maximum-scale=1.0">
Android rozszerza metatag viewport, umożliwiając deweloperom określenie, dla jakiej rozdzielczości ekranu została opracowana witryna:
<meta name="viewport" content="target-densitydpi=device-dpi">
Możliwe wartości parametru target-densitydpi to device-dpi, high-dpi, medium-dpi i low-dpi.
Jeśli chcesz zmodyfikować stronę internetową pod kątem różnych gęstości ekranu, użyj zapytania o media CSS -webkit-device-pixel-ratio lub właściwości window.devicePixelRatio w języku JavaScript, a następnie ustaw właściwość meta target-densitydpi na device-dpi. Dzięki temu Android nie będzie skalować strony internetowej, a Ty możesz wprowadzić niezbędne zmiany dla każdej gęstości za pomocą CSS i JavaScriptu.
Więcej informacji o kierowaniu na rozdzielczości urządzeń docelowych znajdziesz w dokumentacji WebView na Androida.
Przeglądanie na pełnym ekranie
Istnieją jeszcze 2 inne wartości meta, które są specyficzne dla iOS. apple-mobile-web-app-capable i apple-mobile-web-app-status-bar-style będą renderować zawartość strony w trybie pełnoekranowym, podobnie jak w aplikacji, i ustawią przezroczystość paska stanu:
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
Więcej informacji o wszystkich dostępnych opcjach meta znajdziesz w dokumentacji Safari.
Ikony na ekranie głównym
Urządzenia z iOS i Androidem akceptują też linki w formacie rel="apple-touch-icon" (iOS) i rel="apple-touch-icon-precomposed" (Android). Dzięki temu na ekranie głównym użytkownika, który doda Twoją witrynę do zakładek, pojawi się efektowna ikona przypominająca aplikację:
<link rel="apple-touch-icon"
href="/static/images/identity/HTML5_Badge_64.png" />
<link rel="apple-touch-icon-precomposed"
href="/static/images/identity/HTML5_Badge_64.png" />
Jak html5rocks używa metatagów mobilnych
Oto fragment sekcji <head> witryny html5rocks:
<head>
...
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
<link rel="apple-touch-icon"
href="/static/images/identity/HTML5_Badge_64.png" />
<link rel="apple-touch-icon-precomposed"
href="/static/images/identity/HTML5_Badge_64.png" />
...
</head>
Układ pionowy
Na mniejszych ekranach znacznie wygodniej jest przewijać w pionie niż w poziomie. Na urządzeniach mobilnych najlepiej sprawdza się układ jednokolumnowy, pionowy. W przypadku html5rocks użyliśmy zapytań o media CSS3, aby utworzyć taki układ. I znów – bez zmiany znaczników.
Optymalizacje pod kątem urządzeń mobilnych
Większość wprowadzonych przez nas optymalizacji to rzeczy, które powinny zostać zrobione na samym początku. Możesz na przykład zmniejszyć liczbę żądań sieciowych, skompresować pliki JS/CSS, użyć kompresji gzip (dostępnej bezpłatnie w App Engine) i zminimalizować manipulacje DOM. Te techniki to powszechne sprawdzone metody, ale czasami są pomijane, gdy witryna jest tworzona w pośpiechu.
Automatyczne ukrywanie paska adresu
Przeglądarki mobilne nie mają tak dużej powierzchni ekranu jak ich odpowiedniki na komputery. Co gorsza, na różnych platformach na górze ekranu może pojawić się duży pasek adresu, nawet po zakończeniu wczytywania strony.
Jednym z łatwych sposobów na rozwiązanie tego problemu jest przewijanie strony za pomocą JavaScriptu.
Nawet przesunięcie o 1 piksel spowoduje ukrycie paska adresu.
Aby wymusić ukrycie paska adresu na stronie html5rocks, dołączyłem moduł obsługi zdarzeń onload do obiektu window i przewinąłem stronę w pionie o 1 piksel:
// Hides mobile browser's address bar when page is done loading.
window.addEventListener('load', function(e) {
setTimeout(function() { window.scrollTo(0, 1); }, 1);
}, false);
Zastosowaliśmy też w tym detektorze zmienną szablonu is_mobile, ponieważ nie jest on potrzebny na komputerach.
Zmniejszanie liczby żądań sieciowych i oszczędzanie przepustowości
Powszechnie wiadomo, że zmniejszenie liczby żądań HTTP może znacznie poprawić wydajność. Urządzenia mobilne dodatkowo ograniczają liczbę jednoczesnych połączeń, które może nawiązać przeglądarka, więc witryny mobilne odniosą jeszcze większe korzyści z ograniczenia tych niepotrzebnych żądań. Ponadto oszczędzanie każdego bajtu jest kluczowe, ponieważ przepustowość na telefonach jest często ograniczona. Możesz narażać użytkowników na koszty.
Oto niektóre z metod, które zastosowaliśmy, aby zminimalizować liczbę żądań sieciowych i zmniejszyć wykorzystanie przepustowości na html5rocks:
Usuń elementy iframe – są powolne. Duża część opóźnień wynikała z widżetów udostępniania innych firm (Buzz, Google Friend Connect, Twitter, Facebook) na stronach samouczków. Te interfejsy API zostały uwzględnione za pomocą tagów
<script>i tworzą elementy iframe, które zmniejszają szybkość strony. Widżety zostały usunięte z urządzeń mobilnych.display:none– w niektórych przypadkach ukrywaliśmy znaczniki, jeśli nie pasowały do profilu mobilnego. Dobrym przykładem były 4 zaokrąglone pola u góry strony głównej:
Nie ma ich na stronie mobilnej. Pamiętaj, że przeglądarka nadal wysyła żądanie dotyczące każdej ikony, mimo że ich kontener jest ukryty za pomocą display:none. Dlatego nie wystarczyło po prostu ukryć tych przycisków. Nie tylko marnowałoby to przepustowość, ale użytkownik nie widziałby nawet efektów tego marnotrawstwa. Rozwiązaniem było utworzenie wartości logicznej „is_mobile” w naszym szablonie Django, aby warunkowo pomijać sekcje kodu HTML.
Gdy użytkownik wyświetla witrynę na urządzeniu inteligentnym, przyciski nie są widoczne.
Pamięć podręczna aplikacji – nie tylko zapewnia obsługę offline, ale też przyspiesza uruchamianie.
Kompresja CSS/JS – używamy kompresora YUI zamiast kompilatora Closure, głównie dlatego, że obsługuje on zarówno CSS, jak i JS. Jednym z problemów, na które natrafiliśmy, było to, że zapytania o media wbudowane (zapytania o media, które pojawiają się w arkuszu stylów) nie działały w kompresorze YUI 2.4.2 (zobacz ten problem). Problem został rozwiązany dzięki użyciu kompresora YUI w wersji 2.4.4 lub nowszej.
Używanie w miarę możliwości sprite'ów CSS.
Do kompresji obrazów użyto narzędzia pngcrush.
Użyto identyfikatorów dataURI w przypadku małych obrazów. Kodowanie Base64 zwiększa rozmiar obrazu o około 30%, ale pozwala uniknąć żądania sieciowego.
Automatycznie wczytuje wyszukiwarkę niestandardową Google za pomocą pojedynczego tagu skryptu, zamiast wczytywać ją dynamicznie za pomocą
google.load(). W tym drugim przypadku wysyłane jest dodatkowe żądanie.
<script src="//www.google.com/jsapi?autoload={"modules":[{"name":"search","version":"1"}]}"> </script>
- Nasz moduł do formatowania kodu i Modernizr były dołączane do każdej strony, nawet jeśli nigdy nie były używane. Modernizr jest świetny, ale przy każdym ładowaniu przeprowadza wiele testów. Niektóre z tych testów wprowadzają kosztowne modyfikacje modelu DOM i spowalniają wczytywanie strony. Teraz dołączamy te biblioteki tylko na stronach, na których są one rzeczywiście potrzebne. -2 prośby :)
Dodatkowe ulepszenia wydajności:
- Przenieśliśmy cały kod JS na dół strony (tam, gdzie było to możliwe).
- Usunięto tagi
<style>w tekście. - Zapisane w pamięci podręcznej wyszukiwania DOM i zminimalizowane manipulacje DOM – za każdym razem, gdy dotykasz DOM, przeglądarka wykonuje ponowne formatowanie. Na urządzeniach mobilnych ponowne renderowanie jest jeszcze bardziej kosztowne.
- Przeniesiono niepotrzebny kod po stronie klienta na serwer. W szczególności sprawdzenie, czy ustawiono styl nawigacji bieżącej strony:
js var lis = document.querySelectorAll('header nav li'); var i = lis.length; while (i--) { var a = lis[i].querySelector('a'); var section = a.getAttribute("data-section"); if (new RegExp(section).test(document.location.href)) { a.className = 'current'; } } - Elementy o stałej szerokości zostały zastąpione elementami
width:100%lubwidth:autoo płynnej szerokości.
Pamięć podręczna aplikacji
Wersja mobilna html5rocks używa pamięci podręcznej aplikacji, aby przyspieszyć początkowe wczytywanie i umożliwić użytkownikom czytanie treści offline.
Podczas wdrażania AppCache w witrynie bardzo ważne jest, aby nie zapisywać pliku manifestu w pamięci podręcznej (ani bezpośrednio w samym pliku manifestu, ani pośrednio za pomocą nagłówków kontroli pamięci podręcznej). Jeśli plik manifestu zostanie zapisany w pamięci podręcznej przeglądarki, debugowanie będzie bardzo trudne. iOS i Android bardzo dobrze radzą sobie z zapisywaniem tego pliku w pamięci podręcznej, ale nie zapewniają wygodnego sposobu na jej wyczyszczenie, jak ma to miejsce w przypadku przeglądarek na komputery.
Aby zapobiec buforowaniu naszej witryny, najpierw ustawiamy App Engine tak, aby nigdy nie buforował plików manifestu:
- url: /(.*\.(appcache|manifest))
static_files: \1
mime_type: text/cache-manifest
upload: (.*\.(appcache|manifest))
expiration: "0s"
Po drugie, użyliśmy interfejsu JS API, aby poinformować użytkownika o zakończeniu pobierania nowego pliku manifestu. Użytkownik zobaczy prośbę o odświeżenie strony:
window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
window.applicationCache.swapCache();
if (confirm('A new version of this site is available. Load it?')) {
window.location.reload();
}
}
}, false);
Aby ograniczyć ruch w sieci, uprość plik manifestu. Nie musisz więc wymieniać każdej strony w witrynie. Wystarczy, że wymienisz ważne obrazy, pliki CSS i JavaScript. Ostatnią rzeczą, którą chcesz zrobić, jest zmuszenie przeglądarki mobilnej do pobrania dużej liczby zasobów przy każdej aktualizacji pamięci podręcznej aplikacji. Pamiętaj, że przeglądarka będzie automatycznie zapisywać w pamięci podręcznej stronę HTML, gdy użytkownik ją odwiedzi (i będzie ona zawierać atrybut <html manifest="...">).