התאמה של אתר HTML5 לנייד

מבוא

פיתוח לאינטרנט לנייד הוא נושא חם בימים אלה. השנה, בפעם הראשונה, נמכרו יותר סמארטפונים ממחשבים אישיים. יותר ויותר משתמשים גולשים באינטרנט דרך מכשירים ניידים, ולכן חשוב מאוד שמפתחים יבצעו אופטימיזציה של האתרים שלהם לדפדפנים בניידים.

שדה הקרב של הניידים הוא עדיין טריטוריה לא מוכרת להרבה מפתחים. להרבה אנשים יש אתרים ישנים שלא מותאמים בכלל למשתמשים בנייד. במקום זאת, האתר תוכנן בעיקר לגלישה בדפדפן מחשב, והוא לא מוצג בצורה טובה בדפדפנים לנייד. האתר הזה (html5rocks.com) לא יוצא דופן. כשהשקנו את האתר, לא השקענו הרבה מאמץ בגרסה לנייד.

יצירת אתר html5rocks.com שמותאם לניידים

כדי לתרגל, חשבתי שיהיה מעניין לקחת את html5rocks (אתר HTML5 קיים) ולהוסיף לו גרסה שמותאמת לניידים. הדבר העיקרי שהעסיק אותי היה כמות העבודה המינימלית שנדרשת כדי לטרגט סמארטפונים. המטרה של התרגיל שלי לא הייתה ליצור אתר חדש לגמרי לנייד ולתחזק שני בסיסי קוד. זה היה לוקח נצח והיה בזבוז זמן עצום. כבר הגדרנו את מבנה האתר (תגי העיצוב). היה לנו עיצוב (CSS). הפונקציונליות העיקרית (JS) הייתה שם. הנקודה היא שהרבה אתרים נמצאים באותה סירה.

במאמר הזה נסביר איך יצרנו גרסה לניידים של html5rocks שעברה אופטימיזציה למכשירי Android ו-iOS. כדי לראות את ההבדל, פשוט טוענים את html5rocks.com במכשיר שתומך באחת ממערכות ההפעלה האלה. אין הפניות ל-m.html5rocks.com או לכל מיני שטויות אחרות מהסוג הזה. אתם מקבלים את html5rocks כמו שהוא… עם היתרון הנוסף של משהו שנראה נהדר ופועל היטב במכשיר נייד.

מחשב html5rocks.com Mobile html5rocks.com
html5rocks.com במחשב (מימין) ובנייד (משמאל)

שאילתות מדיה ב-CSS

HTML4 ו-CSS2 תומכים בגיליונות סגנונות תלויי מדיה כבר זמן מה. לדוגמה:

<link rel="stylesheet" media="print" href="printer.css">

יטרגט מכשירי הדפסה ויספק סגנון ספציפי לתוכן הדף כשהוא מודפס. ב-CSS3 הרעיון של סוגי מדיה מתקדם עוד יותר, והפונקציונליות שלהם משופרת באמצעות שאילתות מדיה. שאילתות מדיה מרחיבות את השימושיות של סוגי המדיה בכך שהן מאפשרות תיוג מדויק יותר של גיליונות סגנונות. כך אפשר להתאים אישית את הצגת התוכן למגוון ספציפי של מכשירים להצגת מידע בלי לשנות את התוכן עצמו. זה נשמע מושלם לפריסה קיימת שצריך לשנות.

אפשר להשתמש בשאילתות מדיה במאפיין media של גיליונות הסגנונות החיצוניים כדי לטרגט רוחב מסך, רוחב מכשיר, כיוון וכו'. לרשימה המלאה, עיינו במפרט שאילתות המדיה של W3C.

טירגוט לפי גודל מסך

בדוגמה הבאה, phone.css יחול על מכשירים שהדפדפן מחשיב כ"מכשירים ניידים" או על מכשירים עם מסכים ברוחב של עד 320 פיקסלים.

 <link rel='stylesheet'
  media='handheld, only screen and (max-device-width: 320px)' href='phone.css'>

אם מוסיפים את מילת המפתח "only" לפני שאילתות מדיה, דפדפנים שלא תואמים ל-CSS3 יתעלמו מהכלל.

הדוגמה הבאה תטרגט מסכים בגודל של 641 עד 800 פיקסלים:

 <link rel='stylesheet'
  media='only screen and (min-width: 641px) and (max-width: 800px)' href='ipad.css'>

שאילתות מדיה יכולות להופיע גם בתוך תגי <style> מוטבעים. הדוגמה הבאה מטרגטת סוגי מדיה של all כשהם בכיוון לאורך:

 <style>
  @media only all and (orientation: portrait) { ... }
 </style>

media="handheld"

אנחנו צריכים לעצור לרגע ולדבר על media="handheld". העובדה היא שמערכות Android ו-iOS מתעלמות מ-media="handheld". הטענה היא שהמשתמשים יפספסו את התוכן האיכותי שמסופק על ידי גיליונות סגנונות שמטרגטים את media="screen", ושהמפתחים פחות נוטים לתחזק גרסה של media="handheld" באיכות נמוכה יותר. לכן, כחלק מהמוטו "אינטרנט מלא", רוב הדפדפנים המודרניים בסמארטפונים פשוט מתעלמים מגיליונות סגנונות למכשירים ניידים.

התכונה הזו מתאימה במיוחד לטירגוט מכשירים ניידים, אבל דפדפנים שונים הטמיעו אותה בדרכים שונות:

  • חלק מהם קוראים רק את גיליון הסגנונות של מכשירים ניידים.
  • חלק מהדפדפנים קוראים רק את גיליון הסגנונות למכשירים ניידים, אם יש כזה, אבל אם אין, הם משתמשים בגיליון הסגנונות למסך כברירת מחדל.
  • חלק מהדפדפנים קוראים גם את גיליון הסגנונות למכשירים ניידים וגם את גיליון הסגנונות למסכים.
  • חלק מהם קוראים רק את גיליון הסגנונות של המסך.

‫Opera Mini לא מתעלם מ-media="handheld". כדי ש-Windows Mobile יזהה את media="handheld", צריך להשתמש באותיות רישיות בערך המאפיין של המדיה בגיליון הסגנונות של המסך:

 <!-- media="handheld" trick for Windows Mobile -->
 <link rel="stylesheet" href="screen.css" media="Screen">
 <link rel="stylesheet" href="mobile.css" media="handheld">

איך משתמשים בשאילתות מדיה ב-html5rocks

באתר html5rocks לנייד נעשה שימוש נרחב בשאילתות מדיה. הם אפשרו לנו לשנות את הפריסה בלי שנצטרך לבצע שינויים משמעותיים בתגי העיצוב של התבנית של Django… זה ממש הציל אותנו! בנוסף, התמיכה בהם בדפדפנים השונים די טובה.

בקטע <head> של כל דף יופיעו גיליונות הסגנונות הבאים:

 <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 תמיד הגדיר את המראה והתחושה העיקריים של html5rocks.com, אבל עכשיו אנחנו מיישמים סגנונות חדשים (mobile.css) לרוחבי מסך מתחת ל-800 פיקסלים. שאילתת המדיה שלו מכסה סמארטפונים (‎~320px) ואייפדים (‎~768px). התוצאה: אנחנו משנים בהדרגה את הסגנונות ב-base.css (רק לפי הצורך) כדי שהדברים ייראו טוב יותר בנייד.

חלק מהשינויים בסגנון ש-mobile.css אוכף:

  • האפשרות הזו מקטינה את הרווחים הלבנים או את המרווחים הפנימיים באתר. במסכים קטנים, כל פיקסל חשוב.
  • הסרה של :hover מדינות. הם אף פעם לא יוצגו במכשירים עם מסך מגע.
  • משנה את הפריסה לעמודה אחת. בהמשך נרחיב בנושא הזה.
  • הסרת ה-box-shadow מסביב ל-div של מאגר התגים הראשי של האתר. צללים גדולים של תיבות פוגעים בביצועים של הדף.
  • השתמשתי במודל CSS flex box‏ box-ordinal-group כדי לשנות את הסדר של כל קטע בדף הבית. אפשר לראות שהקטע "LEARN BY MAJOR HTML5 FEATURE GROUPS" מופיע לפני הקטע "TUTORIALS" בדף הבית, אבל אחריו בגרסה לנייד. הסדר הזה היה הגיוני יותר לנייד ולא דרש שינויים בתגי העיצוב. ‫CSS flexbox FTW!
  • הסרת opacity שינויים. שינוי ערכי אלפא פוגע בביצועים בנייד.

מטא תגים לנייד

‫Mobile WebKit תומך בכמה תכונות שמשפרות את חוויית הגלישה של המשתמשים במכשירים מסוימים.

הגדרות של אזור התצוגה

הגדרת המטא הראשונה (וההגדרה שתשתמשו בה הכי הרבה) היא המאפיין של אזור התצוגה. הגדרת אזור תצוגה מאפשרת לדפדפן לדעת איך התוכן צריך להתאים למסך המכשיר, ומציינת שהאתר מותאם לניידים. לדוגמה:

 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">

מורה לדפדפן להגדיר את אזור התצוגה לרוחב המכשיר עם קנה מידה ראשוני של 1. הדוגמה הזו גם מאפשרת לשנות את מרחק התצוגה, דבר שעשוי להיות רצוי באתר אבל לא באפליקציית אינטרנט. אפשר למנוע את שינוי מרחק התצוגה באמצעות user-scalable=no או להגביל את קנה המידה לרמה מסוימת:

‫
 <meta name=viewport
  content="width=device-width, initial-scale=1.0, minimum-scale=0.5 maximum-scale=1.0">

ב-Android, המטא תג של אזור התצוגה מורחב ומאפשר למפתחים לציין את רזולוציית המסך שהאתר פותח בשבילה:

 <meta name="viewport" content="target-densitydpi=device-dpi">

הערכים האפשריים של target-densitydpi הם device-dpi,‏ high-dpi,‏ medium-dpi,‏ low-dpi.

אם אתם רוצים לשנות את דף האינטרנט לצפיפויות מסך שונות, השתמשו בשאילתת המדיה -webkit-device-pixel-ratio ב-CSS או במאפיין window.devicePixelRatio ב-JavaScript, ואז הגדירו את המאפיין target-densitydpi meta ל-device-dpi. כך מערכת Android לא תבצע שינוי קנה מידה בדף האינטרנט, ותוכלו לבצע את ההתאמות הנדרשות לכל צפיפות באמצעות CSS ו-JavaScript.

מידע נוסף על טירגוט לפי רזולוציות של מכשירים זמין במסמכי התיעוד של WebView ב-Android.

גלישה במסך מלא

יש שני ערכי מטא אחרים שספציפיים ל-iOS. apple-mobile-web-app-capable ו-apple-mobile-web-app-status-bar-style יציגו את תוכן הדף במצב מסך מלא כמו באפליקציה, ושורת הסטטוס תהיה שקופה:

 <meta name="apple-mobile-web-app-capable" content="yes">
 <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

מידע נוסף על כל אפשרויות המטא הזמינות מופיע במאמרי העזרה של Safari.

סמלים במסך הבית

במכשירי iOS ו-Android אפשר גם להשתמש ב-rel="apple-touch-icon" (iOS) וב-rel="apple-touch-icon-precomposed" (Android) לקישורים. התגים האלה יוצרים סמל נוצץ דמוי אפליקציה במסך הבית של המשתמש כשהוא מוסיף את האתר שלכם לסימניות:

 <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" />

איך html5rocks משתמש במטא תגים לנייד

כדי לחבר את כל החלקים, הנה קטע קוד מהקטע <head> ב-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>

פריסה אנכית

במסכים קטנים, הרבה יותר נוח לגלול אנכית מאשר אופקית. במכשירים ניידים, עדיף להציג את התוכן בפריסה אנכית של עמודה אחת. ב-html5rocks, השתמשנו בשאילתות מדיה של CSS3 כדי ליצור פריסה כזו. שוב, בלי לשנות את תגי העיצוב.

אינדקס המדריכים. מדריך. דף התכונות של HTML5. דף פרופיל המחבר.
פריסה אנכית של עמודה אחת בכל האתר.

אופטימיזציה לניידים

רוב האופטימיזציות שביצענו הן דברים שהיינו צריכים לעשות מלכתחילה. למשל, צמצום מספר הבקשות לאחזור מהרשת, דחיסת JS/CSS, דחיסת gzip (מגיעה בחינם ב-App Engine) וצמצום מניפולציות DOM. השיטות האלה הן שיטות מומלצות נפוצות, אבל לפעמים מתעלמים מהן כשממהרים להשיק אתר.

הסתרה אוטומטית של סרגל הכתובות

בדפדפנים בנייד יש פחות שטח מסך מאשר בדפדפנים במחשב. גרוע מכך, בפלטפורמות שונות, לפעמים מופיע סרגל כתובות גדול וישן בחלק העליון של המסך… גם אחרי שהדף נטען.

דרך קלה אחת להתמודד עם זה היא לגלול את הדף באמצעות JavaScript. אפילו גלילה של פיקסל אחד תגרום לסרגל הכתובות המעצבן להיעלם. כדי להסתיר את סרגל הכתובות ב-html5rocks, צירפתי onload גורם מטפל באירועים לאובייקט window וגללתי את הדף אנכית בפיקסל אחד:

סרגל הכתובות.
סרגל הכתובות המכוער תופס מקום במסך.
  // Hides mobile browser's address bar when page is done loading.
  window.addEventListener('load', function(e) {
    setTimeout(function() { window.scrollTo(0, 1); }, 1);
  }, false);

בנוסף, עטפנו את המאזין הזה במשתנה התבנית is_mobile, כי הוא לא נחוץ במחשב.

הפחתת הבקשות לאחזור מהרשת וחיסכון ברוחב הפס

עובדה ידועה היא שהפחתת מספר בקשות ה-HTTP יכולה לשפר מאוד את הביצועים. במכשירים ניידים יש הגבלה נוספת על מספר החיבורים בו-זמנית שהדפדפן יכול לבצע, כך שאתרים לנייד ירוויחו עוד יותר מהפחתת הבקשות המיותרות האלה. בנוסף, חשוב מאוד לחסוך כל בייט, כי רוחב הפס בטלפונים בדרך כלל מוגבל. יכול להיות שאתם גורמים למשתמשים להוציא כסף מיותר.

הנה כמה מהגישות שבהן השתמשנו כדי לצמצם את הבקשות לאחזור מהרשת ולהפחית את רוחב הפס ב-html5rocks:

  • הסרת רכיבי iframe – רכיבי iframe הם איטיים! חלק גדול מהזמן שלקח לדפים להיטען נבע מווידג'טים של צד שלישי לשיתוף (Buzz, ‏ Google Friend Connect, ‏ Twitter, ‏ Facebook) בדפי ההדרכה. ממשקי ה-API האלה נכללו באמצעות תגי <script> ויוצרים רכיבי iframe שמאטים את מהירות הדף. הווידג'טים הוסרו מהנייד.

  • display:none – במקרים מסוימים, הסתרנו תגי עיצוב אם הם לא התאימו לפרופיל לנייד. דוגמה טובה לכך היא ארבע התיבות המעוגלות בחלק העליון של דף הבית:

כפתורים בצורת תיבה בדף הבית.
כפתורים בצורת תיבה בדף הבית.

הם חסרים באתר לנייד. חשוב לזכור שהדפדפן עדיין שולח בקשה לכל סמל, למרות שהמאגר שלו מוסתר באמצעות display:none. לכן, לא מספיק רק להסתיר את הלחצנים האלה. לא רק שזה יבזבז רוחב פס, אלא שהמשתמש אפילו לא יראה את התוצאות של רוחב הפס המבוזבז הזה. הפתרון היה ליצור משתנה בוליאני is_mobile בתבנית Django כדי להשמיט קטעי HTML באופן מותנה. כשהמשתמש צופה באתר במכשיר חכם, הכפתורים לא מוצגים.

  • מטמון האפליקציה – לא רק שהוא מספק לנו תמיכה במצב אופליין, אלא הוא גם מאפשר הפעלה מהירה יותר.

  • דחיסת CSS/JS – אנחנו משתמשים ב-YUI compressor במקום ב-Closure compiler, בעיקר כי הוא מטפל גם ב-CSS וגם ב-JS. אחת הבעיות שנתקלנו בהן הייתה ששאילתות מדיה מוטבעות (שאילתות מדיה שמופיעות בתוך גיליון סגנונות) נכשלו ב-YUI compressor 2.4.2 (ראו את הבעיה הזו). הבעיה נפתרה באמצעות YUI Compressor 2.4.4 ואילך.

  • שימוש ב-CSS image sprites כשאפשר.

  • השתמשנו ב-pngcrush לדחיסת תמונות.

  • השתמשו ב-dataURI לתמונות קטנות. קידוד Base64 מגדיל את התמונה בכ-30%או יותר, אבל חוסך את הבקשה לאחזור מהרשת.

  • טעינה אוטומטית של חיפוש בהתאמה אישית של Google באמצעות תג סקריפט יחיד במקום טעינה דינמית באמצעות google.load(). האפשרות השנייה שולחת בקשה נוספת.

<script src="//www.google.com/jsapi?autoload={"modules":[{"name":"search","version":"1"}]}"> </script>
  • הוספנו לכל דף את Modernizr ואת הכלי שלנו לעיצוב קוד, גם אם לא השתמשנו בהם. ‫Modernizr הוא כלי נהדר, אבל הוא מריץ הרבה בדיקות בכל טעינה. חלק מהבדיקות האלה מבצעות שינויים יקרים ב-DOM ומאטות את טעינת הדף. עכשיו אנחנו כוללים את הספריות האלה רק בדפים שבהם הן באמת נחוצות. ‫-2 בקשות :)

שינויים נוספים לשיפור הביצועים:

  • העברנו את כל ה-JS לתחתית הדף (כשאפשר).
  • הוסרו תגי <style> מוטבעים.
  • חיפושים במטמון של ה-DOM וצמצום השינויים ב-DOM – בכל פעם שמשנים את ה-DOM, הדפדפן מבצע עיצוב מחדש. עיצוב מחדש של פריסה עולה אפילו יותר במכשיר נייד.
  • העברת קוד מיותר מצד הלקוח לשרת. באופן ספציפי, הבדיקה כדי להגדיר את סגנון הניווט של הדף הנוכחי: 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'; } }
  • רכיבים עם רוחב קבוע הוחלפו ב-width:100% או ב-width:auto גמישים.

מטמון של אפליקציה

הגרסה לנייד של html5rocks משתמשת במטמון האפליקציה כדי לזרז את הטעינה הראשונית ולאפשר למשתמשים לקרוא תוכן אופליין.

כשמטמיעים את AppCache באתר, חשוב מאוד לא לשמור במטמון את קובץ המניפסט (באופן מפורש בקובץ המניפסט עצמו או באופן משתמע באמצעות כותרות כבדות של בקרת מטמון). אם המניפסט נשמר במטמון של הדפדפן, קשה מאוד לנפות באגים. ב-iOS וב-Android הקובץ הזה נשמר במטמון בצורה טובה, אבל אין דרך נוחה לנקות את המטמון כמו בדפדפנים במחשב.

כדי למנוע את השמירה במטמון באתר שלנו, קודם כל מגדירים את App Engine כך שלעולם לא ישמור במטמון קובצי מניפסט:

- url: /(.*\.(appcache|manifest))
  static_files: \1
  mime_type: text/cache-manifest
  upload: (.*\.(appcache|manifest))
  expiration: "0s"

שנית, השתמשנו ב-JS API כדי להודיע למשתמש כשהורדת מניפסט חדש הסתיימה. הם מתבקשים לרענן את הדף:

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);

כדי לחסוך בתנועה ברשת, כדאי לשמור על מניפסט פשוט. כלומר, אל תציינו כל דף באתר. פשוט צריך לציין את קובצי התמונות, ה-CSS וה-JavaScript החשובים. הדבר האחרון שאתם רוצים לעשות הוא לאלץ את הדפדפן בנייד להוריד מספר גדול של נכסים בכל עדכון של appcache. במקום זאת, זכרו שהדפדפן ישמור במטמון באופן משתמע דף HTML כשהמשתמש יבקר בו (והוא כולל מאפיין <html manifest="...">).