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