במאמר הזה נסביר על התמיכה ב-CSS-in-JS בכלי הפיתוח (DevTools) שנוספה בגרסה 85 של Chrome, ובאופן כללי על המשמעות של CSS-in-JS ועל ההבדל בינו לבין CSS רגיל שכלי הפיתוח תומכים בו כבר זמן רב.
מהו CSS-in-JS?
ההגדרה של CSS-in-JS היא קצת מעורפלת. במובן רחב, זוהי גישה לניהול קוד CSS באמצעות JavaScript. לדוגמה, יכול להיות שתוכן ה-CSS מוגדר באמצעות JavaScript ופלט ה-CSS הסופי נוצר על ידי האפליקציה בזמן אמת.
בהקשר של DevTools, CSS-in-JS פירושו שתוכן ה-CSS מוחדר לדף באמצעות ממשקי CSSOM API. הזרקת CSS רגיל מתבצעת באמצעות אלמנטים מסוג <style>
או <link>
, ויש לו מקור סטטי (למשל צומת DOM או משאב רשת). לעומת זאת, ל-CSS-in-JS לעיתים קרובות אין מקור סטטי. מקרה מיוחד הוא שאפשר לעדכן את התוכן של רכיב <style>
באמצעות CSSOM API, וכתוצאה מכך המקור לא מסתנכרן עם גיליון הסגנונות בפועל של ה-CSS.
אם אתם משתמשים בספריית CSS-in-JS כלשהי (למשל styled-component, Emotion, JSS), יכול להיות שהספרייה תזריק סגנונות באמצעות ממשקי API של CSSOM ברקע, בהתאם למצב הפיתוח ולדפדפן.
בואו נעיף מעט בכמה דוגמאות לאופן שבו מוסיפים גיליון סגנונות באמצעות CSSOM API בדומה לפעולות של ספריות CSS-in-JS.
// Insert new rule to an existing CSS stylesheet
const element = document.querySelector('style');
const stylesheet = element.sheet;
stylesheet.replaceSync('.some { color: blue; }');
stylesheet.insertRule('.some { color: green; }');
אפשר גם ליצור גיליון סגנונות חדש לגמרי:
// Create a completely new stylesheet
const stylesheet = new CSSStyleSheet();
stylesheet.replaceSync('.some { color: blue; }');
stylesheet.insertRule('.some { color: green; }');
// Apply constructed stylesheet to the document
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
תמיכה ב-CSS בכלי הפיתוח
בכלי פיתוח, התכונה הנפוצה ביותר בעבודה עם CSS היא החלונית סגנונות. בחלונית Styles (סגנונות) אפשר לראות אילו כללים חלים על רכיב מסוים, לערוך את הכללים ולראות את השינויים בדף בזמן אמת.
לפני השנה שעברה, התמיכה בכללי CSS ששונו באמצעות ממשקי API של CSSOM הייתה מוגבלת למדי: אפשר היה לראות רק את הכללים שהוחלו, אבל לא לערוך אותם. המטרה העיקרית של החברה בשנה שעברה הייתה לאפשר עריכה של כללי CSS-in-JS באמצעות החלונית Styles. לפעמים אנחנו גם קוראים לסגנונות של CSS-in-JS "בנויים" כדי לציין שהם נוצרו באמצעות ממשקי Web API.
נבחן לעומק את אופן העריכה של סגנונות ב-DevTools.
מנגנון לעריכת סגנונות ב-DevTools
כשבוחרים רכיב בכלי הפיתוח, מוצגת החלונית Styles (סגנונות). בחלונית Styles מונפקת פקודת CDP שנקראת CSS.getMatchedStylesForNode כדי לקבל כללי CSS שחלים על האלמנט. CDP הוא ראשי תיבות של Chrome DevTools Protocol (פרוטוקול כלי הפיתוח ל-Chrome). זהו API שמאפשר לחזית של כלי הפיתוח לקבל מידע נוסף על הדף שנבדק.
כשהפונקציה CSS.getMatchedStylesForNode
מופעלת, היא מזהה את כל גיליונות הסגנונות במסמך ומנתחת אותם באמצעות מנתח ה-CSS של הדפדפן. לאחר מכן, המערכת יוצרת אינדקס שמשויך לכל כלל CSS עם מיקום במקור של גיליון הסגנונות.
יכול להיות שתתהו למה צריך לנתח את ה-CSS שוב. הבעיה היא שבשל סיבות שקשורות לביצועים, הדפדפן עצמו לא מודאג ממיקומי המקור של כללי ה-CSS, ולכן הוא לא מאחסן אותם. עם זאת, לכלי הפיתוח נדרשים מיקומי המקור כדי לתמוך בעריכת CSS. אנחנו לא רוצים שמשתמשי Chrome רגילים ישלמו את מחיר הפגיעה בביצועים, אבל אנחנו רוצים שמשתמשי DevTools יקבלו גישה למיקומי המקור. הגישה של הניתוח מחדש הזו נותנת מענה לשני התרחישים לדוגמה, עם כמה חסרונות מינימליים.
בשלב הבא, ההטמעה של CSS.getMatchedStylesForNode
מבקשת ממנוע הסגנונות של הדפדפן לספק כללי CSS שתואמים לרכיב הנתון. לבסוף, השיטה משייכת את הכללים שמוחזרים על ידי מנוע הסגנונות לקוד המקור ומספקת תשובה מובנית לגבי כללי ה-CSS, כדי ש-DevTools תדע איזה חלק מהכלל הוא הסלקטורים או המאפיינים. הוא מאפשר לכלי הפיתוח לערוך את הבורר ואת המאפיינים בנפרד.
עכשיו נסתכל על עריכה. זכור לך ש-CSS.getMatchedStylesForNode
מחזיר את מיקומי המקור של כל כלל? זה חיוני לעריכה. כשמשנים כלל, כלי הפיתוח מנפיקים פקודת CDP נוספת שמעדכנת את הדף בפועל. הפקודה כוללת את המיקום המקורי של קטע הקוד של הכלל שרוצים לעדכן ואת הטקסט החדש שצריך לעדכן את הקטע באמצעותו.
בקצה העורפי, כשמתנהלים עם קריאת העריכה, כלי הפיתוח מעדכנים את גיליון סגנונות היעד. הפעולה הזו גם מעדכנת את העותק של מקור גיליון הסגנון שבו הוא שומר, ומעדכנת את מיקומי המקור של הכלל המעודכן. בתגובה לקריאה לעריכה, ממשק הקצה של DevTools מקבל בחזרה את המיקומים המעודכנים של קטע הטקסט שעודכן זה עתה.
זה מסביר למה עריכת CSS-in-JS בכלי הפיתוח לא עבדה באופן מובנה: ל-CSS-in-JS אין מקור בפועל שמאוחסן במקום כלשהו וכללי ה-CSS נמצאים בזיכרון הדפדפן במבני הנתונים של CSSOM.
איך הוספנו תמיכה ב-CSS-in-JS
לכן, כדי לתמוך בעריכה של כללי CSS-in-JS, החלטנו שהפתרון הטוב ביותר הוא ליצור מקור לגיליונות סגנונות שנוצרו על ידי המערכת, שניתן לערוך אותם באמצעות המנגנון הקיים שתואר למעלה.
השלב הראשון הוא ליצור את טקסט המקור. מנוע הסגנון של הדפדפן מאחסן את כללי ה-CSS במחלקה CSSStyleSheet
. זוהי הכיתה שאפשר ליצור ממנה את המופעים מ-JavaScript, כפי שצוין קודם. הקוד ליצירת טקסט המקור הוא:
String InspectorStyleSheet::CollectStyleSheetRules() {
StringBuilder builder;
for (unsigned i = 0; i < page_style_sheet_->length(); i++) {
builder.Append(page_style_sheet_->item(i)->cssText());
builder.Append('\n');
}
return builder.ToString();
}
הוא מבצע איטרציה על הכללים שנמצאים במופע של CSSStyleSheet ומרכיב מהם מחרוזת אחת. השיטה הזו מופעלת כשיוצרים מופע של מחלקה InspectorStyleSheet. הכיתה InspectorStyleSheet עוטפת מופע של CSSStyleSheet ומחלצת מטא-נתונים נוספים שנדרשים ל-DevTools:
void InspectorStyleSheet::UpdateText() {
String text;
bool success = InspectorStyleSheetText(&text);
if (!success)
success = InlineStyleSheetText(&text);
if (!success)
success = ResourceStyleSheetText(&text);
if (!success)
success = CSSOMStyleSheetText(&text);
if (success)
InnerSetText(text, false);
}
בקטע הקוד הזה, CSSOMStyleSheetText
קורא ל-CollectStyleSheetRules
באופן פנימי. המערכת מפעילה את CSSOMStyleSheetText
אם גיליון הסגנון אינו מוטבע או שהוא גיליון סגנונות של משאב. בעיקרון, שני קטעי הקוד האלה כבר מאפשרים עריכה בסיסית של גיליונות הסגנון שנוצרים באמצעות המבנה new CSSStyleSheet()
.
מקרה מיוחד הוא גיליונות הסגנון שמשויכים לתג <style>
שעברו מוטציה באמצעות CSSOM API. במקרה כזה, גיליון הסגנון מכיל את טקסט המקור וכללים נוספים שלא קיימים במקור. כדי לטפל במקרה הזה, אנחנו משיקים שיטה למיזוג הכללים הנוספים האלה בטקסט המקור. הסדר חשוב כאן כי אפשר להוסיף כללי CSS באמצע טקסט המקור המקורי. לדוגמה, נניח שהרכיב <style>
המקורי הכיל את הטקסט הבא:
/* comment */
.rule1 {}
.rule3 {}
לאחר מכן נוספו לדף כמה כללים חדשים באמצעות ה-JS API, והפיק את סדר הכללים הבא: .rule0 , .rule1 , .rule2 , .rule3 , .rule4? טקסט המקור שנוצר לאחר פעולת המיזוג אמור להיראות כך:
.rule0 {}
/* comment */
.rule1 {}
.rule2 {}
.rule3 {}
.rule4 {}
חשוב לשמור על התגובות וההכנסה המקוריות בתהליך העריכה, כי המיקומים של טקסט המקור של הכללים חייבים להיות מדויקים.
היבט נוסף שמיוחד לגיליונות סגנונות של CSS-in-JS הוא שאפשר לשנות אותם בדף בכל שלב. אם הכללים בפועל של CSSOM לא יהיו מסונכרנים עם גרסת הטקסט, העריכה לא תפעל. לשם כך השקנו probe כזה, שמאפשר לדפדפן להודיע לחלק העורפי של כלי הפיתוח על שינוי של גיליון סגנונות. לאחר מכן, סגנונות ה-CSS שעברו מוטציה מסונכרנים במהלך הקריאה הבאה ל-CSS.getMatchedStylesForNode.
אחרי שכל החלקים האלה מותקנים, אפשר כבר לערוך CSS ב-JS, אבל רצינו לשפר את ממשק המשתמש כדי לציין אם נוצרה גיליון סגנונות. הוספנו מאפיין חדש בשם isConstructed
ל-CSS.CSSStyleSheetHeader ב-CDP, שמאפשר לקצה הקדמי להציג בצורה נכונה את המקור של כלל CSS:
מסקנות
לסיכום, עברנו על תרחישי השימוש הרלוונטיים שקשורים ל-CSS-in-JS שלא נתמכים בכלי הפיתוח, וסברנו על הפתרון לתמיכה בתרחישי השימוש האלה. החלק המעניין בהטמעה הזו הוא שהצלחנו לנצל את הפונקציונליות הקיימת על ידי הוספת טקסט מקור רגיל לכללי ה-CSSOM, וכך למנוע צורך בתכנון מחדש מלא של עריכת הסגנונות ב-DevTools.
לקבלת רקע נוסף, אפשר לעיין בהצעה שלנו לעיצוב או בבאג המעקב ב-Chromium, שמפנה לכל התיקונים הקשורים.
הורדת הערוצים לתצוגה מקדימה
מומלץ להשתמש ב-Chrome Canary, ב-Dev או ב-Beta כדפדפן הפיתוח שמוגדר כברירת מחדל. הערוצים לתצוגה מקדימה אלה מעניקים לך גישה לתכונות החדשות של כלי הפיתוח, מאפשרים לך לבדוק ממשקי API מתקדמים של פלטפורמות אינטרנט ולעזור לך לגלות בעיות באתר שלך לפני שהמשתמשים עושים זאת.
פנייה לצוות של כלי הפיתוח ל-Chrome
אתם יכולים להשתמש באפשרויות הבאות כדי לדון בתכונות החדשות, בעדכונים או בכל דבר אחר שקשור ל-DevTools.
- אתם יכולים לשלוח לנו משוב ובקשות להוספת תכונות בכתובת crbug.com.
- מדווחים על בעיה בכלי הפיתוח באמצעות הסמל אפשרויות נוספות > עזרה > דיווח על בעיה בכלי הפיתוח ב-DevTools.
- שולחים ציוץ אל @ChromeDevTools.
- נשמח לשמוע מה חדש: מה חדש בסרטונים של כלי הפיתוח ב-YouTube או טיפים בנושא כלי פיתוח ב-YouTube.