יום רביעי, 20 ביוני 2012

קללת התאימות לאחור של Internet Explorer


עדכון 20 יוני: פוסט זה עבר שיפור כללי. תודה לר' שהתקילה אותי בשאלות ועזרה לי לסדר את הנושא יותר טוב בראש  - סדר שאני מקווה שישתקף בשינוי שביצעתי.

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

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

חלק גדול ממה שאכתוב פה על Quirks Mode נכון גם ל Firefox או אופרה - אבל עד היום לא נתקלתי באף אחד שהתעסק בנושאים אלו בדפדפן שאינו IE - ולכן אדבר רק על IE.

אם אתם לא כותבים קוד שנדרש לרוץ ב IE8 או גרסאות ישנות יותר, או שאתם יכולים פשוט להגדיר את Chrome Frame [א] שיפתור לכם את הבעיות - רוב הבעיות שיוצגו פה הן כנראה לא בעיות שלכם. אלו נושאים שגרמו סבל ללא מעט אנשים.
המניע לעיסוק המחודש בנושא זה הוא השחרור הקרוב של IE10 (במסגרת Windows 8).
בסוף הפוסט כללתי פרטים גם על גרסה זו.

נתחיל בשאלה, "מדוע מייקרוסופט תומכת לאחור בדפי אינטרנט ישנים ועקומים?".


הערכה של ג'ון רזיג על היחס עלות / תועלת בתמיכה בדפדפנים. פילוח השוק של הדפדפנים שונה ממה שאני מכיר. מקור: http://www.manning.com/resig/resig_meapch1.pdf 


מדוע מייקרוסופט תומכת לאחור בדפי אינטרנט ישנים ועקומים?
למייקרוסופט יש מדיניות ארוכת שנים של Backward Compatibility. בזמן שמתחרים כאלו ואחרים שברו את ה Backward Compatibility (אשתמש מעתה בקיצור המשעשע BC) של המוצרים שלהם, וכך שברו את ליבותיהם של אנשי ה IT שנאלצו להתמודד עם הצרה - מייקרוסופט תמיד הייתה שם בשבילם ותמכה לאחור. אפשר לומר שBC הוא Value Proposition או אפילו ערך מרכזי של החברה. ערך זה מתורגם כמובן למעשים:

Microsoft will offer a minimum of 10 years of support for Business and Developer products. Mainstream Support for Business and Developer products will be provided for 5 years or for 2 years after the successor product (N+1) is released, whichever is longer. Microsoft will also provide Extended Support for the 5 years following Mainstream support or for 2 years after the second successor product (N+2) is released, whichever is longer. Finally, most Business and Developer products will receive at least 10 years of online self-help support.
מקור

הנה כמה דוגמאות:
  • Silverlight 5, טכנולוגיה שנראה שמייקרוסופט רוצה לזנוח - תיתמך עד 2021.
  • Windows Vista הבעייתית תיתמך עד 2017. 5 שנים נוספות מעכשיו.
  • IE8, שהמהדורה אחרונה שלו (עם Bing כ Default) שוחררה ב 2010 - ייתמך עד 2020. 
  • כיצד ניתן להסביר שמייקרוסופט הפסיקה לתמוך בIE6 המפורסם כבר לפני שנה?? האא... הוא שוחרר בשנת 2001.
שלא תבינו לא נכון: כמובן שיש ערך עסקי משמעותי בתמיכה לאחור. עבור רוב המשתמשים מוצרים ששוחררו לפני עשור (נאמר Office 2000) הם מספיק טובים ושדרוג הם כאב-ראש ועלויות מיותרות. העניין הוא שיש ערך כספי, לעתים רב, בשחרור גרסאות חדשות (למשל, אופיס) ואז נוצרת קשת של גרסאות שונות שזמינות בשוק - ומי שמפתח מוצר צד שלישי נאלץ להתאים את עצמו למספר גרסאות.

"העולם שלנו לא נעשה איטי יותר - להיפך". שחרור של גרסה פעם בשלוש-ארבע שנים יצאה לה מהאופנה וברגע שמייקרוסופט מתחילה לשחרר מוצרים, למשל את IE, פעם בשנה - 10 שנות תמיכה היא תקורה משמעותית מאוד להתמודד איתה.

בשנת 2020 מייקרוסופט עתידה לתמוך ב 11 גרסאות שונות של אינטרנט אקספלורר: IE8, IE9, IE10, IE11, IE12, IE13, IE14, IE15, IE16, IE17 ו IE18 [ד]. בסוף פוסט זה תראו שכל גרסה של IE היא סיפור בפני עצמו.

כך עובדים ערכים של חברה: הם מחלחלים לכל פינה. לטוב ולרע.


ה"תאימות לאחור" מתחילה להסתבך
עד כמה שידוע לי הגרסה הראשונה של IE שידעה לרנדר (render) דף HTML ביותר מצורה אחת היא IE6. מייקרוסופט קוראת למודים אלו Document Modes, אני אשתמש בפוסט זה בשם Rendering Mode שנראה לי פחות מבלבל. החלק בדפדפן שאחראי על ציור הדף נקרא Rendering Engine או Layout Engine. הוא מפענח את ה HTML וה CSS, בונה בזיכרון את ה DOM מה-HTML ו Style Tree מה-CSS, מרכיב אותם אחד על השני ומצייר את התוצאה על המסך. המנוע בו IE ל Windows משתמש נקרא Trident (= קלשון, בעברית).



מנוע הרינדור של IE6 הוסיף תמיכה תקנית ב Box Model (הוסבר בפוסט הקודם) - שינוי די משמעותי ש"שובר" דפים שעבדו ב Box Model הישן. על מנת לתמוך "גם וגם" הוא הגדיר 2 מודים:
  • IE6 Standards Mode - שהציג את ה Box Model בצורה התקנית.
  • Quirks Mode - שהציג את הדפים כפי שעבדו בגרסה הקודמת (IE 5.5) - ע"פ ה Box Model של IE.


וכיצד הדפדפן יודע אם מדובר בדף שנכתב עם Box Model "ישן" או "חדש"?
הבעיה הייתה לא רק של IE, אלא גם של FF ואופרה, ו W3C הגדיר פתרון: שימוש בתוית בשם DOCTYPE.
הפתרון, בהפשטה מסוימת, הוא כזה: אם הדף הוא מסוג "חדש", כלומר פועל ע"פ הסטנדרטים של W3C בכל הנוגע ל Box Model ובכלל - הוא יסומך בעזרת תוית DOCTYPE, שממוקמת בראש הדף, מעל תג ה HTML.

אם לדף לא הייתה תגית DOCTYPE - מניחים שמדובר בדף ישן מאוד ולכן IE יריץ אותו ב Quirks Mode. גישה זו שמרה על תאימות טובה לאחור, מכיוון שלא היה צריך לבצע שינויים בדפים ישנים: פשוט לא הייתה בהם תגית DOCTYPE [ה].

יש לציין ש IE6 Standards Mode הוא המוד של IE6 לתמיכה בסטנדרטים, על אף שהתמיכה שהוא מספק היא חלקית למדי.


IE7 שיפר את מנוע הרינדור. הוא תיקן סטיות רבות מתקן ה CSS שהמפורסמת בהן היא תמיכה בשקיפות של קובצי PNG.
מוד הרינדור של IE6 פשוט שופר והוחלף והוא נקרא IE7 Standards Mode.









IE8 כבר עבר את מבחן ה ACID2 (לבדיקת תאימות של דפדפנים לסטנדרטים), אחרי שנים ש IE נכשל במבחן בנחרצות. הוא הוסיף תמיכה, כמעט מלאה, ב CSS 2.1.

CSS 2.1 הוסיף מורכבות חדשה. הוא הגדיר את הדרך בה נקבע הגובה של תאים בטבלה, דרך ששונה ממה ש IE נהג לחשב. שימוש בטבלאות "בלתי נראות" לצורך עימוד הדף היה מאוד נפוץ באותה תקופה - ודפים שנכתבו עבור IE6 או IE7 והוצגו ע"פ הצורה הסטנדרטית של CSS 2.1 - שובשו קשות.


W3C שוב בא לעזרה והגדיר תקן ל Almost Standards Mode, מוד בו הדפדפן מציג דף ע"פ התקן, חוץ מחישוב גובה התאים בטבלה - שמחושב בצורה בה IE נהג לחשב אותה בעבר.
מוד זה נתמך ב IE כמובן, אך גם על גבי פיירפוקס וכרום.


וכיצד הדפדפן יודע "עבור איזה דפדפן נכתב דף ה HTML שמורץ כרגע"?
- W3C הוסיפו הגדרת DTD (אימות מבנה הדף) על תג ה DOCTYPE. סימון Strict Mode מעיד על תמיכה בתקן החדש ו Loose או Transitional הם מודים "רכים" שעובדים ע"פ ההגדרות הישנות.


בניגוד להוספת ה DOCTYPE המקורי, שדף ישן לא דרש שינוי (מכיוון שאין לו Doctype) - במקרה זה אם לא מצוין DTD ההנחה היא שהדף הוא "חדש".


מייקרוסופט, שמחויבותה לתאימות לאחור - גבוהה, החליטה להתעלם מהתקן ולהתייחס לDOCTYPE ללא DTD כדפים ישנים (כלומר Almost Standards Mode) אולם החלטתה יצרה מהומה לא קטנה שבסופה היא התקפלה והחליטה לפעול ע"פ התקן. על פניו, נראה שהגישה של מייקרוסופט הייתה עדיפה מקומית, אך לאורך זמן קיומו של תקן אחיד הוא חשוב אפילו יותר.

הצורך לחזור ולשנות את ה Markup (או קוד, אם מדובר בדף דינאמי) של דפים קיימים על מנת שיוצגו בצורה טובה היה בלתי נסבל עבור מייקרוסופט. מייקרוסופט התמודדה עם הבעיה בעזרת הצגה של תווית META חדשה (שניתן להגדיר גם ברמת פרוטוקול ה HTTP) שדורסת את ההחלטה של ה DOCTYPE לגבי המוד בו יש לרנדר את הדף. Application Servers היו יכולים בדרך זו לשתול את התגית החדשה ברמת ה HTML HEAD או ה HTTP וכך לגרום לדפים שתוכננו עבור IE7 להתרנדר ב Almost Standards Mode - כך שייראו היטב. התגית ה META נראית כך:
<meta http-equiv="X-UA-Compatible" content="IE=7" />

ל IE8 כבר יש אלגוריתם לא פשוט לבחירה ב Rendering Mode (מתוך ה 4 הקיימים). תוכלו למצוא תרשים זרימה וועוד מקור המתארים את האלגוריתם.


עוד השפעות של התאימות לאחור ב IE8 (המשפיעות גם על IE9 ו IE10)

בניגוד ל IE7, שלא שמרה על תאימות מדוייקת ל IE6 Standards Mode, החליטה מייקרוסופט החל מ IE8 (אולי בגלל תלונות של לקוחות) לשמור העתק מדוייק של הדרך בה הדפדפן הקודם רינדר את הדף. זהו ה IE7 Standards Mode שקיים ב IE8. אפילו כאשר מייקרוסופט מציגה מנוע רינדור משופר - הדפדפן יידע להציג את הדף בדיוק רב מאוד לצורה בה הדפדפן הקודם והפחות מוצלח הציג אותו.

החלטה הזו תקפה לא רק על ה Rendering Engine אלא גם על ה JavaScript Engine: באגים וחוסרי תאימות שהיו קיימים ב IE7 נשמרו במנוע הג'אווהסקריפט של IE8 (והלאה). אם הדף מרונדר ב IE7 Standards Mode, מנוע הג'אווהסקריפט החדש יפעיל את משפטי ה IF [ו] המתאימים ויתנהג בדיוק כמו שהתנהג ב IE7.


הערה: מפתחים שרוצים לדעת איזו גרסה אמיתית של IE רצה מולם נתקלים בקושי: ה BC גורם לדפדפן להתנהג בדיוק כמו דפדפן ישן יותר וזה כולל User Agent, יכולות נתמכות ואפילו מנוע ה JavaScript ש"משחזר" באגים ישנים. הדרך האמינה לדעת מול איזה גרסה של IE אתם עובדים היא לתשאל את גרסת ה JavaScript Engine. שלא תזדקקו לזה.

בנוסף, מייקורוסופט לא סומכת רק על ה DOCTYPE ותוית ה X-UA-Compatible שיידעו כיצד על הדף להתרנדר. מייקרוסופט מנהלת רשימה של Domains של אתרים פופולריים וה Rendering Modes של IE בהם הם רצים בצורה הטובה ביותר. רשימה שנוצרה ומתוחזקת בצורה ידנית, כנראה. IE קורא את הרשימה ומגיב אליה.
מייקרוסופט מאפשרת לארגונים לנהל רשימה נוספת משלהם שתשפיע על כל דפדפני ה IE בארגון שלהם.
תוכלו למצוא כיצד רשימות אלו משתלבות באלגוריתם הבחירה בתרשים הזרימה שקישרתי למעלה.


התאימות לאחור ממשיכה להסתבך: IE9
בעת פיתוח IE9, ניצב בפני מייקרוסופט אתגר חדש: התמיכה בשרשרת תקנים שאנו מכירים אותם כיום כ HTML5 ו CSS3. תקנים אלו הם עליית מדרגה מול היכולות שהיו בדפדפנים עד כה. נראה שהמפתחים של IE החליטו שעל מנת לתמוך בתקנים אלו, בצורה Preformant, יש עליהם לכתוב את מנוע הרינדור מחדש.
מה עושים עם התאימות לאחור? אין ברירה. משלבים בדפדפן החדש, IE9, שני מנועי רינדור שונים: מנוע ישן (של IE8) ומנוע חדש שיתמוך בתקנים החדשים:



כל טאב ב IE9 מתרנדר או במנוע החדש או במנוע הישן - אך אף פעם לא בשניהם ביחד.
אם יש דף עם iFrames ייתכן והדף החיצוני (מה שנקרא topFrame) מרונדר במוד אחד (נאמר IE9 Standards) בעוד ה iFrame הפנימי מרונדר במוד אחר (נאמר QME). אולם, בניגוד ל IE6 עד IE8 בהם יכול היה הדפדפן לבחור עבור כל iFrame כל מוד מהרשימה הנתמכת, ב IE9 יש בחירה של מנוע הרינדור ומאותו הרגע הבחירה למוד עבור על Frame מוגבלת למודים הזמינים עבור אותו מנוע רינדור.

הבחירה במנוע הרינדור היא דיי פשוטה: בפעם הראשונה שהדפדפן מזהה סימן שמעיד טיפוס הדף (יהיה זה X-UA-Compatible ברמת ה HTTP או תג Doctype) - הוא בחור את המוד המתאים מכל הרשימה. מנוע הרינדור שיודע לצייר מוד זה הוא מנוע הרינדור ש IE ישתמש בו לשאר הדף.

ריבוי ה Rendering Engines, אם כן, משפיע רק על דפים הכוללים Frames או iFrames. במקרים אלו ה Top Frame יכתיב את מנוע הרינדור עבור ה iFrames שהוא מארח.

הנה הדגמה של התנהגות זו בפועל:
כתבתי דף פשוט בשם page.html שידמה אפליקציה עסקית (הוספתי Source Code בתחתית הפוסט [ג]). הדף מכיל מספר אלמנטים שבהם יש בעיות של תאימות לאחור:
  • עיגול המצוייר ב SVG (תכונה של HTML5)
  • תיבה עם צבע שהוגדר פעמיים: פעם בצורה תקנית (כתום) ופעם נוספת בצורה לא תקרנית (טורקיז).
  • אזור אפור (border עבה במיוחד) שגובהו יהיה חצי מהתיבה ע"פ ה IE Box Model ושליש מהתיבה ע"פ ה W3C Box Model.
אם אני שם בראש דף זה תגית DOCTYPE הוא ייראה שונה למדי מאשר אם לא תהיה תגית כזו. אם יש תגית Doctype אזי IE ייבחר מוד רינדור שונה מזה בו אין Doctype.

ייתרה מכך, אם אשים 2 עותקים של הדף page.html בתוך דף מארח (topframe) - ה Doctype של הדף המארח ייבחר עבורי מנוע רינדור כך שהצורה בה ירונדר הדף תושפע פעם נוספת. 
במקרה 1 למטה - הדף המארח מפעיל את מנוע הרינדור החדש (ומריץ את האפליקציה פעם במוד IE9 Standars ופעם ב QME).
במקרה 2 למטה - הדף המארח מפעיל את מנוע הרינדור הישן (ומריץ את האפליקציה פעם במוד IE8 Standards ופעם במוד Quirks Mode)

ההבדל היחיד בקוד בין מקרה 1 למקרה 2 הוא ה Doctype של ה topframe. התוצאות לפניכם:


חתיכת הבדל בשביל Doctype - לא?

אתם יכולים להבחין ב Scrollbars שונים בשני המקרים שנובעים מ Defaults שונים בין המודים השונים. הבדלים אלו אמורים להתאפס בעקבות CSS Reset.

השלכה משמעותית של ההפרדה ל 2 מנועי רינדור שונים אי חוסר היכולת (בעזרת ifלהציג HTML5 באותו הדף עם תאימות מלאה לדפים ישנים מאוד (Old Quirks Mode) - שיש רבים כאלו במערכות עסקיות.

כיצד מתמודדים עם זה? מייקרוסופט הוסיפה מוד בשם (QME (Quirks Mode Emulation שתואם, במידה רבה, לתקן של W3C כיצד יש לרנדר Quirks Mode - כלומר דפים ישנים מאוד.

ה QME לא מתועד בצורה ברורה כמוד של IE9. לקח לי כמעט חודש של התעסקות בנושא עד שהבנתי שהוא קיים. מייקרוסופט לעיתים קוראת לו "Quirks Layout" (נשמע כמו מימד אחר של פונקציונליות) או Quirks within IE9 Engine - שיכול בקלות לבלבל עם ה Quirks Mode שקיים במנוע הישן. ב Dev Tools של IE10 הוא נקרא פשוט "Quirks Mode" בנוסף ל "Explorer 5 Quirks" שקיים שם. בקיצור: מבלבל. רק לאחרונה אני נתקל במונח QME בצורה יותר מפורשת וברורה.

הנה תיעוד שמציין את קיום ה QME - הייתי זקוק לו בכדי להיות בטוח שאני לא מדמיין. הסיבה שהמוד לא מפורט ברשימת ה modes של הדפדפן קשורה כנראה לכך שIE9 לא מאפשר להשתמש במוד זה ב topmost Frame - כלומר הוא מותיר להשתמש בו רק בתוך iFrames. 
הנה תיאור של ההבדלים בהתנהגות של QME. גם לדפדפנים אחרים יש QME . הנה הגדרת ההתנהגות של QME ב FF.


כשמפעילים את כלי הפיתוח של IE (לחיצה על F12), יש אפשרות לדרוס בכוח את המוד בו ירוץ הדפדפן. אין פה QME או Almost Standards Mode. אליהם ניתן להגיע רק בעזרת אלגוריתם ההחלטה של ה Rendering Modes. האלגוריתם שונה בין הגרסאות של הדפדפן ולכן בכלי הפיתוח ניתן לבחור Browser Mode שהוא קובע באיזו גרסה של האלגוריתם להשתמש. נסו להבין את זה לבד : )




הנה תיאור האלגוריתם בעזרתו IE9 מחשב באיזה Rendering Mode להריץ את הדף. דיי דומה ל IE8 - אך השפעותיו  משמעותיות יותר. 


התאימות לאחור עושה קאמבק (קטן): IE10



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


ב IE10 בוצעו כמה שינויים שמשפיעים על ה BC:

ה Default Rendering Mode עבור מסמך ללא Doctype הוא QME ולא IE5.5 Quirks Mode - מקור. התנהגות זו רצויה, אך היא תגרום לדפי Quirks Mode שרצו יפה ב IE9 - לרוץ פחות יפה ב IE10.
פתרון פשוט: להוסיף תג X-UA-COMPATIBLE, ie=7 בכדי להכריח את מנוע ה rendering הישן לרוץ.
פתרון נכון: לתקן את הדפים לעבוד ב QME, לא לדחות את ההתנתקות מ IE5.5 לנצח! ההבדלים העיקריים בין Quirks Mode ל QME הם מסביב לטבלאות, Box-Model (ניתן לתקן בקלות בעזרת CSS) והדבר הכי קשה: באגים שהיו ב IE5.5, תאימותם נשמרה עד ל IE8 - אך הם תוקנו ב QME.

QME נתמך גם ב topframe, בשונה מה IE9 - אך בדומה לFF או כרום. נראה גם שהיישום של QME קרוב יותר לסטנדרט מאשר IE9 - אך קשה לומר בוודאות לפני ש IE10 ישוחרר ויהיה יותר נסיון לקהילה איתו.

ביטול התמיכה ב Conditional Comments (כגון  <!--[if IE]>).
ביטויים אלו נמצאים בשימוש בכמה ספריות מודרניות כגון ie7.js ו html5shim - אך אלו ספריות של תאימות לאחור שלא יזדקקו, כנראה, ליכולת זו ב IE10. אם הקוד שלכם עושה כאלו בדיקות (נו, נו, נו!) - הזהרו.
בראייה ארוכת טווח, זו כמובן החלטה טובה של מייקרוסופט.

Windows 8 מציגה שני סוגים של "סביבות עבודה": Metro ו Desktop.
Metro הוא ברירת המחדל והעתיד. אופיס 2013 יקבל ממשק מטרו, למשל. מטרו הוא Touch Enabled ויהיה הסביבה היחידה על Windows 8 Tablet.
Desktop היא הסביבה שאנו מכירים מאז Windows 95 ועד Windows 7. סרגל משימות, תפריט "התחל" וכו'.

חווית השימוש ב IE10 בסביבת המטרו היא שונה מסביבת העבודה של ה Desktop. למשל, Plug-Ins ו ActiveX לא ירוצו בסביבת המטרו. פלאש דווקא כן. אם יש לכם דף שמכיל Plug-Ins ואתם רצים על בסביבת המטרו - הדפדפן יפנה אתכם לסביבת ה Desktop. לא בהכרח התנהגות BC מלאה, אך אני מוצא אותה סבירה. ב Tablet כנראה תהיה סתם הערת שגיאה או פשוט התעלמות.


תעשו חיים!

מקורות נוספים בנושא:



-----

[א] Chrome Frame[ב], למי שלא מכיר, הוא Plug-In של גוגל ל IE שכולל את מנוע ה Rendering של Chrome ויכול, ע"פ תג Meta במסמך ה HTML - להפעיל את הדף, מעשית, בכרום[א]. התקנתו לא דורשת הרשאות Administrator והוא יכול להריץ את הגרסה האחרונה של Chrome (כלומר מנוע HTML5 מעולה) בתוך IE6 המיושן. טקטיקה מקובלת היא "לתמוך ב IE6 ו IE7 בעזרת Chrome Frame", כלומר: להפעיל עבור משתמשי IE ישנים את כרום מאחורי הקלעים. יש לשיטה זו כמה מגבלות בכל הנוגע לתקשורת בין iFrames.

[ב] יש לבטא "קרום" ולא "ח-רום" - כפי שישראלים רבים נוהגים.

[ג] 

[ד] נשמע לי קצת מופרך לתאר משהו שיקרה 8 שנים מעכשיו: עידן ועידנים. אני מניח שמשהו יקרה וזו לא תהיה התוצאה בפועל.

[ה] התקן ביקש מבעלי דפים ישנים, כגון HTML 3.2 לסמן את הדפים שלהם ב DOCTYPE מסוים (ש IE ידע להתעלם ממנו) - אך לא הייתה לבעלי הדפים מוטיבציה אמיתית לבצע סימון שכזה.

[ו] אני מניח ומקווה שהשתמשו ב Strategy Design Pattern ולא באמת במשפטי IF.



אין תגובות:

הוסף רשומת תגובה