การสืบทอด

The CSS Podcast - 005: Inheritance

สมมติว่าคุณเพิ่งเขียน CSS บางส่วนเพื่อให้องค์ประกอบดูเหมือนปุ่ม

<a href="http://example.com" class="my-button">I am a button link</a>
.my-button {
  display: inline-block;
  padding: 1rem 2rem;
  text-decoration: none;
  background: pink;
  font: inherit;
  text-align: center;
}

จากนั้นเพิ่มองค์ประกอบลิงก์ลงในบทความของเนื้อหา โดยมีค่า class เป็น .my-button แต่มีปัญหาเกิดขึ้นเนื่องจากข้อความไม่ใช่สีที่คุณคาดไว้ เหตุการณ์นี้เกิดขึ้นได้อย่างไร

พร็อพเพอร์ตี้ CSS บางรายการจะรับค่ามาโดยค่าเริ่มต้นหากคุณไม่ได้ระบุค่า ในกรณีของปุ่มนี้ ปุ่มรับค่า color จาก CSS นี้

article a {
  color: maroon;
}

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

ขั้นตอนการรับค่า

มาดูวิธีการทำงานของการสืบทอดกันโดยใช้ข้อมูลโค้ด HTML นี้

<html>
  <body>
    <article>
      <p>Lorem ipsum dolor sit amet.</p>
    </article>
  </body>
</html>

องค์ประกอบรูท (<html>) จะไม่รับค่าใดๆ มาจากองค์ประกอบอื่นเนื่องจากเป็นองค์ประกอบแรกในเอกสาร เพิ่ม CSS บางส่วนในองค์ประกอบ HTML แล้ว CSS จะเริ่มมีผลกับส่วนต่างๆ ของเอกสาร

html {
  color: lightslategray;
}

องค์ประกอบอื่นๆ จะรับค่าพร็อพเพอร์ตี้ color มาจากค่าเริ่มต้น องค์ประกอบ html มี color: lightslategray ดังนั้นองค์ประกอบทั้งหมดที่รับค่าสีมาจะมีสีเป็น lightslategray

body {
  font-size: 1.2em;
}
p {
  font-style: italic;
}

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

พร็อพเพอร์ตี้ใดบ้างที่รับค่าตามค่าเริ่มต้น

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

วิธีการทํางานของการรับช่วง

องค์ประกอบ HTML ทุกรายการจะมีพร็อพเพอร์ตี้ CSS ทั้งหมดที่กําหนดไว้โดยค่าเริ่มต้นด้วยค่าเริ่มต้น ค่าเริ่มต้นคือพร็อพเพอร์ตี้ที่ไม่ได้รับค่ามาและแสดงเป็นค่าเริ่มต้นหากแคสเคดคำนวณค่าสำหรับองค์ประกอบนั้นไม่สำเร็จ

พร็อพเพอร์ตี้ที่รับค่ามาได้โดยสืบทอดจะส่งต่อค่าไปยังองค์ประกอบย่อย และองค์ประกอบย่อยจะได้รับค่าที่คำนวณแล้วซึ่งแสดงถึงค่าขององค์ประกอบหลัก ซึ่งหมายความว่าหากองค์ประกอบหลักตั้งค่า font-weight เป็น bold องค์ประกอบย่อยทั้งหมดจะเป็นตัวหนา เว้นแต่จะมีการตั้งค่า font-weight เป็นค่าอื่น หรือสไตล์ชีต User Agent มีค่าสำหรับ font-weight ขององค์ประกอบนั้น

วิธีรับช่วงและควบคุมการรับช่วงอย่างชัดแจ้ง

การสืบทอดอาจส่งผลต่อองค์ประกอบในลักษณะที่ไม่คาดคิด ดังนั้น CSS จึงมีเครื่องมือที่จะช่วยจัดการกับปัญหานี้

คีย์เวิร์ด inherit

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

strong {
  font-weight: 900;
}

ข้อมูลโค้ด CSS นี้กำหนดให้องค์ประกอบ <strong> ทั้งหมดมี font-weight เป็น 900 แทนค่าเริ่มต้น bold ซึ่งจะเทียบเท่ากับ font-weight: 700

.my-component {
  font-weight: 500;
}

คลาส .my-component จะตั้งค่า font-weight เป็น 500 แทน หากต้องการให้องค์ประกอบ <strong> ภายใน .my-component font-weight: 500 ด้วย ให้เพิ่มข้อมูลต่อไปนี้

.my-component strong {
  font-weight: inherit;
}

ตอนนี้องค์ประกอบ <strong> ภายใน .my-component จะมี font-weight เป็น 500

คุณสามารถกําหนดค่านี้อย่างชัดเจนได้ แต่หากใช้ inherit และ CSS ของ .my-component มีการเปลี่ยนแปลงในอนาคต คุณสามารถรับประกันได้ว่า <strong> จะอัปเดตตามค่า CSS นั้นโดยอัตโนมัติ

คีย์เวิร์ด initial

การสืบทอดอาจทําให้เกิดปัญหากับองค์ประกอบ และ initial มีตัวเลือกการรีเซ็ตที่มีประสิทธิภาพ

ก่อนหน้านี้คุณได้เรียนรู้ว่าพร็อพเพอร์ตี้ทุกรายการมีค่าเริ่มต้นใน CSS คีย์เวิร์ด initial จะตั้งค่าพร็อพเพอร์ตี้กลับเป็นค่าเริ่มต้นเดิม

aside strong {
  font-weight: initial;
}

ข้อมูลโค้ดนี้จะนําน้ำหนักตัวหนาออกจากองค์ประกอบ <strong> ทั้งหมดภายในองค์ประกอบ <aside> และทำให้เป็นแบบตัวหนาธรรมดาแทน ซึ่งเป็นค่าเริ่มต้น

คีย์เวิร์ด unset

พร็อพเพอร์ตี้ unset จะทํางานแตกต่างกันหากรับค่าพร็อพเพอร์ตี้โดยค่าเริ่มต้นหรือไม่ หากรับค่าพร็อพเพอร์ตี้โดยค่าเริ่มต้น คีย์เวิร์ด unset จะเหมือนกับ inherit หากพร็อพเพอร์ตี้ไม่ได้รับค่าเริ่มต้น คีย์เวิร์ด unset จะเท่ากับ initial

การจดจำว่าพร็อพเพอร์ตี้ CSS ใดรับค่าโดยค่าเริ่มต้นนั้นอาจเป็นเรื่องยาก ในกรณีนี้unsetอาจมีประโยชน์ ตัวอย่างเช่น color จะรับค่าเริ่มต้น แต่ margin จะไม่รับค่าเริ่มต้น คุณจึงเขียนได้ดังนี้

/* Global color styles for paragraph in authored CSS */
p {
  margin-top: 2em;
  color: goldenrod;
}

/* The p needs to be reset in asides, so you can use unset */
aside p {
  margin: unset;
  color: unset;
}

ตอนนี้ระบบจะนำ margin ออกและ color จะเปลี่ยนกลับไปเป็นค่าที่คำนวณแล้วซึ่งรับช่วงมา

คุณใช้ค่า unset กับพร็อพเพอร์ตี้ all ได้ด้วย กลับไปที่ตัวอย่างข้างต้น จะเกิดอะไรขึ้นหากสไตล์ p ระดับส่วนกลางมีพร็อพเพอร์ตี้เพิ่มเติมอีก 2-3 รายการ เฉพาะกฎที่ตั้งค่าไว้สำหรับ margin และ color เท่านั้นที่มีผล

/* Global color styles for paragraph in authored CSS */
p {
    margin-top: 2em;
    color: goldenrod;
    padding: 2em;
    border: 1px solid;
}

/* Not all properties are accounted for anymore */
aside p {
    margin: unset;
    color: unset;
}

หากคุณเปลี่ยนกฎ aside p เป็น all: unset แทน ระบบจะไม่ตั้งค่ารูปแบบส่วนกลางกับ p ในอนาคตไม่ว่ารูปแบบส่วนกลางใดก็ตาม

aside p {
    margin: unset;
    color: unset;
    all: unset;
}

ทดสอบความเข้าใจ

ทดสอบความรู้เรื่องการรับช่วง

พร็อพเพอร์ตี้ใดต่อไปนี้ที่รับค่าเริ่มต้น

animation
ระบบจะไม่ส่งต่อภาพเคลื่อนไหวไปยังรายการย่อย
font-size
🎉
color
🎉
text-align
🎉
line-height
🎉

ค่าใดจะทํางานเหมือน inherit เว้นแต่จะไม่มีค่าที่จะรับช่วงมา แล้วทํางานเหมือน initial

reset
ไม่ใช่ค่าที่ถูกต้อง โปรดลองอีกครั้ง
unset
🎉
superset
ไม่ใช่ค่าที่ถูกต้อง โปรดลองอีกครั้ง

แหล่งข้อมูล