ארכיון פוסטים מהקטגוריה "HTML"

OhBehave – החלת התנהגות על אלמנט סטטי או דינמי בצורה מיידית

יום שישי, 18 בדצמבר, 2009

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

דוגמאות:

  • הפיכת תיבת select לפקד autocomplete
  • השמת אלמנט בתוך מסגרת מורכבת (פינות מעוגלות, שקיפות)
  • החלת אירועי לחיצה על אלמנטים מסוג מסויים
  • השמת תווית צפה מעל פקד טקסט עד ל-focus/שינוי ערכו

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

שימו לב! במידה ומדובר בהצמדת אירועים בלבד כדאי מאוד להשתמש בשיטת ה-Event Delegation

חסרונות השיטה:

  • לפעמים, לוקח מעט זמן עד שה-dom עולה והאלמנט מופיע בגרסתו נטולת ההתנהגות עד לסיום הטעינה
  • כאשר מוסיפים דינמית אלמנטים לעמוד (innerHTML או createElement & appendChild) צריך לדאוג להחיל את ההתנהגות שוב, על כל האלמנטים שדורשים זאת
  • כפיתרון גנרי לאלמנטים דינמיים אפשר להפעיל טיימר על העמוד שיחקור את ה-dom בכל פעם מחדש. זהו תהליך איטי, וב-delay בקריאות ל-interval עלולות להיות קפיצות

דוגמה לעבודה בשיטה זו:

<script type=”text/javascript”>
function applyBehaviors() {
    var elements=$.select(“.behavior”);
    for (var i=0;i<elements.length;i++) applySpecificBehavior(elements[i]);
}

$.domready(function () {
    applyBehaviors();
});

$.ajax("url.html",
    onSuccess:function () {
        applyBehaviors();
    }
);
</script>

(הפונקציות $.select, $.domready, $.ajax הינן פונקציות פיקטיביות המקנות אפשרות לבחור אלמנטים לפי css selector, לבצע פעולה מייד בעליית ה-dom וביצוע בקשת ajax, בהתאמה. ניתן למצוא אותן בכל ספריית javascript המכבדת את עצמה).

הפיתרון הנכסף – OhBehave

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

איך זה עובד?

לכל דפדפן נאלצתי למצוא פיתרון שונה, מאחר וכל אחד מיישם את הפונקציונליות בה רציתי באופן אחר. מתוך כל מנגנון בחרתי להפעיל פונקציה בשם OhBehave.initialize שמקבלת אלמנט ותניע את החלת ההתנהגויות.
התנהגויות האלמנט מוגדרות אף הן ב-class שלו. לדוגמה – oh-behave-WrapWithFrame, oh-behave-Autocomplete (שימו לב לקידומת oh-behave-).
כל התנהגות היא פונקציה המאוחסנת באובייקט OhBehave.behaviors שמקבלת אלמנט עליו היא מחילה התנהגות בודדת.
לא רציתי לכבול לשימוש ב-OhBehave, כך שניתן להגדיר את הפונקציה גם כגלובאלית, ואף ניתן לשנות את קידומת ההתנהגות (ראו בקובץ המצורף).

דוגמה:

OhBehave.behaviors["AlertTheTime"]=function (element) {
    element.onclick=function () {
        alert(new Date());
    };
};

// or -- function AlertTheTime(element) { … }

Firefox ‏ (Gecko Engine) – שימוש ב-XBL

XBL או XML Binding Language היא שפת תגיות מבוססת XML המוגדרת בתקן W3C להחלת התנהגות עשירה לאלמנט. ה-XBL מאפשר להגדיר מאפיינים (כולל getters/setters), אירועים וירייתם, מתודות וקוד CSS/JS שיחול על האלמנט. ה-XBL מוצמד בעזרת css בתצורה:

.oh-behave { -moz-binding:url("oh-behave.xml#oh-behave"); }

ומבנה ה-xml:

<bindings xmlns="http://www.mozilla.org/xbl" xmlns:html="http://www.w3.org/1999/xhtml">
    <binding id="oh-behave">
        <implementation>
            <constructor>OhBehave.initialize(this);</constructor>
        </implementation>
    </binding>
</bindings>

כרגע רק מנוע Gecko תומך ב-XBL, על אף שהוא בתקן.
הצמדתי XBL ל-css class מסויים ומתוכו הפעלתי קוד גנרי המחיל התנהגות.

IE ‏ ‏ (Trident Engine) – שימוש ב-HTC

HTC, או HTML Component הינו יישום של Microsoft להחלת התנהגות עשירה לאלמנט. הוא מאפשר פחות או יותר את מה שה-XBL מאפשר.

Safari/Chrome ‏ (WebKit Engine) – האירוע DOMNodeInserted

מאחר וב-WebKit עוד לא הכניסו את XBL לשימוש (בקוד המקור יש אזכורים אך כנראה האופציה עדיין כבוייה), נאלצתי למצוא פיתרון אחר. האירוע DOMNodeInserted (אירוע המוגדר בתקן) נורה כאשר אלמנט מוכנס לעמוד דינמית (innerHTML / createElement & appendChild). דרך אירוע זה אני מחפש את האלמנטים עליהם יש להחיל את ההתנהגות. חיפוש האלמנטים מתבצע בעזרת querySelectorAll – מתודה של אלמנט או מסמך, המקבלת css selector ומגישה את כל האלמנטים העונים על סלקטור זה, תחת אותו אלמנט.
בעליית העמוד השתמשתי באירוע DOMContentLoaded שרץ מייד בעליית ה-dom. כאן עלולה להיות קפיצה קטנה, אבל המנוע כל-כך מהיר שאני לא חושב שיהיה אפשר להבחין בה.

דוגמה חיה

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

להדגמה של OhBehave

להורדת OhBehave כולל דוגמאות

באגים נפוצים ב-IE6

יום רביעי, 10 בינואר, 2007

דפדפן Interner Explorer בגרסה 6 היה שיפור עצום מבחינת תמיכה בתקנים מאז ימי 5 הזוהרים (ואף מילה על 5.5). ה-CSS התחיל להתנהג בצורה תקנית בעזרת DOCTYPE מתאים וגם ה-dom התחיל להיות תואם להגדרות W3C.

עם זאת, הרבה פעמים אנו נתקלים בבאגים מרגיזים שיכולים לעכב את העבודה שלנו כדי למצוא workarounds. מה לעשות ש-IE7 ו-Firefox עדיין לא השתלטו על השוק, ו-IE6 תופס נתח לא קטן, ואנחנו כמתכנתי web צריכים להתאים את האתרים שלנו לכל הדפדפנים הנפוצים.

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

#1 : ערכי margin כפולים ב-float

לכל אלמנט שחל עליו float כלשהו, ערכי ה-margin שיחולו עליו יוכפלו. אין הסבר הגיוני לזה.

דוגמה:

<div style="float:left;margin-left:100px;">IE6 doubles the margin and renders margin-left with 200px</div>

באג margin כפול ב-float

פתרון:

הצורה הכי אלגנטית לפתור את הבאג הזה היא לתת מאפיין display:inline לאלמנט בעל ה-float. הגדרת ה-float בכל מקרה משכתבת את ה-display ל-block. זה פותר את הבעיה, ולא מונע מהאלמנט להמשיך לתפקד כמו block.

#2 : תזוזה של פיקסל כאשר רוחב/גובה אי זוגיים

כאשר ממקמים אבסולטית אלמנט בתוך אלמנט אחר (בעל position:relative) ורוחבו או גובהו של אלמנט האב אי זוגיים, האלמנט הפנימי יזוז פיקסל אחד אחורה

<div style="width:199px;height:99px;position:relative;border:1px solid #000;">
	<div style="width:100px;position:absolute;background-color:red;right:0;bottom:0;"></div>
</div>
באג ריווח של פיקסל אחדניתן לראות כי יש רווח של פיקסל מימין
ומלמטה

פתרון:

לבאג זה לא מצאתי ממש פתרון קסם, אך בעזרת ה-underscore hack ניתן למשוך את האלמנט למיקום הנכון שלו:

<div style="width:199px;height:99px;position:relative;border:1px solid #000;">
	<div style="width:100px;position:absolute;background-color:red;right:0;bottom:0;_margin-bottom:-1px;_margin-right:-1px;"></div>
</div>

#3 : תמונות וצבעי רקע נחתכים

את מי שלא מכיר דרכי פתרון, הבאג הזה יכול להוציא מהכלים. קצת הסבר כללי – ב-css של IE יש מאפיין readonly שנקרא hasLayout. לאלמנט "יש" layout אם באחד המאפיינים הבאים יש ערך שונה מברירת המחדל: width, height, float, zoom, או אחד מהמאפיינים הבאים: display:inline-block, position:absolute, writing-mode:tb-rl.

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

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

ul li {
	background-image:url('image.gif');
	zoom:1;
}

#4 : opacity, טקסט ו-ClearType (גם ב-IE7)

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

בדוגמה אפשר לראות טקסט בתוך div עם שקיפות של 40%. הטקסט המודגש נראה מגורען ולא חלק.

פתרון:

צבע רקע כלשהו לאלמנט המכיל פותר את הבאג.

#5 : תיבת select עולה על אלמנטים

ללא התחשבות ב-z-index, תיבות בחירה ב-IE6 עולות על כל אלמנט (כמעט).

אם יש לי תפריט שנפתח במעבר עכבר, ומתחת לאיזור בו אמור להפתח התפריט יש select, התיבה תופיע מעל אותו אלמנט.

פתרון:

אלמנט אחד ש-select לא עולה עליו הוא iframe. אבל אלמנטים אחרים כן יכולים לעלות על iframe. המסקנה המתבקשת היא – הצגת iframe מעל ה-select והצגת האלמנט מעל אותו iframe. את ה-iframe אפשר לעשות שקוף בעזרת opacity של 0. את המיקום והגודל של ה-iframe יש להעתיק מהאלמנט אותו אנו חפצים לשים מעל ה-select.

> html
<iframe id="hider-iframe" style="display:none" frameborder="0" scrolling="no"></iframe>

> css
#hider-iframe {
	position:absolute;
	filter:alpha(opacity=0);
}

> js
function ShowMenu() {
	HiderIframeShow(menuElement);
	menuElement.style.display="";
}
function HiderIframeShow(clone) {
	var hiderIframe=document.getElementById("hider-iframe");
	hiderIframe.style.top=clone.style.top;
	hiderIframe.style.left=clone.style.left;
	hiderIframe.style.width=clone.offsetWidth+"px";
	hiderIframe.style.height=clone.offsetHeight+"px";
	hiderIframe.style.display="";
}
אם משתמשים בספריית prototype, הפונקציה Position.clone תעתיק את המיקום המדוייק.

מאפייני ה-top/left מועתקים מערכי האלמנט, בהנחה שגם ה-iframe וגם האלמנט בעלי position:absolute ויושבים תחת אותו offsetParent (הא הראשון בעל position:absolute/relative או ה-body). אם לא כך הדבר – יש להשתמש במנגנון המחשב מיקום מדוייק של האלמנט.

#6 : צבעים של PNG שקוף משתנים

נתקלתי לאחרונה בתופעה מוזרה: כאשר משתמשים ב-AlphaImageLoader filter של IE6 להצגת תמונות PNG עם שקיפות, התמונות התמונות מוצגות כהות יותר ממה שהן במקור. כן, IE6 ממש משנה ערכי RGB על התמונה.

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

לאחר מחקר קטן גיליתי שאכן יש באג במידה וה-PNG יוצאה מפוטושופ (כנראה גם בעורכי תמונות אחרים). מצאתי כלי חינמי המתקן את העוולה -

TweakPNG. לאחר ההפעלה של התוכנה פותחים את קובץ ה-PNG, מוחקים את ה-Chunk בשם gAMA, ושומרים.

(מיותר לציין, Firefox ו-IE7, בעזרת תגית img או background-image, עומדים בגבורה במשימה ומציגים צבעים נכונים מראש).

underscore hack

בהתקלות בכל באג נוסף שמצריך טיפול מיוחד רק ב-IE6 אפשר להשתמש ב-underscore hack: כל מאפיין css שיוצמד לו מקף תחתון לפני שמו – יוחל רק ב-IE6.

.className {
	background-color:red;
	_background-color:blue;
}

בכל דפדפן מלבד IE6 נראה צבע אדום, אך IE6 כן יתייחס ל-_background-color כמאפיין חוקי, ולכן צבע הרקע יהיה כחול.

כדאי לצמצם שימוש בהאקים, ולמצוא פתרון אחיד לכל הדפדפנים.

מידע נוסף

מידע נוסף ניתן למצוא בקישור באגים ב-CSS של IE6.

Lucky Number 8207

יום שישי, 1 בדצמבר, 2006

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

דוגמה

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

קוד

דוגמאות הקוד הבאות מציגות את הקומבינציות האפשריות של שילוב עברית ואנגלית.

<div><span class="subject">נושא עברי</span> <span class="user">שם עברי</span></div>
<div><span class="subject">נושא עברי</span> <span class="user">English name</span></div>
<div><span class="subject">English Subject</span> <span class="user">שם עברי</span></div>
<div><span class="subject">English Subject</span> <span class="user">English name</span></div>

בעיה

בהנחה שאנו עובדים עם direction:rtl, בדוגמה מספר 4 שם המשתמש מופיע בצד ימין, ונניח שהוא בצבע מסויים – שיבש לנו את מראה העמוד.

פתרון

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

ישנה אפשרות נוספת – הזנת התכנים לתוך אלמנט כמו div ושימוש ב-float:right. פתרון נחמד אבל לא פרקטי בכל המקרים (ואף אחד לא מזכיר טבלה כפתרון).

נא להכיר – תו מספר 8207 (או: rlm ‏- right to left mark)

תו "שקוף" זה מבצע פחות או יותר את הפעולה שהאות ו' של תפוז מבצעת, רק שהוא "בלתי נראה" ולא מפריע בהעתקה.

<span class="subject">English Subject</span> &rlm;<span class="user">English name</span>

תוצאה

English Subject ‏English name
הנושא נשאר בצד ימין, והשם בשמאל.

למה זה עוד טוב?

סיום משפט במילים באנגלית, ותחילת משפט נוסף באנגלית.

זהו משפט עברי שנגמר ב-English. This is the next משפט.
ושימוש בתו המיוחד:

זהו משפט עברי שנגמר ב-English.‏ This is the next משפט.

זהו משפט עברי שנגמר ב-English.&rlm; This is the next משפט.

ועוד טיפ

 כמה פעמים קרה לכם, שבכתיבת הודעה במסנג'ר, בפורום או כתיבה בכלל בתוך textarea העברית התבלבלה עם האנגלית?

משפט לדוגמה:
אני מתכנת ב-Visual Studio 2005. (Visual Web Developer Express היא הגרסה החינמית שלו)
לא רק שהמשפט התהפך, גם המשמעות שלו.

אפשר להכניס את ה-rlm ידנית ע"י לחיצה על [+ctrl במצב עברי. והתוצאה:

אני מתכנת ב-Visual Studio 2005.‏ (Visual Web Developer Express היא הגרסה החינמית שלו)
(התו הוכנס לאחר הנקודה ולפני הסוגריים).

מבנה טבלאי ב-CSS

יום חמישי, 30 בנובמבר, 2006

נתקלתי לא פעם במצב הבא:

קיימת רשימת פריטים שצריכה להסתדר בעמוד באופן הבא:

  • לכל אלמנט רוחב/גובה קבועים
  • ישנם מספר אלמנטים בשורה
  • בין שני אלמנטים צריך להיות רווח קבוע

 

רווחים קבועים בין כל תא

well, זהו מקרה קלאסי לטבלה! כן! אני ממש רואה את זה קורה, cellspacing מתאים וצבע רקע לטבלה, זה יהיה מושלם.

.NOT

אז CSS.

ההגדרות הן:

  • כל פריט 50*50
  • רווח בין כל פריט: 15 פיקסלים
  • 4 פריטים בשורה

 

ניצור div שיכלול את כל הפריטים. רוחבו יהיה 245, כדי לאכלס 4 פריטים + 3 ריווחים בין פריט לפריט (4*50 + 3*15).
כדי ליצור רשימה של פריטים בשורה נשתמש ב-float:right (או left) כדי להצמיד אותם לצד כלשהו. גם ל-div הכולל יש לתת את אותו ה-float. בכל פעם שנגיע לגבול התיבה בה נמצאים הפריטים, הפריט הבא ייפול לשורה הבאה.
כדי לרווח בין אלמנט לשני נשתמש ב-margin-left.
ופה הקאצ':

הריווחים הלבנים הם ה-margin של הפריטים שאמורים
להיות בשורה הראשונה

כפי שאפשר לראות, הריווח נוצר עבור כל פריט.
עקב חוסר מקום לריווח מצד ימין, הקוביה האחרונה בכל שורה נופלת. עקב הריווח התחתון, יש ריווח מיותר בסוף התיבה.
כל העיצוב שלנו השתבש.
אבל אם אנחנו לא רוצים להציג לעמודה האחרונה ריווח מהצד ולשורה האחרונה ריווח מלמטה?
תחכומים של css 3 עדיין לא כאן, ולא יהיו פה בזמן הקרוב (עד ש-IE7 יתפוס את מקומו של 6).

הטריק

משאירים את ה-margin.
מגדילים ל-div המכליל שלנו את הרוחב ל-265, כדי שיכיל גם את הריווח השמאלי של התיבה האחרונה.
יוצרים עוד div, נותנים לו את אותו float, מעלימים לו overflow ונותנים לו את הרוחב 245, בתוכו שמים את ה-div עם הפריטים.
ה-div עם הפריטים בעצם ימשיך אבל בגלל ש"חתכנו" אותו בתוך ה-div העוטף החדש, לא נראה את הריווחים המיותרים מהצד.
ומה לגבי הריווחים מלמטה? ניתן margin-bottom שלילי ל-div עם הפריטים כגובה הריווח התחתון.

הקוד

<style type="text/css">
/*<![CDATA[*/
.wrapper {
	direction:rtl;
	float:right;
	overflow:hidden;
	width:245px;
	border:5px solid #000;
}
.table {
	float:right;
	width:260px;
	margin-bottom:-15px;
}
.item {
	background-color:#ADCBDA;
	width:50px;
	height:50px;
	margin-left:15px;
	margin-bottom:15px;
	float:right;
}
/*]]>*/
</style>
<div class="wrapper">
	<div class="table">
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
		<div class="item"></div>
	</div>
</div>
elado
30 בנובמבר, 2006
16 תגובות »