Article · programming
HTML & CSS EP6: Flexbox — จัด Layout เว็บไซต์ให้ยืดหยุ่นและรองรับทุกหน้าจอ
HTML & CSS
เรียนรู้ CSS Flexbox ตั้งแต่การกำหนดแกนหลัก การจัดตำแหน่ง การเว้นระยะ การขึ้นบรรทัดใหม่ และการสร้าง Navigation Bar, Card Layout และ Responsive Layout พร้อมหน้าเว็บ HTML แบบเต็มที่ทดลองได้จริง
1. CSS Flexbox คืออะไร
CSS Flexbox หรือ Flexible Box Layout เป็นระบบจัดวางองค์ประกอบที่ช่วยให้เราจัดตำแหน่งและกระจายพื้นที่ระหว่าง element ภายใน Container ได้สะดวก เหมาะกับงานที่ต้องจัดเรียงรายการในแนวนอนหรือแนวตั้ง เช่น Navigation Bar, กลุ่มปุ่ม, แถวข้อมูล และการ์ดสินค้า
ก่อนมี Flexbox นักพัฒนามักต้องพึ่งเทคนิคหลายอย่างเพื่อจัดตำแหน่งองค์ประกอบ แต่ Flexbox มีคุณสมบัติที่ออกแบบมาเพื่อจัดการพื้นที่ว่าง การจัดแนว และการยืดหรือหดของรายการโดยตรง จึงช่วยลดความซับซ้อนของ CSS ใน Layout หลายประเภท
แนวคิดสำคัญFlex Container คือกล่องแม่ที่เปิดใช้งาน Flexbox ส่วน Flex Items คือ element ลูกโดยตรงภายใน Container การกำหนดคุณสมบัติของ Flexbox ส่วนใหญ่เริ่มจาก Container แล้วจึงปรับพฤติกรรมของแต่ละ Item ตามต้องการ
2. เริ่มต้นใช้งาน display: flex
การเปิดใช้ Flexbox ทำได้โดยกำหนด display: flex ให้ Container จากนั้น element ลูกโดยตรงจะกลายเป็น Flex Items และเรียงตามแกนหลัก ค่าเริ่มต้นของ flex-direction คือ row จึงเรียงรายการจากซ้ายไปขวาในบริบทการเขียนแนวนอนทั่วไป
.container {
display: flex;
gap: 16px;
}
.item {
padding: 20px;
background: #dbeafe;
border-radius: 10px;
}
คุณสมบัติ gap ใช้กำหนดระยะห่างระหว่าง Flex Items โดยไม่ต้องกำหนด margin ให้แต่ละรายการแยกกัน ตัวอย่างนี้ทำให้รายการเรียงในแถวเดียวและมีช่องว่าง 16px ระหว่างกัน หากพื้นที่ไม่พอ รายการอาจหดตามค่าเริ่มต้นของ flex-shrink ได้
3. เข้าใจ Main Axis และ Cross Axis
Flexbox มีแกนหลักที่เรียกว่า Main Axis และแกนตั้งฉากที่เรียกว่า Cross Axis ทิศทางของแกนเหล่านี้ขึ้นอยู่กับ flex-direction เมื่อใช้ row แกนหลักจะเป็นแนวแถว ส่วนแกนตั้งฉากจะเป็นแนวขวาง แต่เมื่อใช้ column แกนหลักจะเปลี่ยนเป็นแนวคอลัมน์
| คุณสมบัติ | หน้าที่ | ตัวอย่างการใช้งาน |
|---|---|---|
| flex-direction | กำหนดทิศทางแกนหลัก | row, column |
| justify-content | จัดแนวตามแกนหลัก | จัดกลุ่มเมนูหรือปุ่ม |
| align-items | จัดแนวตามแกนตั้งฉาก | จัดข้อความให้อยู่กึ่งกลางแนวขวาง |
| align-content | จัดแนวระหว่างหลายแถวบนแกนตั้งฉาก | ใช้เมื่อมีหลายแถวและมีพื้นที่เหลือ |
| gap | กำหนดระยะห่างระหว่างรายการ | เว้นระยะระหว่างการ์ด |
4. กำหนดทิศทางด้วย flex-direction
flex-direction ใช้กำหนดทิศทางการเรียงรายการ ค่าที่ใช้บ่อยคือ row และ column ส่วน row-reverse กับ column-reverse จะกลับลำดับการจัดวางทางสายตา การกลับทิศทางไม่ได้เปลี่ยนลำดับเชิงความหมายของ DOM ดังนั้นควรจัดลำดับ HTML ให้ถูกต้องสำหรับการอ่านด้วยโปรแกรมช่วยเหลือและการนำทางด้วยคีย์บอร์ด
.row-layout {
display: flex;
flex-direction: row;
gap: 12px;
}
.column-layout {
display: flex;
flex-direction: column;
gap: 12px;
}
.reverse-layout {
display: flex;
flex-direction: row-reverse;
gap: 12px;
}
เลือก row เมื่อต้องการเรียงรายการในแนวนอน และเลือก column เมื่อต้องการวางรายการต่อกันในแนวตั้ง การใช้ column กับกลุ่มปุ่มหรือข้อมูลที่มีลำดับชัดเจนมักเหมาะกับหน้าจอมือถือ ส่วน Navigation Bar บนเดสก์ท็อปมักใช้ row
5. จัดตำแหน่งด้วย justify-content
justify-content ใช้จัดตำแหน่ง Flex Items ตามแกนหลัก ค่าที่ใช้บ่อย ได้แก่ flex-start, center, flex-end, space-between, space-around และ space-evenly แต่ละค่ามีวิธีกระจายพื้นที่ว่างแตกต่างกัน จึงควรเลือกตามผลลัพธ์ที่ต้องการ
.toolbar {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
}
.button-group {
display: flex;
justify-content: center;
gap: 12px;
}
space-between จะวางรายการแรกไว้ต้นแกน รายการสุดท้ายไว้ปลายแกน และกระจายพื้นที่ที่เหลือระหว่างรายการ ส่วน center จะจัดกลุ่มรายการไว้กึ่งกลางแกนหลัก ทั้งนี้หากรายการมีความกว้างรวมมากกว่าพื้นที่ Container การจัดตำแหน่งอาจไม่เป็นไปตามที่คาด จึงควรตรวจสอบความกว้างและการหดตัวของรายการด้วย
6. จัดแนวด้วย align-items
align-items ใช้จัดแนวรายการตามแกนตั้งฉากของ Flex Container ค่าที่ใช้บ่อยคือ stretch, flex-start, center, flex-end และ baseline การจัดแนวนี้มีประโยชน์มากเมื่อต้องการให้โลโก้และเมนูอยู่กึ่งกลางแนวตั้ง หรือจัดไอคอนให้ตรงกับข้อความ
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
min-height: 72px;
gap: 20px;
}
.profile-row {
display: flex;
align-items: center;
gap: 12px;
}
เมื่อกำหนด align-items: center รายการจะอยู่กึ่งกลางตามแกนตั้งฉาก หากใช้ flex-direction: row โดยทั่วไปจะเป็นการจัดกึ่งกลางในแนวตั้ง แต่หากเปลี่ยนเป็น column แกนตั้งฉากจะเปลี่ยนไปเป็นแนวนอน
7. อนุญาตให้รายการขึ้นบรรทัดใหม่ด้วย flex-wrap
ค่าเริ่มต้นของ Flexbox คือ flex-wrap: nowrap ซึ่งพยายามจัดรายการไว้ในแถวเดียว รายการอาจหดเพื่อให้พอดีกับพื้นที่ หากต้องการให้รายการขึ้นแถวใหม่เมื่อพื้นที่ไม่เพียงพอ ให้กำหนด flex-wrap: wrap
.card-list {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.card {
flex: 1 1 240px;
min-width: 0;
}
flex: 1 1 240px เป็นรูปแบบย่อที่ระบุ flex-grow, flex-shrink และ flex-basis ตามลำดับ รายการสามารถขยายเพื่อใช้พื้นที่ว่าง หดเมื่อจำเป็น และเริ่มคำนวณขนาดจากฐานประมาณ 240px ได้ตามพื้นที่ที่มี ผลลัพธ์จริงขึ้นอยู่กับขนาด Container, gap และข้อจำกัดความกว้างของรายการ
8. เข้าใจ flex-grow, flex-shrink และ flex-basis
คุณสมบัติทั้งสามควบคุมการแบ่งพื้นที่ของ Flex Items โดย flex-grow กำหนดสัดส่วนการรับพื้นที่ว่าง flex-shrink กำหนดสัดส่วนการหดเมื่อพื้นที่ไม่พอ และ flex-basis กำหนดขนาดตั้งต้นที่ใช้ในการคำนวณพื้นที่ของรายการ
| คุณสมบัติ | ความหมาย | ตัวอย่าง |
|---|---|---|
| flex-grow | สัดส่วนการขยายเมื่อมีพื้นที่ว่าง | flex-grow: 1; |
| flex-shrink | สัดส่วนการหดเมื่อพื้นที่ไม่พอ | flex-shrink: 1; |
| flex-basis | ขนาดตั้งต้นสำหรับคำนวณ | flex-basis: 220px; |
| flex | รูปแบบย่อของคุณสมบัติหลักทั้งสาม | flex: 1 1 220px; |
ตัวอย่างเช่น รายการสองชิ้นที่มี flex-grow: 1 เท่ากันจะรับส่วนแบ่งพื้นที่ว่างตามสัดส่วนเดียวกัน แต่ไม่ได้หมายความว่าทั้งสองชิ้นจะมีความกว้างเท่ากันเสมอ เพราะขนาดตั้งต้นและข้อจำกัดของแต่ละรายการยังมีผลต่อการคำนวณ
9. ใช้ gap เพื่อควบคุมระยะห่าง
gap เป็นวิธีที่สะดวกในการกำหนดช่องว่างระหว่างรายการ โดยไม่ต้องเพิ่ม margin ให้แต่ละรายการแยกกัน สามารถกำหนดค่าเดียวให้ทั้งแถวและคอลัมน์ หรือใช้ row-gap กับ column-gap เพื่อแยกระยะห่างแต่ละทิศทาง
.product-list {
display: flex;
flex-wrap: wrap;
row-gap: 24px;
column-gap: 16px;
}
.product-card {
flex: 1 1 220px;
}
ตัวอย่างนี้เว้นระยะระหว่างแถว 24px และระหว่างคอลัมน์ 16px ช่วยให้กำหนดช่องว่างได้ชัดเจนขึ้น โดยเฉพาะเมื่อรายการขึ้นบรรทัดใหม่ อย่างไรก็ตาม gap ไม่ได้สร้างช่องว่างด้านนอกก่อนรายการแรกหรือหลังรายการสุดท้าย หากต้องการระยะรอบนอกให้กำหนด padding หรือ margin เพิ่มตามความเหมาะสม
10. สร้าง Navigation Bar ด้วย Flexbox
Navigation Bar เป็นตัวอย่างการใช้งาน Flexbox ที่พบได้บ่อย โดยสามารถวางโลโก้ไว้ด้านหนึ่งและกลุ่มลิงก์อีกด้านหนึ่ง ใช้ justify-content: space-between เพื่อแยกกลุ่ม และ align-items: center เพื่อจัดให้อยู่กึ่งกลางแนวตั้ง เมื่อหน้าจอแคบลงควรตรวจสอบว่ารายการยังไม่ล้น Container
<header class="site-header">
<a class="brand" href="#home">MyStudio</a>
<nav class="site-nav" aria-label="เมนูหลัก">
<a href="#features">คุณสมบัติ</a>
<a href="#services">บริการ</a>
<a href="#contact">ติดต่อ</a>
</nav>
</header>
.site-header {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 16px;
padding: 16px 24px;
background: #ffffff;
border-bottom: 1px solid #dbe3ef;
}
.brand {
font-size: 1.25rem;
font-weight: 800;
color: #1d4ed8;
text-decoration: none;
}
.site-nav {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.site-nav a {
color: #334155;
text-decoration: none;
}
.site-nav a:hover {
color: #1d4ed8;
}
ตัวอย่างนี้ใช้ flex-wrap: wrap ทั้งกับ Header และ Navigation เพื่อให้รายการสามารถขึ้นบรรทัดใหม่ได้เมื่อพื้นที่ไม่พอ หากต้องการเมนูแบบยุบเป็นปุ่มบนมือถือ จะต้องเพิ่มโครงสร้างและพฤติกรรมสำหรับเปิดปิดเมนู ซึ่งเป็นอีกขั้นตอนหนึ่งนอกเหนือจากการจัดวางด้วย Flexbox เพียงอย่างเดียว
11. Flexbox กับ Responsive Design
Responsive Design คือการปรับการแสดงผลให้เหมาะกับพื้นที่หน้าจอที่แตกต่างกัน Flexbox ช่วยให้รายการยืด หด และขึ้นบรรทัดใหม่ได้ ส่วน Media Query ใช้เปลี่ยนกฎ CSS เมื่อหน้าจอมีขนาดถึงเงื่อนไขที่กำหนด การใช้สองแนวทางร่วมกันช่วยสร้าง Layout ที่ยืดหยุ่นมากขึ้น
.layout {
display: flex;
align-items: stretch;
gap: 24px;
}
.main-content {
flex: 2 1 0;
min-width: 0;
}
.sidebar {
flex: 1 1 240px;
min-width: 0;
}
@media (max-width: 700px) {
.layout {
flex-direction: column;
}
}
บนหน้าจอขนาดใหญ่ Layout นี้วางเนื้อหาหลักและ Sidebar ไว้ในแถวเดียวกัน เมื่อหน้าจอกว้างไม่เกิน 700px จะเปลี่ยนเป็นแนวตั้ง ทำให้เนื้อหาเรียงต่อกัน อ่านง่ายขึ้น และลดความเสี่ยงที่คอลัมน์จะแคบเกินไป
12. ข้อผิดพลาดที่พบบ่อยเมื่อใช้ Flexbox
ใช้ justify-content เพื่อแก้ปัญหาทุกแนว
justify-content จัดตำแหน่งตามแกนหลัก ส่วน align-items จัดแนวตามแกนตั้งฉาก หากต้องการจัดกึ่งกลางทั้งสองแกน สามารถใช้ justify-content: center และ align-items: center ร่วมกันได้ โดยต้องกำหนดขนาดหรือพื้นที่ของ Container ให้เหมาะสมด้วย
ลืม flex-wrap
เมื่อมีการ์ดหลายใบในแถวเดียว รายการอาจแคบลงหรือทำให้เนื้อหาล้นได้ หากต้องการให้การ์ดขึ้นแถวใหม่ ควรพิจารณา flex-wrap: wrap พร้อมกำหนด flex-basis และข้อจำกัดความกว้างให้เหมาะสม
เนื้อหาภายในรายการดัน Layout ให้ล้น
Flex Item บางชนิดมีขนาดขั้นต่ำที่อิงกับเนื้อหา ทำให้ไม่ยอมหดตามที่คาด หากพบข้อความยาวหรือองค์ประกอบภายในดันคอลัมน์ให้กว้างเกินไป ให้ตรวจสอบ min-width และพิจารณา min-width: 0 ในรายการที่ควรหดได้ รวมถึงใช้ overflow-wrap: anywhere กับข้อความที่ไม่มีจุดแบ่งบรรทัดเหมาะสม
ระวังการจัดลำดับด้วย CSSการใช้ row-reverse หรือ order เปลี่ยนลำดับที่มองเห็นได้ แต่ไม่ได้เปลี่ยนลำดับใน DOM ควรจัดโครงสร้าง HTML ให้มีลำดับที่สมเหตุสมผลก่อน แล้วใช้ CSS เพื่อปรับ Layout
13. สรุปคุณสมบัติ Flexbox ที่ควรจำ
| คุณสมบัติ | ใช้กับ | หน้าที่ |
|---|---|---|
| display: flex | Container | เปิดใช้งาน Flexbox |
| flex-direction | Container | กำหนดทิศทางแกนหลัก |
| justify-content | Container | จัดแนวตามแกนหลัก |
| align-items | Container | จัดแนวตามแกนตั้งฉาก |
| flex-wrap | Container | อนุญาตให้รายการขึ้นแถวใหม่ |
| gap | Container | กำหนดระยะห่างระหว่างรายการ |
| flex | Flex Item | กำหนดการขยาย การหด และขนาดตั้งต้น |
| align-self | Flex Item | ปรับแนวของรายการแต่ละชิ้น |
14. แบบฝึกหัดท้ายบท
คำถามที่ 1: ต้องการเรียงรายการในแนวนอนควรใช้ค่าใด
คำตอบ: กำหนด display: flex และใช้ flex-direction: row ซึ่งเป็นค่าเริ่มต้นของ Flexbox
คำถามที่ 2: ต้องการจัดรายการให้อยู่กึ่งกลางแกนหลักควรใช้คำสั่งใด
คำตอบ: ใช้ justify-content: center โดยแกนหลักจะขึ้นอยู่กับ flex-direction ที่กำหนดไว้
คำถามที่ 3: ต้องการให้การ์ดขึ้นแถวใหม่เมื่อพื้นที่ไม่พอควรทำอย่างไร
คำตอบ: ใช้ flex-wrap: wrap ร่วมกับการกำหนดขนาดตั้งต้นของการ์ด เช่น flex: 1 1 240px
คำถามที่ 4: gap แตกต่างจาก margin อย่างไร
คำตอบ: gap กำหนดช่องว่างระหว่างรายการใน Container ส่วน margin กำหนดระยะห่างด้านนอกของ element แต่ละตัว รวมถึงอาจใช้สร้างระยะจากองค์ประกอบอื่นได้
คำถามที่ 5: หากต้องการเปลี่ยน Layout จากแนวนอนเป็นแนวตั้งบนมือถือ ควรใช้อะไร
คำตอบ: ใช้ Media Query เช่น @media (max-width: 700px) แล้วกำหนด flex-direction: column ให้ Container ที่ต้องการ
15. ทดลองสร้างหน้าเว็บ Flexbox แบบเต็ม
โค้ดต่อไปนี้เป็นเอกสาร HTML แบบเต็มหน้า สามารถบันทึกเป็น index.html แล้วเปิดด้วยเบราว์เซอร์ได้ทันที ตัวอย่างประกอบด้วย Navigation Bar, Hero Section, การ์ดที่จัดเรียงด้วย Flexbox, แถบข้อมูล และปุ่มทดลองเปลี่ยนการจัดวาง ลองปรับขนาดหน้าต่างเบราว์เซอร์เพื่อดูพฤติกรรม Responsive
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flexbox Layout Studio</title>
<style>
:root {
--primary: #2563eb;
--primary-dark: #1d4ed8;
--accent: #7c3aed;
--text: #172033;
--muted: #64748b;
--page: #f3f6fb;
--surface: #ffffff;
--border: #dbe3ef;
--radius: 18px;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
padding: 24px 16px;
font-family: "Noto Sans Thai", Tahoma, sans-serif;
line-height: 1.7;
color: var(--text);
background: var(--page);
}
.app {
width: min(100%, 1050px);
margin-inline: auto;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 16px;
padding: 16px 20px;
margin-bottom: 24px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
}
.brand {
color: var(--primary);
font-size: 1.2rem;
font-weight: 800;
text-decoration: none;
}
.nav-links {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.nav-links a {
color: #334155;
text-decoration: none;
font-size: 0.95rem;
}
.nav-links a:hover {
color: var(--primary);
}
.hero {
padding: clamp(24px, 5vw, 48px);
margin-bottom: 24px;
color: #ffffff;
background: linear-gradient(135deg, var(--primary), var(--accent));
border-radius: 22px;
}
.hero-label {
margin: 0 0 8px;
color: #dbeafe;
font-size: 0.875rem;
font-weight: 700;
}
.hero h1 {
margin: 0 0 12px;
font-size: clamp(2rem, 5vw, 3rem);
line-height: 1.2;
}
.hero p {
max-width: 680px;
margin: 0 0 22px;
color: #eff6ff;
}
.button {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 44px;
padding: 10px 18px;
border: 2px solid transparent;
border-radius: 10px;
background: #ffffff;
color: var(--primary-dark);
font: inherit;
font-weight: 700;
text-decoration: none;
cursor: pointer;
}
.button:hover {
background: #eff6ff;
}
.button:focus-visible,
a:focus-visible {
outline: 3px solid #93c5fd;
outline-offset: 3px;
}
.section-head {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 16px;
}
.section-head h2 {
margin: 0;
font-size: 1.5rem;
}
.section-head p {
margin: 0;
color: var(--muted);
font-size: 0.9rem;
}
.card-list {
display: flex;
flex-wrap: wrap;
align-items: stretch;
gap: 18px;
}
.card {
flex: 1 1 250px;
min-width: 0;
padding: 22px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
box-shadow: 0 8px 22px rgba(15, 23, 42, 0.04);
}
.card-icon {
display: grid;
place-items: center;
width: 48px;
height: 48px;
margin-bottom: 16px;
border-radius: 14px;
background: #dbeafe;
font-size: 1.4rem;
}
.card h3 {
margin: 0 0 8px;
font-size: 1.15rem;
}
.card p {
margin: 0 0 16px;
color: var(--muted);
font-size: 0.95rem;
}
.card a {
color: var(--primary-dark);
font-weight: 700;
text-decoration: none;
}
.card a:hover {
text-decoration: underline;
}
.toolbar {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
margin-top: 24px;
padding: 18px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
}
.toolbar p {
margin: 0;
color: var(--muted);
}
.toolbar .button {
background: var(--primary);
color: #ffffff;
}
.toolbar .button:hover {
background: var(--primary-dark);
}
.status {
margin-top: 14px;
padding: 14px 16px;
color: #1e40af;
background: #eff6ff;
border-radius: 12px;
}
.footer {
padding: 24px 8px 4px;
color: var(--muted);
text-align: center;
font-size: 0.875rem;
}
@media (max-width: 600px) {
body {
padding: 14px 10px;
}
.navbar {
align-items: flex-start;
flex-direction: column;
}
.nav-links {
gap: 12px;
}
.card-list {
flex-direction: column;
}
.toolbar {
align-items: stretch;
flex-direction: column;
}
.toolbar .button {
width: 100%;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
scroll-behavior: auto !important;
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
}
}
</style>
</head>
<body>
<main class="app" id="home">
<header class="navbar">
<a class="brand" href="#home">FlexStudio</a>
<nav class="nav-links" aria-label="เมนูหลัก">
<a href="#features">คุณสมบัติ</a>
<a href="#practice">ทดลองใช้งาน</a>
<a href="#contact">ติดต่อ</a>
</nav>
</header>
<section class="hero">
<p class="hero-label">CSS FLEXBOX PLAYGROUND</p>
<h1>จัด Layout ให้ยืดหยุ่นด้วย Flexbox</h1>
<p>ฝึกจัดเรียงการ์ด กระจายพื้นที่ และสร้างหน้าเว็บที่ปรับตามขนาดหน้าจอโดยใช้ CSS Flexbox</p>
<a class="button" href="#features">เริ่มสำรวจ</a>
</section>
<section id="features" aria-labelledby="features-title">
<div class="section-head">
<h2 id="features-title">ตัวอย่าง Layout</h2>
<p>การ์ดจะปรับจำนวนคอลัมน์ตามพื้นที่ที่มี</p>
</div>
<div class="card-list" id="cardList">
<article class="card">
<div class="card-icon" aria-hidden="true">📐</div>
<h3>Flexible Layout</h3>
<p>ใช้ flex-grow และ flex-basis เพื่อแบ่งพื้นที่ให้รายการอย่างยืดหยุ่น</p>
<a href="#practice">ดูแนวทาง</a>
</article>
<article class="card">
<div class="card-icon" aria-hidden="true">↔️</div>
<h3>Alignment</h3>
<p>ใช้ justify-content และ align-items เพื่อควบคุมการจัดตำแหน่ง</p>
<a href="#practice">ดูแนวทาง</a>
</article>
<article class="card">
<div class="card-icon" aria-hidden="true">📱</div>
<h3>Responsive Design</h3>
<p>ใช้ flex-wrap และ Media Query เพื่อรองรับหน้าจอหลายขนาด</p>
<a href="#practice">ดูแนวทาง</a>
</article>
</div>
</section>
<section id="practice" class="toolbar">
<div>
<strong>ทดลองเปลี่ยนทิศทางการจัดวาง</strong>
<p>กดปุ่มเพื่อสลับระหว่างแถวและคอลัมน์</p>
</div>
<button class="button" id="toggleLayout" type="button">เปลี่ยนเป็นแนวตั้ง</button>
</section>
<div class="status" id="status" role="status" aria-live="polite">ขณะนี้การ์ดจัดเรียงแบบแถวและสามารถขึ้นบรรทัดใหม่ได้</div>
<footer class="footer" id="contact">FlexStudio · ตัวอย่างสำหรับฝึก CSS Flexbox</footer>
</main>
<script>
const cardList = document.getElementById('cardList');
const toggleLayout = document.getElementById('toggleLayout');
const status = document.getElementById('status');
let vertical = false;
toggleLayout.addEventListener('click', function () {
vertical = !vertical;
if (vertical) {
cardList.style.flexDirection = 'column';
toggleLayout.textContent = 'เปลี่ยนเป็นแนวนอน';
status.textContent = 'ขณะนี้การ์ดจัดเรียงเป็นคอลัมน์ในแนวตั้ง';
} else {
cardList.style.flexDirection = '';
toggleLayout.textContent = 'เปลี่ยนเป็นแนวตั้ง';
status.textContent = 'ขณะนี้การ์ดจัดเรียงแบบแถวและสามารถขึ้นบรรทัดใหม่ได้';
}
});
</script>
</body>
</html>
Reach within 500px of the page end and stay for at least 5 minutes to earn EXP once per day.
⏳ Reading timer is running...