[{"data":1,"prerenderedAt":1777},["ShallowReactive",2],{"page-\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Fregistered-properties-and-type-safety\u002F":3,"content-all-pages":1514},{"id":4,"title":5,"body":6,"description":1496,"extension":1497,"meta":1498,"navigation":391,"path":1510,"seo":1511,"stem":1512,"__hash__":1513},"content\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Fregistered-properties-and-type-safety\u002Findex.md","Registered Properties and Type Safety: @property as a Contract for Design Tokens",{"type":7,"value":8,"toc":1486},"minimark",[9,13,32,35,38,43,59,71,82,84,88,95,229,231,235,238,334,848,872,889,891,895,901,1030,1037,1076,1078,1082,1088,1355,1380,1382,1386,1397,1399,1403,1413,1419,1429,1442,1444,1448,1482],[10,11,5],"h1",{"id":12},"registered-properties-and-type-safety-property-as-a-contract-for-design-tokens",[14,15,16,17,21,22,25,26,31],"p",{},"A custom property with no registration is a string with a dollar sign's worth of guarantees. Anything can write to it, nothing validates it, and the first time a value is wrong you find out several layers away when a ",[18,19,20],"code",{},"padding"," declaration silently disappears. The ",[18,23,24],{},"@property"," at-rule changes that: it attaches a grammar, an inheritance decision, and a guaranteed fallback to a token name, and the browser enforces all three. This page, part of the ",[27,28,30],"a",{"href":29},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002F","CSS Custom Properties Architecture"," section, treats registration as a type system rather than an animation trick — what the descriptors actually promise, and how those promises change failure behaviour.",[14,33,34],{},"The narrow scenario: a token layer used by many components, where a wrong value written in one theme file must not be able to break an unrelated rule two files away.",[36,37],"hr",{},[39,40,42],"h2",{"id":41},"why-type-a-token-and-when-it-is-overhead","Why type a token, and when it is overhead",[14,44,45,46,49,50,53,54,58],{},"Unregistered custom properties are deliberately permissive. Their declared value is a sequence of tokens the parser accepts almost unconditionally, precisely so that ",[18,47,48],{},"--config: 1px solid red"," and ",[18,51,52],{},"--fragment: 40%, blue"," can exist. That permissiveness is what makes them useful as a general-purpose storage mechanism, and it is also what makes them dangerous as a contract: nothing checks the value until something tries to ",[55,56,57],"em",{},"use"," it, at which point the failure surfaces in the consumer, not the producer.",[14,60,61,62,65,66,70],{},"Registering the property moves validation to the point of assignment. The browser parses each declared value against the declared grammar and rejects mismatches there, keeping the damage local. You also get two guarantees that unregistered properties cannot provide: the property always has a value of the declared type (there is no \"unset variable\" state to defend against), and the value is a ",[55,63,64],{},"computed"," value rather than a raw token stream, which is what makes it interpolatable — the subject of the separate page on ",[27,67,69],{"href":68},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Fanimating-custom-properties-with-at-property\u002F","animating custom properties with @property",".",[14,72,73,74,77,78,81],{},"Registration is overhead when the property genuinely holds an arbitrary fragment — a shorthand you are splicing into a rule, a partial gradient stop list, a media-query-ish string. ",[18,75,76],{},"syntax: \"*\""," exists for that case but buys you almost nothing beyond ",[18,79,80],{},"inherits"," and an initial value. It is also overhead in tiny stylesheets where the token is written once and read once. The value scales with the number of authors who can write to a token, not with the number of tokens.",[36,83],{},[39,85,87],{"id":86},"what-happens-to-an-invalid-value","What happens to an invalid value",[14,89,90,91,94],{},"The diagram traces a declared value through the type check. The important outcome is on the lower branch: a rejected value degrades the ",[55,92,93],{},"token",", and never the declaration that consumed it.",[96,97,103,104,103,108,103,112,103,119,103,131,103,137,103,142,103,150,103,156,103,160,103,164,103,170,103,174,103,180,103,185,103,190,103,194,103,198,103,202,103,207,103,212],"svg",{"viewBox":98,"role":99,"ariaLabel":100,"xmlns":101,"style":102},"0 0 720 360","img","Flow of a declared value through the syntax check of a registered custom property","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;height:auto;max-width:720px;margin:2rem 0","\n  ",[105,106,107],"title",{},"Validation path for a registered custom property",[109,110,111],"desc",{},"A declared value is checked against the syntax descriptor; a matching value is used, and a mismatching value falls back to the guaranteed initial value.",[113,114,118],"text",{"x":115,"y":116,"style":117},"360","30","text-anchor:middle;fill:currentColor;font:700 18px sans-serif","What a registered property does with a bad value",[120,121],"rect",{"x":122,"y":123,"width":124,"height":125,"rx":126,"fill":127,"stroke":128,"strokeWidth":129,"opacity":130},"24","112","180","60","8","none","currentColor","1.5","0.5",[113,132,136],{"x":133,"y":134,"style":135},"114","138","text-anchor:middle;fill:currentColor;font:12px sans-serif","declared value",[113,138,141],{"x":133,"y":139,"style":140},"158","text-anchor:middle;fill:currentColor;font:12px ui-monospace,monospace;opacity:0.85","--pad: red",[143,144],"line",{"x1":145,"y1":146,"x2":147,"y2":146,"stroke":128,"strokeWidth":148,"markerEnd":149},"206","142","228","2","url(#rp-arr)",[120,151],{"x":152,"y":123,"width":153,"height":125,"rx":126,"fill":154,"opacity":155},"232","190","#7aa2ff","0.18",[113,157,159],{"x":158,"y":134,"style":135},"327","type check",[113,161,163],{"x":158,"y":139,"style":162},"text-anchor:middle;fill:currentColor;font:12px ui-monospace,monospace","syntax: \"\u003Clength>\"",[143,165],{"x1":166,"y1":167,"x2":168,"y2":169,"stroke":128,"strokeWidth":148,"markerEnd":149},"424","136","448","94",[143,171],{"x1":166,"y1":172,"x2":168,"y2":173,"stroke":128,"strokeWidth":148,"markerEnd":149},"150","192",[120,175],{"x":176,"y":177,"width":178,"height":179,"rx":126,"fill":127,"stroke":154,"strokeWidth":129},"452","58","244","56",[113,181,184],{"x":182,"y":183,"style":135},"574","82","matches the grammar",[113,186,189],{"x":182,"y":187,"style":188},"102","text-anchor:middle;fill:currentColor;font:11px sans-serif;opacity:0.75","computed value is used",[120,191],{"x":176,"y":192,"width":178,"height":179,"rx":126,"fill":127,"stroke":128,"strokeWidth":129,"opacity":193},"170","0.55",[113,195,197],{"x":182,"y":196,"style":135},"194","does not match",[113,199,201],{"x":182,"y":200,"style":188},"214","falls back to initial-value",[113,203,206],{"x":115,"y":204,"style":205},"290","text-anchor:middle;fill:currentColor;font:12px sans-serif;opacity:0.85","Either way the rule reading the token still produces a usable value.",[113,208,211],{"x":115,"y":209,"style":210},"316","text-anchor:middle;fill:currentColor;font:12px sans-serif;opacity:0.7","Unregistered, the bad token would instead invalidate that rule.",[213,214,215,216,103],"defs",{},"\n    ",[217,218,224,225,215],"marker",{"id":219,"markerWidth":220,"markerHeight":220,"refX":221,"refY":222,"orient":223},"rp-arr","9","7","4","auto","\n      ",[226,227],"path",{"d":228,"fill":128},"M0 0 L8 4 L0 8 z",[36,230],{},[39,232,234],{"id":233},"a-complete-working-implementation-a-typed-token-layer","A complete working implementation: a typed token layer",[14,236,237],{},"The sheet below defines four tokens with four different grammars, including an enumerated one, and a component that consumes them. Every deliberate mistake in the theme block is contained.",[239,240,245],"pre",{"className":241,"code":242,"language":243,"meta":244,"style":244},"language-html shiki shiki-themes github-light-high-contrast github-dark-high-contrast","\u003Carticle class=\"panel\" style=\"--panel-density: cosy\">\n  \u003Ch2 class=\"panel__title\">Deployment\u003C\u002Fh2>\n  \u003Cp class=\"panel__body\">Typed tokens keep a bad override from reaching this rule.\u003C\u002Fp>\n\u003C\u002Farticle>\n","html","",[18,246,247,281,303,324],{"__ignoreMap":244},[248,249,251,255,259,263,266,270,273,275,278],"span",{"class":143,"line":250},1,[248,252,254],{"class":253},"suds8","\u003C",[248,256,258],{"class":257},"sne4z","article",[248,260,262],{"class":261},"s-5SL"," class",[248,264,265],{"class":253},"=",[248,267,269],{"class":268},"sT6z2","\"panel\"",[248,271,272],{"class":261}," style",[248,274,265],{"class":253},[248,276,277],{"class":268},"\"--panel-density: cosy\"",[248,279,280],{"class":253},">\n",[248,282,284,287,289,291,293,296,299,301],{"class":143,"line":283},2,[248,285,286],{"class":253},"  \u003C",[248,288,39],{"class":257},[248,290,262],{"class":261},[248,292,265],{"class":253},[248,294,295],{"class":268},"\"panel__title\"",[248,297,298],{"class":253},">Deployment\u003C\u002F",[248,300,39],{"class":257},[248,302,280],{"class":253},[248,304,306,308,310,312,314,317,320,322],{"class":143,"line":305},3,[248,307,286],{"class":253},[248,309,14],{"class":257},[248,311,262],{"class":261},[248,313,265],{"class":253},[248,315,316],{"class":268},"\"panel__body\"",[248,318,319],{"class":253},">Typed tokens keep a bad override from reaching this rule.\u003C\u002F",[248,321,14],{"class":257},[248,323,280],{"class":253},[248,325,327,330,332],{"class":143,"line":326},4,[248,328,329],{"class":253},"\u003C\u002F",[248,331,258],{"class":257},[248,333,280],{"class":253},[239,335,339],{"className":336,"code":337,"language":338,"meta":244,"style":244},"language-css shiki shiki-themes github-light-high-contrast github-dark-high-contrast","\u002F* A length. Inherits, because spacing scales should cascade to a subtree. *\u002F\n@property --panel-pad {\n  syntax: \"\u003Clength>\";\n  inherits: true;\n  initial-value: 16px;\n}\n\n\u002F* A colour with a safe default that is legible on either theme surface. *\u002F\n@property --panel-accent {\n  syntax: \"\u003Ccolor>\";\n  inherits: true;\n  initial-value: #7aa2ff;\n}\n\n\u002F* An enumerated token: only these three idents are accepted. *\u002F\n@property --panel-density {\n  syntax: \"compact | cosy | roomy\";\n  inherits: false;\n  initial-value: cosy;\n}\n\n\u002F* A two-value list: exactly two lengths, space separated. *\u002F\n@property --panel-offset {\n  syntax: \"\u003Clength>+\";\n  inherits: false;\n  initial-value: 0px 2px;\n}\n\n.panel {\n  padding: var(--panel-pad);\n  border-inline-start: 3px solid var(--panel-accent);\n  box-shadow: var(--panel-offset) 6px rgb(0 0 0 \u002F 0.18);\n  border-radius: 10px;\n}\n\n.panel__title { margin: 0 0 .5rem; font-size: 1.1rem; }\n.panel__body { margin: 0; }\n\n\u002F* Density is an enum, so it can be matched exactly rather than parsed. *\u002F\n@container style(--panel-density: compact) {\n  .panel { --panel-pad: 8px; }\n}\n\n\u002F* A theme file written by someone else. Two of these four are wrong. *\u002F\n.theme-dark {\n  --panel-pad: 24px;      \u002F* valid: used *\u002F\n  --panel-accent: nope;   \u002F* invalid: --panel-accent stays #7aa2ff *\u002F\n  --panel-offset: 0 3px;  \u002F* invalid: 0 is a number here, not a length *\u002F\n  --panel-density: roomy; \u002F* valid: matches the enum *\u002F\n}\n","css",[18,340,341,347,355,366,371,380,386,393,399,407,417,422,436,441,446,452,460,466,472,480,485,490,496,504,514,519,527,532,537,546,567,594,637,652,657,662,702,718,723,729,738,756,761,766,772,780,798,810,831,843],{"__ignoreMap":244},[248,342,343],{"class":143,"line":250},[248,344,346],{"class":345},"sLBg1","\u002F* A length. Inherits, because spacing scales should cascade to a subtree. *\u002F\n",[248,348,349,352],{"class":143,"line":283},[248,350,24],{"class":351},"sHUrx",[248,353,354],{"class":253}," --panel-pad {\n",[248,356,357,360,363],{"class":143,"line":305},[248,358,359],{"class":253},"  syntax: \"\u003Clength",[248,361,362],{"class":351},">",[248,364,365],{"class":253},"\";\n",[248,367,368],{"class":143,"line":326},[248,369,370],{"class":253},"  inherits: true;\n",[248,372,374,377],{"class":143,"line":373},5,[248,375,376],{"class":257},"  initial-value",[248,378,379],{"class":253},": 16px;\n",[248,381,383],{"class":143,"line":382},6,[248,384,385],{"class":253},"}\n",[248,387,389],{"class":143,"line":388},7,[248,390,392],{"emptyLinePlaceholder":391},true,"\n",[248,394,396],{"class":143,"line":395},8,[248,397,398],{"class":345},"\u002F* A colour with a safe default that is legible on either theme surface. *\u002F\n",[248,400,402,404],{"class":143,"line":401},9,[248,403,24],{"class":351},[248,405,406],{"class":253}," --panel-accent {\n",[248,408,410,413,415],{"class":143,"line":409},10,[248,411,412],{"class":253},"  syntax: \"\u003Ccolor",[248,414,362],{"class":351},[248,416,365],{"class":253},[248,418,420],{"class":143,"line":419},11,[248,421,370],{"class":253},[248,423,425,427,430,433],{"class":143,"line":424},12,[248,426,376],{"class":257},[248,428,429],{"class":253},": ",[248,431,154],{"class":432},"sh5d0",[248,434,435],{"class":253},";\n",[248,437,439],{"class":143,"line":438},13,[248,440,385],{"class":253},[248,442,444],{"class":143,"line":443},14,[248,445,392],{"emptyLinePlaceholder":391},[248,447,449],{"class":143,"line":448},15,[248,450,451],{"class":345},"\u002F* An enumerated token: only these three idents are accepted. *\u002F\n",[248,453,455,457],{"class":143,"line":454},16,[248,456,24],{"class":351},[248,458,459],{"class":253}," --panel-density {\n",[248,461,463],{"class":143,"line":462},17,[248,464,465],{"class":253},"  syntax: \"compact | cosy | roomy\";\n",[248,467,469],{"class":143,"line":468},18,[248,470,471],{"class":253},"  inherits: false;\n",[248,473,475,477],{"class":143,"line":474},19,[248,476,376],{"class":257},[248,478,479],{"class":253},": cosy;\n",[248,481,483],{"class":143,"line":482},20,[248,484,385],{"class":253},[248,486,488],{"class":143,"line":487},21,[248,489,392],{"emptyLinePlaceholder":391},[248,491,493],{"class":143,"line":492},22,[248,494,495],{"class":345},"\u002F* A two-value list: exactly two lengths, space separated. *\u002F\n",[248,497,499,501],{"class":143,"line":498},23,[248,500,24],{"class":351},[248,502,503],{"class":253}," --panel-offset {\n",[248,505,507,509,512],{"class":143,"line":506},24,[248,508,359],{"class":253},[248,510,511],{"class":351},">+",[248,513,365],{"class":253},[248,515,517],{"class":143,"line":516},25,[248,518,471],{"class":253},[248,520,522,524],{"class":143,"line":521},26,[248,523,376],{"class":257},[248,525,526],{"class":253},": 0px 2px;\n",[248,528,530],{"class":143,"line":529},27,[248,531,385],{"class":253},[248,533,535],{"class":143,"line":534},28,[248,536,392],{"emptyLinePlaceholder":391},[248,538,540,543],{"class":143,"line":539},29,[248,541,542],{"class":261},".panel",[248,544,545],{"class":253}," {\n",[248,547,549,552,554,557,560,564],{"class":143,"line":548},30,[248,550,551],{"class":261},"  padding",[248,553,429],{"class":253},[248,555,556],{"class":261},"var",[248,558,559],{"class":253},"(",[248,561,563],{"class":562},"soyes","--panel-pad",[248,565,566],{"class":253},");\n",[248,568,570,573,575,578,581,584,587,589,592],{"class":143,"line":569},31,[248,571,572],{"class":261},"  border-inline-start",[248,574,429],{"class":253},[248,576,577],{"class":261},"3",[248,579,580],{"class":351},"px",[248,582,583],{"class":261}," solid",[248,585,586],{"class":261}," var",[248,588,559],{"class":253},[248,590,591],{"class":562},"--panel-accent",[248,593,566],{"class":253},[248,595,597,600,602,604,606,609,612,615,617,620,622,625,628,630,633,635],{"class":143,"line":596},32,[248,598,599],{"class":261},"  box-shadow",[248,601,429],{"class":253},[248,603,556],{"class":261},[248,605,559],{"class":253},[248,607,608],{"class":562},"--panel-offset",[248,610,611],{"class":253},") ",[248,613,614],{"class":261},"6",[248,616,580],{"class":351},[248,618,619],{"class":261}," rgb",[248,621,559],{"class":253},[248,623,624],{"class":261},"0",[248,626,627],{"class":261}," 0",[248,629,627],{"class":261},[248,631,632],{"class":253}," \u002F ",[248,634,155],{"class":261},[248,636,566],{"class":253},[248,638,640,643,645,648,650],{"class":143,"line":639},33,[248,641,642],{"class":261},"  border-radius",[248,644,429],{"class":253},[248,646,647],{"class":261},"10",[248,649,580],{"class":351},[248,651,435],{"class":253},[248,653,655],{"class":143,"line":654},34,[248,656,385],{"class":253},[248,658,660],{"class":143,"line":659},35,[248,661,392],{"emptyLinePlaceholder":391},[248,663,665,668,671,674,676,678,680,683,686,689,692,694,697,699],{"class":143,"line":664},36,[248,666,667],{"class":261},".panel__title",[248,669,670],{"class":253}," { ",[248,672,673],{"class":261},"margin",[248,675,429],{"class":253},[248,677,624],{"class":261},[248,679,627],{"class":261},[248,681,682],{"class":261}," .5",[248,684,685],{"class":351},"rem",[248,687,688],{"class":253},"; ",[248,690,691],{"class":261},"font-size",[248,693,429],{"class":253},[248,695,696],{"class":261},"1.1",[248,698,685],{"class":351},[248,700,701],{"class":253},"; }\n",[248,703,705,708,710,712,714,716],{"class":143,"line":704},37,[248,706,707],{"class":261},".panel__body",[248,709,670],{"class":253},[248,711,673],{"class":261},[248,713,429],{"class":253},[248,715,624],{"class":261},[248,717,701],{"class":253},[248,719,721],{"class":143,"line":720},38,[248,722,392],{"emptyLinePlaceholder":391},[248,724,726],{"class":143,"line":725},39,[248,727,728],{"class":345},"\u002F* Density is an enum, so it can be matched exactly rather than parsed. *\u002F\n",[248,730,732,735],{"class":143,"line":731},40,[248,733,734],{"class":351},"@container",[248,736,737],{"class":253}," style(--panel-density: compact) {\n",[248,739,741,744,746,748,750,752,754],{"class":143,"line":740},41,[248,742,743],{"class":261},"  .panel",[248,745,670],{"class":253},[248,747,563],{"class":562},[248,749,429],{"class":253},[248,751,126],{"class":261},[248,753,580],{"class":351},[248,755,701],{"class":253},[248,757,759],{"class":143,"line":758},42,[248,760,385],{"class":253},[248,762,764],{"class":143,"line":763},43,[248,765,392],{"emptyLinePlaceholder":391},[248,767,769],{"class":143,"line":768},44,[248,770,771],{"class":345},"\u002F* A theme file written by someone else. Two of these four are wrong. *\u002F\n",[248,773,775,778],{"class":143,"line":774},45,[248,776,777],{"class":261},".theme-dark",[248,779,545],{"class":253},[248,781,783,786,788,790,792,795],{"class":143,"line":782},46,[248,784,785],{"class":562},"  --panel-pad",[248,787,429],{"class":253},[248,789,122],{"class":261},[248,791,580],{"class":351},[248,793,794],{"class":253},";      ",[248,796,797],{"class":345},"\u002F* valid: used *\u002F\n",[248,799,801,804,807],{"class":143,"line":800},47,[248,802,803],{"class":562},"  --panel-accent",[248,805,806],{"class":253},": nope;   ",[248,808,809],{"class":345},"\u002F* invalid: --panel-accent stays #7aa2ff *\u002F\n",[248,811,813,816,818,820,823,825,828],{"class":143,"line":812},48,[248,814,815],{"class":562},"  --panel-offset",[248,817,429],{"class":253},[248,819,624],{"class":261},[248,821,822],{"class":261}," 3",[248,824,580],{"class":351},[248,826,827],{"class":253},";  ",[248,829,830],{"class":345},"\u002F* invalid: 0 is a number here, not a length *\u002F\n",[248,832,834,837,840],{"class":143,"line":833},49,[248,835,836],{"class":562},"  --panel-density",[248,838,839],{"class":253},": roomy; ",[248,841,842],{"class":345},"\u002F* valid: matches the enum *\u002F\n",[248,844,846],{"class":143,"line":845},50,[248,847,385],{"class":253},[14,849,850,851,853,854,857,858,860,861,864,865,868,869,871],{},"Two of those overrides are rejected, and nothing else changes. ",[18,852,591],{}," keeps its registered initial value, so ",[18,855,856],{},"border-inline-start"," still resolves to a real colour instead of dropping out; ",[18,859,608],{}," keeps ",[18,862,863],{},"0px 2px",", so the ",[18,866,867],{},"box-shadow"," shorthand still parses. Delete all four ",[18,870,24],{}," blocks and the same theme file produces a panel with no left border and no shadow at all, because the invalid tokens propagate into those shorthands and invalidate them wholesale.",[14,873,874,875,877,878,880,881,884,885,888],{},"The ",[18,876,608],{}," case is the one that catches people: ",[18,879,624],{}," is a valid length in most CSS contexts, but ",[18,882,883],{},"\u003Clength>"," in a syntax string does not accept a bare zero — write ",[18,886,887],{},"0px",". Registration turns that inconsistency into a caught error rather than a mysterious missing shadow.",[36,890],{},[39,892,894],{"id":893},"the-key-technique-the-syntax-grammar-is-a-small-type-language","The key technique: the syntax grammar is a small type language",[14,896,897,900],{},[18,898,899],{},"syntax"," is not limited to a single type name. It is a restricted grammar with four constructs, and knowing them is what makes registration expressive enough to describe real tokens:",[902,903,904,920],"table",{},[905,906,907],"thead",{},[908,909,910,914,917],"tr",{},[911,912,913],"th",{},"Construct",[911,915,916],{},"Written as",[911,918,919],{},"Accepts",[921,922,923,978,991,1004,1017],"tbody",{},[908,924,925,929,934],{},[926,927,928],"td",{},"Data type",[926,930,931],{},[18,932,933],{},"\"\u003Clength>\"",[926,935,936,937,940,941,940,944,940,947,940,950,940,953,940,956,940,959,940,962,940,965,940,968,940,971,940,974,977],{},"one value of that type (",[18,938,939],{},"\u003Ccolor>",", ",[18,942,943],{},"\u003Cnumber>",[18,945,946],{},"\u003Cpercentage>",[18,948,949],{},"\u003Cangle>",[18,951,952],{},"\u003Ctime>",[18,954,955],{},"\u003Cimage>",[18,957,958],{},"\u003Clength-percentage>",[18,960,961],{},"\u003Cinteger>",[18,963,964],{},"\u003Cresolution>",[18,966,967],{},"\u003Ctransform-function>",[18,969,970],{},"\u003Ccustom-ident>",[18,972,973],{},"\u003Cstring>",[18,975,976],{},"\u003Curl>",")",[908,979,980,983,988],{},[926,981,982],{},"Alternation",[926,984,985],{},[18,986,987],{},"\"\u003Clength> | auto\"",[926,989,990],{},"either branch; also used for literal idents",[908,992,993,996,1001],{},[926,994,995],{},"Space list",[926,997,998],{},[18,999,1000],{},"\"\u003Clength>+\"",[926,1002,1003],{},"one or more values separated by spaces",[908,1005,1006,1009,1014],{},[926,1007,1008],{},"Comma list",[926,1010,1011],{},[18,1012,1013],{},"\"\u003Ccolor>#\"",[926,1015,1016],{},"one or more values separated by commas",[908,1018,1019,1022,1027],{},[926,1020,1021],{},"Universal",[926,1023,1024],{},[18,1025,1026],{},"\"*\"",[926,1028,1029],{},"any token sequence, with no type checking and no interpolation",[14,1031,1032,1033,1036],{},"Literal idents are written bare, which is how the enumerated ",[18,1034,1035],{},"--panel-density"," above works. Alternation is greedy in source order, so put the more specific branch first when two could both match.",[14,1038,1039,1040,1042,1043,940,1045,1047,1048,1051,1052,1054,1055,1058,1059,1062,1063,1065,1066,1069,1070,1072,1073,1075],{},"The other two descriptors are equally load-bearing and both are mandatory — a ",[18,1041,24],{}," rule missing ",[18,1044,899],{},[18,1046,80],{},", or ",[18,1049,1050],{},"initial-value"," is dropped entirely, and its absence is silent. ",[18,1053,80],{}," decides how the token behaves when it is not set on the element: ",[18,1056,1057],{},"true"," walks up to the parent's computed value, ",[18,1060,1061],{},"false"," uses the initial value. Choose it by asking whether a nested instance of the component should pick up the outer instance's value; for state-like tokens the answer is almost always no. ",[18,1064,1050],{}," must itself parse against the grammar, and it is the guarantee that the token is never in an unresolvable state — the reason a consuming declaration can rely on it without a ",[18,1067,1068],{},"var()"," fallback argument. The single exception to the requirement is ",[18,1071,76],{},", where ",[18,1074,1050],{}," may be omitted; the property then behaves like an unregistered one that happens to have a fixed inheritance setting.",[36,1077],{},[39,1079,1081],{"id":1080},"variation-typing-tokens-that-feed-motion","Variation: typing tokens that feed motion",[14,1083,1084,1085,1087],{},"Registration composes with the tokens that drive timing, because a ",[18,1086,952],{}," grammar rejects the classic mistake of writing a unitless duration.",[239,1089,1091],{"className":336,"code":1090,"language":338,"meta":244,"style":244},"@property --speed {\n  syntax: \"\u003Ctime>\";\n  inherits: true;\n  initial-value: 200ms;\n}\n@property --ease {\n  \u002F* An enum of names, resolved to real curves below. *\u002F\n  syntax: \"linear | standard | decelerate\";\n  inherits: true;\n  initial-value: standard;\n}\n\n:root { --speed: 240ms; --ease: decelerate; }\n\n.card {\n  transition: transform var(--speed) var(--curve, cubic-bezier(.2, .8, .2, 1));\n}\n\n\u002F* Map the enum to a curve. Style queries read the typed ident directly. *\u002F\n@container style(--ease: decelerate) { .card { --curve: cubic-bezier(0, .6, .3, 1); } }\n@container style(--ease: linear)     { .card { --curve: linear; } }\n\n@media (prefers-reduced-motion: reduce) {\n  :root { --speed: 1ms; }\n}\n",[18,1092,1093,1100,1112,1116,1123,1127,1134,1139,1144,1148,1155,1159,1163,1189,1193,1200,1250,1254,1258,1263,1301,1322,1326,1334,1351],{"__ignoreMap":244},[248,1094,1095,1097],{"class":143,"line":250},[248,1096,24],{"class":351},[248,1098,1099],{"class":253}," --speed {\n",[248,1101,1102,1105,1108,1110],{"class":143,"line":283},[248,1103,1104],{"class":253},"  syntax: \"\u003C",[248,1106,1107],{"class":257},"time",[248,1109,362],{"class":351},[248,1111,365],{"class":253},[248,1113,1114],{"class":143,"line":305},[248,1115,370],{"class":253},[248,1117,1118,1120],{"class":143,"line":326},[248,1119,376],{"class":257},[248,1121,1122],{"class":253},": 200ms;\n",[248,1124,1125],{"class":143,"line":373},[248,1126,385],{"class":253},[248,1128,1129,1131],{"class":143,"line":382},[248,1130,24],{"class":351},[248,1132,1133],{"class":253}," --ease {\n",[248,1135,1136],{"class":143,"line":388},[248,1137,1138],{"class":345},"  \u002F* An enum of names, resolved to real curves below. *\u002F\n",[248,1140,1141],{"class":143,"line":395},[248,1142,1143],{"class":253},"  syntax: \"linear | standard | decelerate\";\n",[248,1145,1146],{"class":143,"line":401},[248,1147,370],{"class":253},[248,1149,1150,1152],{"class":143,"line":409},[248,1151,376],{"class":257},[248,1153,1154],{"class":253},": standard;\n",[248,1156,1157],{"class":143,"line":419},[248,1158,385],{"class":253},[248,1160,1161],{"class":143,"line":424},[248,1162,392],{"emptyLinePlaceholder":391},[248,1164,1165,1168,1170,1173,1175,1178,1181,1183,1186],{"class":143,"line":438},[248,1166,1167],{"class":261},":root",[248,1169,670],{"class":253},[248,1171,1172],{"class":562},"--speed",[248,1174,429],{"class":253},[248,1176,1177],{"class":261},"240",[248,1179,1180],{"class":351},"ms",[248,1182,688],{"class":253},[248,1184,1185],{"class":562},"--ease",[248,1187,1188],{"class":253},": decelerate; }\n",[248,1190,1191],{"class":143,"line":443},[248,1192,392],{"emptyLinePlaceholder":391},[248,1194,1195,1198],{"class":143,"line":448},[248,1196,1197],{"class":261},".card",[248,1199,545],{"class":253},[248,1201,1202,1205,1208,1210,1212,1214,1216,1218,1220,1223,1225,1228,1230,1233,1235,1238,1240,1242,1244,1247],{"class":143,"line":454},[248,1203,1204],{"class":261},"  transition",[248,1206,1207],{"class":253},": transform ",[248,1209,556],{"class":261},[248,1211,559],{"class":253},[248,1213,1172],{"class":562},[248,1215,611],{"class":253},[248,1217,556],{"class":261},[248,1219,559],{"class":253},[248,1221,1222],{"class":562},"--curve",[248,1224,940],{"class":253},[248,1226,1227],{"class":261},"cubic-bezier",[248,1229,559],{"class":253},[248,1231,1232],{"class":261},".2",[248,1234,940],{"class":253},[248,1236,1237],{"class":261},".8",[248,1239,940],{"class":253},[248,1241,1232],{"class":261},[248,1243,940],{"class":253},[248,1245,1246],{"class":261},"1",[248,1248,1249],{"class":253},"));\n",[248,1251,1252],{"class":143,"line":462},[248,1253,385],{"class":253},[248,1255,1256],{"class":143,"line":468},[248,1257,392],{"emptyLinePlaceholder":391},[248,1259,1260],{"class":143,"line":474},[248,1261,1262],{"class":345},"\u002F* Map the enum to a curve. Style queries read the typed ident directly. *\u002F\n",[248,1264,1265,1267,1270,1272,1274,1276,1278,1280,1282,1284,1286,1289,1291,1294,1296,1298],{"class":143,"line":482},[248,1266,734],{"class":351},[248,1268,1269],{"class":253}," style(--ease: decelerate) { ",[248,1271,1197],{"class":261},[248,1273,670],{"class":253},[248,1275,1222],{"class":562},[248,1277,429],{"class":253},[248,1279,1227],{"class":261},[248,1281,559],{"class":253},[248,1283,624],{"class":261},[248,1285,940],{"class":253},[248,1287,1288],{"class":261},".6",[248,1290,940],{"class":253},[248,1292,1293],{"class":261},".3",[248,1295,940],{"class":253},[248,1297,1246],{"class":261},[248,1299,1300],{"class":253},"); } }\n",[248,1302,1303,1305,1308,1310,1312,1314,1316,1319],{"class":143,"line":487},[248,1304,734],{"class":351},[248,1306,1307],{"class":253}," style(--ease: linear)     { ",[248,1309,1197],{"class":261},[248,1311,670],{"class":253},[248,1313,1222],{"class":562},[248,1315,429],{"class":253},[248,1317,1318],{"class":261},"linear",[248,1320,1321],{"class":253},"; } }\n",[248,1323,1324],{"class":143,"line":492},[248,1325,392],{"emptyLinePlaceholder":391},[248,1327,1328,1331],{"class":143,"line":498},[248,1329,1330],{"class":351},"@media",[248,1332,1333],{"class":253}," (prefers-reduced-motion: reduce) {\n",[248,1335,1336,1339,1341,1343,1345,1347,1349],{"class":143,"line":506},[248,1337,1338],{"class":261},"  :root",[248,1340,670],{"class":253},[248,1342,1172],{"class":562},[248,1344,429],{"class":253},[248,1346,1246],{"class":261},[248,1348,1180],{"class":351},[248,1350,701],{"class":253},[248,1352,1353],{"class":143,"line":516},[248,1354,385],{"class":253},[14,1356,1357,1358,1361,1362,1365,1366,1369,1370,1374,1375,1379],{},"A stray ",[18,1359,1360],{},"--speed: 240"," anywhere in the codebase now resolves to the registered ",[18,1363,1364],{},"200ms"," instead of producing an unparseable ",[18,1367,1368],{},"transition"," shorthand. The pattern pairs directly with ",[27,1371,1373],{"href":1372},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Ffluid-spacing-tokens-driving-transition-durations\u002F","fluid spacing tokens driving transition durations"," and with ",[27,1376,1378],{"href":1377},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state\u002Fstyle-queries-with-custom-properties\u002F","style queries on custom properties",", which are considerably more reliable when the queried token has an enumerated grammar.",[36,1381],{},[39,1383,1385],{"id":1384},"browser-support-note","Browser support note",[14,1387,1388,1390,1391,1393,1394,1396],{},[18,1389,24],{}," is supported in Chrome and Edge 85+, Safari 16.4+, and Firefox 128+, so the registration itself is safe to rely on across evergreen browsers as of mid-2026. The important thing about the fallback path is that it is not a cliff: in an engine without support the at-rule is ignored and every token reverts to unregistered behaviour, which means the values still apply and the components still render — you lose type checking and the guaranteed initial value, not the design. If a specific token's default genuinely must exist everywhere, back it up by writing the same value into a ",[18,1392,1167],{}," declaration and reading it with a ",[18,1395,1068],{}," fallback argument; that costs one line and covers both worlds.",[36,1398],{},[39,1400,1402],{"id":1401},"faq","FAQ",[14,1404,1405,1409,1410,1412],{},[1406,1407,1408],"strong",{},"What happens when a registered property is given a value of the wrong type?","\nThe value is invalid at computed-value time for that custom property alone. A non-inheriting registered property then computes to its ",[18,1411,1050],{}," and an inheriting one takes the parent's computed value, so the declaration that consumed the token still resolves to something usable.",[14,1414,1415,1418],{},[1406,1416,1417],{},"How is that different from an unregistered custom property?","\nAn unregistered property accepts almost any token sequence, so the mistake travels untouched into the consuming declaration and invalidates that instead. You lose the entire property that read the variable rather than just the bad token.",[14,1420,1421,1424,1425,1428],{},[1406,1422,1423],{},"Can a syntax descriptor accept more than one type?","\nYes. A syntax string supports alternation with the pipe character, space-separated and comma-separated lists with the plus and hash multipliers, and literal keyword idents. The universal syntax ",[18,1426,1427],{},"*"," accepts anything but gives up both type checking and interpolation.",[14,1430,1431,1434,1435,1438,1439,1441],{},[1406,1432,1433],{},"Should inherits be true or false for a design token?","\nSet ",[18,1436,1437],{},"inherits: true"," for theme-wide tokens a whole subtree should pick up, such as colours and spacing scales. Set it to ",[18,1440,1061],{}," for component-local or state-like values, so a nested instance cannot silently inherit its parent's state.",[36,1443],{},[39,1445,1447],{"id":1446},"related","Related",[1449,1450,1451,1457,1463,1469,1475],"ul",{},[1452,1453,1454,1456],"li",{},[27,1455,30],{"href":29}," — the parent guide on token layers and theming structure.",[1452,1458,1459,1462],{},[27,1460,1461],{"href":68},"Animating custom properties with @property"," — what registration unlocks for interpolation specifically.",[1452,1464,1465,1468],{},[27,1466,1467],{"href":1372},"Fluid spacing tokens driving transition durations"," — typed time and length tokens feeding motion.",[1452,1470,1471,1474],{},[27,1472,1473],{"href":1377},"Style queries with custom properties"," — query the enumerated tokens defined here.",[1452,1476,1477,1481],{},[27,1478,1480],{"href":1479},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-for-reset-and-tokens\u002F","Cascade layers for reset and tokens"," — where registered tokens belong in the layer order.",[1483,1484,1485],"style",{},"html pre.shiki code .suds8, html code.shiki .suds8{--shiki-default:#0E1116;--shiki-dark:#F0F3F6}html pre.shiki code .sne4z, html code.shiki .sne4z{--shiki-default:#024C1A;--shiki-dark:#72F088}html pre.shiki code .s-5SL, html code.shiki .s-5SL{--shiki-default:#023B95;--shiki-dark:#91CBFF}html pre.shiki code .sT6z2, html code.shiki .sT6z2{--shiki-default:#032563;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sLBg1, html code.shiki .sLBg1{--shiki-default:#66707B;--shiki-dark:#BDC4CC}html pre.shiki code .sHUrx, html code.shiki .sHUrx{--shiki-default:#A0111F;--shiki-dark:#FF9492}html pre.shiki code .sh5d0, html code.shiki .sh5d0{--shiki-default:#6E011A;--shiki-default-font-style:italic;--shiki-dark:#FFB1AF;--shiki-dark-font-style:italic}html pre.shiki code .soyes, html code.shiki .soyes{--shiki-default:#702C00;--shiki-dark:#FFB757}",{"title":244,"searchDepth":283,"depth":283,"links":1487},[1488,1489,1490,1491,1492,1493,1494,1495],{"id":41,"depth":283,"text":42},{"id":86,"depth":283,"text":87},{"id":233,"depth":283,"text":234},{"id":893,"depth":283,"text":894},{"id":1080,"depth":283,"text":1081},{"id":1384,"depth":283,"text":1385},{"id":1401,"depth":283,"text":1402},{"id":1446,"depth":283,"text":1447},"Use @property as a type system for design tokens: syntax grammars, inherits, initial values, and why a bad value falls back instead of breaking a rule.","md",{"pageTitle":1499,"datePublished":1500,"dateModified":1500,"faq":1501},"Registered properties and type safety","2026-07-20",[1502,1504,1506,1508],{"q":1408,"a":1503},"The value is invalid at computed-value time for that custom property only. A non-inheriting registered property computes to its initial-value and an inheriting one takes the parent's computed value, so the rule that consumed it keeps working.",{"q":1417,"a":1505},"An unregistered property accepts almost any token, so the mistake travels into the consuming declaration and invalidates that instead. You lose the whole property that used the variable rather than just the bad token.",{"q":1423,"a":1507},"Yes. A syntax string supports alternation with the pipe character, space-separated and comma-separated lists with plus and hash multipliers, and literal keyword idents. The universal syntax asterisk accepts anything but gives up type checking.",{"q":1433,"a":1509},"Set inherits to true for theme-wide tokens that a whole subtree should pick up, such as colours and spacing scales. Set it to false for component-local values so a nested instance cannot silently inherit its parent's state.","\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Fregistered-properties-and-type-safety",{"title":5,"description":1496},"css-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Fregistered-properties-and-type-safety\u002Findex","jasLqZ1YRlFBDDnWlbJo2r05UzwUdCqchYrF8HVMqNU",[1515,1518,1521,1524,1527,1530,1533,1536,1539,1542,1545,1548,1551,1554,1557,1560,1563,1564,1567,1570,1573,1576,1579,1582,1585,1588,1591,1594,1597,1600,1603,1606,1609,1612,1615,1618,1621,1624,1627,1630,1633,1636,1639,1642,1645,1648,1651,1654,1657,1660,1663,1666,1669,1672,1675,1678,1681,1684,1687,1690,1693,1696,1699,1702,1705,1708,1711,1714,1717,1720,1723,1726,1729,1732,1735,1738,1741,1744,1747,1750,1753,1756,1759,1762,1765,1768,1771,1774],{"path":1516,"title":1517},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fcreating-accessible-focus-indicators","Creating Accessible Focus Indicators: Building a Ring That Survives Any Background",{"path":1519,"title":1520},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations","Accessibility in CSS Animations: Patterns, Specs & Best Practices",{"path":1522,"title":1523},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fprefers-reduced-motion-recipes","prefers-reduced-motion Recipes: A Reduction for Every Common Effect",{"path":1525,"title":1526},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Freducing-motion-preferences-in-css","Reducing Motion Preferences in CSS: How the Setting Becomes a Media Feature",{"path":1528,"title":1529},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Ftarget-size-and-pointer-accessibility","Target Size and Pointer Accessibility: Meeting 2.5.8 Without Redesigning",{"path":1531,"title":1532},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fvestibular-safe-animation-patterns","Vestibular-Safe Animation Patterns: Why Some Motion Makes People Sick",{"path":1534,"title":1535},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fwcag-motion-success-criteria","WCAG Motion Success Criteria: What Each One Actually Requires",{"path":1537,"title":1538},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fcontainer-query-hover-affordances","Container Query Hover Affordances: When Narrow Means Persistent, Not Hidden",{"path":1540,"title":1541},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion","Container-Aware Motion: Animation Sized by the Space a Component Actually Has",{"path":1543,"title":1544},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fmotion-that-scales-with-container-size","Motion That Scales with Container Size: cqi, cqb, and Derived Durations",{"path":1546,"title":1547},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fsuppressing-motion-in-small-containers","Suppressing Motion in Small Containers: Deliberately Animating Nothing",{"path":1549,"title":1550},"\u002Fcss-only-micro-interactions-animations\u002Fcss-animation-vs-web-animations-api","CSS Animation vs the Web Animations API: A Decision Guide",{"path":1552,"title":1553},"\u002Fcss-only-micro-interactions-animations\u002Fcss-animation-vs-web-animations-api\u002Fwhen-to-use-javascript-animation","When to Use JavaScript Instead of CSS for Animation",{"path":1555,"title":1556},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Fanimating-custom-properties-with-at-property","Animating Custom Properties with @property: Typed Variables That Interpolate",{"path":1558,"title":1559},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Ffluid-spacing-tokens-driving-transition-durations","Fluid Spacing Tokens That Drive Transition Durations",{"path":1561,"title":1562},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture","CSS Custom Properties Architecture: Scalable Design Systems & Dynamic UI",{"path":1510,"title":5},{"path":1565,"title":1566},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fcss-transition-timing-functions","CSS Transition Timing Functions: ease, cubic-bezier(), steps() and linear()",{"path":1568,"title":1569},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals","CSS Transition Fundamentals: Architecture, Performance & Patterns",{"path":1571,"title":1572},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fstarting-style-entry-animations","@starting-style: Animating an Element's Very First Style Change",{"path":1574,"title":1575},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Ftransitioning-display-with-allow-discrete","Transitioning display with transition-behavior: allow-discrete and @starting-style",{"path":1577,"title":1578},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Faccessible-css-only-tooltips","Accessible CSS-Only Tooltips and Hover Cards With  and ",{"path":1580,"title":1581},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Ffocus-visible-vs-focus-polyfill-alternatives"," vs :focus: Why It Replaced the Focus-Ring Polyfill",{"path":1583,"title":1584},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Ffocus-within-form-patterns"," Form Patterns: Styling a Group From the Field Inside It",{"path":1586,"title":1587},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design","Hover & Focus State Design: Spec-Compliant Patterns for Modern UIs",{"path":1589,"title":1590},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Fpointer-and-hover-media-queries","Pointer and Hover Media Queries: Gating Affordances by Input Capability",{"path":1592,"title":1593},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Fsmooth-hover-effects-without-javascript","Smooth Hover Effects Without JavaScript: CSS-Only Patterns for Modern UI",{"path":1595,"title":1596},"\u002Fcss-only-micro-interactions-animations","CSS-Only Micro-Interactions & Animations: Architecture, Performance & Implementation",{"path":1598,"title":1599},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcontainer-query-triggered-keyframe-animations","Container-Query-Triggered Keyframe Animations: Animate Differently per Available Space",{"path":1601,"title":1602},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcss-only-accordions-and-disclosure","CSS-Only Accordions and Disclosure Widgets with details and summary",{"path":1604,"title":1605},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcss-only-loading-spinners-and-skeletons","CSS-Only Loading Spinners and Skeleton Shimmer Screens with @keyframes",{"path":1607,"title":1608},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcss-only-toggle-switches-and-checkboxes","CSS-Only Toggle Switches and Checkboxes That Keep the Native Input",{"path":1610,"title":1611},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns","Keyframe Animation Patterns: Spec-Compliant Architectures for Modern UIs",{"path":1613,"title":1614},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fstaggered-list-animations-with-custom-properties","Staggered List Animations Using --i Index Custom Properties",{"path":1616,"title":1617},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration","Performance & GPU Acceleration in CSS: A Developer’s Blueprint",{"path":1619,"title":1620},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Foptimizing-css-animations-for-60fps","Optimizing CSS Animations for 60fps: Budgeting the Frame",{"path":1622,"title":1623},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fprofiling-animations-in-devtools","Profiling CSS Animations in DevTools: Finding the Frame That Costs Too Much",{"path":1625,"title":1626},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fwill-change-and-the-compositor-thread","will-change and the Compositor Thread: Layer Promotion Without the Footguns",{"path":1628,"title":1629},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations","Scroll-Driven Animations: Binding Motion to Scroll Position in Pure CSS",{"path":1631,"title":1632},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-driven-animation-fallbacks","Shipping Scroll-Driven Animations Without Breaking Anything",{"path":1634,"title":1635},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-progress-bar-without-javascript","A Reading Progress Bar Driven by scroll(root)",{"path":1637,"title":1638},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-triggered-reveal-animations","Reveal-on-Scroll with view() and animation-range",{"path":1640,"title":1641},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers","View Transitions for CSS Developers: the Pseudo-Element Tree, Snapshots, and Named Elements",{"path":1643,"title":1644},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fsame-document-view-transitions","Writing a Same-Document View Transition: the CSS You Actually Author",{"path":1646,"title":1647},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fview-transition-names-shared-elements","view-transition-name and Shared Elements: Morphing a Thumbnail into a Hero",{"path":1649,"title":1650},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fview-transitions-with-reduced-motion","Honouring prefers-reduced-motion in View Transitions",{"path":1652,"title":1653},"\u002F","Modern CSS Layouts & Micro-Interactions",{"path":1655,"title":1656},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioned-tooltips","Anchor-Positioned Tooltips: Tethering, Flipping, and Getting the Semantics Right",{"path":1658,"title":1659},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioning-fallbacks","Anchor Positioning Fallbacks: A Graceful Floor for Older Browser Versions",{"path":1661,"title":1662},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays","CSS Anchor Positioning and Overlays: Tethering Elements Without JavaScript",{"path":1664,"title":1665},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fpopover-attribute-and-css-styling","The popover Attribute: Top-Layer Overlays With No JavaScript",{"path":1667,"title":1668},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Ffeature-detection-with-supports","Feature Detection with @supports: Syntax, Semantics, and the Traps",{"path":1670,"title":1671},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Fhandling-container-query-fallbacks-for-older-browsers","Handling Container Query Fallbacks for Older Browsers",{"path":1673,"title":1674},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks","Container Query Fallbacks: Spec-Compliant CSS Strategies for Legacy Browsers",{"path":1676,"title":1677},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-query-units-cqi-cqb-explained","Container Query Units Explained: cqi, cqb, cqw, cqh, cqmin and cqmax",{"path":1679,"title":1680},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-type-size-vs-inline-size","Choosing container-type: inline-size, size, or normal",{"path":1682,"title":1683},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-vs-media-queries-comparison","Container vs Media Queries: Choosing the Right Reference Box",{"path":1685,"title":1686},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fhow-to-use-container-queries-in-production","How to Use Container Queries in Production Without a Rewrite",{"path":1688,"title":1689},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics","Container Query Syntax Basics",{"path":1691,"title":1692},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fnesting-and-naming-container-queries","Nesting and Naming Container Queries: Targeting the Right Ancestor",{"path":1694,"title":1695},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fauto-fit-minmax-responsive-grids","Responsive Grids with repeat(auto-fit, minmax())",{"path":1697,"title":1698},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fbuilding-a-dashboard-with-subgrid","Building a Responsive Dashboard Where Cards Align with Subgrid",{"path":1700,"title":1701},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fholy-grail-layout-with-grid","The Holy-Grail Layout with CSS Grid and Container Queries",{"path":1703,"title":1704},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts","CSS Grid and Subgrid Layouts for Responsive Interfaces",{"path":1706,"title":1707},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fsubgrid-vs-nested-grid","Subgrid vs an Independently Nested Grid",{"path":1709,"title":1710},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Fclamp-vs-media-query-typography","clamp() Fluid Type vs Media-Query Step Typography: Tradeoffs and Anatomy",{"path":1712,"title":1713},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-space-scale-with-clamp","Building a Fluid Spacing Scale with clamp() and Container Units",{"path":1715,"title":1716},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-type-accessibility-and-zoom","Fluid Type, Accessibility and Zoom: The vw-Only Trap",{"path":1718,"title":1719},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-typography-without-javascript","Fluid Typography Without JavaScript: A Precision CSS Reference",{"path":1721,"title":1722},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp","Fluid Typography with clamp(): A Practical Guide for Modern CSS",{"path":1724,"title":1725},"\u002Fmastering-container-queries-responsive-layouts","Mastering Container Queries & Responsive Layouts",{"path":1727,"title":1728},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Faspect-ratio-for-responsive-media","Using aspect-ratio for Responsive Media and Preventing Layout Shift",{"path":1730,"title":1731},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques","Intrinsic Sizing Techniques: Modern CSS Layouts for Responsive UI",{"path":1733,"title":1734},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fmin-max-fit-content-explained","min-content, max-content, and fit-content() Explained",{"path":1736,"title":1737},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fpreventing-flex-and-grid-overflow","The min-width: auto Trap in Flex and Grid Layouts",{"path":1739,"title":1740},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-for-reset-and-tokens","Cascade Layers for Reset and Design Tokens",{"path":1742,"title":1743},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-vs-specificity-hacks","Cascade Layers vs Specificity Hacks: Ordering Instead of Escalating",{"path":1745,"title":1746},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies","Modern CSS Reset Strategies: A Spec-Compliant Foundation",{"path":1748,"title":1749},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fbuilding-responsive-cards-with-container-queries","Building Responsive Cards with Container Queries: A Production-Ready Guide",{"path":1751,"title":1752},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fcontainer-query-data-tables","Container Query Data Tables: Reflowing Tables to Cards",{"path":1754,"title":1755},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fcontainer-query-sidebar-layouts","Container Query Sidebar Layouts That Travel Between Contexts",{"path":1757,"title":1758},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns","Responsive Component Patterns: Architecture & Implementation",{"path":1760,"title":1761},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-forms-with-container-queries","Responsive Forms with Container Queries: Reflow Without Losing the Wiring",{"path":1763,"title":1764},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-navigation-without-media-queries","Responsive Navigation Without Media Queries Using Container Queries",{"path":1766,"title":1767},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state\u002Fcontainer-style-query-theming","Container Style Query Theming: One Token Instead of a Variant Class Matrix",{"path":1769,"title":1770},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state","Style Queries and Container State: Token-Driven Component Variants",{"path":1772,"title":1773},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state\u002Fstyle-queries-with-custom-properties","Style Queries With Custom Properties: Declaring, Inheriting, and Matching Tokens",{"path":1775,"title":1776},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state\u002Fstyle-query-fallbacks-and-support","Style Query Fallbacks and Support: Designing for Older Browser Versions",1784566156606]