- 1 יסודות
- 2 Flexbox
- 3 רשת ורשת משנה
- 4 שאילתות מאגר
- 5 שכבות-על מותאמות, מיקום עוגן והקשרים של סדר הערמה
- 6 מעקב אחרי חריגה ויציבות הפריסה
- 7 מכניקה של אזור התצוגה והפצת טראקים
- 8 שורות ועמודות (נקרא גם "בנייה")
1 Fundamentals
כדי לשפר את הביצועים, כדאי להסתמך על מנוע הפריסה של הדפדפן כשאפשר. השתמשו בגודל פנימי, במאפיינים לוגיים וב-aspect-ratio לפני שתשתמשו במאפיינים בתוך הקוד או בשאילתות מדיה מסובכות.
1.1 באיזה מצב פריסה להשתמש?
עוברים על ההנחיות מלמעלה למטה ועוצרים בהתאמה הראשונה. חשוב לזכור שאפשר להטמיע פריסות זו בתוך זו, וכל החלטה מבוססת על תרחיש השימוש של אותו מאגר.
- האם מדובר בשורה או בעמודה פשוטה של פריטים? משתמשים ב-flexbox – חד-ממדי, מתמקד בתוכן, התוכן מופץ לאורך ציר אחד.
- האם רכיב בתצוגת עץ צריך להתיישר עם המסלולים של רשת הסבא שלו? שימוש ב-subgrid – דו-ממדי, מתמקד בקשרים, יורש את המסלולים של ההורה כדי שהנכדים יוכלו להתיישר עם האחים.
- האם מדובר בדף או במבנה רכיבים מורכב עם שורות וגם עמודות? רשת – דו-ממדית, קודם כל פריסה, אתם מגדירים את השלד והתוכן ממלא אותו.
- האם התוכן הוא טקסט ארוך שצריך לפצל לעמודות מאוזנות? פריסה בכמה עמודות – זרימה חד-ממדית, בסגנון עיתון.
- האם יש פריטים בגבהים שונים שצריך לארוז בצפיפות? השתמשו ב-grid עם
grid-auto-flow: denseהיום; השתמשו ב-masonry מקורי (המכונה גם "grid lanes") רק כשהוא נשלח ביעד הבסיסי שלכם (ראו §8). - האם רכיב צריך לצוף מעל הדף ולהישאר מקושר מרחבית לטריגר, גם מעבר לגבולות ה-DOM או להקשרים של סדר הערימה? משתמשים במיקום עוגן —
anchor-nameבטריגר,position-anchorבשכבת-העל (ראו סעיף 5).
1.2 עקרונות עבודה
- השתמשו במאפיינים לוגיים (
inline-size,block-size,margin-inline,padding-block,inset-inline-start) לממדי הפריסה ולמרווחים – מידע נוסף זמין במאמר CSS: Modern Architecture. - השתמשו במודל המנטלי של "תוכן קודם" לעומת "פריסה קודמת": flexbox כשהפריטים קובעים את הזרימה, ו-grid כשמגדירים קודם את השלד.
- משתמשים בקיצורי הדרך של
place-*(place-content,place-items,place-self) כדי ליישר את שני הצירים בהצהרה אחת. - השתמשו בגודל פנימי (
min-content,max-content,fit-content()) ובמסלולים גמישים (fr,minmax()) לפניwidth/heightקבועים – פחות שאילתות מדיה, פריסות גמישות יותר. - אל תשתמשו ב-
overflow: hiddenכדי להסתיר בעיות בפריסה – תקנו אותן במקור. לדוגמה, רכיבים מסוימים שהוחלפו כמו<canvas>,<img>,<svg>,<video>,<iframe>משתמשים ב-display: inlineכברירת מחדל, מה שיכול להוסיף רווח בפריסות מסוימות. במקום לחתוך את הרווח באמצעותoverflow, צריך להסיר אותו על ידי החלת ערך block display-outside (למשלdisplay: block,grid,flexוכו'). - אפשר להשתמש ב-
aspect-ratioכדי לשמור מקום למדיה ולמנוע שינויי פריסה לפני שהנכסים נטענים.
.sidebar { inline-size: max-content; } /* Size to longest unbreakable token. */
.main-content { inline-size: fit-content; } /* Grow to available space, no further. */
.media { aspect-ratio: 16 / 9; inline-size: 100%; block-size: auto; }
body.centered { display: grid; place-content: center; min-block-size: 100dvb; }
למידע על
calc-size()ועל גודל פנימי שמותאם לאילוצים, אפשר לעיין במאמר חישוב באמצעות גדלים פנימיים.
2 Flexbox
פריסה חד-ממדית – הפריטים זורמים לאורך ציר ראשי אחד עם יישור בציר הנגדי. הוא מתאים לסרגלי ניווט, לסרגלי כלים, לשורות של פריטים ולכל פריסה של שורה או עמודה אחת.
מומלץ:
- מגדירים הקשר באמצעות
display: flexומגדירים את הציר הראשי באמצעותflex-direction(ברירת המחדל היאrow). - השתמשו ב-
flex-wrap: wrapבכל פעם שיש אפשרות לחריגה –nowrapבליoverflow: auto/hiddenיחרוג באזורי תצוגה צרים. - שכבה
flex-wrap: balanceאחריflex-wrap: wrapבשורות עטופות של פריטים קומפקטיים (כמו ענני תגים, כפתורי סינון, קבוצות של לחצנים או קישורי ניווט) כדי לפזר את הפריטים באופן שווה בין השורות ולמנוע פריט בודד בשורה האחרונה. דפדפנים ללא תמיכה חוזרים ל-wrap. - משתמשים בקיצור
flex<grow> <shrink> <basis>(למשל,flex: 1 1 250px) בפריטים במקום להגדיר אתflex-grow/flex-shrink/flex-basisבנפרד. - כדי ליצור רווח בין פריטים, השתמשו ב-
gap(או ב-row-gap/column-gap) במקום בשוליים של רכיבי הצאצא. - כדאי להוסיף את הקידומת
safe(למשל,align-items: safe center) ליישור המיקום כדי שתוכן שאפשר להתמקד בו לא ייחתך כשהמאגר צר יותר מהתוכן שלו. - דוחפים פריט אחד לקצה הרחוק של הציר הראשי באמצעות
margin-inline-start: auto(אוmargin-block-start: auto) – זהו פתח המילוט הרגיל. - אפשר לשנות את היישור של הציר הנגדי לכל פריט באמצעות
align-self. - משתמשים ב-
align-itemsכדי למרכז את כל הפריטים בציר המשני; משתמשים ב-margin: autoבפריט בודד כדי למרכז אותו בשני הצירים באופן עצמאי; משתמשים ב-align-contentרק כשהמאגר עוטף ויש לו מקום נוסף בין השורות. - מגדירים
min-inline-size: 0(אוmin-width: 0) בפריטי flexbox שמכילים תוכן ארוך שלא ניתן לפיצול (כתובות URL, קוד, מחרוזות ארוכות) – פריטי flexbox לא יתכווצו מתחת לגודל התוכן שלהם כברירת מחדל, מה שיגרום לחריגה.
מה לא לעשות:
- אל תשתמשו ב-
justify-selfבפריטי flex – הוא פועל רק בפריסות של רשת, בלוק ומיקום מוחלט. במקום זאת, צריך להשתמש בשוליים אוטומטיים. - אל תשתמשו ב-
orderאו ב-flex-direction: *-reverseכדי לשנות את הסדר של תוכן אינטראקטיבי. הם משנים רק את הסדר החזותי. סדר ה-DOM עדיין קובע את רצף המיקוד, כך שסדר המעבר בין הטאבים במקלדת לא יתאים למה שהמשתמש רואה. - אל תתבלבלו בין
space-around(חצי מרווח בקצוות) לביןspace-evenly(מרווחים שווים לפני, בין ואחרי). - אל תשכחו את היפוך הצירים: כש-
flex-direction: column,justify-contentמתיישר בציר הבלוק ו-align-itemsמתיישר בציר השורה – ההפך מברירת המחדל. - אל תגדירו את הגודל של הקונטיינר ושל הצאצאים שלו כך שהם ימלאו זה את זה – זו סיבה נפוצה לחריגה מהגבולות ולתוצאות מפתיעות. מגדירים גודל מסוים לאחד מהצדדים.
- אל תגדירו גם את
flex-basisוגם אתwidth/inline-sizeבאותו פריט –flex-basisמקבל עדיפות בהקשר של flex ו-widthלא נכלל. השתמשו ב-flex-basis(או בקיצורflex) כמקור האמת היחיד לקביעת הגודל של פריטי flex.
.card-grid { display: flex; flex-flow: row wrap; gap: 1rem; }
.card-item { flex: 1 1 250px; } /* grow, shrink, basis */
.card-item-action { margin-inline-start: auto; } /* Push to main-axis end. */
.toolbar { display: flex; align-items: safe center; }
.tag-list { display: flex; flex-wrap: wrap; flex-wrap: balance; gap: 0.5rem; }
3 רשת ורשת משנה
פריסה דו-ממדית – מגדירים שורות ועמודות באופן מפורש, או מאפשרים למנוע להפיק אותן. רשת משנה מאפשרת לרשת בת לרשת את המסלולים של הרשת הראשית, כך שהנכדים מיושרים בין האחים.
בחירת תכונות של הרשת:
- אתם יודעים בדיוק כמה עמודות אתם צריכים?
- כן – צריך להשתמש בטראקים מפורשים (
grid-template-columns: 200px 1fr,repeat(3, 1fr)וכו') - האם עמודות שונות צריכות להיות בגדלים שונים (סרגל צד + תוכן ראשי, כותרת שמשתרעת על פני כל העמודות)? ← משתמשים ב-
grid-template-areasלאזורים קריאים עם שם - האם כל העמודות אחידות או שהן ממוקמות רק לפי מספר שורה? ← משתמשים ב-
repeat(N, ...)או בקווים עם שם - לא (רספונסיבי, מספר פריטים לא ידוע) – משתמשים ב-
repeat(auto-fit, minmax(min, 1fr)) - האם הפריטים בשורה האחרונה צריכים להימתח כדי למלא את המקום שנותר? ←
auto-fit - האם מסלולים ריקים בשורה האחרונה צריכים לשמור על הגודל המינימלי שלהם (כדי לשמור על משבצות ריקות בעמודה)? ←
auto-fill
- כן – צריך להשתמש בטראקים מפורשים (
- צריכים להציב פריט במיקום ספציפי?
- כן – משתמשים ב-
grid-column: <start> / <end>או ב-grid-area: <name> - לא (רק משתרע על פני כמה טראקים, מיקום הזרימה לא משנה) – משתמשים ב-
grid-column: span <n>
- כן – משתמשים ב-
- האם רכיבי הצאצא צריכים לרשת את גודלי המסלולים של רשת ההורה (יישור קצוות משוננים בין אחים)?
- כן – משתמשים ברשת משנה בציר הרלוונטי
- האם מספר הילדים בכל תא משתנה? ← רשת משנה בציר אחד בלבד; משתמשים ב-
grid-auto-rows/grid-auto-columnsלציר השני - האם מספר הילדים קבוע? → רשת משנה בשני הצירים היא בסדר
- לא – רשת רגילה, אין צורך ברשת משנה
מומלץ:
- הגדרת הקשר באמצעות
display: grid. - כדאי להשתמש ב-
grid-template-areasלפריסות מורכבות ברמת הדף – שמות האזורים מתעדים את עצמם ואפשר ליישר את ההצהרה בשורות ובעמודות כדי שיהיה קל לקרוא אותה. - אפשר להשתמש ב-
repeat(auto-fit, minmax(200px, 1fr))לרשתות של כרטיסים רספונסיביים שמותחות את המסלולים המלאים כדי למלא את השורה, או ב-auto-fillכדי לשמור על המסלולים החוזרים הריקים בגודל המינימלי שלהם. - משתמשים ב-
frכדי להגדיר חלוקה יחסית של הטראקים, וב-minmax(min, max)כדי להגדיר טראקים גמישים אבל מוגבלים. - אפשר למקם פריטים באמצעות
grid-column: span <n>כדי לשנות את הגודל שלהם לאורך טראקים, באמצעותgrid-column: <start> / <end>כדי למקם אותם בשורות ספציפיות, או באמצעותgrid-area: <name>כדי למקם אותם באזורים עם שם. - כדי לפתור את בעיית "הקצוות הלא אחידים" ברשימות של כרטיסים, אפשר להשתמש ברשת משנה (
grid-template-columns: subgridאוgrid-template-rows: subgrid) – רכיבים פנימיים כמו כותרות, מטא-נתונים וקריאות לפעולה מסתדרים בשורה אחת עם רכיבים מקבילים. - כדי שהאתר יפעל כמו שצריך בדפדפנים ישנים, כדאי להוסיף הצהרה על רשת משנה עם הצהרה מפורשת קודמת על
grid-template-rows/-columnsכחלופה לאותו סגנון מדורג.
מה לא לעשות:
- אל תצפו שגודל הטראק
auto-fit/auto-fillיגיע מתוכן הפריט – הוא מגיע מהארגומנט של הגודלrepeat(). - אל תשתמשו ב-
grid-auto-flow: denseבתוכן אינטראקטיבי. הוא אורז פריטים ביעילות אבל משנה את הסדר שלהם באופן חזותי, ומשבש את זרימת הכרטיסיות במקלדת בסדר DOM. - אל תפעילו את subgrid בשני הצירים כשמספר הצאצאים משתנה. התוספות מגיעות למסלול האחרון. במקום זאת, צריך להשתמש ב-
grid-auto-rows/grid-auto-columnsלציר המשתמע. - חשוב להבדיל בין
justify-items/align-items(מיישר את תוכן הפריט בתוך המסלול שלו) לביןjustify-content/align-content(מיישר את מסלולי הרשת בתוך המאגר). אם משתמשים בערך הלא נכון, לא תהיה לכך השפעה. - אל תשתמשו ב-
repeat(auto-fit/auto-fill, ...)בליinline-sizeמוגדר בקונטיינר – בתוךdisplay: inline-gridאו פריט גמיש ללא גודל, לקונטיינר אין רוחב לחלוקה, ולכן מספר הטראקים לא צפוי.
3.1 קוד לדוגמה: רשת ורשת משנה
מעטפת הדף: <main class="page-layout"> מכיל את <header>, <aside>, <section class="card-grid"> עם <div class="card"> צאצאים ו-<footer>.
/* Align grid-template-areas in rows and columns for readability. */
.page-layout {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
gap: 1.5rem;
}
header { grid-area: header; }
aside { grid-area: sidebar; }
footer { grid-area: footer; }
.card-grid {
grid-area: main;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
grid-template-rows: auto 1fr; /* title block, body block */
gap: 1rem;
}
.card {
grid-row: span 2;
display: grid;
/* Same-cascade fallback: ignored when subgrid is supported. */
grid-template-rows: auto 1fr;
grid-template-rows: subgrid;
}
4 שאילתות בנוגע למאגר
שליחת שאילתה לגבי הגודל (או הסגנון המחושב) של מאגר אב במקום של אזור התצוגה. מודל מנטלי: שאילתות קונטיינר = הקשר של רכיב; שאילתות מדיה = פריסת דף גלובלית והעדפות משתמש (prefers-color-scheme, prefers-reduced-motion).
מומלץ:
- כדי שיהיה אפשר לשלוח שאילתות לצאצאים של רכיב wrapper, צריך להגדיר הקשר של הכלה באמצעות
container-type: inline-size(שאילתות רוחב בלבד) אוcontainer-type: size(שני הצירים) ברכיב ה-wrapper. - צריך לתת שם למאגרים באמצעות
container-name(או הקיצור שלcontainer:container: card / inline-size) כשיש סיכוי להתנגשות בין הקשרים בתצוגת עץ. - הכללת יחידות של שאילתות קונטיינר בחישוב של סוג וריווח נוזליים:
cqi/cqb(בלוק/אינליין לוגי),cqw/cqh(פיזי),cqmin/cqmax. - צריך לתת לקונטיינר
block-sizeמוגדר בכל פעם שמשתמשים ב-container-type: size. בלי זה, הצאצאים קורסים כי הכלה של גודל מאלצת את הקונטיינר להתעלם מהתוכן שלו.
מה לא לעשות:
- אל תשתמשו ב-
block-sizeבתור ערך שלcontainer-type– הוא לא תקין. משתמשים ב-sizeלשני הצירים. - אל תצפו שהגודל הפנימי של הצאצאים ישפיע על הקונטיינר אחרי שמצהירים על
container-type. אחרי שההכלה מופעלת, המאגר מחושב כאילו אין לו צאצאים. - אל תסתמכו על יחידות של שאילתות מאגר בתוך צאצאים של אב קדמון שלא עומד בדרישות. הן חוזרות לאזור התצוגה הקטן (
svw/svh).
4.1 דוגמת קוד: טיפוגרפיה גמישה באמצעות יחידות של שאילתות קונטיינר
.card-wrapper {
container: card / inline-size; /* shorthand for container-name / container-type */
}
@container card (inline-size > 400px) {
.content {
display: flex;
gap: 2rem;
}
}
.title {
/* Fluid type bound to the container width, not the viewport. */
font-size: clamp(1rem, 4cqi, 2rem);
}
למידע על תבניות עיצוב רספונסיביות שמבוססות על רכיבים, אפשר לעיין במאמרים עיצוב שמותאם לגודל והתאמה גמישה לעומס.
5 שכבות-על מקוריות, מיקום נקודות עיגון והקשרי סידור
מתי כדאי להשתמש בכל אחד מהפרימיטיבים של שכבות-העל:
- משתמשים ב-
popoverלממשק משתמש זמני, לא מודאלי (תפריטים נשלפים, הודעות קצרות, הסברים על כלים) – נמצא בשכבה העליונה, אין צורך בניהולz-index. - משתמשים ב-
<dialog>עם.showModal()לאינטראקציות מודאליות שדורשות לכידת מיקוד ורקע אינרטי. - אל תשלבו את
popoverו-.showModal()באותו רכיב – אלה מצבי זמן ריצה שמוציאים זה את זה.
מיקום העוגן (פריסה מרחבית של שכבות-על):
- כדי למקם שכבת-על ביחס לטריגר שלה ולשנות את הגודל שלה, משתמשים ב-
position-area(או ב-anchor()בתוספות) וב-anchor-size(). - אפשר להשתמש ב-
position-try-fallbacks: flip-block(או ב-flip-inline) כדי לאפשר לדפדפן לשנות את המיקום כשהשכבה חורגת מאזור התצוגה. - אל תערבבו מילות מפתח פיזיות ולוגיות בערך
position-areaאחד – בחרו מערכת קואורדינטות אחת. - מזהים את התכונה באמצעות
@supports (anchor-name: --x)ומספקים חלופה של מיקום מוחלט.
כדי לקבל פרטים מלאים על ההטמעה, אסטרטגיות של polyfill ומידע על הערך של
popover, אפשר לעיין במאמרים Declarative Dialog and Popover Control ו-Position Aware Tooltips. כדי לראות דוגמאות למיקום של עוגנים בתפריטים נפתחים, בתפריטים צפים ובאינדיקטורים של כרטיסיות, אפשר לעיין במאמרים תפריטים נפתחים שמותאמים לאזור התצוגה וקו תחתון בכרטיסייה למיקום של עוגנים.
6 מעקב אחרי חריגה ויציבות הפריסה
לנהל שינויי פריסה, פסי גלילה וחיתוך באופן צפוי.
מומלץ:
- משתמשים ב-
overflow: autoכדי שפסי הגלילה יופיעו רק כשהתוכן באמת חורג מהגבולות. - אפשר להשתמש ב-
overflow: clipכדי לחתוך תוכן בלי ליצור מאגר גלילה, ולהפעיל גלישה באמצעותoverflow-clip-margin. - אפשר להשתמש ב-
scrollbar-gutter: stableכדי לשמור מקום לפסי גלילה ולמנוע שינויי פריסה כשהתוכן גדל. - משתמשים ב-
overscroll-behavior: contain(או ב-none) באזורי גלילה בתצוגת עץ (כמו סרגלי צד, מודאלים ורשימות) כדי למנוע משרשראות גלילה להופיע בדף, או ב-overscroll-behavior: chainבמעטפות גלילה ביניים (כמו מסלולי החלקה לחשיפה) כשגלילה עודפת צריכה להתפשט לגלילה קודמת בלי להפעיל הקפצה מקומית של גומייה. משתמשים בשילוב של
-webkit-line-clamp+display: -webkit-box+-webkit-box-orient: verticalכדי לחתוך טקסט בכמה שורות. למרות הקידומת, התבנית הזו מוגדרת במלואה ולא הוצאה משימוש. צריך להצהיר על קיצור הדרךline-clampללא קידומת לצד הקיצור עם הקידומת. דפדפנים שעדיין לא תומכים בו יתעלמו מהמאפיין בלי לגרום נזק. מה לא לעשות:אל תשתמשו ב-
overflow: scrollאם אפשר להשתמש ב-auto–scrollמאלץ פסי גלילה גם כשאין מה לגלול.אל תשתמשו ב-
overflow: hiddenאם אתם רק רוצים לחתוך –hiddenיוצר מאגר גלילה שאפשר לגלול בו באופן פרוגרמטי.
.scrollable-list {
max-block-size: 400px;
overflow-y: auto;
scrollbar-gutter: stable; /* Reserve scrollbar space. */
overscroll-behavior: contain; /* No scroll chaining into the page. */
}
.snippet {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
line-clamp: 3; /* Ignored where unsupported. */
overflow: clip;
}
למידע מעמיק על
overflow: clipו-overflow-clip-margin, אפשר לעיין במאמר Overflow Clipping Control. כדי להעביר גלילה בתצוגה בתצוגת עץ עםoverscroll-behavior: chainבממשק משתמש של החלקה לחשיפה, ראו החלקה לחשיפה. כדי לשנות את הצבע, הגודל והעיצוב של סרגל הגלילה, אפשר לעיין במאמרים התאמה אישית של הצבע או העובי של סרגל הגלילה, מצב כהה והתאמת סרגל הגלילה להעדפות של ניגודיות גבוהה.
7 מכניקה של אזור התצוגה והתפלגות המסלולים
- צריך להשתמש ב-
dvh/dvwלמאגרי פריסה לנייד שצריכים להביא בחשבון את השינוי בממשק המשתמש של הדפדפן (כיווץ/הרחבה של סרגל כתובות ה-URL). - אל תשתמשו ב-
100vwלפריסה ברוחב מלא – הוא מתעלם מרוחב סרגל הגלילה וגורם לגלישה אופקית. במקומה צריך להשתמש ב-100%, ב-100dvwאו ב-100svw.
לנקודת הכניסה של העיצוב הרספונסיבי (יחידות דינמיות של אזור התצוגה, שמירת מקום למדיה, טיפוגרפיה גמישה), ראו עיצוב רספונסיבי.
8 שורות ועמודות ברשת (פריסה בלבנים)
המפרט נמצא בפיתוח תחת השם "grid lanes" (למשל, display: grid-lanes), ואילו אבות טיפוס ניסיוניים קודמים השתמשו ב-grid-template-rows: masonry.
מומלץ:
- כדי להציג את הפריטים בצפיפות, אפשר להשתמש ב-grid עם
grid-auto-flow: dense, אבל צריך לקחת בחשבון שסדר ה-DOM לא בהכרח יהיה זהה לסדר הוויזואלי. - כדאי להשתמש בפריסה מרובת עמודות (
columns: 3; column-gap: 1rem) לזרימה דמוית פסיפס עם הרבה תוכן, כשהפריטים הם קטעי מסמכים ולא כרטיסים בעלי משקל שווה. - צריך להתייחס ל-
grid-template-rows: masonryכשיפור הדרגתי בלבד – זיהוי תכונות באמצעות@supports.
מה לא לעשות:
- אל תשיקו את
grid-template-rows: masonryכדרישה מחייבת עד שהיעד של Baseline יתעדכן.
.gallery { columns: 3 200px; column-gap: 1rem; }
.gallery > * { break-inside: avoid; margin-block-end: 1rem; }
@supports (grid-template-rows: masonry) {
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry;
gap: 1rem;
columns: unset;
}
}