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

Category: reference

CSS @property — Typed Custom Properties

CSS @property ทำให้ custom properties มี type, initial value, และ inheritance control — รองรับ animation ของ color, number, และ gradient

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

สารบัญ

@property คืออะไร

CSS Custom Properties ปกติ (--color: red) เป็น untyped string — browser ไม่รู้ว่าเป็น color หรือ number ทำให้ animate ไม่ได้ @property แก้ปัญหานี้โดยระบุ type ให้ชัดเจน

/* ❌ ปกติ: animate ไม่ได้ */
:root { --hue: 220; }

.element {
  background: hsl(var(--hue), 80%, 60%);
  transition: --hue 0.3s;  /* ไม่ทำงาน */
}

/* ✓ @property: animate ได้ */
@property --hue {
  syntax: '<number>';    /* type */
  inherits: false;       /* ไม่ inherit จาก parent */
  initial-value: 220;    /* ค่าเริ่มต้น (required ถ้า inherits: false) */
}

.element {
  --hue: 220;
  background: hsl(var(--hue), 80%, 60%);
  transition: --hue 0.3s ease;  /* ✓ ทำงานแล้ว */
}
.element:hover { --hue: 280; }

Syntax Types ที่ใช้ได้

@property --color { syntax: '<color>'; inherits: true; initial-value: #000; }
@property --length { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --number { syntax: '<number>'; inherits: false; initial-value: 0; }
@property --percentage { syntax: '<percentage>'; inherits: false; initial-value: 0%; }
@property --length-pct { syntax: '<length-percentage>'; inherits: false; initial-value: 0px; }
@property --angle { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
@property --integer { syntax: '<integer>'; inherits: false; initial-value: 0; }

/* หลาย types (pipe = OR) */
@property --size { syntax: '<length> | <percentage>'; inherits: false; initial-value: 0px; }

/* ค่าเฉพาะ (เหมือน enum) */
@property --theme { syntax: 'light | dark'; inherits: true; initial-value: light; }

/* รับทุก value (ไม่มี type checking) */
@property --any { syntax: '*'; inherits: false; initial-value: 0; }

Animate Gradient

/* ❌ ก่อน @property: transition gradient ไม่ได้ */
.gradient {
  background: linear-gradient(90deg, red, blue);
  transition: background 0.5s;  /* ไม่ smooth */
}

/* ✓ หลัง @property: animate ได้ */
@property --from-color {
  syntax: '<color>';
  inherits: false;
  initial-value: #ef4444;
}
@property --to-color {
  syntax: '<color>';
  inherits: false;
  initial-value: #3b82f6;
}

.gradient {
  background: linear-gradient(90deg, var(--from-color), var(--to-color));
  transition: --from-color 0.5s, --to-color 0.5s;
}

.gradient:hover {
  --from-color: #f59e0b;
  --to-color: #10b981;
}

Progress Bar Animation

@property --progress {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 0%;
}

.progress-bar {
  --progress: 0%;
  background: conic-gradient(#2563eb var(--progress), #e2e8f0 var(--progress));
  border-radius: 50%;
  width: 80px;
  height: 80px;
  transition: --progress 0.6s ease-out;
}

/* set จาก JS */
.progress-bar { --progress: 75%; }

Counter Animation

@property --count {
  syntax: '<integer>';
  inherits: false;
  initial-value: 0;
}

@keyframes count-up {
  from { --count: 0; }
  to   { --count: 1000; }
}

.counter {
  animation: count-up 2s ease-out forwards;
  counter-reset: num var(--count);
}

.counter::after {
  content: counter(num);  /* แสดงค่า --count */
}

Color Theme ด้วย @property

@property --brand-hue {
  syntax: '<number>';
  inherits: true;  /* ✓ inherit ลงมาจาก :root */
  initial-value: 220;
}

:root {
  --brand-hue: 220;
  --brand: hsl(var(--brand-hue) 80% 50%);
  --brand-light: hsl(var(--brand-hue) 80% 95%);
  --brand-dark: hsl(var(--brand-hue) 80% 25%);
}

/* เปลี่ยน theme ทั้งหมดด้วยการเปลี่ยน hue เดียว */
.theme-green { --brand-hue: 142; }
.theme-purple { --brand-hue: 280; }
.theme-red { --brand-hue: 0; }

/* animate theme switching */
:root { transition: --brand-hue 0.4s; }

ใช้งานจาก JavaScript

// อ่านค่า
const el = document.querySelector('.element');
getComputedStyle(el).getPropertyValue('--progress');  // '75%'

// ตั้งค่า
el.style.setProperty('--progress', '75%');

// @property ด้วย CSS.registerProperty() (JavaScript version)
CSS.registerProperty({
  name: '--progress',
  syntax: '<percentage>',
  inherits: false,
  initialValue: '0%',
});

Browser Support

Chrome 85+, Edge 85+, Firefox 128+, Safari 16.4+ — ใช้งาน production ได้แล้ว

/* Progressive enhancement */
@supports (animation-timeline: scroll()) {
  /* ใช้ @property features ขั้นสูง */
}

/* หรือ detect ด้วย JS */
const supported = window.CSS?.registerProperty !== undefined;

เปรียบเทียบกับ CSS Variables ปกติ

CSS Variable ปกติ@property
TypeString (untyped)Typed (<color>, <number>, etc.)
Animation❌ ไม่ได้✓ animate ได้
Initial valueไม่มีต้องระบุ
Inheritตามปกติcontrol ได้ (true/false)
Browser supportทุก browserChrome 85+, Firefox 128+