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

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

  • הפחתת הרווחים הלבנים או המרווחים הפנימיים הנוספים באתר. במסכים קטנים, המקום מוגבל!
  • הסרה של :hover מצבים. הם אף פעם לא יוצגו במכשירי מגע.
  • שינוי הפריסה לעמודה אחת. בהמשך נסביר על כך.
  • הסרת ה-box-shadow סביב ה-div הראשי של מאגר האתר. צללי תיבות גדולים פוגעים בביצועי הדף.
  • השתמשו במודל box-ordinal-group של תיבות גמישות ב-CSS כדי לשנות את הסדר של כל קטע בדף הבית. תוכלו לראות שהקטע 'לימוד לפי קבוצות עיקריות של תכונות HTML5' מופיע לפני הקטע 'מדריכים' בדף הבית, אבל אחריו בגרסה לנייד. הסדר הזה הגיוני יותר בנייד ולא נדרש בו שינוי ברכיבי ה-Markup. 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.

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

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

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

יש עוד שני ערכי מטא שהם iOS-sfic. 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 כדי ליצור פריסה כזו. שוב, בלי לשנות את ה-Markup.

אינדקס של הדרכות. מדריך. דף התכונות של 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:

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

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

לחצני תיבות בדף הבית.
לחצני תיבות בדף הבית.

הם חסרים באתר לנייד. חשוב לזכור שהדפדפן עדיין שולח בקשה לכל סמל, למרות שהמאגר שלהם מוסתר באמצעות 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 sprites של תמונות כשהדבר אפשרי.

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

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

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

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

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

  • העברנו את כל ה-JavaScript לתחתית הדף (אם אפשר).
  • הוסרו תגי <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.

Application Cache

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

כשמטמיעים את 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 והתמונות החשובים. הדבר האחרון שתרצו לעשות הוא לאלץ את הדפדפן בנייד להוריד מספר גדול של נכסים בכל עדכון של 'אחסון מטמון לאפליקציות'. במקום זאת, חשוב לזכור שהדפדפן יאחסן בדפים מטמון באופן משתמע דף HTML כשהמשתמש יבקר בו (והוא כולל מאפיין <html manifest="...">).