การแลกเปลี่ยนของ CSS-in-JS

ภาพถ่ายโดยอาร์เทมบาหลี

เมื่อเร็ว ๆ นี้ฉันเขียนภาพรวมระดับสูงของ CSS-in-JS ส่วนใหญ่พูดถึงปัญหาที่วิธีนี้พยายามแก้ไข ผู้เขียนห้องสมุดไม่ค่อยใช้เวลาอธิบายการแลกเปลี่ยนโซลูชัน บางครั้งอาจเป็นเพราะพวกเขามีอคติมากเกินไปและบางครั้งพวกเขาก็ไม่รู้ว่าผู้ใช้ใช้งานเครื่องมืออย่างไร ดังนั้นนี่คือความพยายามที่จะอธิบายถึงการแลกเปลี่ยนที่ฉันได้เห็นไปแล้ว ฉันคิดว่ามันเป็นสิ่งสำคัญที่จะพูดถึงว่าฉันเป็นผู้เขียน JSS ดังนั้นฉันจึงควรได้รับการพิจารณาว่ามีอคติ

ผลกระทบต่อสังคม

มีเลเยอร์ของคนที่ทำงานบนแพลตฟอร์มเว็บและไม่รู้จัก JavaScript ใด ๆ คนเหล่านั้นได้รับเงินเพื่อเขียน HTML และ CSS CSS-in-JS ได้สร้างผลกระทบอย่างมากต่อเวิร์กโฟลว์ของนักพัฒนา การเปลี่ยนแปลงที่เกิดขึ้นอย่างแท้จริงไม่สามารถทำได้หากไม่มีบางคนถูกทอดทิ้ง ฉันไม่ทราบว่า CSS-in-JS จะต้องเป็นวิธีเดียวหรือไม่ แต่การยอมรับโดยรวมเป็นสัญญาณที่ชัดเจนของปัญหาการใช้ CSS ในแอปพลิเคชันที่ทันสมัย

ส่วนใหญ่ของปัญหาคือเราไม่สามารถสื่อสารกรณีการใช้งานอย่างถูกต้องที่ CSS-in-JS ส่องสว่างและวิธีใช้อย่างถูกต้องสำหรับงาน ผู้ที่ชื่นชอบ CSS-JS จำนวนมากประสบความสำเร็จในการโปรโมตเทคโนโลยี แต่มีนักวิจารณ์ไม่มากที่พูดคุยเกี่ยวกับการแลกเปลี่ยนในรูปแบบที่สร้างสรรค์โดยไม่ต้องใช้เครื่องมือเหวี่ยงราคาถูก ด้วยเหตุนี้เราจึงซ่อนการแลกเปลี่ยนไว้มากมายและไม่ได้พยายามอย่างเต็มที่ในการให้คำอธิบายและการแก้ปัญหา

CSS-in-JS เป็นความพยายามในการจัดการกรณีการใช้งานที่ซับซ้อนได้ง่ายขึ้นดังนั้นอย่ากดในที่ที่ไม่จำเป็น!

ค่าใช้จ่ายรันไทม์

เมื่อ CSS ถูกสร้างขึ้นจาก JavaScript ตอนรันไทม์ในเบราว์เซอร์จะมีค่าใช้จ่ายโดยธรรมชาติ ค่าใช้จ่ายในการรันไทม์แตกต่างกันไปในแต่ละไลบรารี นี่เป็นเกณฑ์มาตรฐานที่ดี แต่ให้ทำการทดสอบของคุณเอง ความแตกต่างที่สำคัญที่รันไทม์ปรากฏขึ้นอยู่กับความจำเป็นที่จะต้องมีการแยก CSS อย่างเต็มรูปแบบของสตริงแม่แบบ, จำนวนของการเพิ่มประสิทธิภาพ, รายละเอียดการใช้งานรูปแบบไดนามิก, อัลกอริทึมการแปลงแป้นพิมพ์และการรวมกรอบ

นอกเหนือจากค่าใช้จ่ายที่อาจเกิดขึ้นแล้วคุณต้องพิจารณากลยุทธ์การรวม 4 แบบที่แตกต่างกันเนื่องจากบางไลบรารี CSS-in-JS สนับสนุนหลายกลยุทธ์และขึ้นอยู่กับผู้ใช้ในการใช้งาน *

กลยุทธ์ที่ 1: การสร้างรันไทม์เท่านั้น

การสร้าง CSS แบบรันไทม์เป็นเทคนิคที่สร้างสตริง CSS ใน JavaScript จากนั้นทำการแทรกสตริงนั้นโดยใช้แท็กสไตล์ลงในเอกสาร เทคนิคนี้สร้างสไตล์ชีทไม่ใช่สไตล์อินไลน์

ข้อเสียของการสร้างรันไทม์คือการไม่สามารถให้เนื้อหาที่มีสไตล์ในระยะเริ่มต้นเมื่อเอกสารเริ่มโหลด โดยทั่วไปวิธีการนี้เหมาะสำหรับแอปพลิเคชันที่ไม่มีเนื้อหาที่มีประโยชน์ในทันที โดยปกติแล้วแอปพลิเคชันดังกล่าวต้องมีการโต้ตอบกับผู้ใช้ก่อนที่จะเป็นประโยชน์กับผู้ใช้จริง ๆ บ่อยครั้งที่แอปพลิเคชันดังกล่าวทำงานกับเนื้อหาที่เป็นแบบไดนามิกจนล้าสมัยทันทีที่คุณโหลดดังนั้นคุณต้องสร้างขั้นตอนการอัปเดตก่อนหน้าเช่น Twitter นอกจากนี้เมื่อผู้ใช้ลงชื่อเข้าใช้ไม่จำเป็นต้องให้ HTML สำหรับ SEO

หากการโต้ตอบต้องการ JavaScript ต้องโหลดชุดรวมก่อนที่แอปจะพร้อมใช้งาน ตัวอย่างเช่นคุณสามารถแสดงเนื้อหาของแชนเนลเริ่มต้นเมื่อโหลด Slack ในเอกสาร แต่มีแนวโน้มว่าผู้ใช้จะต้องการเปลี่ยนช่องทันทีหลังจากนั้น ดังนั้นหากคุณโหลดเนื้อหาเริ่มต้นเพียงเพื่อทิ้งทันที

การรับรู้ประสิทธิภาพของแอปพลิเคชันดังกล่าวสามารถปรับปรุงได้ด้วยตัวยึดตำแหน่งและลูกเล่นอื่น ๆ เพื่อให้แอปพลิเคชันรู้สึกได้ทันทีกว่าที่เป็นจริง แอปพลิเคชันดังกล่าวมักจะมีข้อมูลจำนวนมากดังนั้นพวกเขาจะไม่เป็นประโยชน์อย่างรวดเร็วเหมือนบทความ

กลยุทธ์ที่ 2: การสร้างรันไทม์ด้วย Critical CSS

Critical CSS เป็นจำนวนขั้นต่ำของ CSS ที่ต้องใช้ในการจัดสไตล์หน้าเว็บในสถานะเริ่มต้น มันแสดงผลโดยใช้แท็กสไตล์ในส่วนหัวของเอกสาร เทคนิคนี้ใช้กันอย่างแพร่หลายโดยมีและไม่มี CSS-in-JS ในทั้งสองกรณีคุณมีแนวโน้มที่จะโหลดกฎ CSS สองครั้งซึ่งเป็นส่วนหนึ่งของ Critical CSS และอีกครั้งหนึ่งในฐานะส่วนหนึ่งของชุด JavaScript หรือ CSS ขนาดของ Critical CSS นั้นค่อนข้างใหญ่ขึ้นอยู่กับปริมาณของเนื้อหา โดยปกติแล้วเอกสารจะไม่ถูกแคช

หากไม่มี Critical CSS แอปพลิเคชันหน้าเดียวที่มีเนื้อหาหนักหน่วงพร้อมกับ runtime CSS-in-JS จะต้องแสดงตัวยึดตำแหน่งแทนเนื้อหา สิ่งนี้ไม่ดีเพราะอาจเป็นประโยชน์กับผู้ใช้มาก่อนมากปรับปรุงการเข้าถึงอุปกรณ์ต่ำสุดและสำหรับการเชื่อมต่อแบนด์วิดธ์ต่ำ

ด้วย CSS ที่สำคัญการสร้าง CSS แบบรันไทม์สามารถทำได้ในภายหลังโดยไม่ปิดกั้น UI ในระยะเริ่มต้น ได้รับการเตือนว่าสำหรับอุปกรณ์มือถือระดับต่ำซึ่งมีอายุประมาณ 5 ปีขึ้นไปการสร้าง CSS จาก JavaScript อาจส่งผลเสียต่อประสิทธิภาพการทำงาน ขึ้นอยู่กับปริมาณของ CSS ที่ถูกสร้างขึ้นอย่างมากและไลบรารีที่ใช้ดังนั้นจึงไม่สามารถทำให้เป็นมาตรฐานได้

ข้อเสียของกลยุทธ์นี้คือค่าใช้จ่ายในการแยก Critical CSS และค่าใช้จ่ายของการสร้าง CSS แบบรันไทม์

กลยุทธ์ 3: การสกัดแบบบิลด์เวลาเท่านั้น

กลยุทธ์นี้เป็นกลยุทธ์เริ่มต้นบนเว็บที่ไม่มี CSS-in-JS บางไลบรารีใน CSS-JS อนุญาตให้คุณแยก CSS แบบคงที่ในเวลาบิลด์ * ในกรณีนี้ไม่มีการใช้งานโอเวอร์เฮดแบบรันไทม์ CSS จะแสดงผลบนหน้าโดยใช้แท็กลิงก์ ค่าใช้จ่ายในการสร้าง CSS จะได้รับการชำระล่วงหน้าหนึ่งครั้ง

มี 2 ​​การแลกเปลี่ยนที่สำคัญที่นี่:

  1. คุณไม่สามารถใช้ข้อเสนอ CSS-in-JS แบบไดนามิก API บางอย่างที่รันไทม์เนื่องจากคุณไม่สามารถเข้าถึงสถานะได้ บ่อยครั้งที่คุณยังไม่สามารถใช้คุณสมบัติที่กำหนดเองของ CSS ได้เนื่องจากเบราว์เซอร์เหล่านี้ไม่ได้รับการสนับสนุนในทุกเบราว์เซอร์และไม่สามารถโพลีฟิลในเวลาที่สร้างได้ตามปกติ ในกรณีนี้คุณจะต้องแก้ไขปัญหาสำหรับการจัดรูปแบบไดนามิกและการจัดรูปแบบตามสถานะ *
  2. หากไม่มี Critical CSS และด้วยแคชที่ว่างเปล่าคุณจะปิดกั้นการทาสีแรกจนกว่าจะได้รับการโหลด CSS องค์ประกอบลิงค์ในส่วนหัวของเอกสารบล็อกการแสดงผล HTML
  3. ความจำเพาะที่ไม่ได้กำหนดไว้ล่วงหน้าด้วยการแยกบันเดิลตามเพจในแอปพลิเคชันหน้าเดียว *

กลยุทธ์ที่ 4: การสร้างเวลาแยกด้วย Critical CSS

กลยุทธ์นี้ไม่ซ้ำกับ CSS-in-JS การสกัดแบบคงที่เต็มรูปแบบด้วย CSS ที่สำคัญให้ประสิทธิภาพที่ดีที่สุดเมื่อทำงานกับแอปพลิเคชันแบบคงที่มากขึ้น วิธีการนี้ยังคงมีการแลกเปลี่ยน CSS ข้างต้นดังกล่าวข้างต้นยกเว้นว่าแท็กลิงก์บล็อกสามารถย้ายไปที่ด้านล่างของเอกสาร

มีกลยุทธ์การเรนเดอร์ CSS 4 หลัก มีเพียง 2 คนเท่านั้นที่มีความเฉพาะเจาะจงกับ CSS-in-JS และไม่ใช้กับไลบรารีทั้งหมด

การเข้าถึง

CSS-in-JS สามารถลดความสามารถในการเข้าถึงเมื่อใช้งานผิดวิธี สิ่งนี้จะเกิดขึ้นเมื่อไซต์เนื้อหาแบบสแตติกส่วนใหญ่ถูกนำไปใช้โดยไม่มีการแยก Critical CSS เพื่อให้ไม่สามารถวาด HTML ได้ก่อนที่จะมีการโหลดและประเมินบันเดิล JavaScript สิ่งนี้สามารถเกิดขึ้นได้เมื่อไฟล์ CSS ขนาดใหญ่แสดงผลโดยใช้แท็กลิงก์บล็อกในส่วนหัวของเอกสารซึ่งเป็นปัญหาปัจจุบันที่ได้รับความนิยมมากที่สุดด้วยการฝังแบบดั้งเดิมและไม่เฉพาะกับ CSS-in-JS

นักพัฒนาจะต้องรับผิดชอบต่อความสามารถในการเข้าถึง ยังมีความคิดที่เข้าใจผิดที่ชัดเจนว่าการเชื่อมต่ออินเทอร์เน็ตที่ไม่เสถียรเป็นปัญหาของประเทศที่อ่อนแอทางเศรษฐกิจ เรามักจะลืมว่าเรามีปัญหาการเชื่อมต่อทุกวันเมื่อเราเข้าสู่ระบบรถไฟใต้ดินหรืออาคารขนาดใหญ่ การเชื่อมต่อมือถือที่ไม่ต้องใช้สายเคเบิลเป็นสิ่งที่เหลือเชื่อ ไม่ใช่เรื่องง่ายเลยที่จะมีการเชื่อมต่อ WiFi ที่เสถียรตัวอย่างเช่นเครือข่าย Wi-Fi 2.4 GHz สามารถรบกวนจากเตาไมโครเวฟได้!

ค่าใช้จ่ายของ Critical CSS พร้อมการเรนเดอร์ฝั่งเซิร์ฟเวอร์

ในการรับการแยก CSS ที่สำคัญสำหรับ CSS-in-JS เราต้อง SSR SSR เป็นกระบวนการสร้าง HTML ขั้นสุดท้ายสำหรับสถานะที่กำหนดของแอปพลิเคชันบนเซิร์ฟเวอร์ ในความเป็นจริงมันค่อนข้างเป็นกระบวนการที่ซับซ้อนและมีราคาแพง มันต้องการจำนวนรอบของ CPU บนเซิร์ฟเวอร์สำหรับแต่ละคำขอ HTTP

CSS-in-JS มักจะใช้ประโยชน์จากข้อเท็จจริงที่ว่ามันติดอยู่ในขั้นตอนการเรนเดอร์ HTML * มันรู้ว่า HTML ถูกเรนเดอร์อะไรและ CSS นั้นต้องการอะไรเพื่อที่จะสามารถสร้างจำนวนน้อยที่สุด Critical CSS จะเพิ่มโอเวอร์เฮดเพิ่มเติมให้กับการเรนเดอร์ HTML บนเซิร์ฟเวอร์เพราะ CSS นั้นจะต้องรวบรวมเป็นสตริง CSS สุดท้ายด้วย ในบางสถานการณ์มันเป็นเรื่องยากหรือเป็นไปไม่ได้ที่จะทำแคชบนเซิร์ฟเวอร์

แสดงผลกล่องดำ

คุณต้องระวังว่า CSS-in-JS ไลบรารี่ที่คุณใช้นั้นมีการแสดงผล CSS ของคุณอย่างไร ตัวอย่างเช่นผู้คนมักไม่ทราบว่า Styled Components และ Emotion ใช้สไตล์ไดนามิกอย่างไร รูปแบบไดนามิกเป็นไวยากรณ์ที่อนุญาตให้ใช้ฟังก์ชัน JavaScript ภายในการประกาศสไตล์ของคุณ ฟังก์ชั่นเหล่านั้นยอมรับอุปกรณ์ประกอบฉากและส่งคืนบล็อก CSS

เพื่อให้ความจำเพาะเจาะจงของแหล่งที่มาสอดคล้องกันไลบรารีทั้งสองที่มีชื่อด้านบนจะสร้างกฎ CSS ใหม่หากมีการประกาศแบบไดนามิกและการอัปเดตส่วนประกอบด้วยอุปกรณ์ประกอบฉากใหม่ เพื่อแสดงสิ่งที่ฉันหมายถึงฉันสร้างแซนด์บ็อกซ์นี้ ใน JSS เราตัดสินใจเลือกการแลกเปลี่ยนที่แตกต่างกันซึ่งช่วยให้เราสามารถอัปเดตคุณสมบัติแบบไดนามิกโดยไม่ต้องสร้างกฎ CSS ใหม่ *

โค้งการเรียนรู้ที่สูงชัน

สำหรับผู้ที่คุ้นเคยกับ CSS แต่ยังใหม่กับ JavaScript จำนวนงานเริ่มต้นที่จะเพิ่มความเร็วด้วย CSS-in-JS อาจมีขนาดค่อนข้างใหญ่

คุณไม่จำเป็นต้องเป็นนักพัฒนา JavaScript มืออาชีพเพื่อเขียน CSS-in-JS จนถึงจุดที่ตรรกะที่ซับซ้อนเข้ามาเกี่ยวข้อง เราไม่สามารถสรุปความซับซ้อนของการจัดแต่งทรงผมได้จริง ๆ เพราะขึ้นอยู่กับกรณีการใช้งาน ในกรณีที่ CSS-in-JS มีความซับซ้อนมีความเป็นไปได้สูงว่าการใช้งานกับ vanilla CSS จะมีความซับซ้อนยิ่งขึ้น

สำหรับ CSS-in-JS พื้นฐานสไตล์หนึ่งต้องทราบวิธีการประกาศตัวแปรวิธีการใช้สตริงแม่แบบและแก้ไขค่า JavaScript หากใช้การระบุวัตถุต้องรู้วิธีทำงานกับวัตถุ JavaScript และไวยากรณ์ที่อิงกับไลบรารีเฉพาะไลบรารี หากเกี่ยวข้องกับการกำหนดสไตล์แบบไดนามิกคุณจำเป็นต้องรู้วิธีใช้ฟังก์ชัน JavaScript และเงื่อนไขต่างๆ

โดยรวมแล้วมีช่วงการเรียนรู้เราไม่สามารถปฏิเสธได้ ช่วงการเรียนรู้นี้มักจะไม่ใหญ่กว่าการเรียนรู้ Sass ที่จริงแล้วฉันสร้างหลักสูตร egghead นี้เพื่อแสดงให้เห็นถึงสิ่งนี้

ไม่มีการทำงานร่วมกัน

libs CSS-in-JS ส่วนใหญ่ไม่สามารถทำงานร่วมกันได้ ซึ่งหมายความว่าสไตล์ที่เขียนโดยใช้หนึ่งไลบรารีจะไม่สามารถแสดงผลได้โดยใช้ห้องสมุดอื่น ในทางปฏิบัติหมายความว่าคุณไม่สามารถเปลี่ยนแอปพลิเคชันทั้งหมดของคุณได้อย่างง่ายดายจากการใช้งานหนึ่งไปอีกแอปหนึ่ง นอกจากนี้ยังหมายความว่าคุณไม่สามารถแชร์ UI ของคุณบน NPM ได้อย่างง่ายดายโดยไม่ต้องนำไลบรารี CSS-in-JS ของคุณที่เลือกลงในกลุ่มผู้ใช้เว้นแต่คุณจะมีการแยกแบบคงที่สำหรับเวลาในการสร้าง CSS

เราได้เริ่มทำงานกับรูปแบบ ISTF ที่ควรจะแก้ไขปัญหานี้ แต่น่าเสียดายที่เรายังไม่มีเวลามาสู่สถานะพร้อมใช้งานจริง *

ฉันคิดว่าการแชร์องค์ประกอบเฟรมเวิร์ก UI แบบไม่เชื่อเรื่องพระเจ้าในโดเมนสาธารณะยังคงเป็นปัญหาที่แก้ได้ยาก

ความเสี่ยงด้านความปลอดภัย

เป็นไปได้ที่จะแนะนำการรั่วไหลของความปลอดภัยด้วย CSS-in-JS เช่นเดียวกับแอปพลิเคชันฝั่งไคลเอ็นต์คุณจะต้องหลีกเลี่ยงการป้อนข้อมูลผู้ใช้ก่อนที่จะแสดงผลเสมอ

บทความนี้จะให้ข้อมูลเชิงลึกมากขึ้นและตัวอย่างบางส่วนของการ defacing

ชื่อคลาสที่อ่านไม่ได้

บางคนยังคิดว่าเป็นสิ่งสำคัญที่เราจะต้องเก็บชื่อคลาสที่อ่านง่ายบนเว็บ ขณะนี้ไลบรารี CSS-in-JS จำนวนมากให้ชื่อคลาสที่มีความหมายตามชื่อการประกาศหรือชื่อคอมโพเนนต์ในโหมดการพัฒนา บางคนก็ให้คุณปรับแต่งฟังก์ชั่นตัวสร้างชื่อคลาส

ในโหมดการผลิตแม้ว่าส่วนใหญ่จะสร้างชื่อที่สั้นกว่าสำหรับเพย์โหลดขนาดเล็ก นี่คือการแลกเปลี่ยนที่ผู้ใช้ห้องสมุดต้องทำและปรับแต่งห้องสมุดหากจำเป็น

ข้อสรุป

มีการแลกกันอยู่และฉันอาจไม่ได้พูดถึงพวกเขาทั้งหมด แต่ส่วนใหญ่ไม่ได้ใช้กับ CSS-in-JS ทั้งหมด ขึ้นอยู่กับไลบรารีที่คุณใช้และวิธีการใช้งาน

* จะใช้บทความเฉพาะเพื่ออธิบายประโยคนี้ แจ้งให้เราทราบบน Twitter (@ oleg008) เกี่ยวกับสิ่งที่คุณต้องการอ่านเพิ่มเติม