דגם קופסה

The CSS Podcast - 001: The Box Model

נניח שיש לכם את קטע ה-HTML הזה:

<p>I am a paragraph of text that has a few words in it.</p>

ואז כותבים את ה-CSS הזה:

p {
  width: 100px;
  height: 50px;
  padding: 20px;
  border: 1px solid;
}

התוכן מוצג ברוחב של 142px, במקום 100px כמו שצוין, והוא חורג מהרכיב. למה זה קורה?

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

הבנה של מודל התיבה של CSS תעזור לכם להבין למה התוכן לא נכנס בתוך רכיב.

חשוב לזכור שכל מה שמוצג על ידי CSS הוא תיבה, גם אם מדובר רק בטקסט או ב-border-radius שגורם לתיבה להיראות כמו עיגול.

תוכן וגודל

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

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

הנה הדגמה בסיסית שמסבירה את ההבדל:

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

בהדגמה מופיעות המילים CSS is awesome (CSS זה מדהים) בתיבה עם מידות קבועות וגבול עבה. מכיוון שהרוחב של התיבה מוגדר, הגודל שלה נקבע באופן חיצוני. כלומר, הוא שולט בגודל של התוכן שמוצג בתוכו. עם זאת, המילה awesome גדולה מדי בשביל התיבה, ולכן היא חורגת מחוץ לתיבת הגבול של תיבת האב (עוד על כך בהמשך). אחת הדרכים למנוע את החריגה הזו היא לאפשר לתיבה לקבל גודל באופן מהותי, על ידי אי-הגדרת הרוחב או על ידי הגדרת width ל-min-content, כמו במקרה הזה. מילת המפתח min-content אומרת לתיבה להיות ברוחב המינימלי הפנימי של התוכן שלה (המילה awesome). כך התיבה תתאים בדיוק לטקסט.

דוגמה מורכבת יותר שממחישה את ההשפעה של גדלים שונים על תוכן אמיתי:

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

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

כברירת מחדל, לרכיב הזה יש ערך width וערך height של 400px כל אחד. המידות האלה מגדירות גבולות ברורים לכל מה שנמצא בתוך הרכיב, והן נשמרות אלא אם התוכן גדול מדי בשביל התיבה. כדי לראות את זה בפעולה, אפשר לשנות את הכיתוב מתחת לתמונה של הפרח למשהו שגובהו גדול יותר מגובה התיבה.

מונח חשוב: גלישה מתרחשת כשהתוכן גדול מדי בשביל התיבה שבה הוא נמצא. אפשר לנהל את האופן שבו רכיב מטפל בתוכן שגולש מהגבולות שלו באמצעות המאפיין overflow.

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

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

האזורים של מודל התיבה

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

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

תיבת התוכן היא האזור שבו התוכן נמצא. התוכן יכול לשלוט בגודל של הרכיב שמכיל אותו, ולכן זה בדרך כלל האזור שגודלו משתנה הכי הרבה.

תיבת הריווח הפנימי מקיפה את תיבת התוכן, והיא הרווח שנוצר על ידי המאפיין padding. הריווח הפנימי נמצא בתוך התיבה, ולכן הרקע של התיבה גלוי ברווח שנוצר. אם הוגדרו לתיבה כללי גלישה, כמו overflow: auto או overflow: scroll, גם פסי הגלילה תופסים את המקום הזה.

סרגלי הגלילה נמצאים בתיבת הריפוד.

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

האזור האחרון, תיבת השוליים, הוא המרווח מסביב לתיבה, שמוגדר על ידי כלל margin של התיבה. גם מאפיינים כמו outline ו-box-shadow תופסים את המקום הזה, כי הם מצוירים מעל הרכיב ולא משפיעים על גודל התיבה. שינוי outline-width של 200px בתיבה לא משנה שום דבר בתוך קצה הגבול.

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

אנלוגיה שימושית

מודל התיבה הוא מורכב להבנה, אז הנה אנלוגיה שתעזור לכם להבין את מה שלמדתם עד עכשיו.

איור של מודל התיבה עם מסגרת לתמונה.

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

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

ניפוי באגים במודל התיבה

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

כדי לנסות את התכונה הזו ב-Chrome:

  1. פותחים את כלי הפיתוח.
  2. בוחרים רכיב.
  3. הצגת הכלי לניפוי באגים של מודל התיבה.
הכלי לניפוי באגים של מודל התיבה בהדגמה של soutline.

שליטה במודל התיבה

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

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

גיליון הסגנונות של סוכן המשתמש מגדיר את ערך ברירת המחדל של רכיבים שמקבלים את הערך display. לדוגמה, ערך ברירת המחדל של display במאפיין <div> הוא block, ערך ברירת המחדל של display במאפיין <li> הוא list-item, וערך ברירת המחדל של display במאפיין <span> הוא inline.

לאלמנט inline יש שוליים של בלוק, אבל אלמנטים אחרים לא מתחשבים בהם. עם inline-block, אלמנטים אחרים מכבדים את שולי הבלוק, אבל האלמנט הראשון שומר על רוב ההתנהגויות שהיו לו כאלמנט inline. פריט block ממלא כברירת מחדל את השטח הזמין בשורה, בעוד שהאלמנטים inline ו-inline-block גדולים רק כמו התוכן שלהם.

גיליון הסגנונות של סוכן המשתמש מגדיר גם ערכי ברירת מחדל ל-box-sizing, שמציין לתיבה איך לחשב את הגודל שלה. כברירת מחדל, כל הרכיבים מוגדרים כ-box-sizing: content-box;. כלומר, כשמגדירים מאפיינים כמו width ו-height, המאפיינים האלה חלים על תיבת התוכן. אם לאחר מכן מגדירים את padding ואת border, הערכים האלה מתווספים לגודל של תיבת התוכן.

בדיקה של רמת ההבנה שלך

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

.my-box {
  width: 200px;
  border: 10px solid;
  padding: 20px;
}

מה לדעתך יהיה הרוחב של .my-box?

‫200px
מכיוון שערך ברירת המחדל של box-sizing הוא content-box, הריפוד והגבולות מתווספים לרוחב. ‫200px יהיה נכון אם בתיבה יהיה box-sizing: border-box.
‫260px
ברירת המחדל של גודל התיבה היא content-box, כלומר הריווח והגבולות מתווספים לתיבה הכוללת.

הרוחב בפועל של התיבה הזו הוא 260 פיקסלים. מכיוון ש-CSS משתמש בערך ברירת המחדל box-sizing: content-box, הרוחב שמוגדר הוא רוחב התוכן, ומוסיפים לו את הערכים padding ו-border משני הצדדים. רוחב התוכן הוא 200 פיקסלים, המרווח הפנימי הוא 40 פיקסלים והגבול הוא 20 פיקסלים, כך שהרוחב הכולל של הרכיב הוא 260 פיקסלים.

אפשר לשנות את זה על ידי ציון border-box גודל:

.my-box {
  box-sizing: border-box;
    width: 200px;
    border: 10px solid;
    padding: 20px;
}

מודל התיבה החלופי הזה אומר ל-CSS להחיל את width על תיבת הגבול במקום על תיבת התוכן. המשמעות היא שהערכים border ו-padding מוזנים, כך שכאשר מגדירים את .my-box לרוחב של 200px, הוא מוצג בפועל ברוחב של 200px.

כדי לראות איך זה עובד, אפשר לצפות בהדגמה האינטראקטיבית הבאה. כשמעבירים את הערך box-sizing למצב מופעל, האזור הכחול מראה איזה CSS מוחל בתוך התיבה.

השוואה בין ההשפעות של הגדרת גודל מסוג content-box ו-border-box.
*,
*::before,
*::after {
  box-sizing: border-box;
}

כלל ה-CSS הזה בוחר כל רכיב במסמך וכל פסאודו רכיב ::before ו-::after ומחיל את box-sizing: border-box. המשמעות היא שכל רכיב משתמש עכשיו במודל התיבה החלופי הזה.

מכיוון שמודל התיבה החלופי יכול להיות צפוי יותר, מפתחים מוסיפים לעיתים קרובות את הכלל הזה לאיפוסים ולנורמליזציות, כמו A (more) Modern CSS Reset.

משאבים

גיליונות סגנונות של סוכן משתמש