Nieelastyczne podejście do tworzenia aplikacji internetowych na różne urządzenia

Zapytania o media są świetne, ale...

Zapytania o multimedia to świetna sprawa dla deweloperów witryn, którzy chcą wprowadzić drobne zmiany w arkuszach stylów, aby zwiększyć wygodę użytkowników urządzeń o różnych rozmiarach. Zapytania o multimedia umożliwiają dostosowanie CSS witryny do rozmiaru ekranu. Zanim zapoznasz się z tym artykułem, dowiedz się więcej o projektowaniu responsywnym i zapoznaj się z kilkoma przykładami zapytań o media, które są dostępne tutaj: mediaqueri.es.

Jak wspomniał Brad Frost we wcześniejszym artykule, zmiana wyglądu to tylko jedna z wielu kwestii, które należy wziąć pod uwagę podczas tworzenia witryny mobilnej. Jeśli tworzysz witrynę mobilną, musisz dostosować jej układ za pomocą zapytań o media, mamy do czynienia z taką sytuacją:

  • Wszystkie urządzenia korzystają z tego samego kodu JavaScript, CSS i zasobów (obrazów, filmów), co sprawia, że wczytywanie trwa dłużej niż jest to konieczne.
  • Wszystkie urządzenia korzystają z tego samego początkowego modelu DOM, co potencjalnie zmusza deweloperów do napisania zbyt skomplikowanego kodu CSS.
  • Mała elastyczność w określaniu niestandardowych interakcji dostosowanych do poszczególnych urządzeń.

Aplikacje internetowe potrzebują czegoś więcej niż zapytań o multimedia

Nie chcę źle. Nie zniechęcam się do projektowania responsywnego za pomocą zapytań o media i myślę, że ma swoje znaczenie. Poza tym niektóre z powyższych problemów można rozwiązać za pomocą takich metod jak obrazy elastyczne, dynamiczne ładowanie skryptów itp. Jednak w pewnym momencie możesz zauważyć, że wprowadzasz zbyt wiele przyrostowych poprawek i sprawdzasz różne wersje reklamy.

Z czasem złożony z komponentów interfejs jest coraz bardziej złożony i chcesz sięgnąć po aplikacje internetowe składające się z jednej strony, więc warto dodatkowo dostosować interfejsy do poszczególnych typów urządzeń. Z tego artykułu dowiesz się, jak wprowadzić te zmiany przy minimalnym nakładzie pracy. Ogólne podejście obejmuje klasyfikowanie urządzenia użytkownika według odpowiedniej klasy i wyświetlanie mu odpowiedniej wersji, a także maksymalizację wykorzystania kodu w różnych wersjach.

Na jakie klasy urządzeń kierujesz reklamy?

W internecie jest mnóstwo urządzeń połączonych z internetem, a niemal wszystkie mają przeglądarkę. Trzeba pamiętać o ich różnorodności: laptopy Mac, stacje robocze z systemem Windows, iPhone'y, iPady, telefony z Androidem z dotykowym wprowadzaniem danych, kółkami przewijania, klawiaturą, wprowadzaniem głosowym, urządzeniami czułymi na nacisk, zegarkami smartwatch, tosterami, lodówkami i wieloma innymi. Niektóre z tych urządzeń są dostępne wszędzie, inne występują bardzo rzadko.

Różne urządzenia
Różne urządzenia (źródło).

Aby zadbać o wygodę użytkowników, musisz wiedzieć, kim są ich użytkownicy i z jakich urządzeń korzystają. Jeśli tworzysz interfejs dla użytkownika komputera z myszą i klawiaturą, a potem przekazujesz go użytkownikowi smartfona, interfejs będzie frustrujący, ponieważ jest zaprojektowany z myślą o innym rozmiarze ekranu i innym sposobie wprowadzania danych.

Różnorodność metod ma 2 skrajne końce:

  1. Utwórz jedną wersję, która działa na wszystkich urządzeniach. Będzie to negatywnie wpływać na wygodę użytkowników, bo różne urządzenia mają różne aspekty konstrukcyjne.

  2. Utwórz wersję dla każdego urządzenia, które chcesz obsługiwać. Potrwa to bezterminowo, ponieważ będziesz tworzyć zbyt wiele wersji swojej aplikacji. Poza tym, gdy pojawi się nowy smartfon (co mniej więcej co tydzień), będzie trzeba utworzyć kolejną wersję.

Istnieje tu zasadniczy kompromis: im więcej kategorii urządzeń, tym lepsze wrażenia użytkownika możesz zapewnić, ale tym więcej pracy będzie trzeba zaprojektować, wdrożyć i utrzymać.

Utworzenie osobnej wersji dla każdej klasy urządzenia może być dobrym pomysłem ze względu na wydajność lub gdy wersje, które chcesz wyświetlać w różnych klasach urządzeń, znacznie się różnią. W przeciwnym razie elastyczne projektowanie witryn to całkiem rozsądne podejście.

Potencjalne rozwiązanie

Oto kompromis: klasyfikuj urządzenia według kategorii i zaprojektuj je tak, by każda z nich działała jak najlepiej. To, jakie kategorie wybierzesz, zależy od produktu i docelowego użytkownika. Oto przykładowa klasyfikacja, która obejmuje dobrze istniejące obecnie urządzenia z obsługą internetu.

  1. mały ekran + dotyk (większość telefonów)
  2. duży ekran + dotyk (głównie tablety)
  3. duże ekrany + klawiatura/mysz (głównie komputery stacjonarne/laptopy),

To tylko jedno z wielu możliwych podziałów, ale takie, które w momencie pisania ma sens, Na liście powyżej nie ma urządzeń mobilnych bez ekranów dotykowych (np. telefony z podstawową przeglądarką, niektóre dedykowane czytniki e-booków). Większość z nich ma jednak zainstalowane oprogramowanie do nawigacji za pomocą klawiatury lub czytnika ekranu, które dobrze działają, jeśli tworzysz witrynę z myślą o ułatwieniach dostępu.

Przykłady aplikacji internetowych zależnych od formatu

Istnieje wiele przykładów usług internetowych wyświetlających zupełnie różne wersje dla różnych formatów. Robi to wyszukiwarka Google i Facebook. Warto wziąć pod uwagę zarówno wydajność (pobieranie zasobów, renderowanie stron), jak i ogólne wrażenia użytkownika.

W świecie aplikacji natywnych wielu deweloperów dostosowuje swoje działanie do klasy urządzenia. Na przykład Flipboard na iPadzie ma zupełnie inny interfejs niż Flipboard na iPhonie. Wersja na tablety jest zoptymalizowana pod kątem obsługi obu rąk i odwracania w poziomie, a telefonu do obsługi jedną ręką i do odwrócenia w pionie. Wiele innych aplikacji na iOS ma też znacznie odmienne wersje na telefony i tablety, np. Things (lista zadań) i Showyou (filmy społecznościowe) wymienione poniżej:

Znaczne dostosowanie interfejsu dla telefonu i tabletu.
Znaczne dostosowanie interfejsu do potrzeb telefonu i tabletu.

Metoda 1. Wykrywanie po stronie serwera

Na serwerze mamy znacznie ograniczone informacje o urządzeniu, z którym mamy do czynienia. Prawdopodobnie najbardziej przydatną dostępną wskazówką jest ciąg klienta użytkownika, który jest podawany w odpowiedzi na każde żądanie w nagłówku User-Agent. Dlatego ta sama metoda wykrywania w UA będzie działać tutaj. Projekty DeviceAtlas i WURFL już to robią (i dostarczają mnóstwo dodatkowych informacji na temat urządzenia).

Niestety każde z tych rozwiązań niesie ze sobą inne wyzwania. WURFL jest bardzo duży, ponieważ zawiera 20 MB pliku XML, co może powodować znaczne obciążenie serwera w przypadku każdego żądania. Istnieją projekty, które dzielą plik XML ze względu na wydajność. DeviceAtlas nie jest oprogramowaniem typu open source i wymaga płatnej licencji.

Istnieją również prostsze, bezpłatne alternatywy, takie jak projekt Detect Mobile Browsers. Wadą jest oczywiście to, że wykrywanie urządzeń będzie nieuchronnie mniej szczegółowe. Ponadto udostępnia rozróżnienie między urządzeniami mobilnymi i innymi niż mobilne, a obsługa tabletów w niewielkim zakresie zapewnia jedynie doraźny zestaw poprawek.

Podejście 2. Wykrywanie po stronie klienta

Dzięki wykrywaniu funkcji możemy sporo dowiedzieć się o przeglądarce i urządzeniu użytkownika. Musimy najpierw określić, czy urządzenie obsługuje dotyk i czy jest duży czy mały ekran.

Musimy wyznaczyć granice, aby rozróżnić małe i duże urządzenia dotykowe. A co z skrajnymi etui, takimi jak Galaxy Note 5"? Na ilustracji poniżej widać kilka popularnych urządzeń z Androidem i iOS (w odpowiadających im rozdzielczościach ekranu). Gwiazdka oznacza, że urządzenie jest lub może mieć podwójną gęstość. Choć gęstość pikseli może się podwoić, CSS nadal podaje te same rozmiary.

Krótka uwaga na temat pikseli w CSS: piksele CSS w internecie mobilnym nie są takie same jak piksele ekranu. W urządzeniach z iOS retina wprowadzono podwojenie gęstości pikseli (np. iPhone 3GS zamiast 4, iPad 2 vs 3). Przeglądarka UA Retina Mobile Safari nadal podaje w raportach tę samą szerokość urządzeń, co chroni przed łamaniem internetu. Ponieważ inne urządzenia (np. Androida) mają ekrany o wyższej rozdzielczości, tak samo się wyświetlają w przypadku różnych urządzeń.

Rozdzielczość urządzenia (w pikselach).
Rozdzielczość urządzenia (w pikselach).

Ważne jest jednak, aby rozważyć odbiór obrazów zarówno w orientacji pionowej, jak i poziomej. Nie chcemy ładować strony ponownie ani wczytywać dodatkowych skryptów przy każdej zmianie orientacji urządzenia, choć możemy zechcieć ją renderować w inny sposób.

Na tym diagramie kwadraty przedstawiają maksymalne wymiary każdego urządzenia, ponieważ nakładamy na obraz poziomy i pionowy (i wypełniając kwadrat):

Rozdzielczość pionowa + pozioma (w pikselach)
Rozdzielczość pionowa i pozioma (w pikselach)

Gdy ustawisz próg na 650px, zaklasyfikujemy iPhone'a, Galaxy Nexusa jako małego urządzenia, iPada i Galaxy Tab jako „tablet”. androgyniczna Galaxy Note jest w tym przypadku sklasyfikowana jako „telefon” i będzie miała układ telefonu.

Rozsądna strategia może więc wyglądać tak:

if (hasTouch) {
  if (isSmall) {
    device = PHONE;
  } else {
    device = TABLET;
  }
} else {
  device = DESKTOP;
}

Zobacz minimalny przykład metody wykrywania cech w praktyce.

Alternatywnym rozwiązaniem jest użycie funkcji sniffingu UA do wykrywania typu urządzenia. Mówiąc w skrócie, tworzysz zbiór danych heurystycznych i dopasowujesz je do parametru navigator.userAgent użytkownika. Pseudokod wygląda mniej więcej tak:

var ua = navigator.userAgent;
for (var re in RULES) {
  if (ua.match(re)) {
    device = RULES[re];
    return;
  }
}

Zobacz przykładową metodę wykrywania UA.

Uwaga na temat wczytywania po stronie klienta

Jeśli na swoim serwerze korzystasz z wykrywania UA, możesz określić, które elementy CSS, JavaScript i DOM mają być wyświetlane po otrzymaniu nowego żądania. Jeśli jednak przeprowadzasz wykrywanie po stronie klienta, sytuacja jest bardziej złożona. Masz do wyboru kilka opcji:

  1. Przekieruj użytkownika na adres URL przeznaczony dla określonego typu urządzenia, który zawiera wersję dla tego typu urządzeń.
  2. Dynamiczne ładowanie zasobów związanych z konkretnym typem urządzenia.

Pierwszy sposób jest prosty i wymaga przekierowania, takiego jak window.location.href = '/tablet'. Jednak do lokalizacji będą teraz dołączane informacje o tym typie urządzenia, więc warto wyczyścić URL za pomocą interfejsu History API. Niestety to działanie wymaga przekierowania, które może być powolne, zwłaszcza na urządzeniach mobilnych.

Drugi sposób jest nieco bardziej skomplikowany we wdrożeniu. Potrzebny jest mechanizm dynamicznego ładowania plików CSS i JS. (W zależności od przeglądarki) możesz nie być w stanie np. dostosowywać <meta viewport>. Nie ma też przekierowania, więc nie można zachować oryginalnego kodu HTML, który został wyświetlony. Oczywiście możesz manipulować nimi za pomocą JavaScriptu, ale w zależności od aplikacji może to być powolne lub niee.

Podejmowanie decyzji o kliencie lub serwerze

Oto kompromisy między tymi podejściami:

Klient wersji Pro:

  • Lepsze zabezpieczenia na przyszłość, ponieważ bazują na rozmiarach i możliwościach ekranów, a nie w UA.
  • Nie musisz stale aktualizować listy UA.

Pro Server:

  • Pełna kontrola nad tym, która wersja ma być wyświetlana na poszczególnych urządzeniach.
  • Większa wydajność: brak konieczności stosowania przekierowań klienta ani dynamicznego wczytywania.

Wolę zacząć od device.js i wykrywania po stronie klienta. Jeśli w miarę rozwoju aplikacji zauważysz, że przekierowanie po stronie klienta jest znaczną wadą wydajności, możesz łatwo usunąć skrypt device.js i zaimplementować wykrywanie UA na serwerze.

Przedstawiamy device.js

Biblioteka Device.js jest punktem wyjścia do semantycznego wykrywania urządzeń na podstawie zapytań o multimedia bez konieczności specjalnej konfiguracji po stronie serwera. Pozwala to zaoszczędzić czas i wysiłek potrzebny do analizowania ciągu znaków klienta użytkownika.

Chodzi o to, aby u góry strony <head> umieścić znaczniki przyjazne dla wyszukiwarek (linkrel=alternate), które wskazują, które wersje witryny chcesz udostępnić.

<link rel="alternate" href="http://foo.com" id="desktop"
    media="only screen and (touch-enabled: 0)">

Następnie możesz samodzielnie wykonać wykrywanie UA po stronie serwera i przekierowywanie wersji albo użyć skryptu device.js, aby wykonać przekierowanie po stronie klienta z wykorzystaniem funkcji.

Więcej informacji znajdziesz na stronie projektu device.js oraz na temat fałszywej aplikacji, która używa device.js do przekierowania po stronie klienta.

Zalecenie: MVC z widokami na poszczególne formaty

Teraz pewnie myślisz, że proponuję utworzyć 3 zupełnie odrębne aplikacje, po jednej na każdy typ urządzenia. Nie! Najważniejsze jest udostępnianie kodu.

Prawdopodobnie korzystasz ze platformy podobnej do MVC, np. Backbone, Ember itp. Jeśli zdarzyło Ci się już stosować taką zasadę, wiesz, że interfejs użytkownika (warstwa widoku danych) powinien być oddzielony od logiki (warstwy modelu). Jeśli dopiero zaczynasz, na początek zapoznaj się z tymi zasobami o MVC i MVC w języku JavaScript.

Historia konwersji z różnych urządzeń doskonale wpasowuje się w dotychczasową strukturę MVC. Widoki można łatwo przenieść do osobnych plików, tworząc niestandardowy widok dla każdego typu urządzenia. Potem możesz serwować ten sam kod wszystkim urządzeniom z wyjątkiem warstwy widoku.

MVC na różnych urządzeniach.
MVC na różnych urządzeniach.

Twój projekt może mieć następującą strukturę (oczywiście możesz wybrać strukturę, która najlepiej pasuje do Twojej aplikacji):

modele/ (modele współdzielone) item.js item-collection.js

kontrolery/ (kontrolery współdzielone) item-controller.js

wersji/ (treści dostosowane do urządzenia) tablet/ komputer/ telefon/ (kod przypisany do telefonu) style.css index.html views/ item.js item-list.js

Taka struktura pozwala w pełni kontrolować, jakie zasoby są wczytywane w poszczególnych wersjach, ponieważ dla każdego urządzenia istnieje niestandardowy kod HTML, CSS i JavaScript. To bardzo zaawansowane rozwiązanie, które może prowadzić do powstania najefektywniejszego i najbardziej wydajnego sposobu tworzenia treści na potrzeby sieci na różnych urządzeniach, bez konieczności korzystania z takich sztuczek jak obrazy adaptacyjne.

Po uruchomieniu ulubionego narzędzia do kompilacji zminifikuj wszystkie skrypty JavaScript i CSS do pojedynczych plików, aby szybciej się ładowały. Twój produkcyjny kod HTML będzie wyglądał mniej więcej tak (na telefonie za pomocą parametru device.js):

<!doctype html>
<head>
  <title>Mobile Web Rocks! (Phone Edition)</title>

  <!-- Every version of your webapp should include a list of all
        versions. -->
  <link rel="alternate" href="http://foo.com" id="desktop"
      media="only screen and (touch-enabled: 0)">
  <link rel="alternate" href="http://m.foo.com" id="phone"
      media="only screen and (max-device-width: 650px)">
  <link rel="alternate" href="http://tablet.foo.com" id="tablet"
      media="only screen and (min-device-width: 650px)">

  <!-- Viewport is very important, since it affects results of media
        query matching. -->
  <meta name="viewport" content="width=device-width">

  <!-- Include device.js in each version for redirection. -->
  <script src="device.js"></script>

  <link rel="style" href="phone.min.css">
</head>
<body>
  <script src="phone.min.js"></script>
</body>

Zwróć uwagę, że zapytanie o multimedia (touch-enabled: 0) jest niestandardowe (implementowane tylko w Firefoksie za prefiksem dostawcy moz), ale obsługiwane prawidłowo (dzięki Modernizr.touch) przez device.js.

Zastąpienie wersji

Wykrywanie urządzenia może pójść nie tak, a w niektórych przypadkach użytkownik może preferować sprawdzenie układu tabletu na telefonie (np. Galaxy Note). Dlatego ważne jest, aby użytkownicy sami sami wybierali wersję witryny, z której chcą korzystać ręcznie.

Zwykle polega to na podaniu linku do wersji mobilnej z poziomu wersji na komputer. Jest to wystarczająco łatwe do wdrożenia, ale device.js obsługuje tę funkcję za pomocą parametru GET device.

Kończenie

Podsumowując, tworząc jednostronicowe UI na różnych urządzeniach, które nie pasują do elastycznego projektowania stron, zrób to:

  1. Wybierz zestaw klas urządzeń do obsługi i kryteria klasyfikowania urządzeń według klas.
  2. Zaprojektuj aplikację MVC w taki sposób, aby wyraźnie oddzielić potencjalne problemy i oddzielić widoki od reszty bazy kodu.
  3. Do wykrywania klasy urządzenia po stronie klienta używaj pliku device.js.
  4. Gdy wszystko będzie gotowe, spakuj skrypt i arkusze stylów do poszczególnych klas urządzenia.
  5. Jeśli występuje problem z działaniem przekierowań po stronie klienta, zrezygnuj z tagu device.js i przełącz się na wykrywanie UA po stronie serwera.