สำรวจ SMACSS: สถาปัตยกรรมที่ปรับขนาดได้และโมดูลาร์สำหรับ CSS

เผยแพร่แล้ว: 2022-03-11

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

สิ่งที่หลายคนทำคือพวกเขาได้สร้างสถาปัตยกรรม CSS เพื่อช่วยในการจัดรูปแบบโค้ดเพื่อให้ CSS อ่านง่ายขึ้น SMACSS —ie , Scalable and Modular Architecture for CSS —มีจุดมุ่งหมายที่จะทำเช่นนั้น เป็นชุดแนวทางสถาปัตยกรรม CSS โดยเฉพาะจาก Jonathan Snook ที่ฉันนำมาใช้

แนวทางสถาปัตยกรรมของ SMACSS แตกต่างไปจากเฟรมเวิร์ก CSS เช่น Bootstrap หรือ Foundation เล็กน้อย แต่เป็นชุดของกฎเกณฑ์ เหมือนกับเทมเพลตหรือคู่มือมากกว่า มาดูรูปแบบการออกแบบ CSS เพื่อดูว่าเราจะใช้รูปแบบเหล่านี้เพื่อทำให้โค้ดของเราดีขึ้น สะอาดขึ้น อ่านง่ายขึ้น และเป็นแบบแยกส่วนได้อย่างไร

โครงสร้างโครงการ SMACSS ทั้งหมดใช้ห้าหมวดหมู่:

  1. ฐาน
  2. เค้าโครง
  3. โมดูล
  4. สถานะ
  5. ธีม

ฐาน

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

ในสไตล์พื้นฐาน คุณควรรวมเฉพาะตัวเลือกองค์ประกอบเปล่า หรือตัวเลือกที่มีคลาสหลอก แต่ไม่รวมถึงตัวเลือกคลาสหรือ ID (คุณควรมีเหตุผลที่ดีจริง ๆ ที่จะใส่คลาสหรือ ID ไว้ข้างใน บางทีก็ต่อเมื่อคุณกำหนดสไตล์ให้กับองค์ประกอบของปลั๊กอินของบุคคลที่สาม และคุณจำเป็นต้องแทนที่สไตล์เริ่มต้นสำหรับองค์ประกอบนั้นโดยเฉพาะ)

นี่คือตัวอย่างลักษณะของหน่วยไฟล์พื้นฐาน:

 html { margin: 0; font-family: sans-serif; } a { color: #000; } button { color: #ababab; border: 1px solid #f2f2f2; }

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

SMACSS หรือไม่ ฉันขอแนะนำอย่างยิ่งให้หลีกเลี่ยงการใช้ !important ให้มากที่สุด และอย่าใช้ Deep nesting แต่ฉันจะพูดถึงเรื่องนี้มากขึ้นในโพสต์นี้ นอกจากนี้ หากแนวทางปฏิบัติของคุณคือการใช้ reset CSS นี่คือที่ที่คุณควรรวมไว้ (ฉันชอบใช้ Sass มากกว่า ดังนั้นฉันจึงรวมไว้ที่ด้านบนของไฟล์ แทนที่จะต้องคัดลอกหรืออ้างอิงแยกจากองค์ประกอบ <head> ของแต่ละหน้า)

ที่เกี่ยวข้อง: ธีมด้วย Sass: บทช่วยสอน SCSS

เค้าโครง

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

ตัวอย่างรูปแบบเค้าโครง SMACSS: ส่วนหัว แถบด้านข้าง เนื้อหา/หลัก และส่วนท้าย

รูปแบบเค้าโครง SMACSS มีไว้สำหรับส่วนหลัก เช่น ส่วนหัว แถบด้านข้าง เนื้อหา/หลัก และส่วนท้าย

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

ตัวอย่างหน้าเว็บที่สามารถจัดระเบียบเป็นรูปแบบเค้าโครงส่วนหัว หลัก และส่วนท้ายโดยใช้SMACSS

ที่นี่เรามีส่วนหัว หลัก และส่วนท้าย เลย์เอาต์เหล่านี้มีโมดูลต่างๆ เช่น ลิงก์และโลโก้ที่ส่วนหัวด้านบน กล่องและบทความในหัวข้อหลัก และลิงก์และลิขสิทธิ์สำหรับส่วนท้าย เรามักจะให้ตัวเลือก ID แก่เลย์เอาต์ เนื่องจากเลย์เอาต์ไม่ได้แสดงซ้ำบนเพจและมีเอกลักษณ์เฉพาะตัว

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

นี่คือตัวอย่างว่าควรมีลักษณะอย่างไร:

 #header { background: #fcfcfc; } #header .l-right { float: right; } #header .l-align-center { text-align: center; }

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

สำหรับตัวอย่างอื่น คุณสามารถใช้ระยะขอบเริ่มต้นบางอย่างในกล่องเค้าโครง เช่น .l-margin ที่มีระยะขอบ 20px จากนั้น ทุกที่ที่คุณต้องการช่องว่างภายในสำหรับคอนเทนเนอร์ องค์ประกอบ การ์ด หรือกล่อง คุณเพียงแค่เพิ่มคลาส l-margin ลงไป แต่คุณต้องการบางสิ่งที่นำกลับมาใช้ใหม่ได้:

 .l-full-width { width: 100%; }

ไม่ใช่สิ่งที่เชื่อมต่อภายในเช่นนี้:

 .l-width-25 { width: 25px; }

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

ฉันไม่รู้ว่าคุณเคยประสบปัญหาต่อไปนี้หรือไม่ คุณกำลังเขียน CSS และคุณมีป้ายกำกับสำหรับบางสิ่ง คุณใส่สไตล์ใดก็ได้ที่คุณต้องการ และเรียกคลาสของคุณ . .label แต่หลังจากนั้น คุณมาที่องค์ประกอบอื่นในภายหลัง และคุณต้องการให้เป็น .label แต่จัดรูปแบบให้แตกต่างออกไป ดังนั้นสองสิ่งที่แตกต่างกันจึงมีชื่อเหมือนกัน—การตั้งชื่อที่ขัดแย้งกัน

Namespacing ช่วยคุณแก้ปัญหานี้ได้ ในท้ายที่สุด สิ่งเหล่านี้ถูกเรียกว่าเป็นสิ่งเดียวกันในระดับหนึ่ง แต่มีเนมสเปซที่แตกต่างกัน—คำนำหน้าที่แตกต่างกัน—และสามารถแสดงสไตล์ที่แตกต่างกันสองแบบ:

 .box--label { color: blue; } .card--label { color: red; }

โมดูล

เช่นเดียวกับที่ฉันได้กล่าวไว้ก่อนหน้านี้ โมดูล SMACSS เป็นโค้ดขนาดเล็กกว่าที่นำมาใช้ใหม่ได้บนหน้า และเป็นส่วนหนึ่งของเค้าโครงเดียว นี่เป็นส่วนหนึ่งของ CSS ที่เราต้องการจัดเก็บไว้ในโฟลเดอร์แยกต่างหาก เนื่องจากเราจะมีสิ่งเหล่านี้จำนวนมากในหน้าเดียว และเมื่อโปรเจ็กต์เติบโตขึ้น เราสามารถแบ่งได้โดยใช้แนวทางปฏิบัติที่ดีที่สุดของโครงสร้างโฟลเดอร์ กล่าวคือ ตามโมดูล/หน้า:

ตัวอย่างลำดับชั้นของไฟล์/โฟลเดอร์โดยใช้ SMACSS และ Sass

ในตัวอย่างก่อนหน้านี้ เรามีบทความซึ่งสามารถเป็นโมดูลได้ด้วยตัวเอง CSS ควรมีโครงสร้างอย่างไรที่นี่ เราควรจะมี class .article ซึ่งสามารถมี title องค์ประกอบลูกและ text ได้ เพื่อให้สามารถเก็บไว้ในโมดูลเดียวกันได้ เราจำเป็นต้องเติมคำนำหน้าองค์ประกอบย่อย:

 .article { background: #f32; } .article--title { font-size: 16px; } .article--text { font-size: 12px; }

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

นอกจากนี้ คุณสามารถซ้อนโมดูลภายในโมดูลได้ หากโมดูลใดใช้พื้นที่ส่วนใหญ่ของหน้า:

 <div class="box"> <div class="box--label">This is box label</div> <ul class="box--list list"> <li class="list--li">Box list element</li> </ul> </div>

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

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

ดี (สังเกตตัวเลือกเดียว):

 .red--box { background: #fafcfe; } .red-box--list { color: #000; }

ไม่ดี (สังเกตการซ้ำซ้อนภายในตัวเลือกและวิธีการอ้างอิงที่ทับซ้อนกัน):

 .red .box { background: #fafcfe; } .red .box .list { color: #000; } .box ul { color: #fafafa; }

สถานะ

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

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

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

 <header> <ul class="nav"> <li class="nav--item is-selected">Contact</li> <li class="nav--item">About</li> </ul> </header>
 .nav--item.is-selected { color: #fff; }

ในที่นี้ อาจใช้ !important เนื่องจาก state มักใช้เป็นการแก้ไข JavaScript ไม่ใช่เวลาแสดงผล ตัวอย่างเช่น คุณมีองค์ประกอบที่ซ่อนอยู่ในการโหลดหน้าเว็บ เมื่อคลิกปุ่มคุณต้องการแสดง แต่คลาสเริ่มต้นจะเป็นดังนี้:

 .box .element { display: none; }

ดังนั้นหากคุณเพิ่มสิ่งนี้:

 .is-shown { display: block; }

มันจะยังคงซ่อนอยู่แม้ว่าคุณจะเพิ่มคลาส .is-shown ให้กับองค์ประกอบผ่าน JavaScript เนื่องจากกฎข้อแรกมีความลึกสองระดับและจะแทนที่กฎนั้น

ดังนั้นคุณสามารถกำหนดคลาสของรัฐได้ดังนี้:

 .is-shown { display: block !important; }

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

ธีม

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

 .button-large { width: 60px; height: 60px; }
 <button class="button-large">Like</button>

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

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

ระเบียบวิธีขององค์กร CSS

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

ได้ คุณสามารถใช้วิธีการขั้นสูง เช่น OOCSS และ BEM หลังครอบคลุมเวิร์กโฟลว์ส่วนหน้าเกือบทั้งหมดและเทคโนโลยี ตัวเลือก BEM อาจใช้ได้ผลดีสำหรับบางคน แต่บางคนอาจพบว่าตัวเลือกยาวเกินไปและยากเกินไป และยังซับซ้อนเกินไปที่จะใช้งาน หากคุณต้องการบางสิ่งที่ง่ายกว่าซึ่งง่ายต่อการหยิบจับและรวมเข้ากับเวิร์กโฟลว์ของคุณ—และสิ่งที่กำหนดกฎพื้นฐานสำหรับคุณและทีมของคุณ SMACSS เหมาะสมอย่างยิ่ง

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