CSS
Fundamentals
CSS Units
CSS มีหน่วยวัดหลายประเภท — px สำหรับค่าตายตัว, rem สำหรับ typography, em สำหรับ component scaling, % สำหรับ layout, vw/vh สำหรับ viewport และ clamp() สำหรับ fluid design โดยไม่ต้องใช้ media query
CSS Units คืออะไร
ทุกครั้งที่กำหนดขนาด — font-size, width, padding, margin, border — CSS ต้องการ "หน่วย" เพื่อบอกว่าวัดด้วยอะไร หน่วยใน CSS แบ่งเป็นสองกลุ่มหลัก: • Absolute units — ค่าตายตัว ไม่เปลี่ยนตาม context เช่น px, cm, mm • Relative units — ค่าสัมพัทธ์ เปลี่ยนตาม context เช่น %, em, rem, vw, vh การเลือกหน่วยให้ถูกต้องเป็นพื้นฐานของการสร้าง layout ที่ responsive และ accessible
| กลุ่ม | หน่วย | อ้างอิงจาก |
|---|---|---|
| Absolute | px | pixel บนหน้าจอ |
| Absolute | cm, mm, in, pt | ขนาดจริงในโลก (ใช้กับ print) |
| Relative — Font | em | font-size ของ element นั้น (หรือ parent) |
| Relative — Font | rem | font-size ของ root element (<html>) |
| Relative — Viewport | vw | 1% ของความกว้าง viewport |
| Relative — Viewport | vh | 1% ของความสูง viewport |
| Relative — Viewport | svh / dvh / lvh | viewport สำหรับมือถือ (CSS4) |
| Relative — Container | % | ขนาดของ parent element |
| Relative — Container | ch | ความกว้างของตัวอักษร '0' |
| Relative — Container | ex | ความสูง x-height ของ font |
px — Pixel (Absolute)
px คือหน่วยที่ใช้บ่อยที่สุดและคาดเดาผลได้ง่ายที่สุด ค่า 16px จะเป็น 16px เสมอ ไม่ว่า parent จะเป็นอะไร ในหน้าจอ HiDPI (Retina) 1 CSS px อาจแมปกับ 2 หรือ 3 physical pixel แต่ browser จัดการให้อัตโนมัติ เหมาะสำหรับ: border, border-radius, box-shadow, icon size, spacing ที่ต้องการความแม่นยำสูง ไม่ควรใช้กับ: font-size หลัก (กระทบ accessibility เมื่อ user ปรับขนาด font ใน browser)
px เหมาะกับ decorative properties ที่ไม่ควรยืดหยุ่นตาม font ผู้ใช้
/* ✅ ดีสำหรับ border และ spacing ละเอียด */
.card {
border: 1px solid #e5e7eb;
border-radius: 8px;
padding: 16px 24px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
/* ⚠️ ใช้ px กับ font-size ทำให้ user ปรับขนาดใน browser ไม่ได้ */
body {
font-size: 16px; /* ควรใช้ rem แทน */
}% — Percentage (Relative to Parent)
% อ้างอิงจากค่าของ property เดียวกันใน parent element width: 50% — ครึ่งหนึ่งของ width ของ parent padding: 10% — 10% ของ width ของ parent (ทั้ง top/bottom ด้วย!) font-size: 150% — 1.5 เท่าของ font-size ของ parent height: 50% — ครึ่งหนึ่งของ height ของ parent (ต้องการให้ parent มี height กำหนดไว้)
padding-top: 56.25% เป็น trick คลาสสิกสำหรับ fixed aspect ratio
/* layout แบ่งคอลัมน์ */
.container {
width: 100%;
max-width: 1200px;
}
.sidebar {
width: 25%;
float: left;
}
.main {
width: 75%;
float: left;
}
/* padding ตาม viewport width (trick สำหรับ responsive ratio) */
.video-wrapper {
width: 100%;
padding-top: 56.25%; /* 16:9 aspect ratio */
position: relative;
}em — Relative to Current Font Size
em อ้างอิงจาก font-size ของ element นั้นเอง (หรือ parent ถ้าใช้กับ font-size) กฎ: • เมื่อใช้กับ font-size — 1em = font-size ของ parent • เมื่อใช้กับ property อื่น เช่น padding, margin — 1em = font-size ของ element นั้น ปัญหา Compounding: ถ้า parent มี font-size: 1.2em และ child มี font-size: 1.2em ด้วย — child จะได้ 1.44em ของ root (1.2 × 1.2) ซึ่งอาจไม่ได้ตั้งใจ
em เหมาะกับ component-level sizing ที่ต้องการ scale ตาม font
/* em กับ padding — ปรับตาม font-size ของ component นั้น */
.btn-sm {
font-size: 0.875rem;
padding: 0.5em 1em; /* = 0.4375rem 0.875rem */
}
.btn-lg {
font-size: 1.25rem;
padding: 0.5em 1em; /* = 0.625rem 1.25rem */
}
/* padding ปรับตาม font-size อัตโนมัติ — component scale ได้เอง */
/* ⚠️ Compounding problem กับ font-size */
.parent { font-size: 1.2em; } /* 19.2px (ถ้า root = 16px) */
.parent .child { font-size: 1.2em; } /* 23.04px (19.2 × 1.2) */
.parent .child .deep { font-size: 1.2em; } /* 27.648px! */rem — Relative to Root Font Size (แนะนำ)
rem (root em) อ้างอิงจาก font-size ของ <html> element เสมอ — ไม่มีปัญหา compounding เหมือน em default font-size ของ browser คือ 16px ดังนั้น: 1rem = 16px, 1.5rem = 24px, 0.875rem = 14px rem เหมาะที่สุดสำหรับ font-size เพราะ: • ถ้า user ปรับขนาด font ใน browser settings — ทุก rem จะปรับตาม • ไม่มี compounding — 1rem เป็น 16px เสมอ ไม่ว่าจะซ้อนกี่ชั้น • เขียนอ่านง่ายกว่า px
rem เป็นมาตรฐานที่นิยมมากที่สุดสำหรับ typography ปัจจุบัน
/* ✅ ใช้ rem กับ font-size — responsive ต่อ user preference */
html { font-size: 16px; } /* หรือไม่ต้องเขียน เพราะ default อยู่แล้ว */
h1 { font-size: 2rem; } /* 32px */
h2 { font-size: 1.5rem; } /* 24px */
h3 { font-size: 1.25rem; } /* 20px */
p { font-size: 1rem; } /* 16px */
small { font-size: 0.875rem; } /* 14px */
/* ใช้ rem กับ spacing เพื่อให้ layout scale ตาม font ผู้ใช้ */
.section {
padding: 3rem 2rem;
gap: 1.5rem;
}vw และ vh — Viewport Units
vw (viewport width) และ vh (viewport height) อ้างอิงจากขนาดของ browser window 1vw = 1% ของความกว้าง viewport 1vh = 1% ของความสูง viewport 100vw = ความกว้างเต็ม viewport 100vh = ความสูงเต็ม viewport ใช้บ่อยกับ: • Hero section ที่ต้องการเต็มหน้าจอ (height: 100vh) • Full-width element (width: 100vw) • Typography ที่ scale ตามหน้าจอ (font-size: clamp(1rem, 2.5vw, 2rem))
clamp(min, preferred, max) เป็น pattern ที่ทรงพลังสำหรับ fluid typography
/* Hero section เต็มหน้าจอ */
.hero {
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
/* Typography ที่ fluid ตามหน้าจอด้วย clamp() */
h1 {
font-size: clamp(1.75rem, 4vw, 3.5rem);
/* min 1.75rem — fluid 4vw — max 3.5rem */
}
/* ปัญหา 100vh บนมือถือ: address bar ทำให้ viewport เปลี่ยน */
/* ใช้ dvh แทน vh สำหรับ mobile */
.hero-mobile {
height: 100dvh; /* dynamic viewport height */
}vmin, vmax, svh, dvh, lvh
หน่วย viewport เพิ่มเติม: vmin — ค่าที่น้อยกว่าระหว่าง vw กับ vh vmax — ค่าที่มากกว่าระหว่าง vw กับ vh หน่วย viewport ใหม่สำหรับมือถือ (CSS Level 4): svh (small viewport height) — ความสูงเมื่อ browser UI ปรากฏ (เล็กสุด) lvh (large viewport height) — ความสูงเมื่อ browser UI หายไป (ใหญ่สุด) dvh (dynamic viewport height) — ปรับตาม browser UI แบบ real-time ปัญหา 100vh บนมือถือ: address bar ทำให้ viewport กระตุก — ใช้ 100dvh แทน
dvh เป็น best practice ปัจจุบันสำหรับ full-height layout บนมือถือ
/* vmin/vmax */
.square {
width: 50vmin;
height: 50vmin; /* สี่เหลี่ยมจตุรัสที่ fit ทั้ง portrait/landscape */
}
/* แก้ปัญหา 100vh บนมือถือ */
.full-screen {
/* fallback สำหรับ browser เก่า */
height: 100vh;
/* ใช้ dvh เมื่อรองรับ */
height: 100dvh;
}ch และ ex — Character Units
ch อ้างอิงจากความกว้างของตัวอักษร "0" (zero) ใน font ปัจจุบัน ex อ้างอิงจาก x-height ของ font (ความสูงตัวอักษรพิมพ์เล็ก เช่น "x") ch มีประโยชน์มากสำหรับ: • กำหนด max-width ของ text block ให้อ่านสบาย (40–75 ch เป็น optimal line length) • Input ที่มีความกว้างตาม format เช่น input สำหรับ credit card (16 ตัวเลข)
max-width: 65ch เป็นค่านิยมสำหรับ body text ที่อ่านสบาย
/* optimal reading width */
article {
max-width: 65ch; /* ประมาณ 65 ตัวอักษรต่อบรรทัด */
margin: 0 auto;
}
/* input กว้างพอดีกับเนื้อหา */
input[type="tel"] {
width: 12ch; /* ตัวเลข 12 หลัก */
}
input[name="postal-code"] {
width: 6ch; /* รหัสไปรษณีย์ 5 หลัก + buffer */
}เปรียบเทียบการใช้งาน: เลือกหน่วยอะไรดี
| Use Case | หน่วยแนะนำ | เหตุผล |
|---|---|---|
| font-size หลัก | rem | responsive ต่อ user settings ไม่มี compounding |
| font-size component | em หรือ rem | em เมื่อต้องการ scale ตาม parent |
| padding / margin component | em หรือ rem | em ทำให้ component scale ตัวเอง |
| border, border-radius | px | ค่าตายตัว ไม่ควรยืดตาม font |
| box-shadow | px | ค่าตายตัว |
| width layout | % หรือ fr (grid) | fluid ตาม container |
| width ตายตัว | px หรือ rem | ขึ้นกับว่าควร scale ตาม font ไหม |
| max-width บทความ | ch | กำหนดความยาวบรรทัดได้แม่นยำ |
| full-screen section | 100dvh | แก้ปัญหา address bar บนมือถือ |
| fluid typography | clamp() + vw | scale ราบรื่นโดยไม่ต้องใช้ media query |
clamp() — กำหนดขอบเขต min/preferred/max
clamp(min, preferred, max) เป็น CSS function ที่ใช้กับทุกหน่วย ไม่ใช่ unit เอง แต่เกี่ยวข้องโดยตรงกับการใช้ vw ความหมาย: ใช้ค่า preferred แต่ไม่น้อยกว่า min และไม่เกิน max clamp(1rem, 2.5vw, 2rem) หมายถึง: • น้อยสุด 1rem (16px) • ถ้า 2.5vw มากกว่า 1rem — ใช้ 2.5vw • มากสุด 2rem (32px)
clamp() ทำให้ responsive design ไม่ต้องใช้ media query สำหรับ typography
/* fluid font-size ที่ไม่เล็กหรือใหญ่เกินไป */
h1 {
font-size: clamp(1.75rem, 4vw + 1rem, 3.5rem);
}
p {
font-size: clamp(1rem, 1.5vw, 1.25rem);
}
/* fluid padding */
.section {
padding: clamp(2rem, 5vw, 5rem);
}
/* fluid gap */
.grid {
gap: clamp(1rem, 3vw, 2.5rem);
}สรุปท้ายบท
- px — ตายตัว เหมาะ border, shadow, icon ไม่ควรใช้กับ font-size
- % — สัมพัทธ์กับ parent เหมาะ layout width
- em — สัมพัทธ์กับ font-size ปัจจุบัน เหมาะ padding ของ component
- rem — สัมพัทธ์กับ root font-size เหมาะ typography ทั่วทั้งหน้า
- vw / vh — สัมพัทธ์กับ viewport เหมาะ hero section และ fluid typography
- dvh — แก้ปัญหา 100vh บนมือถือ ใช้แทน vh สำหรับ full-height layout
- ch — กำหนด reading width ตาม font เหมาะ max-width บทความ
- clamp(min, val, max) — fluid scaling ไม่ต้องใช้ media query
Lab 1: rem และ em
เป้าหมาย: ฝึกใช้ rem สำหรับ font-size และ em สำหรับ padding ของ component โจทย์: 1. กำหนด font-size ของ h1 เป็น 2rem 2. กำหนด font-size ของ p เป็น 1rem 3. กำหนด padding ของ .btn เป็น 0.5em 1.25em (em — scale ตาม font-size ของปุ่ม)
Lab 2: % และ ch
เป้าหมาย: ฝึกใช้ % สำหรับ layout และ ch สำหรับ reading width โจทย์: 1. กำหนด .sidebar ให้มี width: 30% 2. กำหนด .content ให้มี width: 70% 3. กำหนด .article ให้มี max-width: 65ch เพื่อให้อ่านสบาย
Lab 3: vw/vh และ clamp()
เป้าหมาย: ฝึกใช้ vh สำหรับ full-height section และ clamp() สำหรับ fluid typography โจทย์: 1. กำหนด .hero ให้มี min-height: 100vh 2. กำหนด .hero-title ให้มี font-size: clamp(2rem, 5vw, 4rem)