לדלג לתוכן

1.6 גריד הרצאה

מה זה גריד - CSS Grid

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

בדיוק בשביל זה יש לנו CSS Grid.
גריד הוא מערכת layout דו-מימדית - הכלי החזק ביותר ב-CSS לבניית מבנים מורכבים של עמודים.


הפעלת גריד - display: grid

כמו פלקסבוקס, גם גריד עובד על עיקרון של מיכל (container) וילדים (items).
מגדירים display: grid על האלמנט ההורה, וכל הילדים הישירים שלו הופכים ל-grid items.

.container {
  display: grid;
}

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


עמודות ושורות - grid-template-columns ו-grid-template-rows

כדי להגדיר כמה עמודות ושורות יהיו בגריד, ומה הגודל של כל אחת:

.container {
  display: grid;
  grid-template-columns: 200px 200px 200px;
  grid-template-rows: 100px 100px;
}

הקוד הזה יוצר גריד עם 3 עמודות ברוחב 200 פיקסלים כל אחת, ו-2 שורות בגובה 100 פיקסלים כל אחת.
אפשר לערבב יחידות שונות:

.container {
  display: grid;
  grid-template-columns: 200px 50% auto;
}
  • העמודה הראשונה: 200 פיקסלים קבועים
  • העמודה השניה: 50% מהרוחב הזמין
  • העמודה השלישית: auto - תתפוס את מה שנשאר

יחידת fr - fraction

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

.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

שלוש עמודות שוות - כל אחת תופסת שליש מהמרחב הזמין.

.container {
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
}

שלוש עמודות - האמצעית רחבה פי 2 מהצדדיות.
אפשר לחשוב על fr כמו חלוקת עוגה - אם יש סך הכל 4fr, כל 1fr שווה רבע מהעוגה.

אפשר גם לשלב fr עם יחידות קבועות:

.container {
  display: grid;
  grid-template-columns: 250px 1fr;
}

העמודה הראשונה תהיה 250 פיקסלים קבועים, והשניה תתפוס את כל שאר המרחב.
זה דפוס נפוץ מאוד לבניית sidebar + main content.


הפונקציה repeat

כשרוצים עמודות (או שורות) חוזרות, אין צורך לכתוב את אותו ערך שוב ושוב:

/* במקום לכתוב */
grid-template-columns: 1fr 1fr 1fr 1fr;

/* אפשר לכתוב */
grid-template-columns: repeat(4, 1fr);

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

/* חוזר על הדפוס 200px 1fr שלוש פעמים */
grid-template-columns: repeat(3, 200px 1fr);
/* תוצאה: 200px 1fr 200px 1fr 200px 1fr */

הפונקציה minmax

הפונקציה minmax() מאפשרת להגדיר גודל מינימלי ומקסימלי לעמודה או שורה:

.container {
  display: grid;
  grid-template-columns: minmax(200px, 1fr) 2fr;
}

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

דוגמה נפוצה ושימושית מאוד:

.container {
  display: grid;
  grid-template-columns: repeat(3, minmax(250px, 1fr));
}

שלוש עמודות - כל אחת לפחות 250 פיקסלים ולכל היותר 1fr.


auto-fit ו-auto-fill

הנה הטריק הכי חזק של גריד - גריד רספונסיבי בלי media queries.

auto-fit

.container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}

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

auto-fill

.container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}

נראה דומה, אבל ההבדל חשוב:

מה ההבדל?

  • auto-fit - מותח את העמודות הקיימות למלא את כל המרחב. אם יש 2 אלמנטים ומקום ל-4 עמודות, 2 העמודות של האלמנטים יתרחבו למלא הכל.
  • auto-fill - ממלא את המרחב בעמודות ריקות. אם יש 2 אלמנטים ומקום ל-4 עמודות, ייווצרו 4 עמודות (2 עם תוכן ו-2 ריקות).

ברוב המקרים auto-fit הוא מה שרוצים - הוא נותן תוצאה יותר יפה כי האלמנטים ממלאים את כל המרחב.


רווחים - gap

ה-property של gap מגדיר רווח בין האלמנטים בגריד:

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

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

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  row-gap: 20px;
  column-gap: 10px;
}

/* או בקיצור */
.container {
  gap: 20px 10px; /* row-gap column-gap */
}

שימו לב - gap שונה מ-margin. הוא מוסיף רווח רק בין האלמנטים, לא בקצוות החיצוניים.


אזורי גריד - grid-template-areas

זה אחד הפיצ'רים הכי מגניבים של גריד. אפשר להגדיר את ה-layout ויזואלית בצורת "מפה":

.container {
  display: grid;
  grid-template-columns: 1fr 3fr 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header  header  header"
    "sidebar main   aside"
    "footer  footer  footer";
  min-height: 100vh;
  gap: 10px;
}

ואז מקצים כל אלמנט לאזור שלו:

.header {
  grid-area: header;
}

.sidebar {
  grid-area: sidebar;
}

.main {
  grid-area: main;
}

.aside {
  grid-area: aside;
}

.footer {
  grid-area: footer;
}
<div class="container">
  <header class="header">header</header>
  <nav class="sidebar">sidebar</nav>
  <main class="main">main content</main>
  <aside class="aside">aside</aside>
  <footer class="footer">footer</footer>
</div>

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

grid-template-areas:
  "header header header"
  "sidebar main ."
  "footer footer footer";

אפשר גם לשנות את ה-areas ב-media queries - וככה לקבל layout שונה לגמרי במובייל ובדסקטופ:

/* mobile */
.container {
  grid-template-columns: 1fr;
  grid-template-areas:
    "header"
    "main"
    "sidebar"
    "aside"
    "footer";
}

/* desktop */
@media (min-width: 768px) {
  .container {
    grid-template-columns: 1fr 3fr 1fr;
    grid-template-areas:
      "header  header  header"
      "sidebar main   aside"
      "footer  footer  footer";
  }
}

מאפייני ילדים - grid-column ו-grid-row

כל אלמנט בגריד יכול לשלוט על המיקום שלו באמצעות grid-column ו-grid-row.
הערכים מתייחסים לקווים (lines) של הגריד - הקו הראשון הוא 1, השני הוא 2, וכן הלאה.

.item {
  grid-column: 1 / 3; /* from line 1 to line 3 (spans 2 columns) */
  grid-row: 1 / 2;    /* from line 1 to line 2 (spans 1 row) */
}

אפשר גם להשתמש ב-span כדי לציין כמה תאים לתפוס:

.item {
  grid-column: span 2; /* takes up 2 columns from current position */
  grid-row: span 3;    /* takes up 3 rows from current position */
}

דוגמה מלאה - אלמנט שתופס את כל רוחב הגריד:

.container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
}

.full-width {
  grid-column: 1 / -1; /* -1 means the last line */
}

הערך -1 מייצג את הקו האחרון - אז 1 / -1 אומר "מהקו הראשון עד הקו האחרון" כלומר כל הרוחב.

grid-area כקיצור

grid-area יכול לשמש גם כקיצור ל-grid-row-start / grid-column-start / grid-row-end / grid-column-end:

.item {
  grid-area: 1 / 2 / 3 / 4;
  /* row-start / column-start / row-end / column-end */
}

יישור - alignment

כמו בפלקסבוקס, גם בגריד יש מנגנון יישור חזק:

יישור הפריטים בתוך התאים שלהם

.container {
  display: grid;
  grid-template-columns: repeat(3, 200px);
  grid-template-rows: repeat(2, 200px);

  justify-items: center; /* horizontal alignment of items within their cell */
  align-items: center;   /* vertical alignment of items within their cell */
}

ערכים אפשריים: start, end, center, stretch (ברירת מחדל).

יישור הגריד כולו בתוך המיכל

.container {
  display: grid;
  grid-template-columns: repeat(3, 200px);
  height: 100vh;

  justify-content: center; /* horizontal alignment of the entire grid */
  align-content: center;   /* vertical alignment of the entire grid */
}

ערכים אפשריים: start, end, center, stretch, space-between, space-around, space-evenly.

קיצורים

.container {
  /* place-items = align-items + justify-items */
  place-items: center center;

  /* place-content = align-content + justify-content */
  place-content: center center;
}

/* if both values are the same, use one value */
.container {
  place-items: center;
  place-content: center;
}

יישור פריט בודד

.item {
  justify-self: end;   /* override horizontal alignment for this item */
  align-self: start;   /* override vertical alignment for this item */
}

גריד מרומז - implicit grid

מה קורה אם יש לנו יותר אלמנטים ממה שהגדרנו בgrid-template?
הגריד יוצר שורות ועמודות חדשות אוטומטית - זה נקרא implicit grid.

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* only defined columns, not rows */
}

אם יש 9 אלמנטים, הגריד ייצור אוטומטית 3 שורות (3 עמודות * 3 שורות = 9 תאים).
אפשר לשלוט על הגודל של השורות/עמודות שנוצרות אוטומטית:

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 200px; /* implicit rows will be 200px tall */
}

שימוש נפוץ - minmax לשורות אוטומטיות:

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: minmax(100px, auto); /* at least 100px, grows with content */
}

אפשר גם לשנות את כיוון המיקום האוטומטי:

.container {
  grid-auto-flow: column; /* fill columns first, then add new columns */
}

גריד מול פלקסבוקס - Grid vs Flexbox

זו שאלה שנשאלת הרבה - מתי להשתמש בגריד ומתי בפלקסבוקס?

פלקסבוקס - Flexbox

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

גריד - Grid

  • דו-מימדי - שורות ועמודות בו-זמנית
  • מתאים ל-layout של כל העמוד
  • מצוין כשהמבנה קובע את הגודל
  • מושלם לגלריות, dashboards, layouts מורכבים

כלל אצבע

  • ה-layout הכללי של העמוד? גריד
  • ניווט עליון? פלקסבוקס
  • גלריית תמונות? גריד
  • כרטיס עם כותרת, תוכן וכפתור? פלקסבוקס
  • טבלת מחירים עם עמודות? גריד
  • מרכוז אלמנט בודד? שניהם עובדים

אפשר (וצריך) לשלב ביניהם. אפשר להגדיר layout ראשי בגריד, ואז להשתמש בפלקסבוקס בתוך כל grid item לסידור התוכן הפנימי.


תת-גריד - subgrid

subgrid הוא פיצ'ר חדש יחסית שמאפשר ל-grid item להשתמש בקווי הגריד של ההורה שלו.

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

.card {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid; /* use parent's row lines */
}

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

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


דוגמאות מעשיות

דוגמה 1 - layout של עמוד שלם

body {
  display: grid;
  grid-template-columns: 250px 1fr;
  grid-template-rows: 60px 1fr 50px;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  min-height: 100vh;
  margin: 0;
}

.header  { grid-area: header;  background: #1a1a2e; color: white; }
.sidebar { grid-area: sidebar; background: #16213e; color: white; }
.main    { grid-area: main;    padding: 20px; }
.footer  { grid-area: footer;  background: #1a1a2e; color: white; }

דוגמה 2 - גלריית תמונות רספונסיבית

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 15px;
  padding: 15px;
}

.gallery img {
  width: 100%;
  height: 250px;
  object-fit: cover;
  border-radius: 8px;
}

דוגמה 3 - dashboard

.dashboard {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: auto;
  gap: 20px;
  padding: 20px;
}

.widget-large {
  grid-column: span 2;
  grid-row: span 2;
}

.widget-wide {
  grid-column: span 2;
}

.widget-tall {
  grid-row: span 2;
}

.widget {
  background: white;
  border-radius: 12px;
  padding: 20px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

דוגמה 4 - מרכוז מושלם

.center-grid {
  display: grid;
  place-items: center;
  min-height: 100vh;
}

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


סיכום

גריד הוא כלי חזק מאוד. הנקודות העיקריות:
- display: grid על ההורה, grid-template-columns ו-grid-template-rows להגדרת המבנה
- יחידת fr לחלוקה יחסית של המרחב
- repeat() ו-minmax() לגריד חכם ורספונסיבי
- auto-fit + minmax() = גריד רספונסיבי בלי media queries
- grid-template-areas ל-layout ויזואלי וברור
- grid-column ו-grid-row למיקום ומריחה של פריטים
- gap לרווחים, properties יישור לשליטה מלאה
- גריד ל-layout דו-מימדי, פלקסבוקס לסידור חד-מימדי