การฝัง CSS

ฟีเจอร์หนึ่งในเครื่องมือเตรียม CSS ที่เราชื่นชอบตอนนี้ได้รวมอยู่ในภาษาแล้ว ซึ่งก็คือกฎสไตล์ที่ฝังอยู่

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

ก่อน
.nesting {   color: hotpink; }  .nesting > .is {   color: rebeccapurple; }  .nesting > .is > .awesome {   color: deeppink; }

หลังจากการฝังแล้ว คุณจะใช้ตัวเลือกต่อและจัดกลุ่มกฎสไตล์ที่เกี่ยวข้องไว้ด้วยกันได้

หลัง
.nesting {   color: hotpink;    > .is {     color: rebeccapurple;      > .awesome {       color: deeppink;     }   } }

ลองทำในเบราว์เซอร์

การฝังช่วยให้นักพัฒนาซอฟต์แวร์ไม่ต้องใช้ตัวเลือกซ้ำๆ และวางกฎสไตล์สำหรับองค์ประกอบที่เกี่ยวข้องไว้ด้วยกัน และยังช่วยให้สไตล์ตรงกับ HTML ที่กําหนดเป้าหมายได้ด้วย หากคอมโพเนนต์ .nesting ในตัวอย่างก่อนหน้านี้ถูกนําออกจากโปรเจ็กต์ คุณสามารถลบทั้งกลุ่มแทนการค้นหาไฟล์สําหรับอินสแตนซ์ตัวเลือกที่เกี่ยวข้อง

การฝังจะช่วยในเรื่องต่อไปนี้ - การจัดระเบียบ - การลดขนาดไฟล์ - การจัดระเบียบใหม่

การจัดกลุ่มใช้ได้ใน Chrome 112 และลองใช้ใน Safari Technical Preview 162 ได้ด้วย

เริ่มต้นใช้งานการฝัง CSS

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

ตารางกริดสีสันสดใสของวงกลม สามเหลี่ยม และสี่เหลี่ยมจัตุรัสขนาดเล็กและขนาดใหญ่

ภายในแซนด์บ็อกซ์มีวงกลม สามเหลี่ยม และสี่เหลี่ยม บางห้องมีขนาดเล็ก กลาง หรือใหญ่ ส่วนอีกกลุ่มเป็นสีน้ำเงิน สีชมพู หรือสีม่วง ทั้งหมดอยู่ภายในองค์ประกอบ .demo ที่มี ต่อไปนี้คือตัวอย่างองค์ประกอบ HTML ที่คุณกําลังกําหนดเป้าหมาย

<div class="demo">   <div class="sm triangle pink"></div>   <div class="sm triangle blue"></div>   <div class="square blue"></div>   <div class="sm square pink"></div>   <div class="sm square blue"></div>   <div class="circle pink"></div>   … </div> 

ตัวอย่างการฝัง

การฝัง CSS ช่วยให้คุณกําหนดสไตล์สําหรับองค์ประกอบภายในบริบทของตัวเลือกอื่นได้

.parent {   color: blue;    .child {     color: red;   } } 

ในตัวอย่างนี้ ตัวเลือกคลาส .child จะฝังอยู่ภายในตัวเลือกคลาส .parent ซึ่งหมายความว่าตัวเลือก .child ที่ฝังอยู่จะมีผลกับองค์ประกอบที่เป็นองค์ประกอบย่อยขององค์ประกอบที่มีคลาส .parent เท่านั้น

ตัวอย่างนี้เขียนโดยใช้สัญลักษณ์ & แทนก็ได้ เพื่อระบุตำแหน่งที่ควรวางคลาสหลักอย่างชัดเจน

.parent {   color: blue;    & .child {     color: red;   } } 

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

การเลือกวงกลม

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

หากไม่มีการวางซ้อน CSS ในปัจจุบันจะมีลักษณะดังนี้

.demo .circle {   opacity: .25;   filter: blur(25px); } 

เมื่อมีการฝัง คุณจะดำเนินการได้ 2 วิธีดังนี้

/* & is explicitly placed in front of .circle */ .demo {   & .circle {     opacity: .25;     filter: blur(25px);   } } 

หรือ

/* & + " " space is added for you */ .demo {   .circle {     opacity: .25;     filter: blur(25px);   } } 

ผลลัพธ์คือองค์ประกอบทั้งหมดภายใน .demo ที่มีคลาส .circle จะเบลอและแทบมองไม่เห็น

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

การเลือกสามเหลี่ยมและสี่เหลี่ยมจัตุรัส

งานนี้ต้องเลือกองค์ประกอบที่ฝังอยู่หลายรายการ หรือที่เรียกว่าตัวเลือกกลุ่ม

หากไม่มีการวางซ้อน CSS ในปัจจุบันมี 2 วิธีดังนี้

.demo .triangle, .demo .square {   opacity: .25;   filter: blur(25px); } 

หรือใช้ :is()

/* grouped with :is() */ .demo :is(.triangle, .square) {   opacity: .25;   filter: blur(25px); } 

เมื่อมีการฝัง คุณจะดำเนินการได้ 2 วิธีดังนี้

.demo {   & .triangle,   & .square {     opacity: .25;     filter: blur(25px);   } } 

หรือ

.demo {   .triangle, .square {     opacity: .25;     filter: blur(25px);   } } 

ผลลัพธ์ มีเพียงองค์ประกอบ .circle ที่เหลืออยู่ภายใน .demo

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

การเลือกสามเหลี่ยมและวงกลมขนาดใหญ่

งานนี้ต้องใช้ตัวเลือกแบบผสม ซึ่งองค์ประกอบต้องมีทั้ง 2 คลาสจึงจะเลือกได้

หากไม่มีการวางซ้อน CSS ในปัจจุบันจะมีลักษณะดังนี้

.demo .lg.triangle, .demo .lg.square {   opacity: .25;   filter: blur(25px); } 

หรือ

.demo .lg:is(.triangle, .circle) {   opacity: .25;   filter: blur(25px); } 

เมื่อมีการฝัง คุณจะดำเนินการได้ 2 วิธีดังนี้

.demo {   .lg.triangle,   .lg.circle {     opacity: .25;     filter: blur(25px);   } } 

หรือ

.demo {   .lg {     &.triangle,     &.circle {       opacity: .25;       filter: blur(25px);     }   } } 

ผลลัพธ์คือ สามเหลี่ยมและวงกลมขนาดใหญ่ทั้งหมดซ่อนอยู่ใน .demo

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

สัญลักษณ์ & มีประโยชน์ในสถานการณ์นี้ เนื่องจากแสดงวิธีต่อเชื่อมตัวเลือกที่ฝังไว้อย่างชัดเจน ลองพิจารณาตัวอย่างต่อไปนี้

.demo {   .lg {     .triangle,     .circle {       opacity: .25;       filter: blur(25px);     }   } } 

แม้ว่าจะเป็นวิธีฝังที่ถูกต้อง แต่ผลลัพธ์จะไม่ตรงกับองค์ประกอบที่คุณอาจคาดหวัง สาเหตุคือ หากไม่มี & เพื่อระบุผลลัพธ์ที่ต้องการของ .lg.triangle, .lg.circle ที่รวมกัน ผลลัพธ์จริงจะเป็น .lg .triangle, .lg .circle ซึ่งเป็นตัวเลือกที่สืบทอด

การเลือกรูปทรงทั้งหมดยกเว้นรูปทรงสีชมพู

งานนี้ต้องใช้คลาสจำลองแบบปฏิเสธฟังก์ชัน ซึ่งองค์ประกอบต้องไม่มีตัวเลือกที่ระบุ

หากไม่มีการวางซ้อน CSS ในปัจจุบันจะมีลักษณะดังนี้

.demo :not(.pink) {   opacity: .25;   filter: blur(25px); } 

เมื่อมีการฝัง คุณจะดำเนินการได้ 2 วิธีดังนี้

.demo {   :not(.pink) {     opacity: .25;     filter: blur(25px);   } } 

หรือ

.demo {   & :not(.pink) {     opacity: .25;     filter: blur(25px);   } } 

ผลลัพธ์คือ รูปทรงทั้งหมดที่ไม่ใช่สีชมพูจะซ่อนอยู่ภายใน .demo

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

สมมติว่าคุณต้องการกําหนดเป้าหมาย .demo ด้วยตัวเลือก :not() & ต้องระบุสำหรับกรณีต่อไปนี้

.demo {   &:not() {     ...   } } 

สูตรนี้รวม .demo และ :not() เป็น .demo:not() ซึ่งต่างจากตัวอย่างก่อนหน้าที่ต้องใช้ .demo :not() การช่วยเตือนนี้มีความสําคัญอย่างยิ่งเมื่อต้องการฝังการโต้ตอบ :hover

.demo {   &:hover {     /* .demo:hover */   }    :hover {     /* .demo :hover */   } } 

ตัวอย่างการฝังเพิ่มเติม

ข้อกำหนด CSS สำหรับการฝังมีตัวอย่างเพิ่มเติมมากมาย หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับไวยากรณ์ผ่านตัวอย่าง เรามีตัวอย่างที่ถูกต้องและไม่ถูกต้องมากมาย

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

การฝัง @media

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

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

.card {   font-size: 1rem;    @media (width >= 1024px) {     font-size: 1.25rem;   } } 

นอกจากนี้ คุณยังใช้ & อย่างชัดแจ้งได้เช่นกัน

.card {   font-size: 1rem;    @media (width >= 1024px) {     &.large {       font-size: 1.25rem;     }   } } 

ตัวอย่างนี้แสดงไวยากรณ์แบบขยายที่มี & พร้อมกับกําหนดเป้าหมาย.large การ์ดเพื่อแสดงให้เห็นว่าฟีเจอร์การฝังเพิ่มเติมยังคงทํางานต่อไป

ดูข้อมูลเพิ่มเติมเกี่ยวกับการฝัง @rules

การวางซ้อนได้ทุกที่

ตัวอย่างทั้งหมดจนถึงตอนนี้จะต่อหรือต่อท้ายบริบทก่อนหน้า คุณสามารถเปลี่ยนหรือจัดเรียงบริบทใหม่ทั้งหมดได้หากต้องการ

.card {   .featured & {     /* .featured .card */   } } 

สัญลักษณ์ & แสดงการอ้างอิงออบเจ็กต์ตัวเลือก (ไม่ใช่สตริง) และสามารถวางไว้ที่ใดก็ได้ในตัวเลือกที่ฝัง โดยสามารถวางได้หลายครั้ง

.card {   .featured & & & {     /* .featured .card .card .card */   } } 

แม้ว่าตัวอย่างนี้อาจดูไร้ประโยชน์ แต่ก็มีบางสถานการณ์ที่การทําซ้ำบริบทตัวเลือกจะมีประโยชน์

ตัวอย่างการซ้อนที่ไม่ถูกต้อง

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

การฝังและการต่อเชื่อม

รูปแบบการตั้งชื่อคลาส CSS จำนวนมากอาศัยการฝังเพื่อต่อหรือต่อท้ายตัวเลือกราวกับว่าเป็นสตริง การดำเนินการนี้ใช้ไม่ได้กับการฝัง CSS เนื่องจากตัวเลือกไม่ใช่สตริง แต่เป็นข้อมูลอ้างอิงออบเจ็กต์

.card {   &--header {     /* is not equal to ".card--header" */   } } 

ดูคำอธิบายเชิงลึกเพิ่มเติมได้ในข้อกำหนดเฉพาะ

ตัวอย่างการฝังที่ยุ่งยาก

การฝังภายในรายการตัวเลือกและ :is()

ลองดูบล็อก CSS ที่ฝังอยู่ต่อไปนี้

.one, #two {   .three {     /* some styles */   } } 

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

เพื่อให้ความตั้งใจของการฝังทำงานได้ เบราว์เซอร์จะรวมรายการตัวเลือกที่ไม่ใช่การฝังด้านในสุดไว้ด้วย :is() การแยกบรรทัดนี้จะช่วยรักษาการจัดกลุ่มรายการตัวเลือกภายในบริบทที่เขียนไว้ ผลข้างเคียงของการจัดกลุ่ม :is(.one, #two) นี้คือการใช้ความเฉพาะเจาะจงของคะแนนสูงสุดภายในตัวเลือกในวงเล็บ :is() ทํางานแบบนี้เสมอ แต่อาจทำให้ประหลาดใจเมื่อใช้ไวยากรณ์การฝัง เนื่องจากไม่ใช่สิ่งที่เขียนไว้ สรุปกลเม็ดคือ การวางซ้อนด้วยรหัสและรายการตัวเลือกอาจทําให้ตัวเลือกมีความเฉพาะเจาะจงสูงมาก

สรุปตัวอย่างที่เข้าใจยากให้ชัดเจนคือ ระบบจะใช้บล็อกการฝังก่อนหน้ากับเอกสารดังนี้

:is(.one, #two) .three {   /* some styles */ } 

โปรดคอยสังเกตหรือสอนโปรแกรมตรวจไวยากรณ์ให้เตือนเมื่อมีการฝังภายในรายการตัวเลือกที่ใช้ตัวเลือกรหัส ความเฉพาะเจาะจงของการฝังทั้งหมดภายในรายการตัวเลือกนั้นจะสูง

การผสมการฝังและการประกาศ

ลองดูบล็อก CSS ที่ฝังอยู่ต่อไปนี้

.card {   color: green;   & { color: blue; }   color: red; } 

สีขององค์ประกอบ .card จะเป็น blue

ระบบจะยกการประกาศสไตล์ที่ผสมกันไว้ที่ด้านบน ราวกับว่าเขียนขึ้นก่อนที่จะมีการฝัง ดูรายละเอียดเพิ่มเติมได้ในข้อกำหนดเฉพาะ

แต่ก็มีวิธีแก้ปัญหา ตัวอย่างต่อไปนี้จะตัดสไตล์สี 3 สไตล์ใน & ซึ่งจะรักษาลําดับการแสดงผลตามลําดับตามผู้เขียนต้องการ สีขององค์ประกอบ .card จะเป็นสีแดง

.card {   color: green;   & { color: blue; }   & { color: red; } } 

อันที่จริงแล้ว แนวทางปฏิบัติแนะนำคือให้ตัดสไตล์ใดก็ตามที่ตามหลังการฝังด้วย &

.card {   color: green;    @media (prefers-color-scheme: dark) {     color: lightgreen;   }    & {     aspect-ratio: 4/3;   } } 

การตรวจหาองค์ประกอบ

การตรวจหาการฝัง CSS ทำได้ 2 วิธี ได้แก่ ใช้การฝังหรือใช้ @supports เพื่อตรวจสอบความสามารถในการแยกวิเคราะห์ตัวเลือกการฝัง

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

การใช้การฝัง

html {   .has-nesting {     display: block;   }    .no-nesting {     display: none;   } } 

วิธีใช้ @supports

@supports (selector(&)) {   /* nesting parsing available */ } 

เพื่อนร่วมงานของฉัน Bramus มี Codepen ที่ยอดเยี่ยมซึ่งแสดงกลยุทธ์นี้

การแก้ไขข้อบกพร่องด้วยเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome

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

ภาพหน้าจอของไวยากรณ์การฝังของเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome

Chrome 113 วางแผนที่จะรองรับการฝัง CSS เพิ่มเติม โปรดอดใจรอ

อนาคต

การฝัง CSS มีให้บริการในเวอร์ชัน 1 เท่านั้น เวอร์ชัน 2 จะเพิ่มรูปแบบคำสั่งที่อ่านง่ายขึ้นและอาจลดกฎที่ต้องจำ ผู้ใช้จำนวนมากต้องการให้การแยกวิเคราะห์การฝังไม่จํากัดหรือมีช่วงเวลาที่ยุ่งยาก

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

สุดท้ายนี้ นี่คือตัวอย่างที่ใช้ @scope, การฝัง และ @layer ร่วมกัน ทุกอย่างน่าตื่นเต้นมาก

การ์ดสีอ่อนบนพื้นหลังสีเทา การ์ดมีชื่อและข้อความ ปุ่มดำเนินการ 2-3 ปุ่ม และรูปภาพสไตล์ไซเบอร์พังก์