การฝัง CSS

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

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

ก่อน
.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 สำหรับการซ้อน มี ตัวอย่างเพิ่มเติมมากมาย หากคุณต้องการเรียนรู้เพิ่มเติมเกี่ยวกับไวยากรณ์ผ่านตัวอย่าง ข้อกำหนดนี้ครอบคลุมตัวอย่างที่ถูกต้องและไม่ถูกต้องหลากหลายรายการ

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

การซ้อน @media

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

เพื่อความสะดวกในการใช้ไวยากรณ์ หาก 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 เพื่อแสดงให้เห็นว่าฟีเจอร์การซ้อนเพิ่มเติมยังคงทำงานได้

ดูข้อมูลเพิ่มเติมเกี่ยวกับการซ้อน @กฎ

การซ้อนทุกที่

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

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

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

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

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

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

มีสถานการณ์ไวยากรณ์การซ้อนบางอย่างที่ไม่ถูกต้องและอาจทำให้คุณประหลาดใจหากคุณเคยซ้อนใน Preprocessor

การซ้อนและการเชื่อม

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

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

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

ตัวอย่างการซ้อนที่ซับซ้อน

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

ลองดูบล็อก CSS การซ้อนต่อไปนี้

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

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

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

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

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

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

การผสมการซ้อนและการประกาศ

ลองดูบล็อก 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;
  }
}

การตรวจหาฟีเจอร์

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

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

การใช้การซ้อน

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

  .no-nesting {
    display: none;
  }
}

การใช้ @supports

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

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

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

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

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

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

อนาคต

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

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

สุดท้ายนี้ ลองดูเดโม ที่ใช้ @scope การซ้อน และ @layer ร่วมกัน ซึ่งเป็นเรื่องที่น่าตื่นเต้นมาก

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