บทความนี้กล่าวถึงการรองรับ CSS-in-JS ในเครื่องมือสำหรับนักพัฒนาเว็บที่เริ่มใช้มาตั้งแต่ Chrome 85 และโดยทั่วไปความหมายของ CSS-in-JS และสิ่งที่แตกต่างจาก CSS ทั่วไปที่ได้รับการสนับสนุนจากเครื่องมือสำหรับนักพัฒนาเว็บมาเป็นเวลานาน
CSS-in-JS คืออะไร
คำจำกัดความของ CSS-in-JS ค่อนข้างคลุมเครือ ในความหมายกว้างๆ นี่คือแนวทางในการจัดการโค้ด CSS โดยใช้ JavaScript ตัวอย่างเช่น อาจหมายความว่าเนื้อหา CSS ได้รับการกำหนดโดยใช้ JavaScript และแอปจะสร้างเอาต์พุต CSS สุดท้ายแบบเรียลไทม์
ในบริบทของเครื่องมือสำหรับนักพัฒนาเว็บ นั้น CSS-in-JS หมายความว่าจะมีการแทรกเนื้อหา CSS ลงในหน้าเว็บโดยใช้ CSSOM API ระบบจะแทรก CSS ปกติโดยใช้องค์ประกอบ <style>
หรือ <link>
และมีแหล่งที่มาแบบคงที่ (เช่น โหนด DOM หรือทรัพยากรเครือข่าย) ในทางตรงกันข้าม CSS-in-JS มักไม่มีแหล่งที่มาแบบคงที่ กรณีพิเศษในที่นี้คือสามารถอัปเดตเนื้อหาขององค์ประกอบ <style>
ได้โดยใช้ CSSOM API ซึ่งทำให้แหล่งที่มาไม่สอดคล้องกับสไตล์ชีต CSS จริง
หากคุณใช้ไลบรารี CSS-in-JS (เช่น styled-component, Emotion, JSS) ไลบรารีอาจแทรกสไตล์โดยใช้ CSSOM API ขั้นสูง โดยขึ้นอยู่กับโหมดของการพัฒนาและเบราว์เซอร์
มาดูตัวอย่างวิธีแทรกสไตล์ชีตโดยใช้ 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 ในเครื่องมือสำหรับนักพัฒนาเว็บ
ใน DevTools ฟีเจอร์ที่ใช้กันมากที่สุดเมื่อทำงานกับ CSS คือแผงรูปแบบ ในแผงรูปแบบ คุณสามารถดูกฎที่ใช้กับองค์ประกอบหนึ่งๆ รวมถึงแก้ไขกฎและดูการเปลี่ยนแปลงในหน้าเว็บแบบเรียลไทม์ได้
ก่อนปีที่แล้ว การรองรับกฎ CSS ที่แก้ไขโดยใช้ CSSOM API นั้นค่อนข้างถูกจำกัด นั่นคือคุณจะเห็นเฉพาะกฎที่ใช้แล้วแต่แก้ไขไม่ได้ เป้าหมายหลักของเราเมื่อปีที่แล้วคือการอนุญาตให้แก้ไขกฎ CSS-in-JS โดยใช้แผงรูปแบบ บางครั้งเรายังเรียกรูปแบบ CSS-in-JS ว่า "constructed" เพื่อระบุว่ารูปแบบดังกล่าวสร้างขึ้นโดยใช้ Web API
มาเจาะลึกรายละเอียดของการแก้ไขรูปแบบในเครื่องมือสำหรับนักพัฒนาเว็บกัน
กลไกการแก้ไขรูปแบบในเครื่องมือสำหรับนักพัฒนาเว็บ
เมื่อเลือกองค์ประกอบในเครื่องมือสำหรับนักพัฒนาเว็บ แผงรูปแบบจะปรากฏขึ้น แผงรูปแบบจะออกคำสั่ง CDP ชื่อ CSS.getMatchedStylesForNode เพื่อรับกฎ CSS ที่ใช้กับองค์ประกอบ CDP ย่อมาจาก Chrome DevTools Protocol และเป็น API ที่ช่วยให้ฟรอนท์เอนด์ของเครื่องมือสำหรับนักพัฒนาเว็บได้รับข้อมูลเพิ่มเติมเกี่ยวกับหน้าที่ตรวจสอบ
เมื่อเรียกใช้ CSS.getMatchedStylesForNode
จะระบุสไตล์ชีตทั้งหมดในเอกสารและแยกวิเคราะห์โดยใช้โปรแกรมแยกวิเคราะห์ CSS ของเบราว์เซอร์ จากนั้นจะสร้างดัชนีที่เชื่อมโยงกฎ CSS ทั้งหมดกับตำแหน่งในแหล่งที่มาของสไตล์ชีต
คุณอาจถามว่าเหตุใดจึงต้องแยกวิเคราะห์ CSS อีกครั้ง ปัญหาก็คือ เนื่องจากเหตุผลด้านประสิทธิภาพ เบราว์เซอร์เองไม่กังวลเกี่ยวกับตำแหน่งแหล่งที่มาของกฎ CSS จึงไม่จัดเก็บกฎเหล่านั้นไว้ แต่เครื่องมือสำหรับนักพัฒนาเว็บต้องใช้ตำแหน่งต้นทางเพื่อรองรับการแก้ไข CSS เราไม่ต้องการให้ผู้ใช้ Chrome ทั่วไปจ่ายโทษต่อประสิทธิภาพการทำงาน แต่เราต้องการให้ผู้ใช้เครื่องมือสำหรับนักพัฒนาเว็บสามารถเข้าถึงตําแหน่งต้นทางได้ แนวทางการแยกวิเคราะห์ใหม่นี้จะช่วยแก้ปัญหาทั้ง 2 กรณีโดยมีข้อเสียน้อยที่สุด
จากนั้น การใช้งาน CSS.getMatchedStylesForNode
จะขอให้เครื่องมือรูปแบบของเบราว์เซอร์ระบุกฎ CSS ที่ตรงกับองค์ประกอบที่กำหนด และสุดท้าย เมธอดจะเชื่อมโยงกฎที่เครื่องมือรูปแบบแสดงผลกับซอร์สโค้ด และแสดงคำตอบแบบมีโครงสร้างเกี่ยวกับกฎ CSS เพื่อให้เครื่องมือสำหรับนักพัฒนาเว็บรู้ว่าส่วนใดของกฎคือตัวเลือกหรือพร็อพเพอร์ตี้ ช่วยให้เครื่องมือสำหรับนักพัฒนาเว็บแก้ไขตัวเลือกและคุณสมบัติแยกกันได้
ตอนนี้เรามาดูการแก้ไขกัน อย่าลืมว่า CSS.getMatchedStylesForNode
แสดงตำแหน่งต้นทางสำหรับทุกกฎใช่ไหม ซึ่งเป็นสิ่งที่สำคัญมากสำหรับการตัดต่อ เมื่อเปลี่ยนกฎ เครื่องมือสำหรับนักพัฒนาเว็บจะออกคำสั่ง CDP อีกรายการหนึ่งซึ่งอัปเดตหน้าเว็บจริงๆ คำสั่งนี้จะมีตำแหน่งเดิมของส่วนย่อยของกฎที่ได้รับการอัปเดต และข้อความใหม่ที่ต้องอัปเดตส่วนย่อย
ในแบ็กเอนด์ เมื่อจัดการการเรียกแก้ไข เครื่องมือสำหรับนักพัฒนาเว็บจะอัปเดตสไตล์ชีตเป้าหมาย นอกจากนี้ ยังอัปเดตสำเนาของแหล่งที่มาของสไตล์ชีตที่เก็บรักษาไว้ และอัปเดตตำแหน่งแหล่งที่มาสำหรับกฎที่อัปเดต ฟรอนท์เอนด์ของเครื่องมือสำหรับนักพัฒนาเว็บจะรับตำแหน่งที่อัปเดตสำหรับส่วนย่อยข้อความที่เพิ่งอัปเดตตามการเรียกแก้ไข
ปัญหานี้จะอธิบายสาเหตุที่การแก้ไข CSS-in-JS ใน DevTools ไม่ทำงานตั้งแต่แกะกล่อง: 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.getMatchStylesForNode ครั้งถัดไป
เมื่อมีส่วนประกอบทั้งหมดเหล่านี้แล้ว การแก้ไข CSS-in-JS ก็ใช้ได้อยู่แล้ว แต่เราต้องการปรับปรุง UI เพื่อระบุว่ามีการสร้างสไตล์ชีตหรือไม่ เราได้เพิ่มแอตทริบิวต์ใหม่ที่ชื่อว่า isConstructed
ไปยัง CSS.CSSStyleSheetHeader ของ CDP ซึ่งฟรอนท์เอนด์ใช้เพื่อแสดงแหล่งที่มาของกฎ CSS อย่างถูกต้องดังนี้
บทสรุป
เพื่อสรุปเรื่องราวของเราในที่นี้ เราได้ดู Use Case ที่เกี่ยวข้องซึ่งเกี่ยวข้องกับ CSS-in-JS ที่เครื่องมือสำหรับนักพัฒนาเว็บไม่รองรับและอธิบายโซลูชันเพื่อสนับสนุนกรณีการใช้งานเหล่านั้นโดยละเอียด สิ่งที่น่าสนใจของการนำเครื่องมือนี้ไปใช้คือเราสามารถใช้ประโยชน์จากฟังก์ชันที่มีอยู่โดยทำให้กฎ CSSOM CSS มีข้อความต้นฉบับที่สม่ำเสมอ ซึ่งช่วยให้ไม่ต้องแก้ไขสไตล์ทั้งหมดในเครื่องมือสำหรับนักพัฒนาเว็บอีกต่อไป
หากต้องการทราบข้อมูลพื้นฐานเพิ่มเติม โปรดดูข้อเสนอการออกแบบของเราหรือข้อบกพร่องในการติดตามของ Chromium ซึ่งอ้างอิงแพตช์ที่เกี่ยวข้องทั้งหมด
ดาวน์โหลดเวอร์ชันตัวอย่าง
ลองใช้ Chrome Canary, Dev หรือ เบต้า เป็นเบราว์เซอร์เริ่มต้นสำหรับการพัฒนา ช่องทางพรีวิวเหล่านี้จะทำให้คุณเข้าถึงฟีเจอร์ล่าสุดของเครื่องมือสำหรับนักพัฒนาเว็บ ทดสอบ API แพลตฟอร์มเว็บที่ล้ำสมัย และพบปัญหาในเว็บไซต์ก่อนผู้ใช้
ติดต่อทีม Chrome DevTools
ใช้ตัวเลือกต่อไปนี้เพื่อพูดคุยเกี่ยวกับฟีเจอร์ใหม่และการเปลี่ยนแปลงในโพสต์ หรืออื่นๆ ที่เกี่ยวข้องกับเครื่องมือสำหรับนักพัฒนาเว็บ
- ส่งข้อเสนอแนะหรือความคิดเห็นถึงเราทาง crbug.com
- รายงานปัญหาเกี่ยวกับเครื่องมือสำหรับนักพัฒนาเว็บโดยใช้ตัวเลือกเพิ่มเติม
> ความช่วยเหลือ > รายงานปัญหาเกี่ยวกับเครื่องมือสำหรับนักพัฒนาเว็บในเครื่องมือสำหรับนักพัฒนาเว็บ
- ทวีตที่ @ChromeDevTools
- แสดงความคิดเห็นว่ามีอะไรใหม่ในวิดีโอ YouTube เครื่องมือสำหรับนักพัฒนาเว็บ หรือวิดีโอ YouTube สำหรับเครื่องมือสำหรับนักพัฒนาเว็บ