הדור הבא של עיצוב באינטרנט

עדכונים על חלק מהתכונות המעניינות ב-CSS מודרני.

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

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

תוכן עניינים

'הצמדה לגלילה'

תכונת Scroll Snap מאפשרת להגדיר נקודות הצמדה כשהמשתמש גולל את התוכן שלכם בצורה אנכית, אופקית או בשניהם. הוא כולל תאוצה ועצירה מובנות לגלילה, והוא תומך במגע.

הקוד לדוגמה הזה מגדיר גלילה אופקית ברכיב <section> עם נקודות הצמדה מיושרות לצד שמאל של רכיבי <picture> צאצא:

section {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
}

section > picture {
  scroll-snap-align: start;
}

ככה זה עובד:

  • ברכיב ההורה <section>,
    • הערך של overflow-x מוגדר ל-auto כדי לאפשר גלילה אופקית.
    • overscroll-behavior-x מוגדר לערך contain כדי למנוע גלילה של רכיבי הורה כשהמשתמש מגיע לגבולות אזור הגלילה של הרכיב <section>. (הפעולה הזו לא חובה כדי לבצע צמד, אבל בדרך כלל כדאי לעשות אותה).
    • הערך של scroll-snap-type מוגדר כ-x – כדי לבצע הצמדה אופקית – וכ-mandatory – כדי לוודא שאזור התצוגה תמיד יתחבר לנקודת ההצמדה הקרובה ביותר.
  • באלמנטים הצאצאים <picture>, הערך של scroll-snap-align מוגדר כ-start, וכך נקבעות נקודות הצמדה בצד ימין של כל תמונה (בהנחה ש-direction מוגדר כ-ltr).

וזו הדגמה של השימוש בפועל:

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

:focus-within

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

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

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

.menu:focus-within {
  display: block;
  opacity: 1;
  visibility: visible;
}

איור שמציג את ההבדל בהתנהגות בין מיקוד להתמקדות.

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

רמה 5 של שאילתות מדיה

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

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

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

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

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

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

מאפיינים לוגיים

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

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

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

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

  • המאפיין בלוק נמצא מאונך לזרימת הטקסט בשורה. (בעברית, block-size זהה ל-height).
  • המאפיין inline הוא מקביל לזרימת הטקסט בשורה. (בעברית, inline-size זהה ל-width).

שמות המאפיינים האלה חלים על כל מאפייני הפריסה הלוגיים. לדוגמה, באנגלית, הערך block-start זהה לערך top, והערך inline-end זהה לערך right.

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

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

כדי לראות איך עובדים מאפיינים לוגיים, אפשר להגדיר ערכים שונים למאפיין writing-mode ברכיב <body> בדמו הבא:

position: sticky

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

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

Sticky Stack

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

שקף קבוע

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

Sticky Desperado

בדומה ל'שקף דביק', האלמנטים הדביקים בהדגמה הזו הם בני דודים. עם זאת, הם הוצבו בקונטיינרים שהוגדרו בתצוגת רשת של שתי עמודות.

backdrop-filter

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

לדוגמה, בהדגמה הזו נעשה שימוש באפקט backdrop-filter כדי להשיג טשטוש בסגנון מערכת ההפעלה:

כבר פרסמנו פוסט מעולה בנושא backdrop-filter, כך שאפשר לעבור אליו כדי לקבל מידע נוסף.

:is()

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

הנה דוגמה מהירה:

button.focus,
button:focus {
  
}

article > h1,
article > h2,
article > h3,
article > h4,
article > h5,
article > h6 {
  
}

/* selects the same elements as the code above */
button:is(.focus, :focus) {
  
}

article > :is(h1,h2,h3,h4,h5,h6) {
  
}

gap

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

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

חדשות טובות עוד יותר: gap מגיע ל-Flexbox, עם כל היתרונות של הרווח בין הפריטים שיש ל-Grid:

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

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

נכון לעכשיו, רק דפדפן Firefox תומך ב-gap בפריסות גמישות, אבל כדאי לנסות את ההדגמה הזו כדי לראות איך זה עובד:

CSS Houdini

Houdini הוא קבוצה של ממשקי API ברמה נמוכה למנוע הרינדור של הדפדפן, שמאפשרת לכם להורות לדפדפן איך לפרש CSS מותאם אישית. במילים אחרות, הוא מעניק לכם גישה למודל האובייקטים של CSS, ומאפשר לכם extend את CSS באמצעות JavaScript. יש לכך כמה יתרונות:

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

איור שמראה איך Houdini פועל בהשוואה ל-polyfills המסורתיים של JavaScript.

Houdini הוא שם כולל למספר ממשקי API. מידע נוסף על התכונות האלה והסטטוס הנוכחי שלהן זמין במאמר האם Houdini מוכן? בשיחה שלנו, דיברנו על Properties ו-Value API, Paint API ועל worklet של אנימציה, כי הם הנפוצים ביותר כרגע. אפשר בקלות להקדיש פוסט שלם לכל אחד מממשקי ה-API המעניינים האלה, אבל בינתיים כדאי לצפות בהרצאה שלנו כדי לקבל סקירה כללית ודמואים מגניבים שנותנים מושג לגבי מה שאפשר לעשות עם ממשקי ה-API.

אפשרויות נוספות

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

  • size: מאפיין שיאפשר לכם להגדיר גובה ורוחב בו-זמנית
  • aspect-ratio: מאפיין שמגדיר יחס גובה-רוחב לאלמנטים שאין להם יחס כזה באופן מהותי
  • min(),‏ max() ו-clamp(): פונקציות שמאפשרות להגדיר אילוצים מספריים על כל נכס CSS, ולא רק על רוחב וגובה
  • list-style-type הוא מאפיין קיים, אבל בקרוב תהיה תמיכה בטווח רחב יותר של ערכים, כולל אמוג'י ו-SVG
  • display: outer inner: בקרוב, יהיה אפשר להשתמש בשני פרמטרים במאפיין display. הפרמטרים האלה יאפשרו לכם לציין במפורש את הפריסות החיצונית והפנימית של המאפיין, במקום להשתמש במילות מפתח מורכבות כמו inline-flex.
  • אזורים ב-CSS: מאפשרים למלא אזור ספציפי, לא מלבני, שהתוכן יכול לזרום אליו ומחוץ לו.
  • מודולים של CSS: JavaScript תוכל לבקש מודול CSS ולקבל בחזרה אובייקט עשיר שקל לבצע עליו פעולות