תחילת העבודה עם שאילתות סגנון

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

Browser Support

  • Chrome: 105.
  • Edge: 105.
  • Firefox: 110.
  • Safari: 16.

Source

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

Browser Support

  • Chrome: 111.
  • Edge: 111.
  • Firefox: not supported.
  • Safari: 18.

Source

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

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

איך מתחילים להשתמש בשאילתות סגנון

נניח שיש לנו את הקוד הבא ב-HTML:

<ul class="card-list">
  <li class="card-container">
    <div class="card">
      ...
    </div>
  </li>
</ul>

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

שליחת שאילתות להורים ישירים

תרשים של שאילתת סגנון.

בניגוד לשאילתות סגנון, אין צורך להחיל את המגבלה באמצעות המאפיין container-type או container על .card-container כדי ש-.card יוכל לשלוח שאילתות לגבי הסגנונות של ההורה הישיר שלו. עם זאת, אנחנו צריכים להחיל את הסגנונות (ערכים של מאפיינים מותאמים אישית במקרה הזה) על מאגר (.card-container במקרה הזה) או על כל אלמנט שמכיל את הרכיב שאנחנו מחילים עליו סגנון ב-DOM. אנחנו לא יכולים להחיל סגנונות שאנחנו שולחים עליהם שאילתה על האלמנט הישיר שאנחנו מעצבים באמצעות השאילתה הזו, כי זה עלול לגרום ללופים אינסופיים.

כדי לשלוח שאילתה ישירות להורה, אפשר לכתוב:

/* styling .card based on the value of --theme on .card-container */
@container style(--theme: warm) {
  .card {
    background-color: wheat;
    border-color: brown; 
    ...
  }
}

יכול להיות ששמתם לב ששאילתת הסגנון עוטפת את השאילתה ב-style(). המטרה היא להבדיל בין ערכי המידה לבין הסגנונות. לדוגמה, אפשר לכתוב שאילתה לגבי רוחב המאגר כ-@container (min-width: 200px) { … }. הסגנונות יחולו אם מאגר האב יהיה ברוחב של 200 פיקסלים לפחות. עם זאת, min-width יכול להיות גם מאפיין CSS, ואפשר לשלוח שאילתה לגבי הערך של min-width ב-CSS באמצעות שאילתות סגנון. לכן כדאי להשתמש ב-wrapper של style() כדי להבהיר את ההבדל: @container style(min-width: 200px) { … }.

עיצוב של רכיבי הורה לא ישירים

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

/* styling .card based on the value of --moreGlobalVar on .card-list */
@container cards style(--moreGlobalVar: value) {
  .card {
    ...
  }
}

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

אבל כל זה ברור יותר בפועל. ריכזנו כאן כמה דוגמאות:

שאילתות סגנון בפעולה

תמונה לדוגמה עם כמה כרטיסי מוצרים, חלקם עם תגים &#39;חדש&#39; או &#39;מלאי מוגבל&#39;, והכרטיס &#39;מלאי מוגבל&#39; עם רקע אדום.

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

 <div class="product-list">
  <div class="product-card-container" style="--detail: new">
    <div class="product-card">
      <div class="media">
        <img .../>
      <div class="comment-block"></div>
    </div>
  </div>
  <div class="meta">
    ...
  </div>
  </div>
  <div class="product-card-container" style="--detail: low-stock">
    ...
  </div>
  <div class="product-card-container">
    ...
  </div>
  ...
</div>

בעזרת הנתונים המובְנים האלה, אפשר להעביר ערכים אל --detail ולהשתמש במאפיין ה-CSS המותאם אישית הזה כדי להחיל את הסגנונות:

@container style(--detail: new) {
  .comment-block {
    display: block;
  }
  
  .comment-block::after {
    content: 'New';
    border: 1px solid currentColor;
    background: white;
    ...
  }
}

@container style(--detail: low-stock) {
  .comment-block {
    display: block;
  }
  
  .comment-block::after {
    content: 'Low Stock';
    border: 1px solid currentColor;
    background: white;
    ...
  }
  
  .media-img {
    border: 2px solid brickred;
  }
}

הקוד שלמעלה מאפשר לנו להחיל צ'יפ על --detail: low-stock ו---detail: new, אבל יכול להיות ששמתם לב למיותר מסוים בקוד. נכון לעכשיו, אין אפשרות להריץ שאילתות רק על נוכחות של --detail עם @container style(--detail), מה שיאפשר שיתוף יעיל יותר של סגנונות ופחות חזרות. היכולת הזו נמצאת כרגע בבדיקה בקבוצת העבודה.

כרטיסי מזג אוויר

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

הדגמה של כרטיסי מזג אוויר.

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

@container style(--sunny: true) {
  .weather-card {
    background: linear-gradient(-30deg, yellow, orange);
  }
  
  .weather-card:after {
    content: url(<data-uri-for-demo-brevity>);
    background: gold;
  }
}

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

@container style(--sunny: true) and style(--cloudy: true) {
    .weather-card {
      background: linear-gradient(24deg, pink, violet);
    }
  
  .weather-card:after {
      content: url(<data-uri-for-demo-brevity>);
      background: violet;
  }
}

הפרדת נתונים מהעיצוב

בשני הדמואים האלה, יש יתרון מבני בהפרדה בין שכבת הנתונים (DOM שיומר בדף) לבין הסגנונות שחלים. הסגנונות נכתבים כאפשרויות שונות שקיימות בסגנון הרכיבים, ואילו נקודת קצה יכולה לשלוח את הנתונים שבהם היא תשתמש כדי להגדיר את הסגנון של הרכיב. אפשר להשתמש בערך יחיד, כמו במקרה הראשון, ולעדכן את הערך --detail, או במספר משתנים, כמו במקרה השני (הגדרת --rainy או --cloudy או --sunny. והחלק הכי טוב הוא שאפשר לשלב גם את הערכים האלה. בדיקה של --sunny וגם של --cloudy עשויה להציג סגנון של 'חלקית מעונן'.

אפשר לעדכן את ערכי המאפיינים בהתאמה אישית באמצעות JavaScript בצורה חלקה, גם בזמן הגדרת מודל ה-DOM (כלומר בזמן פיתוח הרכיב במסגרת) וגם בכל שלב באמצעות <parentElem>.style.setProperty('--myProperty’, <value>). I

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

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

const themePicker = document.querySelector('#theme-picker')
const btnParent = document.querySelector('.btn-section');

themePicker.addEventListener('input', (e) => {
  btnParent.style.setProperty('--theme', e.target.value);
})

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