การสืบทอด (Inheritance) ใน SASS
บทความนี้อธิบายเกี่ยวกับการสืบทอดใน SASS
เราจะอธิบายการสืบทอดใน SASS พร้อมตัวอย่างที่ใช้งานจริง
YouTube Video
การสืบทอด (Inheritance) ใน SASS
การสืบทอดใน SASS (@extend) คือกลไกที่ช่วยให้เราสามารถนำสไตล์ของ selector หนึ่งไปใช้กับอีก selector หนึ่ง โดยไม่เกิดความซ้ำซ้อน เนื่องจากสไตล์เดียวกันจะถูก 'รวม' และส่งออกสำหรับองค์ประกอบหลายตัวใน markup จึงช่วยลดความซ้ำซ้อนใน CSS ได้ อย่างไรก็ตาม หากใช้อย่างไม่ระมัดระวัง อาจทำให้ selector ถูกควบรวมอย่างไม่ตั้งใจได้
พื้นฐาน: วิธีใช้ @extend
ด้านล่างคือตัวอย่างพื้นฐานที่ .btn--primary สืบทอดสไตล์จาก .btn @extend เป็นคำสั่งที่ใช้ขยาย selector เป้าหมาย
1// Base button styles
2.btn {
3 padding: 0.5rem 1rem;
4 border-radius: 4px;
5 border: 1px solid #ccc;
6 background: white;
7 color: #333;
8}
9
10/* Primary button extends the base .btn */
11.btn--primary {
12 @extend .btn;
13 background: #007bff;
14 color: white;
15}- ด้วยการใช้
@extend.btn--primaryจะสืบทอดสไตล์พื้นฐานของ.btnและเขียนทับเฉพาะส่วนที่จำเป็น
CSS ที่ได้จากการประมวลผล
1.btn, .btn--primary {
2 padding: 0.5rem 1rem;
3 border-radius: 4px;
4 border: 1px solid #ccc;
5 background: white;
6 color: #333;
7}
8
9.btn--primary {
10 background: #007bff;
11 color: white;
12}แนวทางที่ดีที่สุด: การใช้ Placeholder (%placeholder)
ตัวเลือก Placeholder (%name) คือเซเลกเตอร์ที่ไม่ได้ถูกแปลงออกมาเป็น CSS ตัวเลือกเหล่านี้ถูกใช้อย่างแพร่หลาย โดยเฉพาะเมื่อคุณต้องการแบ่งปันสไตล์ทั่วไปอย่างปลอดภัยสำหรับการสืบทอดร่วมกันระหว่างหลายคอมโพเนนต์
1// %placeholder will not be output directly
2%card-base {
3 padding: 1rem;
4 border-radius: 6px;
5 box-shadow: 0 1px 3px rgba(0,0,0,0.08);
6 background: #fff;
7}
8
9/* Components extend the placeholder */
10.card {
11 @extend %card-base;
12 border: 1px solid #eee;
13}
14
15.panel {
16 @extend %card-base;
17 border: 1px solid #ddd;
18}- ทั้ง
.cardและ.panelสืบทอดจาก%card-baseทำให้ทั้งคู่ใช้สไตล์ร่วมกันได้และเพิ่มเติมความแตกต่างได้ตามต้องการ
CSS ที่ได้จากการประมวลผล
1.card, .panel {
2 padding: 1rem;
3 border-radius: 6px;
4 box-shadow: 0 1px 3px rgba(0,0,0,0.08);
5 background: #fff;
6}
7
8.card {
9 border: 1px solid #eee;
10}
11
12.panel {
13 border: 1px solid #ddd;
14}การสืบทอดแบบหลายแหล่ง (Multiple @extend)
คุณสามารถสืบทอด Placeholder หรือคลาสได้หลายรายการพร้อมกัน แม้ว่าจะช่วยให้สามารถนำสไตล์มาใช้ซ้ำได้ดีขึ้น แต่สิ่งสำคัญคือควรติดตามว่าแต่ละกฎถูกผสมกับเซเลกเตอร์ใดบ้าง
1%btn-base {
2 display: inline-block;
3 padding: 0.5rem 1rem;
4 border-radius: 3px;
5}
6
7%btn-large {
8 padding: 0.75rem 1.5rem;
9 font-size: 1.125rem;
10}
11
12/* Composite button that extends both placeholders */
13.btn--lg {
14 @extend %btn-base;
15 @extend %btn-large;
16 background: #222;
17 color: #fff;
18}- นี่คือตัวอย่างปุ่มที่สืบทอด Placeholder สองรายการ คือ 'base' และ 'size'
.btn--lgจะสืบทอดทั้ง%btn-baseและ%btn-largeรวมเลย์เอาต์พื้นฐานกับขนาดที่ใหญ่ขึ้นด้วยกัน
CSS ที่ได้จากการประมวลผล
1.btn--lg {
2 display: inline-block;
3 /* %btn-large overrides the padding from %btn-base */
4 padding: 0.75rem 1.5rem;
5 border-radius: 3px;
6 font-size: 1.125rem;
7 background: #222;
8 color: #fff;
9}พฤติกรรมของ @extend (กลไกการรวม) และข้อควรระวังเรื่อง 'Selector Explosion'
@extend จะนำ selector ที่ตรงกันทั้งหมดมารวมเข้าด้วยกัน ซึ่งอาจทำให้เกิดการรวมที่ไม่ตั้งใจได้
ตัวอย่างต่อไปนี้แสดงให้เห็นว่าการนำ base class เดียวกันไป extend ในหลายที่จะทำให้ CSS ที่ได้เพิ่มขึ้นอย่างไร
1/* Many components extend .utility */
2/* A generic utility class */
3.utility {
4 margin-bottom: 1rem;
5}
6
7/* Nested selectors that extend .utility */
8.header {
9 @extend .utility;
10 .title {
11 font-weight: bold;
12 }
13}
14
15.footer {
16 @extend .utility;
17 .note {
18 color: #888;
19 }
20}
21
22.article {
23 @extend .utility;
24 .content {
25 line-height: 1.6;
26 }
27}
28
29.sidebar {
30 @extend .utility;
31 .section {
32 padding: 1rem;
33 }
34}- เมื่อมีคอมโพเนนต์มากมายสืบทอด
.utilityselector จะถูกรวมเข้าด้วยกัน และในโครงการขนาดใหญ่ อาจทำให้ CSS มีขนาดใหญ่เกินไปได้
CSS ที่ได้จากการประมวลผล
1.utility,
2.header,
3.footer,
4.article,
5.sidebar {
6 margin-bottom: 1rem;
7}
8
9.header .title {
10 font-weight: bold;
11}
12
13.footer .note {
14 color: #888;
15}
16
17.article .content {
18 line-height: 1.6;
19}
20
21.sidebar .section {
22 padding: 1rem;
23}@extend กับ .class เทียบกับ Selector สำหรับ Element (Tag) — ลำดับความสำคัญและผลข้างเคียง
@extend สามารถนำไปใช้ได้กับทั้งคลาสและเซเลกเตอร์ขององค์ประกอบ HTML อย่างไรก็ตาม การสืบทอดกับองค์ประกอบจะเพิ่มขอบเขตที่ได้รับผลกระทบ ทำให้เสี่ยงที่กฎจะถูกนำไปใช้ในที่ที่ไม่ตั้งใจ
ด้านล่างคือตัวอย่างการขยาย selector ของ element และผลที่เกิดขึ้น
1/* Extending an element selector (not recommended) */
2h1 {
3 font-size: 2rem;
4 margin-bottom: 0.5rem;
5}
6
7/* If you extend h1, the resulting selector will include your class with h1 */
8.title {
9 @extend h1;
10 color: #333;
11}
12
13/* Output becomes:
14h1, .title { font-size: 2rem; margin-bottom: 0.5rem; }
15*/- ในตัวอย่างนี้ การสืบทอด selector ของ element
h1จะทำให้.titleถูกรวมสไตล์เดียวกับh1 - แม้จะดูเหมาะสมสำหรับงานขนาดเล็ก แต่เมื่อโปรเจกต์เติบโตขึ้น อาจเกิดเหตุการณ์ที่กฎของ
h1ถูกรวมเข้ากับ.titleโดยไม่คาดคิด ส่งผลให้รูปแบบสไตล์มีความซับซ้อนมากขึ้นและบำรุงรักษายากขึ้น ดังนั้น การออกแบบสไตล์โดยเน้นไปที่คลาสและ Placeholder จะช่วยให้บำรุงรักษาได้ง่ายกว่า
CSS ที่ได้จากการประมวลผล
1h1,
2.title {
3 font-size: 2rem;
4 margin-bottom: 0.5rem;
5}
6
7.title {
8 color: #333;
9}กรณีการใช้งาน @extend และ !optional
หากคุณระบุ !optional ร่วมกับ @extend จะสามารถป้องกันข้อผิดพลาดเมื่อเป้าหมายของการสืบทอดไม่มีอยู่จริง ฟีเจอร์นี้มีประโยชน์อย่างยิ่งในกรณีที่เขียนโค้ดแบบไลบรารี หรือกรณีที่มีการกำหนด Placeholder แบบมีเงื่อนไข
ต่อไปนี้คือตัวอย่างของการพยายามสืบทอดคลาสที่อาจไม่มีอยู่ โดยใช้ !optional เพื่อความปลอดภัย
1/* Try to extend a class that might not exist */
2.component {
3 @extend .maybe-existing !optional;
4 padding: 1rem;
5}- หาก
.maybe-existingไม่มีอยู่ จะไม่มีอะไรเกิดขึ้นและคำสั่งจะถูกข้ามไป สามารถใช้วิธีนี้เมื่อคุณต้องการขยายอย่างปลอดภัย
CSS ที่ได้จากการประมวลผล
1.component {
2 padding: 1rem;
3}เปรียบเทียบ @extend กับ Mixin (@mixin / @include)
@extend และ @mixin บางครั้งมีวัตถุประสงค์คล้ายกัน แต่ผลลัพธ์และกรณีการใช้งานต่างกัน
-
@extend- CSS ที่สร้างจะลดความซ้ำซ้อนด้วยการรวม selector
- เนื่องจาก selector จะถูกรวมกันหลังจากสร้าง CSS อาจเกิดการจับคู่อย่างไม่ตั้งใจได้
- ไม่สามารถส่งพารามิเตอร์ได้ (แต่อาจทดแทนได้ด้วยการรวม placeholder)
-
@mixin/@include- การเรียกแต่ละครั้งทำให้เกิดสไตล์ซ้ำกัน (ส่งผลให้ output ซ้ำซ้อน)
- สามารถส่งพารามิเตอร์และใส่โค้ดลอจิก เช่น เงื่อนไขหรือ loop ได้
- ผลลัพธ์ทำนายง่ายขึ้น แต่ขนาดไฟล์จะใหญ่ขึ้น
ด้านล่างคือการเปรียบเทียบการใช้ @mixin และ @extend เพื่อทำปุ่มเดียวกัน
1/* Mixin approach */
2@mixin btn-styles($bg, $color) {
3 display: inline-block;
4 padding: 0.5rem 1rem;
5 background: $bg;
6 color: $color;
7 border-radius: 4px;
8}
9
10/* Use mixin */
11.btn {
12 @include btn-styles(white, #333);
13}
14
15.btn--primary {
16 @include btn-styles(#007bff, white);
17}
18
19/* Extend approach (shared placeholder) */
20%btn-base {
21 display: inline-block;
22 padding: 0.5rem 1rem;
23 border-radius: 4px;
24}
25
26.btn2 {
27 @extend %btn-base;
28 background: white;
29 color: #333;
30}
31
32.btn2--primary {
33 @extend %btn-base;
34 background: #007bff;
35 color: white;
36}@mixinให้ความยืดหยุ่นในการใส่สไตล์ ส่วน@extendจะรวมผลลัพธ์อย่างมีประสิทธิภาพ คุณสามารถเลือกใช้งานแต่ละอย่างตามความเหมาะสม
CSS ที่ได้จากการประมวลผล
ผลลัพธ์ที่ได้จาก @mixin
1.btn {
2 display: inline-block;
3 padding: 0.5rem 1rem;
4 background: white;
5 color: #333;
6 border-radius: 4px;
7}
8
9.btn--primary {
10 display: inline-block;
11 padding: 0.5rem 1rem;
12 background: #007bff;
13 color: white;
14 border-radius: 4px;
15}ผลลัพธ์ที่ได้จาก @extend
1.btn2,
2.btn2--primary {
3 display: inline-block;
4 padding: 0.5rem 1rem;
5 border-radius: 4px;
6}
7
8.btn2 {
9 background: white;
10 color: #333;
11}
12
13.btn2--primary {
14 background: #007bff;
15 color: white;
16}แนวทางปฏิบัติที่แนะนำ
การสืบทอด (Inheritance) ใน SASS เป็นฟีเจอร์ทรงพลังที่ช่วยเพิ่มความสามารถในการนำสไตล์มาใช้ซ้ำ อย่างไรก็ตาม หากใช้ไม่ถูกต้อง การรวมสไตล์จะซับซ้อนและบำรุงรักษายากขึ้น ด้านล่างนี้คือจุดสำคัญในการใช้ฟีเจอร์ inheritance อย่างปลอดภัยและมีประสิทธิภาพ
- ควรใช้ Placeholder สำหรับสไตล์ส่วนประกอบพื้นฐานทั่วไป เช่น โครงสร้างและเลย์เอาต์ นอกจากนี้ หากต้องการพารามิเตอร์ที่เปลี่ยนแปลงได้ สามารถใช้
@mixinเพิ่มเติม - ควรหลีกเลี่ยงการสืบทอดองค์ประกอบ HTML โดยตรง เช่น
h1อาจเกิดการรวมเซเลกเตอร์ที่ไม่ตั้งใจ ส่งผลให้เกิด CSS ที่ไม่คาดคิดได้ - การใช้หลักการตั้งชื่อเช่น BEM หรือการใช้ prefix ที่ชัดเจน จะช่วยให้รู้ว่า placeholder นั้นใช้เพื่ออะไรและเพิ่มความปลอดภัย
- การใช้
@extendภายในไฟล์เดียวกันจะปลอดภัยกว่า โดยเฉพาะในโปรเจกต์ขนาดใหญ่ ควรออกแบบ inheritance ให้จำกัดอยู่ภายในคอมโพเนนต์แต่ละตัว เพื่อให้ง่ายต่อการติดตามความสัมพันธ์ของการสืบทอด
สรุป
ฟีเจอร์ @extend ใน SASS ช่วยให้สามารถนำสไตล์ทั่วไปมาใช้ซ้ำได้อย่างมีประสิทธิภาพและทำให้ดีไซน์มีความสม่ำเสมอ อย่างไรก็ตาม เนื่องจากการรวมเซเลกเตอร์สามารถซับซ้อนได้ง่าย จึงควรใช้งานฟีเจอร์นี้อย่างระมัดระวังและในขอบเขตที่จำกัด โดยการจัดกลุ่มสไตล์ที่ใช้ร่วมกันด้วย Placeholder Selector (%placeholder) และใช้ @mixin สำหรับส่วนที่ต้องการพารามิเตอร์แบบไดนามิก จะช่วยให้การออกแบบมีความเรียบง่ายและบำรุงรักษาได้ง่าย
คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย