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

אונה קראבץ
אונה קראבטס

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

תמיכה בדפדפן

  • 105
  • 105
  • 110
  • 16

מקור

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

תמיכה בדפדפן

  • 111
  • 111
  • x
  • x

מקור

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

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

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

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

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

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

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

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

בניגוד לשאילתות סגנון, אין צורך להחיל על .card-container הגבלה באמצעות הנכס container-type או 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, וניתן להריץ שאילתות על ערך ה-CSS של min-width באמצעות שאילתות סגנון. לכן כדאי להשתמש ב-wrapper של style() כדי להבהיר את ההבדל: @container style(min-width: 200px) { … }.

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

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

/* 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 שיעובד בדף) מהסגנונות שהוחלו. הסגנונות נכתבים בתור וריאנטים אפשריים של סגנון הרכיבים, ואילו נקודת קצה (endpoint) יכולה לשלוח את הנתונים שישמשו אותה לעיצוב הרכיב. אפשר להשתמש בערך יחיד, כמו במקרה הראשון, עדכון הערך --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 מעבר למאפיינים מותאמים אישית. האפשרות הזו כבר נכללת ברמת המפרט הנוכחית, אבל היא עדיין לא מוטמעת באף דפדפן. ההערכה לגבי ההקשר הבוליאני צפויה להתווסף לרמת המפרט הנוכחית לאחר פתרון הבעיה שהבעיה לא נפתרה, ואילו שאילתות טווח מתוכננת לרמה הבאה של המפרט.