Box Model: ทุก element คือกล่อง
4 ชั้นของกล่อง (content/padding/border/margin), box-sizing ที่แก้ปัญหา width: 100% overflow, และ margin collapsing ที่ทำให้ spacing ไม่ตรงความคิด
ถ้ามีกฎข้อเดียวที่ต้องจำเรื่อง CSS layout ก็คือ ทุก element บน HTML คือกล่อง ไม่ว่าจะเป็นหัวข้อ ปุ่ม รูป หรือแม้แต่ตัวอักษร ล้วนเป็นกล่องสี่เหลี่ยมทั้งหมด บางกล่องใหญ่ บางกล่องเล็ก บางกล่องมีกล่องอื่นซ้อนอยู่ข้างใน แต่ทั้งหมดก็ยังคือกล่อง
และกล่องใน CSS ไม่ใช่กล่องธรรมดา มันมี 4 ชั้น ซ้อนกันอยู่ ถ้าเข้าใจ 4 ชั้นนี้แล้ว ก็เท่ากับเข้าใจ layout ของเว็บไปแล้วกว่า 80%
4 ชั้นของกล่อง
ทุกกล่องมี 4 ชั้นซ้อนกัน ไล่จากชั้นในสุดออกมา
- Content คือเนื้อหาจริง เช่น ตัวอักษร รูป หรือปุ่ม
- Padding คือช่องว่างภายในกล่องที่อยู่ระหว่าง content กับเส้น border
- Border คือเส้นขอบของกล่อง
- Margin คือช่องว่างภายนอกกล่อง ที่ดันกล่องอื่นให้ห่างออกไป
ลอง slider ดูให้เห็นความต่าง
180px
width: 180px หมายถึงแค่ content ไม่รวม padding กับ border ขนาดจริงคือ 236px ลอง slider padding กับ border ดู content width ไม่เปลี่ยน แต่ box ขยายออกwidth ไม่ได้คุมความกว้างทั้งหมด
นี่คือ pain point ที่ dev ทุกคนต้องเจอ เรากำหนด width: 100% ให้ element ลูก คิดว่ามันจะพอดีกับ parent แต่กลับล้นออกไปซะงั้น เพราะ padding กับ border ถูกบวกเพิ่มจาก width อีกชั้น
เช่น parent กว้าง 400px ถ้าลูกกำหนด width: 100%; padding: 20px; border: 2px solid จริงๆ แล้วลูกจะกว้างถึง 444px (content 400 + padding 40 + border 4) ล้น parent ไปถึง 44px
นี่คือการทำงานของ box-sizing: content-box ซึ่งเป็น default ของ CSS มาแต่ไหนแต่ไร โดย width หมายถึง ขนาดของ content เท่านั้น ส่วน padding กับ border ถูกบวกเพิ่มจากนั้นอีกชั้นหนึ่ง
Margin Collapse เรื่องแปลกที่ทุกคนเจอ
นี่คืออีกเรื่องที่มือใหม่หัด code ทุกคนต้องงง เช่น เขียน .a { margin-bottom: 32px } แล้ว .b { margin-top: 16px } เราคาดว่าจะมีระยะห่าง 48px ระหว่าง element ทั้งสอง แต่จริงๆ ได้แค่ 32px
.a { margin-bottom: 32px; }
.b { margin-top: 16px; }
/* ความคิดว่า: gap = 32 + 16
= 48px */gap แทน margin จะเลี่ยงได้เลยกฎของมันก็คือ เวลาที่ block element 2 ตัววางต่อกันในแนวตั้ง margin ที่ชนกันจะ ยุบเหลือแค่ค่าที่ใหญ่กว่า ไม่ใช่บวกกัน ปรากฏการณ์นี้เรียกว่า margin collapsing
สรุป
- ทุก element คือกล่องที่มี 4 ชั้น ได้แก่ content, padding, border, margin
- padding คือช่องว่างข้างใน ส่วน margin คือช่องว่างข้างนอกที่ดันกล่องอื่นให้ห่างออกไป
box-sizing: content-boxซึ่งเป็น default ทำให้widthหมายถึงแค่ content ส่วน padding กับ border ถูกบวกเพิ่มจากนั้น จึงทำให้ element ล้น parentbox-sizing: border-boxทำให้widthหมายถึงขนาดกล่องทั้งหมด ซึ่งตรงกับที่เราคาดหวัง ควรใส่*reset ในทุก project- Margin collapse คือเวลาที่ block element 2 ตัวชนกันในแนวตั้ง margin จะยุบเหลือตัวที่ใหญ่กว่า หลบด้วย flexbox หรือ grid กับ gap
บทถัดไปคือ Flexbox เครื่องมือ layout ที่เว็บสมัยใหม่ใช้กันเป็นหลัก รู้แค่ 2 axis (main กับ cross) กับ property อีกไม่กี่ตัว ก็จัดการ layout ทั้งแนวตั้งและแนวนอนได้หมด โดยไม่ต้องใช้ float หรือ table อีกต่อไป