การฝัง CSS

หนึ่งในฟีเจอร์สำหรับผู้ประมวลผลข้อมูลล่วงหน้า CSS ที่เราชื่นชอบมีอยู่ในภาษาแล้ว นั่นคือการซ้อนกฎรูปแบบ

Adam Argyle
Adam Argyle

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

ก่อน
.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

.nesting > .is > .awesome {
  color: deeppink;
}

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

หลัง
.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

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

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

การวางซ้อนมีประโยชน์สำหรับสิ่งต่างๆ ต่อไปนี้ - องค์กร - การลดขนาดไฟล์ - การเปลี่ยนโครงสร้างภายในโค้ด

การทำ Nest มีให้บริการใน Chrome 112 และยังลองใช้ใน Safari Technical Preview 162 ได้อีกด้วย

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

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

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

ภายในแซนด์บ็อกซ์จะมีวงกลม สามเหลี่ยม และสี่เหลี่ยมจัตุรัส บ้างก็เล็กหรือปานกลาง หรือใหญ่ ส่วนบางประเภทก็เป็นสีน้ำเงิน ชมพู หรือม่วง ทุกคนอยู่ใน .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

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

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

.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 Nesting เป็นเวอร์ชัน 1 เท่านั้น เวอร์ชัน 2 จะเปิดตัวน้ำตาลแบบไวยากรณ์ที่มากขึ้น และกฎที่อาจมีน้อยลง จดจำ มีความต้องการจำนวนมากในการแยกวิเคราะห์การซ้อนเพื่อไม่จำกัด หรือมีช่วงเวลาที่ยุ่งยาก

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

เราขอแนะนำว่าลองดูการสาธิตนี้ ที่ใช้ @scope, การซ้อน และ @layer พร้อมกัน ทั้งหมดน่าตื่นเต้นมากเลย

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