PlusMagi's Blog By Pitt Phunsanit Technology เจาะลึกเทคนิคการเขียน CSS จำลองเอฟเฟกต์ Glassmorphism

เจาะลึกเทคนิคการเขียน CSS จำลองเอฟเฟกต์ Glassmorphism

เทคนิคการทำ Glassmorphism (เอฟเฟกต์กระจกฝ้าโปร่งแสง) ใน CSS ให้ดูสมจริง มีมิติ และมีประสิทธิภาพสูง ต้องอาศัยการผสมผสานคุณสมบัติหลัก 4 อย่างเข้าด้วยกัน ได้แก่ การเบลอฉากหลัง (Backdrop Blur), ความโปร่งใสของสี (Translucency), แสงสะท้อนขอบ (Specular Edge Highlight), และมิติความลึก (Layered Depth)


โค้ดพื้นฐาน (Core Anatomy)

CSS

.glass-panel {
  /* 1. Backdrop Filter: หัวใจสำคัญของเอฟเฟกต์กระจกฝ้า */
  backdrop-filter: blur(16px) saturate(180%);
  -webkit-backdrop-filter: blur(16px) saturate(180%); /* รองรับ Safari */

  /* 2. Semi-transparent Base: สีพื้นโปร่งแสง */
  background: rgba(255, 255, 255, 0.15);

  /* 3. Rim Lighting: เส้นขอบสะท้อนแสงทิศทางเดียว */
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 16px;

  /* 4. Multi-layered Shadows: เงามืดและแสงฟุ้งรอบตัว */
  box-shadow: 
    0 8px 32px 0 rgba(0, 0, 0, 0.18),
    inset 0 1px 1px 0 rgba(255, 255, 255, 0.3);
}

เทคนิคขั้นสูงเพื่อความสมจริง (Hyper-Realistic Details)


จำลองแสงตกกระทบด้วย Directional Border (Fresnel Effect)

กระจกจริงแสงจะตกกระทบขอบด้านบนมากกว่าขอบด้านล่าง การใช้ border: 1px solid สีเดียวกันทุกด้านจะทำให้ดูแบน การใช้ border-image แบบ Linear Gradient ช่วยจำลองแสงตกกระทบได้ดีขึ้น

CSS

.glass-realistic-border {
  border: 1px solid transparent;
  background-clip: padding-box, border-box;
  background-origin: padding-box, border-box;
  background-image: 
    linear-gradient(to bottom right, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.05)),
    linear-gradient(to bottom right, rgba(255, 255, 255, 0.6), rgba(255, 255, 255, 0.0));
}

เพิ่มความสดของสีฉากหลังด้วย saturate()

เมื่อใช้ blur() พิกเซลสีด้านหลังจะเกลี่ยเข้าหากันจนดูหม่น การใส่ saturate(180%) ควบคู่ไปกับ blur() จะดึงความสดของสีข้างหลังขึ้นมา ทำให้กระจกดูมีชีวิตชีวาแบบเดียวกับ Fluent Design ของ Windows หรือ macOS


ใส่พื้นผิวกระจกขรุขระ (Frosted Noise Texture)

กระจกฝ้าของจริงจะมี Grain เล็กๆ สามารถใช้ SVG Noise เป็น Overlay ช่วยลดปัญหา Color Banding บนหน้าจอทั่วไป

CSS

.glass-textured {
  position: relative;
}

.glass-textured::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)' opacity='0.04'/%3E%3C/svg%3E");
  pointer-events: none;
}

การรองรับ Fallback & Performance


การตรวจสอบเบราว์เซอร์ที่ไม่รองรับ (@supports)

บางสภาพแวดล้อมหรือเบราว์เซอร์รุ่นเก่าอาจไม่รองรับ backdrop-filter ต้องเตรียมสีทึบไว้สำรองเสมอเพื่อให้อ่านเนื้อหาออก

.glass-panel {
  /* Fallback สำหรับเบราว์เซอร์ที่ไม่รองรับ */
  background: rgba(30, 30, 35, 0.85);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .glass-panel {
    background: rgba(255, 255, 255, 0.15);
    backdrop-filter: blur(16px) saturate(180%);
    -webkit-backdrop-filter: blur(16px) saturate(180%);
  }
}

ประสิทธิภาพและการเรนเดอร์ (GPU Rendering)

  • หลีกเลี่ยงการเคลื่อนไหว (Animate) ตัว backdrop-filter โดยตรง
    การทำ Transition ค่า blur() จะบังคับให้ GPU คำนวณเบลอแบบ Real-time ทุกเฟรม ส่งผลให้เฟรมเรตร่วง (Jank) รุนแรง
  • ทางแก้
    ให้ใช้ opacity บน Layer ซ้อน หรือใช้การเคลื่อนไหวเฉพาะ transform แทน
  • แยก Compositing Layer
    หากการ์ดมีแอนิเมชัน ให้ใส่ will-change: transform; เพื่อยกองค์ประกอบขึ้นไปรันบนเลเยอร์ GPU แยกต่างหาก

Accessibility (A11y) & การจัดวาง

  1. Contrast Ratio (เกณฑ์ WCAG 2.2)
    จุดอ่อนที่สุดของ Glassmorphism คือการอ่านข้อความ (Readability) หากฉากหลังเปลี่ยนตำแหน่ง เลื่อนได้ หรือมีรูปภาพที่สว่างสลับมืด ข้อความอาจจมหาย
    • แก้โดยใช้ Text Shadow แบบละเอียด: text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
    • หรือจำกัดสีพื้นหลังของกระจกให้มี Alpha ไม่ต่ำกว่า 0.2 ถึง 0.3
  2. User Preferences (prefers-reduced-transparency)
    รองรับผู้ใช้ที่ตั้งค่าลดความโปร่งแสงในระดับ OS เพื่อความสบายตา

CSS

@media (prefers-reduced-transparency: reduce) {
  .glass-panel {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: #1e1e24; /* ใช้สีทึบเพื่อความชัดเจนสูงสุด */
  }
}