ข้ามไปเนื้อหาหลัก

Category: reference

Responsive Design Patterns — CSS ที่ใช้จริงบน Static Site

Pattern สำหรับ responsive layout บน CSS ล้วนๆ ที่ใช้ได้จริง ครอบคลุม fluid typography, container queries, intrinsic grid และ mobile-first approach

· อ่านประมาณ 2 นาที

สารบัญ

Mobile-First คืออะไร

เขียน CSS สำหรับ mobile ก่อน แล้ว override สำหรับ screen ใหญ่ขึ้นด้วย min-width:

/* base: mobile */
.grid {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* tablet+ */
@media (min-width: 640px) {
  .grid {
    flex-direction: row;
    flex-wrap: wrap;
  }
}

/* desktop+ */
@media (min-width: 1024px) {
  .grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
  }
}

ตรงข้ามกับ desktop-first (เริ่มจาก desktop แล้ว override ด้วย max-width) ซึ่งมักทำให้ mobile code ซับซ้อน

Fluid Typography ด้วย clamp()

ปรับขนาดตัวอักษรตาม viewport อัตโนมัติ โดยไม่ต้องใช้ breakpoint:

h1 {
  /* min: 1.5rem, preferred: 4vw, max: 2.5rem */
  font-size: clamp(1.5rem, 4vw, 2.5rem);
}

.section-title {
  font-size: clamp(1.1rem, 2.5vw, 1.75rem);
}

.section-description {
  font-size: clamp(0.9rem, 1.5vw, 1.1rem);
}

clamp(MIN, PREFERRED, MAX) ทำให้ไม่เล็กเกินหรือใหญ่เกิน

Intrinsic Grid (Auto-fill)

Grid ที่ปรับ columns อัตโนมัติโดยไม่ต้อง media query:

.grid-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1rem;
}

auto-fill + minmax(280px, 1fr) หมายถึง “ใส่ให้มากที่สุดเท่าที่จะได้ โดยแต่ละ column กว้างอย่างน้อย 280px”

เหมาะมากสำหรับ card grid ที่ไม่รู้ว่าจะมีกี่ card

Container Queries (CSS ล่าสุด)

ตอบสนองต่อขนาดของ container ไม่ใช่ viewport — รองรับ browser ทุกตัวที่ modern แล้ว:

.card-wrapper {
  container-type: inline-size;
}

@container (min-width: 400px) {
  .card {
    display: flex;
    flex-direction: row;
  }
}

ต่างจาก media query ที่ดู viewport — container query ดูขนาดของ parent element เหมาะกับ reusable components

Fluid Spacing

.section {
  padding-block: clamp(2rem, 5vw, 4rem);
}

.container {
  width: min(1100px, 100% - 2rem);
  margin-inline: auto;
}

min() เลือกค่าน้อยกว่า — ทำให้ container ไม่กว้างเกิน 1100px และมี padding 1rem ทั้งสองข้างบน mobile

Logical Properties

ใช้ block/inline แทน top/bottom/left/right สำหรับ i18n-ready layout:

/* แทน */
margin-top: 1rem;
margin-bottom: 1rem;
padding-left: 1.5rem;
padding-right: 1.5rem;

/* ใช้ */
margin-block: 1rem;
padding-inline: 1.5rem;

Stack Layout Pattern

เนื้อหาเรียงแนวตั้งที่มีระยะห่างสม่ำเสมอ โดยไม่ต้องแตะ margin บน child elements:

.stack > * + * {
  margin-top: 1.5rem;
}

/* หรือใช้ flex gap */
.stack {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

Aspect Ratio

รักษาสัดส่วนของ element โดยไม่ต้องใช้ padding-top hack:

.hero-image {
  aspect-ratio: 16 / 9;
  width: 100%;
  object-fit: cover;
}

.avatar {
  width: 4rem;
  aspect-ratio: 1;
  border-radius: 50%;
}

Common Breakpoints

/* Mobile-first breakpoints */
/* xs: < 480px — default */
@media (min-width: 480px) { /* sm */ }
@media (min-width: 640px) { /* md */ }
@media (min-width: 768px) { /* lg */ }
@media (min-width: 1024px) { /* xl */ }
@media (min-width: 1280px) { /* 2xl */ }

Tailwind CSS ใช้ breakpoints ชุดนี้ — ถ้าเคยใช้ Tailwind จะคุ้นเคย

Debugging Responsive Issues

/* เปิด outline ทุก element เพื่อดู box model */
* {
  outline: 1px solid red;
}

/* ดู overflow ที่ซ่อนอยู่ */
* {
  overflow-x: hidden;
}

หรือใช้ Chrome DevTools → Toggle device toolbar (Ctrl+Shift+M) เพื่อทดสอบ breakpoints