כך תעמדו דף אינטרנט של שני טורים עם float (הצפות)

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

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

טכניקה בסיסית לעימוד עם floats

html

קוד ה-html צריך להראות כך:

<div class="container">
  <div class="content">
  </div>
  <aside>
  </aside>
</div>

לצפיה בדוגמה (html בלבד)

הייתי יכול להשתמש גם ב-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>

לצפיה בפתרון ג (clearfix)

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

תגיות:, , , , , , ,

3 תגובות

  1. מושקע מאוד,
    תודה
    מיכאל.

  2. תודה על המידע, למדתי כמה דברים חדשים.

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

    נעמה
  3. מדריך מדויק מקיף!

    הלל