- สาเหตุสำคัญของประสิทธิภาพเว็บไซต์ที่แย่ลงในช่วงหลังคือ การใช้ JavaScript มากเกินไป และสคริปต์ติดตามต่าง ๆ ซึ่งในหลายกรณีสามารถแทนที่ได้ด้วย HTML/CSS เพียงอย่างเดียว
- ฟีเจอร์ที่เพิ่งเพิ่มเข้ามาเมื่อไม่นานนี้ เช่น CSS nesting, relative colors, หน่วย viewport แบบใหม่ (lvh, svh, dvh) ช่วยให้แก้ปัญหาที่แต่ก่อนต้องพึ่งพา JS หรือ preprocessor ได้อย่างง่ายดาย
- CSS ไม่ใช่แค่เครื่องมือจัดสไตล์ธรรมดา แต่เป็นภาษาที่ทรงพลังซึ่งสามารถสร้างได้ตั้งแต่ แอนิเมชัน, การตรวจสอบข้อมูลนำเข้า, ธีม dark mode, ไปจนถึงเมนู accordion
- ในด้านประสิทธิภาพ CSS ยังทำงานด้วยการเร่งผ่าน GPU และทำงานบนเธรดแยก จึง ลื่นไหลและมีประสิทธิภาพกว่า JS สำหรับแอนิเมชันและเอฟเฟกต์เปลี่ยนผ่าน
- ผู้เขียนเน้นว่า CSS ไม่ได้เป็นเพียงเครื่องมือเชิงปฏิบัติ แต่ยังเป็น สื่อของการแสดงออกและศิลปะ และแนะนำให้นักพัฒนาเว็บใช้ศักยภาพของ CSS ยุคใหม่ให้มากขึ้น
บทนำ: ความซับซ้อนของเว็บ และความพยายามครั้งใหม่
- หลายเว็บไซต์กำลังเผชิญกับปัญหาประสิทธิภาพและความซับซ้อนจากการใช้ JavaScript framework มากเกินไป
- แอป React ใช้เวลาหลายวินาทีในการโหลด และ NextJS ก็ก่อให้เกิด hydration error
- โฟลเดอร์
node_modules กินพื้นที่หลายกิกะไบต์
- แม้ไม่มี JavaScript ก็ยังสามารถสร้างฟังก์ชันที่ทรงพลังได้ด้วย HTML และ CSS เพียงอย่างเดียว
- นอกเหนือจากรถเข็นช็อปปิงของเว็บอีคอมเมิร์ซที่ซับซ้อนหรือแดชบอร์ดแล้ว JavaScript อาจไม่ได้จำเป็นเสมอไป
- บทความนี้แนะนำ ฟีเจอร์ใหม่ล่าสุด ของ CSS และชวนให้นักพัฒนาสำรวจความเป็นไปได้ที่หลากหลายโดยไม่ต้องพึ่งพา JavaScript เพียงอย่างเดียว
ความเข้าใจผิดและมุมมองต่อ CSS
CSS ยากและใช้งานลำบากจริงหรือ?
- มุมมองเชิงลบต่อ CSS มักเกิดจาก การเรียนรู้พื้นฐานไม่เพียงพอ
- นักพัฒนาจำนวนมากข้ามพื้นฐานของ CSS แล้วไปโฟกัสที่ JavaScript หรือ TypeScript
- CSS ไม่ใช่แค่เครื่องมือจัดสไตล์ธรรมดา แต่เป็น ภาษาเฉพาะทาง (domain-specific language) ที่มีความสามารถสูง
- CSS สามารถทำเลย์เอาต์ที่ซับซ้อนได้ง่ายด้วยเครื่องมืออย่าง flexbox
- ตัวอย่าง: ใช้
display: flex และ justify-content: center เพื่อจัด div ให้อยู่กึ่งกลางได้อย่างง่ายดาย
- เครื่องมือนักพัฒนา ของเบราว์เซอร์มีวิดเจ็ตสำหรับปรับคุณสมบัติ flexbox แบบมองเห็นได้
- หากเจาะลึกอยู่ฝั่งเดียวเท่านั้น (เช่น JS) และละเลย CSS ก็เป็นธรรมดาที่จะรู้สึกว่ามันเป็นภาระ
ความเจ็บปวดของการเขียน CSS และการเปลี่ยนแปลง
- ในอดีตการเขียน CSS ไม่ได้สะดวกนัก จึงเกิดเครื่องมืออย่าง Sass และ Tailwind ขึ้นมา
- ตัวอย่าง: ต้องคอยจัดการ selector chain ที่ยาวอย่าง
.post > .buttons .like:hover
- ช่วงหลังมีการเพิ่ม ฟีเจอร์ที่ช่วยยกระดับคุณภาพการเขียน (เช่น nesting) ทำให้พัฒนาได้สบายขึ้นด้วย CSS พื้นฐานเพียงอย่างเดียว
- CSS nesting ช่วยรวมสไตล์ที่เกี่ยวข้องไว้ในที่เดียวและเพิ่มความอ่านง่าย
- ตัวอย่าง:
.post { & > .buttons { .like { &:hover { ... } } } }
- ความสัมพันธ์ระหว่าง parent-child ชัดเจนขึ้น ทำให้ใช้ชื่อคลาสที่สั้นและเรียบง่ายได้
- relative colors ทำให้การปรับแต่งสีง่ายขึ้น
- สามารถปรับความสว่างได้ด้วย
hsl(from #123456 h s calc(l + 10))
- ใช้
color-mix() เพื่อผสมสองสีและสร้างสีแบบไดนามิก
- ไวยากรณ์ช่วงของ media query ทำให้ตั้งเงื่อนไขที่เข้าใจง่ายอย่าง
(width <= 768px) ได้
- หน่วย lh รองรับการจัดสไตล์ให้สอดคล้องกับความสูงบรรทัด
- พร็อพเพอร์ตี scrollbar-gutter ช่วยแก้ปัญหาเลย์เอาต์ขยับเพราะสกรอลล์บาร์
- Baseline ช่วยรับประกันความเข้ากันได้ของฟีเจอร์กับเบราว์เซอร์หลัก
- newly available คือฟีเจอร์ที่ทำงานได้ในเบราว์เซอร์รุ่นล่าสุด
- widely available คือรองรับไปถึงเบราว์เซอร์เมื่อ 2.5 ปีก่อน
- ตัวอย่าง: CSS nesting ได้รับการรองรับจากทุกเบราว์เซอร์ตั้งแต่เดือนธันวาคม 2023
ทำไมจึงพัฒนาโดยใช้ CSS/HTML เท่านั้น?
- ผู้ใช้บางส่วน ปิดการทำงานของ JavaScript เป็นค่าเริ่มต้น (ด้วยเหตุผลด้านความปลอดภัย ความเป็นส่วนตัว ฯลฯ)
- หากให้บริการเว็บไซต์ด้วย CSS/HTML ล้วน ผู้ใช้เหล่านี้ก็มีโอกาสใช้งานเว็บไซต์ได้มากขึ้น
- ทั้งในมุมของนักพัฒนาและผู้ใช้ การใช้เพียง CSS/HTML มี ข้อดี มากในด้านความเร็ว การเข้าถึง และการใช้ CPU/แบตเตอรี่
- CSS animation ทำงานบน compositor thread จึงลดภาระของ CPU
- JavaScript ทำงานผ่าน event loop จึงอาจเกิดความหน่วงเล็กน้อยได้
- การเข้าถึง และ ความสะดวกในการใช้งาน ดีขึ้น
- เอฟเฟกต์ hover ของปุ่ม, toast animation, การตรวจสอบข้อมูลนำเข้า ฯลฯ สามารถทำได้ง่ายด้วย CSS
ตัวอย่างการใช้งานจริงและฟีเจอร์สำคัญของ CSS
สร้างแอนิเมชันเริ่มต้นที่เป็นธรรมชาติด้วย @starting-style
- ก่อนหน้านี้การทำแอนิเมชันตอนองค์ประกอบปรากฏขึ้นต้องใช้โครงสร้างที่ซับซ้อน เช่น keyframes หรือ JS trigger
- การมาของ @starting-style ทำให้กำหนดสถานะเริ่มต้นได้ง่ายขึ้น และสร้างแอนิเมชันสถานะเริ่มต้นขององค์ประกอบ (เช่น fade-in) ได้สะดวก
- ตั้งค่าได้ด้วย
transition: opacity 1s; @starting-style { opacity: 0; }
- ทำงานได้โดยไม่ต้องมี
@keyframes หรือ JavaScript เพิ่มเติม
- เพียงระบุสถานะเริ่มต้นร่วมกับ transition ก็จะได้แอนิเมชันที่เป็นธรรมชาติ
- ตัวอย่าง: เปลี่ยนความทึบและตำแหน่งของข้อความ toast ได้อย่างนุ่มนวล
ตั้งค่าธีม dark/light mode ได้ง่าย
color-scheme: light dark สลับธีมอัตโนมัติตามความชอบของผู้ใช้
- ฟังก์ชัน light-dark(#000, #FFF) ใช้กำหนดสีให้เหมาะกับโหมดสว่าง/มืด
- รองรับการเลือกธีมด้วยปุ่มวิทยุและ selector :has
- สลับธีมได้ด้วย CSS เพียงอย่างเดียวโดยไม่ต้องใช้ JavaScript
- จะเพิ่ม JavaScript เพื่อบันทึก/โหลดธีมแบบเลือกใช้ก็ได้
สร้าง UI แบบกำหนดเองด้วย radio/checkbox และ :has, :checked
- อินเทอร์แอ็กชันที่ซับซ้อนอย่างแท็บ, accordion, toggle ก็ ทำได้โดยไม่ใช้ JavaScript
- ปุ่มวิทยุ สามารถจัดสไตล์เองได้ด้วย :checked และ :has
- ตัวอย่าง:
label:has(input:checked) เพื่อกำหนดสไตล์ของปุ่มที่ถูกเลือก
- ซ่อน input ด้วย
opacity: 0 แต่ยังคงการเข้าถึงสำหรับโปรแกรมอ่านหน้าจอไว้ได้
- องค์ประกอบ details เหมาะสำหรับสร้าง เมนู accordion อย่าง FAQ
- ใช้แอตทริบิวต์
name เพื่อควบคุมให้เปิดได้ครั้งละรายการเดียว
- สามารถเพิ่มแอนิเมชันตามสถานะ
[open] ได้
การตรวจสอบข้อมูลนำเข้าและการสะท้อนสถานะ
- การใช้แอตทริบิวต์ HTML เช่น pattern, required ร่วมกับ CSS pseudo-class (:valid, :invalid, :user-valid ฯลฯ) ช่วยให้ ตรวจสอบแบบเรียลไทม์และแสดงผลตอบกลับทางภาพ ได้
- ปรับปรุงประสบการณ์ผู้ใช้ด้วยการเปลี่ยนสไตล์ outline/border ของช่องกรอกข้อมูล เป็นต้น
- ใช้ แอตทริบิวต์ pattern ของ HTML เพื่อตรวจสอบความถูกต้องของช่องกรอกข้อมูล
- ตัวอย่าง:
\w{3,16} อนุญาตตัวอักษร/ตัวเลข/ขีดล่าง 3–16 ตัว
- ใช้ :valid และ :invalid ของ CSS เพื่อจัดสไตล์ตามสถานะความถูกต้อง
- :user-valid และ :user-invalid จะใช้สไตล์ก็ต่อเมื่อผู้ใช้ได้ป้อนข้อมูลแล้วเท่านั้น
- ใช้ selector :has เพื่อจัดสไตล์องค์ประกอบอื่นตามสถานะของ input ได้
- ในบางกรณี (เช่น เงื่อนไขอินพุตที่ซับซ้อน) อาจยังต้องใช้ JS แต่ส่วนใหญ่ CSS/HTML ก็เพียงพอ
วิธีใช้หน่วย viewport ให้ถูกต้อง
- หน่วย vw/vh มี ปัญหาความแม่นยำ บนมือถือเมื่อแถบที่อยู่ (navigation bar) ปรากฏหรือซ่อน
- แนะนำให้ใช้หน่วย viewport รุ่นใหม่อย่าง lvh/svh/dvh (largest/smallest/dynamic viewport height)
- lvh: สำหรับเต็มหน้าจอ (เช่น พื้นหลังเต็มจอ)
- svh: เหมาะกับปุ่มหรือลิงก์ที่ต้องมองเห็นบนหน้าจอเสมอ
- dvh: จัดสรรขนาดแบบยืดหยุ่นตามการเปลี่ยนแปลง เช่น การเลื่อนหน้าจอ
- การซ้อนทับของคีย์บอร์ดจัดการได้ด้วยพร็อพเพอร์ตี interactive-widget หรือ VirtualKeyboard API
<meta name="viewport" content="width=device-width, interactive-widget=resizes-content">
- ในเบราว์เซอร์ที่ใช้ Chromium สามารถใช้
navigator.virtualKeyboard.overlaysContent = true
Wishlist ของ CSS (สิ่งที่ยังน่าเสียดายหรืออยากให้มี)
- บล็อกที่นำกลับมาใช้ซ้ำได้: ใช้คลาสอื่นภายในคลาส (เช่น
@apply border)
- selector ของ media query ที่รวมกันได้: ผสาน
@media กับ class selector
- ตัวแปร nth-child:
span { --nth: nth-child(); } สำหรับจัดสไตล์แบบไดนามิก
- selector nth-letter: จัดสไตล์อักษรบางตัวโดยเฉพาะ (เช่น
p::nth-letter(2))
- การลบหน่วย: สร้างค่าที่ไม่มีหน่วยด้วย
calc(100vw / 1px)
- ฟังก์ชัน image(): รองรับสีสำรองและชิ้นส่วนภาพ
- แท็ก style ภายใน body: หากรองรับเป็นมาตรฐานทางการ จะช่วยบรรเทาปัญหา FOUC
ปิดท้าย: CSS และความเป็นศิลปะของเว็บ
- CSS ไม่ใช่แค่เครื่องมือ แต่เป็นสื่อของ การแสดงออกเชิงสร้างสรรค์
- เครื่องมือ AI หรือ build chain (linter, เครื่องมือ minify) อาจจำกัดความคิดสร้างสรรค์ได้
- CSS ตอบโจทย์ได้พร้อมกันทั้ง ประสิทธิภาพ, การเข้าถึง, และ การแสดงออกทางศิลปะ
- บทความนี้เขียนด้วย HTML/CSS ที่ไม่มี JavaScript ขนาดประมาณ 49kB
- วิดเจ็ตแบบโต้ตอบและองค์ประกอบภาพทั้งหมดทำขึ้นด้วยมือ
- ตัวอย่าง: เกมคลิกด้วย CSS แสดงให้เห็นถึงความเป็นไปได้ของ CSS ในฐานะภาษาการเขียนโปรแกรม
ยังไม่มีความคิดเห็น