สัปดาห์ที่ 4 CSS Layout (Flexbox และ Grid)

สไลด์บทเรียน

วัตถุประสงค์

  1. จัด layout ด้วย Flexbox และ CSS Grid ได้
  2. เลือกใช้ Flexbox หรือ Grid ให้เหมาะกับปัญหา layout ได้
  3. ปรับหน้าเว็บให้รองรับหลายขนาดหน้าจอได้

หัวข้อย่อย

  1. Normal Flow และ Display
  2. Flex Container และ Flex Items
  3. Main Axis และ Cross Axis
  4. CSS Grid Container, Tracks และ Areas
  5. Responsive Layout
  6. Media Queries
  7. Layout Debugging ด้วย DevTools

เนื้อหา

Flexbox เหมาะกับการจัดวางในมิติเดียว เช่น เมนู แถวปุ่ม หรือรายการการ์ด ส่วน CSS Grid เหมาะกับ layout สองมิติ เช่น หน้า dashboard หรือ gallery ที่ต้องควบคุมทั้งแถวและคอลัมน์

Responsive Layout คือการออกแบบให้หน้าเว็บปรับตามพื้นที่แสดงผล หลักคิดสำคัญคือ mobile first, content first และใช้ breakpoint เมื่อเนื้อหาต้องเปลี่ยนรูปแบบจริง ๆ

1. Normal Flow และ Display

ก่อนใช้ Flexbox หรือ Grid ควรเข้าใจก่อนว่า HTML มีการจัดวางตามธรรมชาติที่เรียกว่า Normal Flow เบราว์เซอร์จะวาง element ตามลำดับที่ปรากฏใน HTML จากบนลงล่าง โดยพฤติกรรมขึ้นกับชนิดการแสดงผลของ element

ค่า display เป็น property สำคัญที่กำหนดว่า element จะแสดงตัวเองและจัดการลูกภายในอย่างไร

ค่า display พฤติกรรมหลัก ตัวอย่าง element
block ขึ้นบรรทัดใหม่ กินพื้นที่เต็มแนวกว้างเท่าที่ทำได้ div, section, p, h1
inline อยู่ในบรรทัดเดียวกับข้อความ กำหนด width/height โดยตรงไม่ได้ a, span, strong
inline-block อยู่ในบรรทัดเดียวได้ แต่กำหนด width/height ได้ ปุ่มหรือ badge
none ไม่แสดงผลและไม่กินพื้นที่ ใช้ซ่อน element
flex เปิด Flexbox layout ให้ลูกโดยตรง navbar, button group
grid เปิด Grid layout ให้ลูกโดยตรง page layout, gallery

ตัวอย่าง normal flow:

<h1>หัวข้อหลัก</h1>
<p>ย่อหน้าที่หนึ่ง</p>
<p>ย่อหน้าที่สอง</p>
<a href="#">Link ที่อยู่ในบรรทัดเดียว</a>
<a href="#">Link ถัดไป</a>

ตัวอย่างเปลี่ยนพฤติกรรมด้วย display:

.tag {
  display: inline-block;
  padding: 4px 10px;
  border: 1px solid #d1d5db;
  border-radius: 999px;
}

.hidden {
  display: none;
}

แนวคิดสำคัญคืออย่ารีบใช้ Flexbox/Grid ทุกอย่าง หาก normal flow เพียงพอ ควรปล่อยให้ HTML ไหลตามธรรมชาติ แล้วใช้ layout tool เฉพาะจุดที่ต้องควบคุมตำแหน่งจริง ๆ

2. Flex Container และ Flex Items

Flexbox เริ่มทำงานเมื่อกำหนด display: flex ให้ parent element โดย parent จะกลายเป็น Flex Container และลูกโดยตรงจะกลายเป็น Flex Items

<nav class="nav">
  <a href="#">Home</a>
  <a href="#">Courses</a>
  <a href="#">Contact</a>
</nav>
.nav {
  display: flex;
  gap: 16px;
  align-items: center;
}

Property ที่ใช้กับ Flex Container:

Property หน้าที่
display: flex เปิด flex layout
flex-direction กำหนดทิศทางหลัก เช่น row, column
justify-content จัดตำแหน่งบน main axis
align-items จัดตำแหน่งบน cross axis
gap ระยะห่างระหว่าง item
flex-wrap อนุญาตให้ item ขึ้นบรรทัดใหม่

Property ที่ใช้กับ Flex Items:

Property หน้าที่
flex กำหนดการยืด/หดและขนาดเริ่มต้น
flex-grow ให้ item ขยายกินพื้นที่ว่าง
flex-shrink ให้ item หดเมื่อพื้นที่ไม่พอ
flex-basis ขนาดตั้งต้นของ item
align-self จัดตำแหน่ง item เฉพาะตัว

ตัวอย่าง card row ที่ยืดเท่ากัน:

.card-row {
  display: flex;
  gap: 16px;
}

.card {
  flex: 1;
  padding: 16px;
  border: 1px solid #d1d5db;
}

ถ้าพื้นที่ไม่พอและต้องการให้ item ขึ้นแถวใหม่ ให้ใช้ flex-wrap

.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

3. Main Axis และ Cross Axis

Flexbox มีแนวคิดสำคัญคือ main axis และ cross axis โดย main axis คือแกนหลักตามทิศทางของ flex-direction ส่วน cross axis คือแกนที่ตั้งฉากกับ main axis

flex-direction Main Axis Cross Axis
row ซ้ายไปขวา บนลงล่าง
row-reverse ขวาไปซ้าย บนลงล่าง
column บนลงล่าง ซ้ายไปขวา
column-reverse ล่างขึ้นบน ซ้ายไปขวา

ตัวอย่างเมื่อ flex-direction: row:

.nav {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
}

ในกรณีนี้ justify-content จัดแนวนอน ส่วน align-items จัดแนวตั้ง

ตัวอย่างเมื่อ flex-direction: column:

.sidebar {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: stretch;
}

เมื่อเปลี่ยนเป็น column, main axis จะกลายเป็นแนวตั้ง ดังนั้น justify-content จะจัดแนวตั้ง และ align-items จะจัดแนวนอน สิ่งนี้เป็นจุดที่ผู้เริ่มต้นมักสับสน

ตัวอย่างจัดปุ่มให้อยู่กลางทั้งแนวตั้งและแนวนอน:

.center-box {
  min-height: 240px;
  display: flex;
  justify-content: center;
  align-items: center;
}

4. CSS Grid Container, Tracks และ Areas

CSS Grid เหมาะกับ layout สองมิติ เพราะควบคุมได้ทั้ง row และ column พร้อมกัน Grid เริ่มทำงานเมื่อกำหนด display: grid ให้ parent element

.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

คำศัพท์สำคัญ:

คำ ความหมาย
Grid Container element ที่กำหนด display: grid
Grid Item ลูกโดยตรงของ grid container
Track แถวหรือคอลัมน์ใน grid
Gap ช่องว่างระหว่าง track
Grid Area พื้นที่ที่ตั้งชื่อและนำ item ไปวางได้

ตัวอย่าง responsive card grid:

.course-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
}

auto-fit และ minmax(240px, 1fr) ช่วยให้ browser ปรับจำนวนคอลัมน์อัตโนมัติ หากพื้นที่แคบจะลดจำนวนคอลัมน์ลงเอง

ตัวอย่าง page layout ด้วย Grid Areas:

.page {
  display: grid;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  grid-template-columns: 240px 1fr;
  gap: 16px;
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
<div class="page">
  <header class="header">Header</header>
  <aside class="sidebar">Sidebar</aside>
  <main class="main">Main</main>
  <footer class="footer">Footer</footer>
</div>

Grid Areas ทำให้ layout อ่านง่าย เพราะเห็นภาพรวมของหน้าเว็บจาก CSS ได้ทันที

5. Responsive Layout

Responsive Layout คือการออกแบบให้หน้าเว็บใช้งานได้ดีบนหน้าจอหลายขนาด เช่น mobile, tablet และ desktop หลักการสำคัญคือเนื้อหาต้องอ่านง่าย กดใช้งานสะดวก และไม่ล้นจอ

แนวคิดพื้นฐาน:

  1. Mobile First: ออกแบบจากจอเล็กก่อน แล้วเพิ่ม layout สำหรับจอใหญ่
  2. Fluid Layout: ใช้หน่วยที่ยืดหยุ่น เช่น %, fr, rem, minmax
  3. Content First: ให้เนื้อหาเป็นตัวกำหนด breakpoint ไม่ใช่ยึด device รุ่นใดรุ่นหนึ่ง
  4. Flexible Images: รูปภาพไม่ควรล้น container

ตัวอย่างรูปภาพที่ยืดหยุ่น:

img {
  max-width: 100%;
  height: auto;
}

ตัวอย่าง container ที่อ่านง่าย:

.container {
  width: min(100% - 32px, 960px);
  margin-inline: auto;
}

ตัวอย่าง grid ที่ responsive โดยไม่ต้องใช้ media query:

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
}

การทำ responsive ที่ดีควรทดสอบทั้งความกว้างหน้าจอจริง การอ่านข้อความ ความกว้างของปุ่ม และ spacing ระหว่างส่วนต่าง ๆ

6. Media Queries

Media Query ใช้กำหนด CSS เฉพาะเงื่อนไข เช่น เมื่อหน้าจอกว้างกว่า/แคบกว่าค่าที่กำหนด เหมาะกับการเปลี่ยน layout เมื่อเนื้อหาเริ่มอึดอัดหรือต้องแสดงผลต่างกันจริง ๆ

ตัวอย่าง Mobile First:

.layout {
  display: grid;
  gap: 16px;
}

@media (min-width: 768px) {
  .layout {
    grid-template-columns: 240px 1fr;
  }
}

ในตัวอย่างนี้ ค่าเริ่มต้นเหมาะกับ mobile คือเรียงลงมา 1 คอลัมน์ เมื่อพื้นที่กว้างตั้งแต่ 768px จึงเปลี่ยนเป็น sidebar + main content

ตัวอย่างปรับ navigation:

.nav {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

@media (min-width: 640px) {
  .nav {
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
  }
}

แนวทางเลือก breakpoint:

  1. เริ่มจากเนื้อหาจริงบน mobile
  2. ขยายหน้าจอจน layout เริ่มอ่านยากหรือแน่นเกินไป
  3. ตั้ง breakpoint ตรงจุดที่เนื้อหาต้องเปลี่ยนรูปแบบ
  4. หลีกเลี่ยง breakpoint มากเกินจำเป็น

7. Layout Debugging ด้วย DevTools

Chrome DevTools ช่วยตรวจ layout ได้รวดเร็ว โดยเฉพาะเมื่อ element ไม่อยู่ตำแหน่งที่คาดไว้ มีพื้นที่เกิน หรือ responsive ไม่ทำงาน

ขั้นตอน debug layout:

  1. คลิกขวาที่ element แล้วเลือก Inspect
  2. ดูแท็บ Elements เพื่อตรวจ HTML structure
  3. ดูแท็บ Styles เพื่อตรวจว่า CSS rule ใดถูกใช้หรือถูกขีดทับ
  4. ดู Box Model panel เพื่อตรวจ margin, border, padding และ content size
  5. เปิด overlay ของ Flex หรือ Grid เพื่อดูเส้น layout
  6. ใช้ Device Mode เพื่อทดสอบหน้าจอหลายขนาด
  7. ลองปิด/เปิด CSS property ทีละตัวเพื่อหาสาเหตุ

ปัญหาที่พบบ่อยและแนวทางตรวจ:

ปัญหา จุดที่ควรตรวจ
item ไม่เรียงตามต้องการ display, flex-direction, grid-template-columns
ระยะห่างแปลก margin, padding, gap
element ล้นจอ width, min-width, รูปภาพ, long text
media query ไม่ทำงาน syntax, breakpoint, ลำดับ CSS, viewport meta
CSS ไม่ถูกใช้ selector, specificity, path ของไฟล์ CSS

ตัวอย่าง debug ง่าย ๆ:

* {
  outline: 1px solid rgba(37, 99, 235, 0.35);
}

ใช้ outline ชั่วคราวเพื่อดูขอบเขต element ได้ชัดเจน แต่ควรลบออกก่อนส่งงาน

Checklist ก่อนส่งงาน Layout

  1. ใช้ normal flow เมื่อเพียงพอ ไม่บังคับ layout เกินจำเป็น
  2. ใช้ Flexbox กับ layout มิติเดียว เช่น menu, toolbar, card row
  3. ใช้ Grid กับ layout สองมิติ เช่น gallery, dashboard, page layout
  4. ใช้ gap แทน margin ซับซ้อนเมื่อจัด item ใน flex/grid
  5. รูปภาพไม่ล้น container
  6. หน้าเว็บอ่านได้บน mobile, tablet และ desktop
  7. ใช้ media query เมื่อเนื้อหาต้องเปลี่ยน layout จริง ๆ
  8. ตรวจ layout ด้วย DevTools ก่อนส่ง

ตัวอย่าง

.course-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
}

กิจกรรมในชั้นเรียน

สร้างหน้า gallery หรือ card layout ที่ปรับจำนวนคอลัมน์อัตโนมัติตามขนาดหน้าจอ

ศึกษาค้นคว้านอกเวลา

ปรับปรุงเว็บไซต์ส่วนตัวให้รองรับ mobile, tablet และ desktop

คำถามทบทวน

  1. Flexbox เหมาะกับ layout แบบใด
  2. CSS Grid เหมาะกับ layout แบบใด
  3. Media Query ควรใช้เมื่อใด

กลับรายวิชา