CSS
Box Model
display basics
เรียนรู้ว่าทำไมบาง element ขึ้นบรรทัดใหม่โดยอัตโนมัติ ในขณะที่บาง element เรียงต่อกันในบรรทัดเดียว — ทั้งหมดถูกควบคุมด้วย property ชื่อ display (ดิสเพลย์) ซึ่งเป็นพื้นฐานสำคัญของ layout ใน CSS
หัวข้อนี้คืออะไร
คุณเคยสังเกตไหมว่า <h1> หรือ <p> ขึ้นบรรทัดใหม่เสมอ แต่ <span> หรือ <a> กลับอยู่ในบรรทัดเดียวกับข้อความรอบข้าง? พฤติกรรมเหล่านั้นไม่ได้เกิดขึ้นเองตามธรรมชาติ — มันถูกกำหนดโดย CSS property ที่ชื่อว่า display (ดิสเพลย์) display บอก browser ว่า element นั้นควรแสดงผลในรูปแบบใด จะกินพื้นที่เต็มบรรทัดหรือเรียงต่อกันกับ element อื่น และสามารถกำหนดขนาดได้หรือไม่ ค่าพื้นฐานที่ต้องรู้จัก:
- block (บล็อก) — ขึ้นบรรทัดใหม่เสมอ กินความกว้างเต็ม parent กำหนด width/height ได้
- inline (อินไลน์) — เรียงต่อกันในบรรทัดเดียว กินพื้นที่แค่เท่าเนื้อหา กำหนด width/height ไม่ได้
- inline-block (อินไลน์บล็อก) — เรียงต่อกันในบรรทัดเดียวได้ แต่กำหนด width/height ได้เหมือน block
- none (ไม่มีการแสดงผล) — ซ่อน element ออกจาก layout ทั้งหมด ราวกับไม่มีอยู่
ทำไมหัวข้อนี้จึงสำคัญ
display เป็น property ที่ส่งผลต่อ layout ของหน้าเว็บโดยตรง และเป็นรากฐานที่คุณต้องเข้าใจก่อนเรียน Flexbox และ Grid ถ้าไม่เข้าใจ display คุณจะพบปัญหาเหล่านี้: - กำหนด width/height ให้ <span> หรือ <a> แล้วไม่ได้ผล เพราะมันเป็น inline โดย default - งงว่าทำไม element ขึ้นบรรทัดใหม่ทั้งที่ไม่ต้องการ - ไม่รู้วิธีทำให้ปุ่มหรือป้ายหลายอันเรียงในบรรทัดเดียวกัน - ไม่สามารถซ่อน element ออกจาก layout ได้อย่างถูกต้อง การเข้าใจ display ช่วยให้คุณ: - ควบคุมการวาง element ในหน้าเว็บได้ตามต้องการ - แก้ปัญหา layout พื้นฐานได้ด้วยตัวเอง - ต่อยอดไปยัง display: flex และ display: grid ได้อย่างมั่นใจ
ตัวอย่างจากชีวิตจริง
ลองนึกภาพการวางของบนโต๊ะทำงาน 📦 display: block — เหมือนกล่องใหญ่ที่วางเต็มแถว คุณวางกล่องลงบนโต๊ะ มันกินพื้นที่ตลอดแนวกว้าง กล่องถัดไปต้องวางใต้ลงมา วางข้างๆ กันไม่ได้ → เหมือน <div>, <p>, <h1> ที่ขึ้นบรรทัดใหม่เสมอ 📝 display: inline — เหมือนคำในประโยค คำแต่ละคำเรียงต่อกันในบรรทัดเดียว ขนาดพอดีกับตัวอักษร คุณไม่สามารถบังคับให้คำหนึ่งมีขนาด 100px ได้ — มันจะกว้างแค่ความยาวของตัวเอง → เหมือน <span>, <a>, <strong> ที่อยู่ในบรรทัดเดียวกับข้อความ 🏷️ display: inline-block — เหมือนป้ายราคาสินค้าหลายใบเรียงกัน ป้ายแต่ละใบอยู่ต่อกันในแถวเดียว แต่คุณกำหนดขนาดของแต่ละป้ายได้ตายตัว → ใช้สร้างปุ่ม แท็ก badge ที่เรียงต่อกันได้แต่มีขนาดแน่นอน 🚫 display: none — เหมือนเอาของชิ้นนั้นออกจากห้อง ของหายไปเลย ไม่เหลือร่องรอย สิ่งของรอบข้างถูกจัดใหม่ราวกับมันไม่เคยมีอยู่ → ใช้ซ่อน element โดยไม่ให้กินพื้นที่ใน layout
แนวคิดหลักที่ต้องเข้าใจ
block = เต็มแถว | inline = ไหลตามข้อความ | inline-block = เรียงกันแต่กำหนดขนาดได้ | none = ไม่แสดง
ก่อนดูโค้ด ทำความเข้าใจพฤติกรรมของแต่ละค่า: block — กล่องเต็มแถว กินความกว้างเต็ม parent เสมอ (ถ้าไม่กำหนด width) ขึ้นบรรทัดใหม่ก่อนและหลัง element นี้เสมอ กำหนด width, height, padding, margin ได้ทุกทิศ ตัวอย่าง default: <div>, <p>, <h1>–<h6>, <section> inline — ไหลตามข้อความ กินพื้นที่แค่เท่าเนื้อหาของตัวเอง เรียงต่อกันในบรรทัดเดียว กำหนด width และ height ไม่ได้ (ถูกเพิกเฉย) margin และ padding แนวซ้าย-ขวาใช้ได้ แต่แนวบน-ล่างไม่ส่งผลต่อ layout ตัวอย่าง default: <span>, <a>, <strong>, <em> inline-block — เรียงในบรรทัด + กำหนดขนาดได้ เรียงต่อกันเหมือน inline แต่กำหนด width, height ได้เหมือน block ไม่มีค่า default ใน HTML — ต้องกำหนดเองเสมอ เหมาะสำหรับปุ่ม badge เมนูที่ต้องเรียงในบรรทัดเดียว none — ไม่มีใน layout element หายไปจาก layout ทั้งหมด ไม่กินพื้นที่ element รอบข้างถูกจัดวางใหม่ราวกับไม่มีมัน (ต่างจาก visibility: hidden ที่ซ่อนแต่ยังกินพื้นที่อยู่)
การทำงานทีละขั้นตอน
เมื่อ browser render หน้าเว็บ นี่คือลำดับที่เกิดขึ้นสำหรับแต่ละ element:
- 1. browser อ่าน HTML tag และตรวจสอบค่า display — แต่ละ HTML tag มีค่า display default ของตัวเอง เช่น <div> เป็น block, <span> เป็น inline ค่า CSS ที่คุณกำหนดจะ override ค่า default นี้
- 2. ถ้า display: block — browser เริ่ม element ใหม่ในบรรทัดใหม่ ขยายความกว้างเต็ม parent และบังคับให้ element ถัดไปขึ้นบรรทัดใหม่ด้วย
- 3. ถ้า display: inline — browser วาง element ต่อจากเนื้อหาก่อนหน้าในบรรทัดเดียวกัน กินพื้นที่แค่เท่าเนื้อหา ถ้าบรรทัดเต็มจะขึ้นบรรทัดใหม่อัตโนมัติ
- 4. ถ้า display: inline-block — browser วาง element ในบรรทัดเดียวกับเนื้อหาก่อนหน้า แต่คำนึงถึง width และ height ที่กำหนดไว้ กล่องนั้นมีขนาดตายตัว
- 5. ถ้า display: none — browser ข้าม element นั้นไปเลย ไม่วาง ไม่กินพื้นที่ element ถัดไปวางต่อจาก element ก่อนหน้า element ที่ none ราวกับไม่มีมัน
ตัวอย่างเชิงเทคนิค — โค้ดจริง
element เดียวกัน สี่แบบ ด้วยค่า display ต่างกัน:
สังเกตว่า inline-block เป็นตัวเลือกที่ดีสำหรับปุ่มหรือป้ายที่ต้องเรียงต่อกันแต่มีขนาดแน่นอน — ก่อนที่ flexbox จะเป็นที่นิยม inline-block คือวิธีหลักในการสร้าง navigation menu
/* 1. block — กินเต็มบรรทัด */
.box-block {
display: block;
width: 200px; /* กำหนดได้ */
height: 60px; /* กำหนดได้ */
background: #3b82f6;
/* ขึ้นบรรทัดใหม่ก่อนและหลังเสมอ */
}
/* 2. inline — ไหลตามข้อความ */
.label-inline {
display: inline;
/* width: 200px; */ /* ถูกเพิกเฉย ไม่มีผล */
/* height: 60px; */ /* ถูกเพิกเฉย ไม่มีผล */
background: #22c55e;
padding: 4px 8px; /* padding ซ้าย-ขวาใช้ได้ */
}
/* 3. inline-block — เรียงกัน + กำหนดขนาดได้ */
.badge-inline-block {
display: inline-block;
width: 80px; /* กำหนดได้ */
height: 32px; /* กำหนดได้ */
background: #8b5cf6;
/* อยู่ในบรรทัดเดียวกับ element inline อื่น */
}
/* 4. none — หายไปจาก layout */
.tooltip {
display: none;
/* ไม่แสดงผล ไม่กินพื้นที่ */
/* element ข้างๆ วางราวกับไม่มีมัน */
}ดูความแตกต่างแบบ Interactive
ทดลองเปลี่ยนค่า display ของ .box แล้วสังเกตว่า element วางตัวอย่างไร:
จุดที่ผู้เริ่มต้นมักสับสน
ตรวจสอบว่าคุณเข้าใจถูกต้องหรือยัง:
- ❌ กำหนด width/height ให้ inline element แล้วไม่เห็นผล — inline element เพิกเฉย width และ height ต้องเปลี่ยนเป็น inline-block หรือ block ก่อน ถึงจะกำหนดขนาดได้
- ❌ ไม่เข้าใจความต่างระหว่าง inline กับ inline-block — ทั้งคู่อยู่ในบรรทัดเดียวกันได้ แต่ inline ไม่รับ width/height ส่วน inline-block รับได้เหมือน block
- ❌ สับสน display: none กับ visibility: hidden — display: none ทำให้ element หายไปจาก layout ทั้งหมด element รอบข้างถูกจัดใหม่ แต่ visibility: hidden ซ่อนการแสดงผลแต่ยังกินพื้นที่ใน layout อยู่
- ❌ ไม่รู้ว่า HTML tag แต่ละตัวมีค่า display default ต่างกัน — <div>, <p>, <h1>–<h6> เป็น block โดย default ส่วน <span>, <a>, <strong> เป็น inline — คุณเปลี่ยนได้ด้วย CSS เสมอ
- ❌ คิดว่า block ต้องกว้างเต็มหน้าจอ — block กว้างเต็ม parent เท่านั้น ไม่ใช่เต็มหน้าจอ ถ้า parent กว้าง 300px block ลูกก็กว้างแค่ 300px
เปรียบเทียบค่า display พื้นฐาน
สรุปความแตกต่างหลักในตารางเดียว:
| ค่า | ขึ้นบรรทัดใหม่ | กำหนด width/height | กินพื้นที่ | ตัวอย่าง default |
|---|---|---|---|---|
| block | ใช่ — เสมอ | ได้ | เต็ม parent | <div>, <p>, <h1> |
| inline | ไม่ — เรียงต่อกัน | ไม่ได้ | เท่าเนื้อหา | <span>, <a>, <strong> |
| inline-block | ไม่ — เรียงต่อกัน | ได้ | เท่า width/height ที่กำหนด | ไม่มี — ต้องกำหนดเอง |
| none | ไม่มีใน layout | ไม่มีผล | ไม่กินเลย | ไม่มี — ต้องกำหนดเอง |
สรุปท้ายบท
จำง่ายๆ แบบนี้: "display กำหนดว่า element นั้นจะ 'อยู่ในโลกของ layout' อย่างไร"
- display: block — กล่องเต็มแถว ขึ้นบรรทัดใหม่เสมอ กำหนดขนาดได้
- display: inline — ไหลตามข้อความ เรียงต่อกัน กำหนด width/height ไม่ได้
- display: inline-block — เรียงต่อกันได้ + กำหนดขนาดได้ — best of both worlds
- display: none — หายจาก layout ทั้งหมด ไม่กินพื้นที่
- <div> และ <p> เป็น block โดย default | <span> และ <a> เป็น inline โดย default
- inline ≠ block: กำหนด width/height ให้ inline element ไม่มีผล
- display เป็นพื้นฐานก่อนเรียน flex และ grid
Lab 1 — สังเกตพฤติกรรม block กับ inline
เป้าหมาย: เห็นความแตกต่างที่ชัดเจนระหว่าง block และ inline โจทย์: ตอนนี้ .box-a และ .box-b เป็น display: block ทั้งคู่ วางซ้อนกันอยู่ เปลี่ยน .box-b ให้เป็น display: inline เพื่อให้มันเรียงอยู่ข้างๆ .box-a ในบรรทัดเดียวกัน ระบบจะตรวจ: 1. .box-b มี display: inline ใน CSS 2. computed display ของ .box-b = inline ใน browser 3. .box-b อยู่ในตำแหน่งเดียวกับ .box-a (offsetTop เท่ากันหรือใกล้เคียง) เงื่อนไข: ห้ามเปลี่ยน display ของ .box-a
Lab 2 — จัดเมนูด้วย inline-block
เป้าหมาย: ใช้ inline-block ทำให้ element เรียงต่อกันในบรรทัดเดียวและกำหนดขนาดได้ โจทย์: .nav-item ตอนนี้เป็น display: block วางซ้อนกันอยู่ เปลี่ยนให้ .nav-item เป็น display: inline-block พร้อมกำหนด width: 100px และ height: 40px ระบบจะตรวจ: 1. .nav-item มี display: inline-block ใน CSS 2. .nav-item มี width: 100px ใน CSS 3. computed display = inline-block ใน browser 4. offsetWidth = 100 และ offsetHeight = 40 เงื่อนไข: ต้องใช้ inline-block ไม่ใช่ flex หรือ grid
Lab 3 — แก้ layout พื้นฐานด้วย display
เป้าหมาย: เลือกค่า display ที่เหมาะสมกับแต่ละสถานการณ์ โจทย์: มีสอง element ที่แสดงผลไม่ตรงเป้าหมาย 1. .badge — ตอนนี้เป็น block กินทั้งบรรทัด แต่ต้องการให้แสดงเรียงกันในบรรทัดเดียวและกำหนดขนาดได้ → ต้องเปลี่ยนเป็น display: inline-block 2. .hidden-tip — ตอนนี้เป็น block กินพื้นที่อยู่ แต่ต้องการซ่อนออกจาก layout ทั้งหมด → ต้องเปลี่ยนเป็น display: none เงื่อนไข: ห้ามเปลี่ยน CSS อื่นนอกจาก display ของแต่ละ element