כך תעמדו דף אינטרנט של שני טורים עם float (הצפות)
אחת הטכניקות הנפוצות ביותר לעימוד דפי אינטרנט היא בעזרת float
(להלן: הצפות). ה-floats מעולם לא נועדו לעימוד דפים, אלא לגלישת טקסט סביב לתמונות ולאלמנטים שונים - ממש כפי שהיינו עושים בוורד או באינדיזיין. מפני שעימוד דפים אינו הייעוד המקורי של ההצפות, נוצרות בעיות שונות כשמשתמשים ב-float
לעימוד דפים.
בפוסט זה אני רוצה לסקור את הטכניקה הבסיסית לעימוד דף בשני טורים עם הצפות. נסקור את הבעיות של עימוד עם הצפות וכמה פתרונות אפשריים. ולבסוף נבחן טכניקה אלטרנטיבית לעימוד טורים.
טכניקה בסיסית לעימוד עם floats
html
קוד ה-html צריך להראות כך:
<div class="container">
<div class="content">
</div>
<aside>
</aside>
</div>
הייתי יכול להשתמש גם ב-div class=sidebar
, אך העדפתי את aside
- שהוא אחד האלמנטים הסמנטיים החדשים של html5.
css
כעת ל-css: אנו רוצים ששני בלוקים (התוכן והפס הצדדי) יעמדו זה לצד זה, ולא אחד מעל השני - שזו ההתנהגות הרגילה של אלמנטים עם display:block
כמו div
ו-aside
.
לשם כך אנו צריכים:
א. להגדיר לכל אחד מהבלוקים רוחב, ולוודא שהקונטיינר רחב דיו כדי להכיל את שניהם
.container {
width: 800px;
}
.content {
width: 600px;
}
aside {
width: 200px;
}
לצפיה בדוגמה (הגדרת רוחב בלבד - האלמנטים עומדים אחד מעל השני)
ב. להציף את כל אחד מהבלוקים
.content {
width: 600px;
float: right;
}
aside {
width: 200px;
float: left;
}
לצפיה בדוגמה (הצפות - האלמנטים עומדים אחד לצד השני)
קריסת הקונטיינר וגלישת טקסט לא רצויה
כל מי שעימד אתר עם הצפות יודע שאי אפשר להסתפק במה שכתבנו למעלה. אם ניתן עכשיו צבע רקע לקונטיינר - שום דבר לא ייצבע, כי גובהו של הקונטיינר עכשיו הוא אפס. אלמנטים שיש להם float
יוצאים מהזרימה של המסמך. כל האלמנטים בתוך הקונטיינר מוצפים ולכן הוא מתנהג כמו דיב ריק.
.container {
width: 800px;
background: #fff;
}
עוד בעיה יכולה להיווצר אם נוסיף אלמנט לאחר הקונטיינר (למשל footer
); הטקסט באלמנט החדש יגלוש מסביב לאלמנטים המוצפים.
<div class="container">
<div class="content">
</div>
<aside>
</aside>
</div>
<footer></footer>
נציג כאן שלושה פתרונות אפשריים. כולם יביאו לאותה התוצאה - הקונטיינר יתחשב בגובה האלמנטים שבתוכו, והפוטר יתחיל בשורה חדשה אחרי הקונטיינר.
פתרון א - הוספת דיב עם class=clear לאחר האלמנטים המוצפים
הגדרת clear:both
לאלמנט, תגרום לו להפסיק את ההצפות שמעליו ולהתחיל שורה חדשה. אחד הפתרונות הפופולריים לבעיות שה-float
יוצר הוא להוסיף דיב ריק לאחר האלמנטים המוצפים, וב-css להגדיר לו clear:both
.
<div class="container">
<div class="content">
</div>
<aside>
</aside>
<div class="clear"></div>
</div>
.clear {
clear: both;
}
- יתרון: אפשר להתחיל הצפות חדשות מיד אחרי הדיב (אפילו בתוך הקונטיינר)
- חסרון: מצריך הוספת דיב
פתרון ב - הוספת overflow:hidden לקונטיינר
התכונה overflow
קובעת מה יש לעשות עם תוכן שחורג מגבולות האלמנט. לדוגמה: אם יש דיב שהגדרנו לו גובה של 200 פיקסלים, ובתוכו יש תמונה בגובה של 300 פיקסלים - מה יקרה עם 100 הפיקסלים שחורגים מגובה הדיב? בעזרת הגדרת overflow
לדיב, אפשר לקבוע האם להוסיף פסי גלילה, האם לתת לתמונה לחרוג מגבולות הדיב או האם להסתיר את החלק החורג.
לפי תקן ה-w3c, כשאנו מגדירים overflow
שאינו visible
באלמנט מסויים, נוצר הקשר עיצוב של בלוק חדש. או במילים אחרות, אם נוסיף overflow:hidden
לקונטיינר שמכיל רק אלמנטים מוצפים, הקונטיינר יקבל גובה לפי האלמנטים שבתוכו והבעיות שלעיל ייפתרו.
.container {
width: 800px;
overflow: hidden;
}
לצפיה בפתרון ב (overflow:hidden)
- יתרון: לא מצריך אלמנט נוסף, קוד פשוט
- חסרון: כל מה שחורג מגבולות הקונטיינר יוסתר
פתרון ג - הוספת class=clearfix
לקונטיינר
טכניקת ה-clearfix היא דרך פופולרית להכיל אלמנטים מוצפים, מבלי להזדקק לאלמנט נוסף כדי לנקות את ההצפות. ישנן מספר גרסאות ל-clearfix. הפתרון הקומפקטי והנפוץ ביותר כיום פותח על ידי ניקולס גאלאגר, והוא עושה שימוש באלמנטים מדומים.
אם אתם משתמשים ב-html5 boilerplate, הקוד הבא כבר צריך להיות ב-css שלכם. אם לא, תמיד אפשר להעתיק ולהדביק:
.clearfix:before, .clearfix:after {
content: "";
display: table;
}
.clearfix:after {
clear: both;
}
.clearfix {
zoom:1; /* ie7 fix */
}
ב-html יש להוסיף class=clearfix
לקונטיינר, כדי להחיל עליו את הסגנונות דלעיל:
<div class="container clearfix">
<div class="content">
</div>
<aside>
</aside>
</div>
- יתרון: לא מצריך הוספת אלמנט ל-html
- חסרון: צריך להשתמש בקוד css ארוך ולהוסיף את המחלקה
clearfix
לכל קונטיינר
הוספת padding (ריפוד)
לכאורה, ראינו כמה וכמה פתרונות לבעיות שההצפות יוצרות, ובכך סיימנו. אך שוב, כל מי שבנה כמה אתרים בחייו יודע שזה קצת יותר מסובך. למשל, אם נוסיף padding
(להלן: ריפוד) של 10 פיקסלים לאזור התוכן ולפס הצדדי, הם כבר לא יהיו ברוחב שהגדרנו, אלא גדולים ב-20 פיקסלים מרוחב זה. זאת בגלל מודל הקופסה, הקובע שהגודל הכולל של האלמנט הוא הרוחב שהגדרנו בתוספת הריפוד והגבולות.
.container {
width:800px; /* 620 + 220 = 840, doesn't fit in the 800px container */
}
.content {
float: right;
width: 600px;
padding: 10px; /* now .content is 620px wide */
}
aside {
float: left;
width: 200px;
padding: 10px; /* now aside is 220px wide */
}
פתרון א - הפחתה של הריפוד שהוספנו מהרוחב
הפתרון הפשוט ביותר הוא להפחית את גודל הריפוד מרוחב האלמנט. מאחר והגדרנו ריפוד מכל הכיוונים של 10 פיקסלים, אנו מקבלים תוספת של 10 פיקסלים מצד ימין ו-10 פיקסלים מצד שמאל. כך שעלינו להפחית סה"כ 20 פיקסלים מהגדרת הרוחב בכל אחד מהאלמנטים המוצפים.
.container {
width:800px; /* 580+20 + 180+20 = 800, perfect! */
}
.content {
float: right;
width: 580px; /* 600-20 */
padding: 10px;
}
aside {
float: left;
width: 180px; /* 200-20 */
padding: 10px;
}
- יתרון: עובד בכל הדפדפנים
- חסרון: מסורבל, מקשה על שינויים, אי אפשר להשתמש באחוזים אם יש
border
פתרון ב - box-sizing:border-box
הפתרון שצובר פופולריות כיום הוא שימוש במודל קופסה אחר, שבו הריפוד לא מוסיף רוחב לאלמנט, אלא פונה כלפי פנים, על ידי הגדרת box-sizing: border-box
. שימו לב ש-box-sizing
מצריך הוספת קידומות למוזילה ולוובקיט. באופן מפתיע, דווקא אקספלורר 8 ומעלה תומך ב-box-sizing
ללא שום קידומת. השורות הבאות יחילו את מודל הקופסה הנ”ל על כל האלמנטים במסמך:
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
לצפיה בפתרון השני (שימוש במודל הקופסה החדש)
- יתרון: מודל קופסה אינטואיטיבי יותר, מאפשר לעבוד באחוזים בקלות
- חסרון: לא עובד באקספלורר 7, אם זה מדאיג אתכם
טכניקה אלטרנטיבית לעימוד טורים
הפתרון שאני נוטה לכיוונו מצריך שינויים גדולים יותר, אך הוא חוסך בקוד וחוסך כאבי ראש. בניגוד לשיטה המקובלת, מגדירים רוחב והצפה רק לפס הצדדי. כדי שההצפה תעבוד, צריך למקם את הפס הצדדי לפני אזור התוכן. כעת, הפס הצדדי יופיע בתוך אזור התוכן, כשהטקסט של אזור התוכן גולש סביב הפס הצדדי. כדי למנוע את גלישת הטקסט מסביב לאלמנט המוצף, משתמשים ב-overflow:hidden
, שיגרום לאזור התוכן להראות כמו טור נפרד.
א. ב-css יש לתת float ורוחב רק לפס הצדדי
.container {
width:800px;
}
.content, aside {
padding: 10px;
}
aside {
float: left;
width: 200px;
}
ב. צריך למקם את הפס הצדדי לפני אזור התוכן ב-html
<div class="container">
<aside>
</aside>
<div class="content">
</div>
</div>
כפי שניתן לראות, השתמשנו ב-float
כמו בשימוש המקורי שלו - כמו תמונה שמוצפת לשמאל והטקסט שאחריה גולש מסביבה.
ג. הטריק - הוספת overflow:hidden לאזור התוכן
שימוש ב-overflow:hidden
יגרום לאזור התוכן לתפוס את כל המקום שנשאר מבלי לגלוש מסביב לפס הצדדי. באופן זה, אנחנו לא צריכים להגדיר רוחב לאזור התוכן ולחשב כמה מקום נשאר. וגם נפתרו הבעיות שקשורות לקריסת הקונטיינר ולגלישת הטקסט הלא רצויה באלמנטים שאחרי הקונטיינר.
לפני כמה זמן נתקלתי בטכניקה זו בפוסט של ניקול סאליבן מ-2009. מסתבר שלא מדובר בפיצ'ר חדש, אך הוא הצריך לקרוא את תקן ה-css כדי להבין מה overflow
באמת עושה.
.content {
overflow: hidden;
}
- יתרון: עובד בכל הדפדפנים, חסכוני בקוד, מאפשר גמישות אם יש צורך בשינוי הרוחב, פותר את כל הבעיות שסקרנו
- חסרון: מסתיר תוכן שיוצא מחוץ לגבולות הדיב, צריך למקם את הפס הצדדי לפני אזור התוכן - מה שיכול להקשות בעיצוב רספונסיבי, כשבמסכים קטנים נרצה למקם את הפס הצדדי מתחת לאזור התוכן ולא לצידו (עדיין אפשרי לפתור את הבעיה הזו עם ג’אווה-סקריפט).
סיכום
ראינו כיצד ליצור קוד בסיסי לעימוד דף בעל שני טורים עם float
. סקרנו את הבעיות השונות שנוצרות מכך וכיצד לפתור אותן. ל-float
יש עוד שימושים שקשורים לעימוד קופסאות אחת ליד השניה, כמו למשל: תפריט ניווט אופקי, יצירת גריד של תמונות. הפתרונות שראינו (חוץ מהפתרון האחרון) מתאימים גם למקרים כאלו.
ישנן טכניקות עימוד אפשריות נוספות, למשל, עימוד עם display: inline-block
, או עימוד עם position:absolute
. אפשר גם להשתמש בגריד מוכן כמו 960.gs ודומיו כדי לעמד את הדף.
ולסיום, מילה על העתיד: הסטנדרט החדש שאמור לעזור לנו לעמד את הדף הוא flex-box
. התמיכה ב-flex-box
מאוד מצומצמת כיום, בין השאר מפני שהסטנדרט השתנה באופן משמעותי בשנים האחרונות. לפיכך, נראה שנמשיך להשתמש בהצפות לעימוד דפים עוד זמן רב.