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

การฝังมีประโยชน์ดังนี้ - องค์กร - การลดขนาดไฟล์ - การปรับโครงสร้าง

การ Nesting มีให้ใช้งานใน Chrome 112 และคุณยังลองใช้ใน Technical Preview 162 ของ Safari ได้ด้วย

เริ่มต้นใช้งาน 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;
  }
}

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

การเลือกแวดวง

สำหรับตัวอย่างแรกนี้ งานคือการเพิ่มรูปแบบให้จางลงและเบลอเฉพาะวงกลมภายในการสาธิต

โดยไม่ซ้อน 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

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

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

.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 */
  }
}

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

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

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

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

แบบแผนการตั้งชื่อคลาส 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 DevTools

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

อนาคต

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

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

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

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