[{"data":1,"prerenderedAt":1711},["ShallowReactive",2],{"page-\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fwcag-motion-success-criteria\u002F":3,"content-all-pages":1448},{"id":4,"title":5,"body":6,"description":1429,"extension":1430,"meta":1431,"navigation":820,"path":1444,"seo":1445,"stem":1446,"__hash__":1447},"content\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fwcag-motion-success-criteria\u002Findex.md","WCAG Motion Success Criteria: What Each One Actually Requires",{"type":7,"value":8,"toc":1415},"minimark",[9,13,23,29,57,62,70,90,231,234,238,253,256,278,282,285,292,314,318,324,345,355,358,362,366,369,383,385,389,392,604,1250,1255,1267,1271,1274,1311,1324,1328,1341,1345,1351,1357,1366,1372,1376,1411],[10,11,5],"h1",{"id":12},"wcag-motion-success-criteria-what-each-one-actually-requires",[14,15,16,17,22],"p",{},"Accessibility reviews of animated interfaces tend to produce vague findings — \"too much motion\", \"add reduced motion support\" — because the reviewer and the CSS author are not working from the same list. There is a specific, short list. Four WCAG 2.2 success criteria govern motion and moving content, they sit at three different conformance levels, and only some of them can be satisfied in CSS at all. This page enumerates them precisely, states what each one requires, and names the corresponding obligation for the person writing the stylesheet. It belongs to ",[18,19,21],"a",{"href":20},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002F","Accessibility in CSS Animations",", which covers the techniques; this page covers the rules those techniques exist to meet.",[14,24,25],{},[26,27,28],"strong",{},"The four criteria, at a glance:",[30,31,32,39,45,51],"ul",{},[33,34,35,38],"li",{},[26,36,37],{},"2.2.2 Pause, Stop, Hide"," — Level A — anything moving or auto-updating for more than five seconds",[33,40,41,44],{},[26,42,43],{},"2.3.1 Three Flashes or Below Threshold"," — Level A — flashing content and seizure risk",[33,46,47,50],{},[26,48,49],{},"1.4.13 Content on Hover or Focus"," — Level AA — tooltips, popovers, dropdowns",[33,52,53,56],{},[26,54,55],{},"2.3.3 Animation from Interactions"," — Level AAA — motion triggered by user action",[58,59,61],"h2",{"id":60},"why-the-level-matters-before-the-technique","Why the level matters before the technique",[14,63,64,65,69],{},"If you are targeting Level AA — the near-universal contractual and regulatory baseline — then three of these four are binding on you: both Level A criteria are inherited by AA conformance, plus 1.4.13 itself. Only 2.3.3 is AAA, which means a strictly AA-conformant product can legally ship an interface that animates heavily on interaction with no way to turn it off. That is a bad product, and honouring ",[66,67,68],"code",{},"prefers-reduced-motion"," remains the right default, but it is important not to tell a team that a AAA criterion is a failure against their AA target. Overstating requirements erodes trust in the ones that genuinely bind.",[14,71,72,73,76,77,81,82,85,86,89],{},"The second thing to establish early: ",[26,74,75],{},"CSS cannot satisfy 2.2.2 by itself in the general case."," The criterion demands a ",[78,79,80],"em",{},"mechanism"," the user can operate. A CSS-only mechanism is possible for a narrow class of components — a checkbox or a ",[66,83,84],{},":hover"," region can toggle ",[66,87,88],{},"animation-play-state"," — but a mechanism that survives page navigation, applies to a video element, or persists as a preference needs script. The other three criteria are much closer to pure styling concerns. The diagram maps each criterion to its level and to what CSS is actually on the hook for.",[91,92,98,99,98,103,98,107,98,114,98,126,98,132,98,137,98,143,98,149,98,154,98,159,98,162,98,166,98,170,98,172,98,175,98,177,98,180,98,183,98,187,98,191,98,194,98,198,98,200,98,203,98,206,98,210,98,214,98,217,98,221,98,223,98,226],"svg",{"viewBox":93,"role":94,"ariaLabel":95,"xmlns":96,"style":97},"0 0 720 350","img","Four WCAG motion criteria mapped to conformance level and CSS obligation","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;height:auto;max-width:720px;margin:2rem 0","\n  ",[100,101,102],"title",{},"Motion success criteria, level, and CSS obligation",[104,105,106],"desc",{},"Four rows pair a WCAG success criterion with its conformance level and the corresponding stylesheet responsibility.",[108,109,113],"text",{"x":110,"y":111,"style":112},"360","26","text-anchor:middle;fill:currentColor;font:700 17px sans-serif","Criterion, level, and what CSS owes it",[115,116],"rect",{"x":117,"y":118,"width":119,"height":120,"rx":121,"fill":122,"stroke":123,"strokeWidth":124,"opacity":125},"20","48","250","56","8","none","currentColor","1.5","0.6",[108,127,131],{"x":128,"y":129,"style":130},"145","70","text-anchor:middle;fill:currentColor;font:600 13px sans-serif","2.2.2",[108,133,136],{"x":128,"y":134,"style":135},"90","text-anchor:middle;fill:currentColor;font:12px sans-serif;opacity:0.85","Pause, Stop, Hide",[115,138],{"x":139,"y":118,"width":140,"height":120,"rx":121,"fill":141,"opacity":142},"290","60","#7aa2ff","0.3",[108,144,148],{"x":145,"y":146,"style":147},"320","82","text-anchor:middle;fill:currentColor;font:600 14px sans-serif","A",[115,150],{"x":151,"y":118,"width":152,"height":120,"rx":121,"fill":122,"stroke":123,"strokeWidth":124,"opacity":153},"370","330","0.45",[108,155,158],{"x":156,"y":146,"style":157},"535","text-anchor:middle;fill:currentColor;font:12px sans-serif","CSS alone is not enough: ship a control",[115,160],{"x":117,"y":161,"width":119,"height":120,"rx":121,"fill":122,"stroke":123,"strokeWidth":124,"opacity":125},"116",[108,163,165],{"x":128,"y":164,"style":130},"138","2.3.1",[108,167,169],{"x":128,"y":168,"style":135},"158","Three Flashes \u002F Threshold",[115,171],{"x":139,"y":161,"width":140,"height":120,"rx":121,"fill":141,"opacity":142},[108,173,148],{"x":145,"y":174,"style":147},"150",[115,176],{"x":151,"y":161,"width":152,"height":120,"rx":121,"fill":122,"stroke":123,"strokeWidth":124,"opacity":153},[108,178,179],{"x":156,"y":174,"style":157},"keep keyframe flashes under 3 per second",[115,181],{"x":117,"y":182,"width":119,"height":120,"rx":121,"fill":122,"stroke":123,"strokeWidth":124,"opacity":125},"184",[108,184,186],{"x":128,"y":185,"style":130},"206","1.4.13",[108,188,190],{"x":128,"y":189,"style":135},"226","Content on Hover or Focus",[115,192],{"x":139,"y":182,"width":140,"height":120,"rx":121,"fill":141,"opacity":193},"0.22",[108,195,197],{"x":145,"y":196,"style":147},"218","AA",[115,199],{"x":151,"y":182,"width":152,"height":120,"rx":121,"fill":122,"stroke":123,"strokeWidth":124,"opacity":153},[108,201,202],{"x":156,"y":196,"style":157},"dismissable, hoverable, persistent",[115,204],{"x":117,"y":205,"width":119,"height":120,"rx":121,"fill":122,"stroke":123,"strokeWidth":124,"opacity":125},"252",[108,207,209],{"x":128,"y":208,"style":130},"274","2.3.3",[108,211,213],{"x":128,"y":212,"style":135},"294","Animation from Interactions",[115,215],{"x":139,"y":205,"width":140,"height":120,"rx":121,"fill":141,"opacity":216},"0.12",[108,218,220],{"x":145,"y":219,"style":147},"286","AAA",[115,222],{"x":151,"y":205,"width":152,"height":120,"rx":121,"fill":122,"stroke":123,"strokeWidth":124,"opacity":153},[108,224,225],{"x":156,"y":219,"style":157},"a reduced-motion path for every effect",[108,227,230],{"x":110,"y":228,"style":229},"334","text-anchor:middle;fill:currentColor;font:12px sans-serif;opacity:0.7","Level A and AA are inherited by an AA conformance target; AAA is not.",[232,233],"hr",{},[58,235,237],{"id":236},"_222-pause-stop-hide-level-a","2.2.2 Pause, Stop, Hide — Level A",[14,239,240,241,244,245,248,249,252],{},"The criterion covers two things. For ",[26,242,243],{},"moving, blinking or scrolling"," information that starts automatically, lasts more than five seconds, and is presented in parallel with other content, the user must have a way to pause, stop, or hide it. For ",[26,246,247],{},"auto-updating"," information that starts automatically and is presented in parallel with other content, the user must have a way to pause, stop, or hide it ",[78,250,251],{},"or"," to control its update frequency.",[14,254,255],{},"Three qualifiers do real work. \"Starts automatically\" excludes anything the user initiated. \"More than five seconds\" excludes a two-second entrance animation or a short spinner that resolves. \"In parallel with other content\" excludes a full-screen loading state where the animation is the only thing on the page — there is nothing for it to distract from. An exception also covers movement that is essential to the activity, such as a progress indicator whose whole purpose is to report ongoing work.",[14,257,258,261,262,265,266,269,270,273,274,277],{},[26,259,260],{},"The CSS obligation."," Anything with ",[66,263,264],{},"animation-iteration-count: infinite"," that shares the viewport with readable content is a candidate failure. Your obligation is to make sure a mechanism exists and that your stylesheet respects it, typically by exposing ",[66,267,268],{},"animation-play-state: paused"," through a state hook rather than hard-coding ",[66,271,272],{},"running",". Write the animation so it ",[78,275,276],{},"can"," be paused; the control itself is a component-level responsibility, and for video, GIFs and script-driven counters it will not be CSS.",[58,279,281],{"id":280},"_231-three-flashes-or-below-threshold-level-a","2.3.1 Three Flashes or Below Threshold — Level A",[14,283,284],{},"Web pages must not contain anything that flashes more than three times in any one second period, unless the flashing is below the general flash and red flash thresholds. This is a seizure-safety criterion, not a comfort one, and it is the only motion criterion where the failure mode is medical harm.",[14,286,287,288,291],{},"A flash is a pair of opposing changes in relative luminance, where the changes occupy more than 25 percent of a 10-degree field of view. Saturated red transitions are treated separately and more strictly. Note the Level AAA sibling, ",[26,289,290],{},"2.3.2 Three Flashes",", which removes the threshold escape hatch entirely: at AAA, nothing may flash more than three times per second regardless of area or luminance.",[14,293,294,296,297,300,301,304,305,308,309,313],{},[26,295,260],{}," Audit any keyframe set that alternates high-contrast values — an attention-getting ",[66,298,299],{},"background-color"," blink, a strobing ",[66,302,303],{},"opacity",", a rapid ",[66,306,307],{},"filter: invert()",". The practical rule is to keep any full-cycle alternation at or above roughly 333ms per cycle, and to prefer small, low-contrast, or spatially limited effects over large full-bleed ones. A pulsing dot 12 pixels wide cannot cross the 25 percent field-of-view threshold; a page-wide background flash easily can. The material in ",[18,310,312],{"href":311},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fvestibular-safe-animation-patterns\u002F","Vestibular-Safe Animation Patterns"," covers the adjacent category of motion that triggers nausea rather than seizures — different mechanism, different guidance.",[58,315,317],{"id":316},"_1413-content-on-hover-or-focus-level-aa","1.4.13 Content on Hover or Focus — Level AA",[14,319,320,321,323],{},"When additional content becomes visible on pointer hover or keyboard focus and then hidden again, three conditions must hold unless the content is a user-agent-rendered feature such as a native ",[66,322,100],{}," tooltip:",[325,326,327,333,339],"ol",{},[33,328,329,332],{},[26,330,331],{},"Dismissable"," — the user can dismiss the additional content without moving pointer hover or keyboard focus, and without the content itself disappearing on its own. The standard mechanism is the Escape key.",[33,334,335,338],{},[26,336,337],{},"Hoverable"," — if pointer hover can trigger the content, the pointer can be moved over the additional content without it disappearing.",[33,340,341,344],{},[26,342,343],{},"Persistent"," — the content stays visible until hover or focus is removed, the user dismisses it, or its information is no longer valid.",[14,346,347,349,350,354],{},[26,348,260],{}," Hoverable and Persistent are almost entirely CSS problems, and both are commonly failed by the same mistake: positioning the panel with a visual gap between the trigger and the panel, so the pointer crosses dead space and the panel vanishes mid-journey. Keep the panel's box adjacent to or overlapping the trigger, use transparent padding to bridge any visual offset, and include the panel itself in the reveal condition. Dismissable requires a key handler, so it is the one condition CSS cannot own. The tooltip patterns in ",[18,351,353],{"href":352},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Faccessible-css-only-tooltips\u002F","Accessible CSS-Only Tooltips"," show the markup side of this.",[14,356,357],{},"Hover the term below, then move the pointer down onto the panel — it stays put, which is the Hoverable condition demonstrated.",[359,360],"live-demo",{"name":361},"a11ym-hover-content-persistent",[58,363,365],{"id":364},"_233-animation-from-interactions-level-aaa","2.3.3 Animation from Interactions — Level AAA",[14,367,368],{},"Motion animation triggered by interaction can be disabled, unless the animation is essential to the functionality or the information being conveyed. \"Motion animation\" here means movement — translation, scaling, rotation, parallax — not a colour change, an opacity fade, or a change in an element's own appearance without displacement. A cross-fade between two views is explicitly not motion animation for this purpose.",[14,370,371,373,374,377,378,382],{},[26,372,260],{}," Provide a path where movement-bearing effects resolve to no displacement. Honouring ",[66,375,376],{},"prefers-reduced-motion: reduce"," is the accepted technique, and the syntax and cascade behaviour are covered in ",[18,379,381],{"href":380},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Freducing-motion-preferences-in-css\u002F","Reducing Motion Preferences in CSS",". Be careful with the word \"disabled\": the criterion is satisfied by a mechanism the user controls, and the operating-system preference counts as one. It does not require an in-page toggle, though for a heavily animated product one is worth building anyway.",[232,384],{},[58,386,388],{"id":387},"a-stylesheet-shaped-by-all-four","A stylesheet shaped by all four",[14,390,391],{},"The following is one component — an auto-scrolling announcement strip with a hover panel — written so that each rule traces back to a criterion. It is CSS-only, and the comments mark exactly where the criteria stop being satisfiable in a stylesheet.",[393,394,399],"pre",{"className":395,"code":396,"language":397,"meta":398,"style":398},"language-html shiki shiki-themes github-light-high-contrast github-dark-high-contrast","\u003Cdiv class=\"strip\">\n  \u003Cinput class=\"strip__toggle\" type=\"checkbox\" id=\"pause-strip\">\n  \u003Clabel class=\"strip__label\" for=\"pause-strip\">Pause announcements\u003C\u002Flabel>\n  \u003Cdiv class=\"strip__viewport\">\n    \u003Cp class=\"strip__track\">Maintenance window Saturday 02:00 UTC — status page updated hourly\u003C\u002Fp>\n  \u003C\u002Fdiv>\n  \u003Cspan class=\"alert\" tabindex=\"0\">Why am I seeing this?\n    \u003Cspan class=\"alert__panel\">This strip appears while a maintenance window is scheduled.\u003C\u002Fspan>\n  \u003C\u002Fspan>\n\u003C\u002Fdiv>\n","html","",[66,400,401,428,462,491,507,529,539,564,585,594],{"__ignoreMap":398},[402,403,406,410,414,418,421,425],"span",{"class":404,"line":405},"line",1,[402,407,409],{"class":408},"suds8","\u003C",[402,411,413],{"class":412},"sne4z","div",[402,415,417],{"class":416},"s-5SL"," class",[402,419,420],{"class":408},"=",[402,422,424],{"class":423},"sT6z2","\"strip\"",[402,426,427],{"class":408},">\n",[402,429,431,434,437,439,441,444,447,449,452,455,457,460],{"class":404,"line":430},2,[402,432,433],{"class":408},"  \u003C",[402,435,436],{"class":412},"input",[402,438,417],{"class":416},[402,440,420],{"class":408},[402,442,443],{"class":423},"\"strip__toggle\"",[402,445,446],{"class":416}," type",[402,448,420],{"class":408},[402,450,451],{"class":423},"\"checkbox\"",[402,453,454],{"class":416}," id",[402,456,420],{"class":408},[402,458,459],{"class":423},"\"pause-strip\"",[402,461,427],{"class":408},[402,463,465,467,470,472,474,477,480,482,484,487,489],{"class":404,"line":464},3,[402,466,433],{"class":408},[402,468,469],{"class":412},"label",[402,471,417],{"class":416},[402,473,420],{"class":408},[402,475,476],{"class":423},"\"strip__label\"",[402,478,479],{"class":416}," for",[402,481,420],{"class":408},[402,483,459],{"class":423},[402,485,486],{"class":408},">Pause announcements\u003C\u002F",[402,488,469],{"class":412},[402,490,427],{"class":408},[402,492,494,496,498,500,502,505],{"class":404,"line":493},4,[402,495,433],{"class":408},[402,497,413],{"class":412},[402,499,417],{"class":416},[402,501,420],{"class":408},[402,503,504],{"class":423},"\"strip__viewport\"",[402,506,427],{"class":408},[402,508,510,513,515,517,519,522,525,527],{"class":404,"line":509},5,[402,511,512],{"class":408},"    \u003C",[402,514,14],{"class":412},[402,516,417],{"class":416},[402,518,420],{"class":408},[402,520,521],{"class":423},"\"strip__track\"",[402,523,524],{"class":408},">Maintenance window Saturday 02:00 UTC — status page updated hourly\u003C\u002F",[402,526,14],{"class":412},[402,528,427],{"class":408},[402,530,532,535,537],{"class":404,"line":531},6,[402,533,534],{"class":408},"  \u003C\u002F",[402,536,413],{"class":412},[402,538,427],{"class":408},[402,540,542,544,546,548,550,553,556,558,561],{"class":404,"line":541},7,[402,543,433],{"class":408},[402,545,402],{"class":412},[402,547,417],{"class":416},[402,549,420],{"class":408},[402,551,552],{"class":423},"\"alert\"",[402,554,555],{"class":416}," tabindex",[402,557,420],{"class":408},[402,559,560],{"class":423},"\"0\"",[402,562,563],{"class":408},">Why am I seeing this?\n",[402,565,567,569,571,573,575,578,581,583],{"class":404,"line":566},8,[402,568,512],{"class":408},[402,570,402],{"class":412},[402,572,417],{"class":416},[402,574,420],{"class":408},[402,576,577],{"class":423},"\"alert__panel\"",[402,579,580],{"class":408},">This strip appears while a maintenance window is scheduled.\u003C\u002F",[402,582,402],{"class":412},[402,584,427],{"class":408},[402,586,588,590,592],{"class":404,"line":587},9,[402,589,534],{"class":408},[402,591,402],{"class":412},[402,593,427],{"class":408},[402,595,597,600,602],{"class":404,"line":596},10,[402,598,599],{"class":408},"\u003C\u002F",[402,601,413],{"class":412},[402,603,427],{"class":408},[393,605,609],{"className":606,"code":607,"language":608,"meta":398,"style":398},"language-css shiki shiki-themes github-light-high-contrast github-dark-high-contrast","\u002F* --- 2.2.2 -----------------------------------------------------------\n   The marquee runs longer than five seconds beside readable content, so a\n   mechanism is mandatory. The checkbox IS that mechanism; the stylesheet's\n   job is to make the animation pausable rather than to hard-code it. *\u002F\n.strip__viewport { overflow: hidden; }\n.strip__track {\n  margin: 0;\n  white-space: nowrap;\n  animation: strip-scroll 22s linear infinite;\n}\n.strip__toggle:checked ~ .strip__viewport .strip__track {\n  animation-play-state: paused;   \u002F* pause, not remove: position is kept *\u002F\n}\n@keyframes strip-scroll {\n  from { translate: 100% 0; }\n  to   { translate: -100% 0; }\n}\n\n\u002F* --- 2.3.1 -----------------------------------------------------------\n   An attention pulse on the label. One full cycle takes 2s, so the pair of\n   opposing luminance changes occurs well under three times per second, and\n   the change is confined to a small element rather than a full-bleed area. *\u002F\n.strip__label {\n  animation: strip-pulse 2s ease-in-out infinite;\n}\n@keyframes strip-pulse {\n  0%, 100% { background-color: #ffe9a8; }\n  50%      { background-color: #fff6d6; }\n}\n\n\u002F* --- 1.4.13 ----------------------------------------------------------\n   Hoverable: the panel is flush against the trigger (top: 100%, no gap), so\n   the pointer never crosses dead space. Persistent: the panel's own :hover\n   is part of the reveal condition, so it survives the pointer landing on it.\n   Dismissable still needs an Escape-key handler in script. *\u002F\n.alert { position: relative; }\n.alert__panel {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  width: 16rem;\n  padding: 0.6rem;\n  background: #ffffff;\n  border: 1px solid #94a3b8;\n  visibility: hidden;\n}\n.alert:hover .alert__panel,\n.alert:focus-visible .alert__panel,\n.alert__panel:hover {\n  visibility: visible;\n}\n\n\u002F* --- 2.3.3 -----------------------------------------------------------\n   The scroll is displacement, so it goes. The pulse is a colour change with\n   no displacement and is not motion animation under this criterion, but the\n   marquee stops moving and the text is shown statically instead. *\u002F\n@media (prefers-reduced-motion: reduce) {\n  .strip__track {\n    animation: none;\n    white-space: normal;    \u002F* let the full text wrap and be read at rest *\u002F\n  }\n}\n","css",[66,610,611,617,622,627,632,652,660,673,685,708,713,730,747,752,764,788,810,815,822,828,834,840,846,854,874,879,889,912,930,935,940,946,952,958,964,970,988,996,1009,1023,1035,1051,1065,1078,1100,1112,1117,1129,1139,1147,1159,1164,1169,1175,1181,1187,1193,1202,1210,1222,1239,1245],{"__ignoreMap":398},[402,612,613],{"class":404,"line":405},[402,614,616],{"class":615},"sLBg1","\u002F* --- 2.2.2 -----------------------------------------------------------\n",[402,618,619],{"class":404,"line":430},[402,620,621],{"class":615},"   The marquee runs longer than five seconds beside readable content, so a\n",[402,623,624],{"class":404,"line":464},[402,625,626],{"class":615},"   mechanism is mandatory. The checkbox IS that mechanism; the stylesheet's\n",[402,628,629],{"class":404,"line":493},[402,630,631],{"class":615},"   job is to make the animation pausable rather than to hard-code it. *\u002F\n",[402,633,634,637,640,643,646,649],{"class":404,"line":509},[402,635,636],{"class":416},".strip__viewport",[402,638,639],{"class":408}," { ",[402,641,642],{"class":416},"overflow",[402,644,645],{"class":408},": ",[402,647,648],{"class":416},"hidden",[402,650,651],{"class":408},"; }\n",[402,653,654,657],{"class":404,"line":531},[402,655,656],{"class":416},".strip__track",[402,658,659],{"class":408}," {\n",[402,661,662,665,667,670],{"class":404,"line":541},[402,663,664],{"class":416},"  margin",[402,666,645],{"class":408},[402,668,669],{"class":416},"0",[402,671,672],{"class":408},";\n",[402,674,675,678,680,683],{"class":404,"line":566},[402,676,677],{"class":416},"  white-space",[402,679,645],{"class":408},[402,681,682],{"class":416},"nowrap",[402,684,672],{"class":408},[402,686,687,690,693,696,700,703,706],{"class":404,"line":587},[402,688,689],{"class":416},"  animation",[402,691,692],{"class":408},": strip-scroll ",[402,694,695],{"class":416},"22",[402,697,699],{"class":698},"sHUrx","s",[402,701,702],{"class":416}," linear",[402,704,705],{"class":416}," infinite",[402,707,672],{"class":408},[402,709,710],{"class":404,"line":596},[402,711,712],{"class":408},"}\n",[402,714,716,719,722,725,728],{"class":404,"line":715},11,[402,717,718],{"class":416},".strip__toggle:checked",[402,720,721],{"class":698}," ~",[402,723,724],{"class":416}," .strip__viewport",[402,726,727],{"class":416}," .strip__track",[402,729,659],{"class":408},[402,731,733,736,738,741,744],{"class":404,"line":732},12,[402,734,735],{"class":416},"  animation-play-state",[402,737,645],{"class":408},[402,739,740],{"class":416},"paused",[402,742,743],{"class":408},";   ",[402,745,746],{"class":615},"\u002F* pause, not remove: position is kept *\u002F\n",[402,748,750],{"class":404,"line":749},13,[402,751,712],{"class":408},[402,753,755,758,762],{"class":404,"line":754},14,[402,756,757],{"class":698},"@keyframes",[402,759,761],{"class":760},"soyes"," strip-scroll",[402,763,659],{"class":408},[402,765,767,770,772,775,777,780,783,786],{"class":404,"line":766},15,[402,768,769],{"class":416},"  from",[402,771,639],{"class":408},[402,773,774],{"class":416},"translate",[402,776,645],{"class":408},[402,778,779],{"class":416},"100",[402,781,782],{"class":698},"%",[402,784,785],{"class":416}," 0",[402,787,651],{"class":408},[402,789,791,794,797,799,801,804,806,808],{"class":404,"line":790},16,[402,792,793],{"class":416},"  to",[402,795,796],{"class":408},"   { ",[402,798,774],{"class":416},[402,800,645],{"class":408},[402,802,803],{"class":416},"-100",[402,805,782],{"class":698},[402,807,785],{"class":416},[402,809,651],{"class":408},[402,811,813],{"class":404,"line":812},17,[402,814,712],{"class":408},[402,816,818],{"class":404,"line":817},18,[402,819,821],{"emptyLinePlaceholder":820},true,"\n",[402,823,825],{"class":404,"line":824},19,[402,826,827],{"class":615},"\u002F* --- 2.3.1 -----------------------------------------------------------\n",[402,829,831],{"class":404,"line":830},20,[402,832,833],{"class":615},"   An attention pulse on the label. One full cycle takes 2s, so the pair of\n",[402,835,837],{"class":404,"line":836},21,[402,838,839],{"class":615},"   opposing luminance changes occurs well under three times per second, and\n",[402,841,843],{"class":404,"line":842},22,[402,844,845],{"class":615},"   the change is confined to a small element rather than a full-bleed area. *\u002F\n",[402,847,849,852],{"class":404,"line":848},23,[402,850,851],{"class":416},".strip__label",[402,853,659],{"class":408},[402,855,857,859,862,865,867,870,872],{"class":404,"line":856},24,[402,858,689],{"class":416},[402,860,861],{"class":408},": strip-pulse ",[402,863,864],{"class":416},"2",[402,866,699],{"class":698},[402,868,869],{"class":416}," ease-in-out",[402,871,705],{"class":416},[402,873,672],{"class":408},[402,875,877],{"class":404,"line":876},25,[402,878,712],{"class":408},[402,880,882,884,887],{"class":404,"line":881},26,[402,883,757],{"class":698},[402,885,886],{"class":760}," strip-pulse",[402,888,659],{"class":408},[402,890,892,895,898,901,903,905,907,910],{"class":404,"line":891},27,[402,893,894],{"class":416},"  0%",[402,896,897],{"class":408},", ",[402,899,900],{"class":416},"100%",[402,902,639],{"class":408},[402,904,299],{"class":416},[402,906,645],{"class":408},[402,908,909],{"class":416},"#ffe9a8",[402,911,651],{"class":408},[402,913,915,918,921,923,925,928],{"class":404,"line":914},28,[402,916,917],{"class":416},"  50%",[402,919,920],{"class":408},"      { ",[402,922,299],{"class":416},[402,924,645],{"class":408},[402,926,927],{"class":416},"#fff6d6",[402,929,651],{"class":408},[402,931,933],{"class":404,"line":932},29,[402,934,712],{"class":408},[402,936,938],{"class":404,"line":937},30,[402,939,821],{"emptyLinePlaceholder":820},[402,941,943],{"class":404,"line":942},31,[402,944,945],{"class":615},"\u002F* --- 1.4.13 ----------------------------------------------------------\n",[402,947,949],{"class":404,"line":948},32,[402,950,951],{"class":615},"   Hoverable: the panel is flush against the trigger (top: 100%, no gap), so\n",[402,953,955],{"class":404,"line":954},33,[402,956,957],{"class":615},"   the pointer never crosses dead space. Persistent: the panel's own :hover\n",[402,959,961],{"class":404,"line":960},34,[402,962,963],{"class":615},"   is part of the reveal condition, so it survives the pointer landing on it.\n",[402,965,967],{"class":404,"line":966},35,[402,968,969],{"class":615},"   Dismissable still needs an Escape-key handler in script. *\u002F\n",[402,971,973,976,978,981,983,986],{"class":404,"line":972},36,[402,974,975],{"class":416},".alert",[402,977,639],{"class":408},[402,979,980],{"class":416},"position",[402,982,645],{"class":408},[402,984,985],{"class":416},"relative",[402,987,651],{"class":408},[402,989,991,994],{"class":404,"line":990},37,[402,992,993],{"class":416},".alert__panel",[402,995,659],{"class":408},[402,997,999,1002,1004,1007],{"class":404,"line":998},38,[402,1000,1001],{"class":416},"  position",[402,1003,645],{"class":408},[402,1005,1006],{"class":416},"absolute",[402,1008,672],{"class":408},[402,1010,1012,1015,1017,1019,1021],{"class":404,"line":1011},39,[402,1013,1014],{"class":416},"  top",[402,1016,645],{"class":408},[402,1018,779],{"class":416},[402,1020,782],{"class":698},[402,1022,672],{"class":408},[402,1024,1026,1029,1031,1033],{"class":404,"line":1025},40,[402,1027,1028],{"class":416},"  left",[402,1030,645],{"class":408},[402,1032,669],{"class":416},[402,1034,672],{"class":408},[402,1036,1038,1041,1043,1046,1049],{"class":404,"line":1037},41,[402,1039,1040],{"class":416},"  width",[402,1042,645],{"class":408},[402,1044,1045],{"class":416},"16",[402,1047,1048],{"class":698},"rem",[402,1050,672],{"class":408},[402,1052,1054,1057,1059,1061,1063],{"class":404,"line":1053},42,[402,1055,1056],{"class":416},"  padding",[402,1058,645],{"class":408},[402,1060,125],{"class":416},[402,1062,1048],{"class":698},[402,1064,672],{"class":408},[402,1066,1068,1071,1073,1076],{"class":404,"line":1067},43,[402,1069,1070],{"class":416},"  background",[402,1072,645],{"class":408},[402,1074,1075],{"class":416},"#ffffff",[402,1077,672],{"class":408},[402,1079,1081,1084,1086,1089,1092,1095,1098],{"class":404,"line":1080},44,[402,1082,1083],{"class":416},"  border",[402,1085,645],{"class":408},[402,1087,1088],{"class":416},"1",[402,1090,1091],{"class":698},"px",[402,1093,1094],{"class":416}," solid",[402,1096,1097],{"class":416}," #94a3b8",[402,1099,672],{"class":408},[402,1101,1103,1106,1108,1110],{"class":404,"line":1102},45,[402,1104,1105],{"class":416},"  visibility",[402,1107,645],{"class":408},[402,1109,648],{"class":416},[402,1111,672],{"class":408},[402,1113,1115],{"class":404,"line":1114},46,[402,1116,712],{"class":408},[402,1118,1120,1123,1126],{"class":404,"line":1119},47,[402,1121,1122],{"class":416},".alert:hover",[402,1124,1125],{"class":416}," .alert__panel",[402,1127,1128],{"class":408},",\n",[402,1130,1132,1135,1137],{"class":404,"line":1131},48,[402,1133,1134],{"class":416},".alert:focus-visible",[402,1136,1125],{"class":416},[402,1138,1128],{"class":408},[402,1140,1142,1145],{"class":404,"line":1141},49,[402,1143,1144],{"class":416},".alert__panel:hover",[402,1146,659],{"class":408},[402,1148,1150,1152,1154,1157],{"class":404,"line":1149},50,[402,1151,1105],{"class":416},[402,1153,645],{"class":408},[402,1155,1156],{"class":416},"visible",[402,1158,672],{"class":408},[402,1160,1162],{"class":404,"line":1161},51,[402,1163,712],{"class":408},[402,1165,1167],{"class":404,"line":1166},52,[402,1168,821],{"emptyLinePlaceholder":820},[402,1170,1172],{"class":404,"line":1171},53,[402,1173,1174],{"class":615},"\u002F* --- 2.3.3 -----------------------------------------------------------\n",[402,1176,1178],{"class":404,"line":1177},54,[402,1179,1180],{"class":615},"   The scroll is displacement, so it goes. The pulse is a colour change with\n",[402,1182,1184],{"class":404,"line":1183},55,[402,1185,1186],{"class":615},"   no displacement and is not motion animation under this criterion, but the\n",[402,1188,1190],{"class":404,"line":1189},56,[402,1191,1192],{"class":615},"   marquee stops moving and the text is shown statically instead. *\u002F\n",[402,1194,1196,1199],{"class":404,"line":1195},57,[402,1197,1198],{"class":698},"@media",[402,1200,1201],{"class":408}," (prefers-reduced-motion: reduce) {\n",[402,1203,1205,1208],{"class":404,"line":1204},58,[402,1206,1207],{"class":416},"  .strip__track",[402,1209,659],{"class":408},[402,1211,1213,1216,1218,1220],{"class":404,"line":1212},59,[402,1214,1215],{"class":416},"    animation",[402,1217,645],{"class":408},[402,1219,122],{"class":416},[402,1221,672],{"class":408},[402,1223,1225,1228,1230,1233,1236],{"class":404,"line":1224},60,[402,1226,1227],{"class":416},"    white-space",[402,1229,645],{"class":408},[402,1231,1232],{"class":416},"normal",[402,1234,1235],{"class":408},";    ",[402,1237,1238],{"class":615},"\u002F* let the full text wrap and be read at rest *\u002F\n",[402,1240,1242],{"class":404,"line":1241},61,[402,1243,1244],{"class":408},"  }\n",[402,1246,1248],{"class":404,"line":1247},62,[402,1249,712],{"class":408},[1251,1252,1254],"h3",{"id":1253},"the-one-rule-doing-the-heavy-lifting","The one rule doing the heavy lifting",[14,1256,1257,1259,1260,1263,1264,1266],{},[66,1258,268],{}," is the property that makes 2.2.2 tractable in CSS. Setting ",[66,1261,1262],{},"animation: none"," under a paused state would satisfy nothing useful: the element would snap back to its unanimated position and the user would lose their place in the content. ",[66,1265,740],{}," freezes the animation at its current computed values, so the announcement stays exactly where it was when the user asked it to stop. That is the difference between a pause control and a delete control, and the criterion asks for the former. Everything else in the sheet is arithmetic — cycle durations kept above 333ms, gaps kept at zero — but this one property changes what is achievable without script.",[58,1268,1270],{"id":1269},"variation-pausing-on-hover-as-well","Variation: pausing on hover as well",[14,1272,1273],{},"Some auto-advancing components pause when the pointer rests on them, which is a courtesy rather than a conformance mechanism — it does not satisfy 2.2.2 on its own, because a keyboard-only user cannot invoke it and the effect is not discoverable. Layered on top of a real control it is still worth having:",[393,1275,1277],{"className":606,"code":1276,"language":608,"meta":398,"style":398},".strip:hover .strip__track,\n.strip:focus-within .strip__track {\n  animation-play-state: paused;\n}\n",[66,1278,1279,1288,1297,1307],{"__ignoreMap":398},[402,1280,1281,1284,1286],{"class":404,"line":405},[402,1282,1283],{"class":416},".strip:hover",[402,1285,727],{"class":416},[402,1287,1128],{"class":408},[402,1289,1290,1293,1295],{"class":404,"line":430},[402,1291,1292],{"class":416},".strip:focus-within",[402,1294,727],{"class":416},[402,1296,659],{"class":408},[402,1298,1299,1301,1303,1305],{"class":404,"line":464},[402,1300,735],{"class":416},[402,1302,645],{"class":408},[402,1304,740],{"class":416},[402,1306,672],{"class":408},[402,1308,1309],{"class":404,"line":493},[402,1310,712],{"class":408},[14,1312,1313,1314,1316,1317,1320,1321,1323],{},"Pairing ",[66,1315,84],{}," with ",[66,1318,1319],{},":focus-within"," at least keeps keyboard users at parity while they are inside the component. Note that the pointer-capability caveats matter here too: on a touch device ",[66,1322,84],{}," behaviour is unreliable, which is why the visible checkbox remains the mechanism of record.",[58,1325,1327],{"id":1326},"browser-support","Browser support",[14,1329,1330,1331,1333,1334,1336,1337,1340],{},"Nothing in this page depends on a recent feature. ",[66,1332,88],{}," has been supported in every engine for many years, and ",[66,1335,68],{}," since Chrome 74, Edge 79, Firefox 63 and Safari 10.1. ",[66,1338,1339],{},":focus-visible"," is the newest thing used, at Chrome 86, Edge 86, Firefox 85 and Safari 15.4. The conformance obligations themselves are independent of browser support: an engine that ignores your media query does not excuse a missing pause control.",[58,1342,1344],{"id":1343},"faq","FAQ",[14,1346,1347,1350],{},[26,1348,1349],{},"Which WCAG success criteria apply to CSS animation?","\nFour apply directly: 2.2.2 Pause, Stop, Hide (Level A), 2.3.1 Three Flashes or Below Threshold (Level A), 1.4.13 Content on Hover or Focus (Level AA), and 2.3.3 Animation from Interactions (Level AAA). Only 2.3.3 is AAA, so the other three are in scope for most conformance targets.",[14,1352,1353,1356],{},[26,1354,1355],{},"Does the five-second rule in 2.2.2 apply to a hover transition?","\nNo. 2.2.2 covers movement that starts automatically, so a transition you trigger by hovering is outside its scope. It applies to carousels, tickers, looping background video and auto-refreshing counters that run for more than five seconds alongside other content.",[14,1358,1359,1365],{},[26,1360,1361,1362,1364],{},"Is ",[66,1363,68],{}," enough to satisfy WCAG?","\nIt satisfies the common failure technique for 2.3.3 at Level AAA, but it is not sufficient for 2.2.2. That criterion requires a mechanism the user can operate on the page itself, and a person who has not set an operating-system preference still needs a visible pause control.",[14,1367,1368,1371],{},[26,1369,1370],{},"What counts as a flash under 2.3.1?","\nA pair of opposing changes in relative luminance covering more than 25 percent of a 10-degree field of view, or a transition to or from saturated red. Three or fewer such flashes per second passes; above that you must stay below the general and red flash thresholds.",[58,1373,1375],{"id":1374},"related","Related",[30,1377,1378,1383,1390,1397,1404],{},[33,1379,1380,1382],{},[18,1381,21],{"href":20}," — the parent guide these criteria sit behind.",[33,1384,1385,1389],{},[18,1386,1388],{"href":1387},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Ftarget-size-and-pointer-accessibility\u002F","Target Size and Pointer Accessibility"," — the pointer-side criteria, 2.5.8 and 2.5.5.",[33,1391,1392,1396],{},[18,1393,1395],{"href":1394},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fprefers-reduced-motion-recipes\u002F","prefers-reduced-motion Recipes"," — component-level blocks for the 2.3.3 obligation.",[33,1398,1399,1403],{},[18,1400,1402],{"href":1401},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fcreating-accessible-focus-indicators\u002F","Creating Accessible Focus Indicators"," — the focus criteria that sit alongside these.",[33,1405,1406,1410],{},[18,1407,1409],{"href":1408},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-type-accessibility-and-zoom\u002F","Fluid Type Accessibility and Zoom"," — the reflow and text-resize criteria on the layout side.",[1412,1413,1414],"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 .soyes, html code.shiki .soyes{--shiki-default:#702C00;--shiki-dark:#FFB757}",{"title":398,"searchDepth":430,"depth":430,"links":1416},[1417,1418,1419,1420,1421,1422,1425,1426,1427,1428],{"id":60,"depth":430,"text":61},{"id":236,"depth":430,"text":237},{"id":280,"depth":430,"text":281},{"id":316,"depth":430,"text":317},{"id":364,"depth":430,"text":365},{"id":387,"depth":430,"text":388,"children":1423},[1424],{"id":1253,"depth":464,"text":1254},{"id":1269,"depth":430,"text":1270},{"id":1326,"depth":430,"text":1327},{"id":1343,"depth":430,"text":1344},{"id":1374,"depth":430,"text":1375},"A precise reference to the WCAG criteria that govern motion: 2.2.2 Pause Stop Hide, 2.3.1 Three Flashes, 2.3.3 Animation from Interactions and 1.4.13.","md",{"pageTitle":1432,"datePublished":1433,"dateModified":1433,"faq":1434},"WCAG Success Criteria That Govern Motion","2026-07-20",[1435,1437,1439,1442],{"q":1349,"a":1436},"Four apply directly: 2.2.2 Pause, Stop, Hide (Level A), 2.3.1 Three Flashes or Below Threshold (Level A), 1.4.13 Content on Hover or Focus (Level AA), and 2.3.3 Animation from Interactions (Level AAA). Only 2.3.3 is AAA, so the other three are in scope for most conformance targets.",{"q":1355,"a":1438},"No. 2.2.2 covers movement that starts automatically, so a transition you trigger by hovering is outside its scope. It applies to carousels, tickers, looping background video and auto-refreshing counters that run for more than five seconds alongside other content.",{"q":1440,"a":1441},"Is prefers-reduced-motion enough to satisfy WCAG?","It satisfies the common failure technique for 2.3.3 at Level AAA, but it is not sufficient for 2.2.2. That criterion requires a mechanism the user can operate on the page itself, and a person who has not set an operating-system preference still needs a visible pause control.",{"q":1370,"a":1443},"A pair of opposing changes in relative luminance covering more than 25 percent of a 10-degree field of view, or a transition to or from saturated red. Three or fewer such flashes per second passes; above that you must stay below the general and red flash thresholds.","\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fwcag-motion-success-criteria",{"title":5,"description":1429},"css-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fwcag-motion-success-criteria\u002Findex","bQdvoDznEQgebR7hDTvWhYfViiz3VeTWf-x06qp3TlQ",[1449,1452,1455,1458,1461,1464,1467,1468,1471,1474,1477,1480,1483,1486,1489,1492,1495,1498,1501,1504,1507,1510,1513,1516,1519,1522,1525,1528,1531,1534,1537,1540,1543,1546,1549,1552,1555,1558,1561,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],{"path":1450,"title":1451},"\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":1453,"title":1454},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations","Accessibility in CSS Animations: Patterns, Specs & Best Practices",{"path":1456,"title":1457},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fprefers-reduced-motion-recipes","prefers-reduced-motion Recipes: A Reduction for Every Common Effect",{"path":1459,"title":1460},"\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":1462,"title":1463},"\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":1465,"title":1466},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fvestibular-safe-animation-patterns","Vestibular-Safe Animation Patterns: Why Some Motion Makes People Sick",{"path":1444,"title":5},{"path":1469,"title":1470},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fcontainer-query-hover-affordances","Container Query Hover Affordances: When Narrow Means Persistent, Not Hidden",{"path":1472,"title":1473},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion","Container-Aware Motion: Animation Sized by the Space a Component Actually Has",{"path":1475,"title":1476},"\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":1478,"title":1479},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fsuppressing-motion-in-small-containers","Suppressing Motion in Small Containers: Deliberately Animating Nothing",{"path":1481,"title":1482},"\u002Fcss-only-micro-interactions-animations\u002Fcss-animation-vs-web-animations-api","CSS Animation vs the Web Animations API: A Decision Guide",{"path":1484,"title":1485},"\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":1487,"title":1488},"\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":1490,"title":1491},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Ffluid-spacing-tokens-driving-transition-durations","Fluid Spacing Tokens That Drive Transition Durations",{"path":1493,"title":1494},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture","CSS Custom Properties Architecture: Scalable Design Systems & Dynamic UI",{"path":1496,"title":1497},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Fregistered-properties-and-type-safety","Registered Properties and Type Safety: @property as a Contract for Design Tokens",{"path":1499,"title":1500},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fcss-transition-timing-functions","CSS Transition Timing Functions: ease, cubic-bezier(), steps() and linear()",{"path":1502,"title":1503},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals","CSS Transition Fundamentals: Architecture, Performance & Patterns",{"path":1505,"title":1506},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fstarting-style-entry-animations","@starting-style: Animating an Element's Very First Style Change",{"path":1508,"title":1509},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Ftransitioning-display-with-allow-discrete","Transitioning display with transition-behavior: allow-discrete and @starting-style",{"path":1511,"title":1512},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Faccessible-css-only-tooltips","Accessible CSS-Only Tooltips and Hover Cards With  and ",{"path":1514,"title":1515},"\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":1517,"title":1518},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Ffocus-within-form-patterns"," Form Patterns: Styling a Group From the Field Inside It",{"path":1520,"title":1521},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design","Hover & Focus State Design: Spec-Compliant Patterns for Modern UIs",{"path":1523,"title":1524},"\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":1526,"title":1527},"\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":1529,"title":1530},"\u002Fcss-only-micro-interactions-animations","CSS-Only Micro-Interactions & Animations: Architecture, Performance & Implementation",{"path":1532,"title":1533},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcontainer-query-triggered-keyframe-animations","Container-Query-Triggered Keyframe Animations: Animate Differently per Available Space",{"path":1535,"title":1536},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcss-only-accordions-and-disclosure","CSS-Only Accordions and Disclosure Widgets with details and summary",{"path":1538,"title":1539},"\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":1541,"title":1542},"\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":1544,"title":1545},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns","Keyframe Animation Patterns: Spec-Compliant Architectures for Modern UIs",{"path":1547,"title":1548},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fstaggered-list-animations-with-custom-properties","Staggered List Animations Using --i Index Custom Properties",{"path":1550,"title":1551},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration","Performance & GPU Acceleration in CSS: A Developer’s Blueprint",{"path":1553,"title":1554},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Foptimizing-css-animations-for-60fps","Optimizing CSS Animations for 60fps: Budgeting the Frame",{"path":1556,"title":1557},"\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":1559,"title":1560},"\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":1562,"title":1563},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations","Scroll-Driven Animations: Binding Motion to Scroll Position in Pure CSS",{"path":1565,"title":1566},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-driven-animation-fallbacks","Shipping Scroll-Driven Animations Without Breaking Anything",{"path":1568,"title":1569},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-progress-bar-without-javascript","A Reading Progress Bar Driven by scroll(root)",{"path":1571,"title":1572},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-triggered-reveal-animations","Reveal-on-Scroll with view() and animation-range",{"path":1574,"title":1575},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers","View Transitions for CSS Developers: the Pseudo-Element Tree, Snapshots, and Named Elements",{"path":1577,"title":1578},"\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":1580,"title":1581},"\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":1583,"title":1584},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fview-transitions-with-reduced-motion","Honouring prefers-reduced-motion in View Transitions",{"path":1586,"title":1587},"\u002F","Modern CSS Layouts & Micro-Interactions",{"path":1589,"title":1590},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioned-tooltips","Anchor-Positioned Tooltips: Tethering, Flipping, and Getting the Semantics Right",{"path":1592,"title":1593},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioning-fallbacks","Anchor Positioning Fallbacks: A Graceful Floor for Older Browser Versions",{"path":1595,"title":1596},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays","CSS Anchor Positioning and Overlays: Tethering Elements Without JavaScript",{"path":1598,"title":1599},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fpopover-attribute-and-css-styling","The popover Attribute: Top-Layer Overlays With No JavaScript",{"path":1601,"title":1602},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Ffeature-detection-with-supports","Feature Detection with @supports: Syntax, Semantics, and the Traps",{"path":1604,"title":1605},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Fhandling-container-query-fallbacks-for-older-browsers","Handling Container Query Fallbacks for Older Browsers",{"path":1607,"title":1608},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks","Container Query Fallbacks: Spec-Compliant CSS Strategies for Legacy Browsers",{"path":1610,"title":1611},"\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":1613,"title":1614},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-type-size-vs-inline-size","Choosing container-type: inline-size, size, or normal",{"path":1616,"title":1617},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-vs-media-queries-comparison","Container vs Media Queries: Choosing the Right Reference Box",{"path":1619,"title":1620},"\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":1622,"title":1623},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics","Container Query Syntax Basics",{"path":1625,"title":1626},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fnesting-and-naming-container-queries","Nesting and Naming Container Queries: Targeting the Right Ancestor",{"path":1628,"title":1629},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fauto-fit-minmax-responsive-grids","Responsive Grids with repeat(auto-fit, minmax())",{"path":1631,"title":1632},"\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":1634,"title":1635},"\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":1637,"title":1638},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts","CSS Grid and Subgrid Layouts for Responsive Interfaces",{"path":1640,"title":1641},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fsubgrid-vs-nested-grid","Subgrid vs an Independently Nested Grid",{"path":1643,"title":1644},"\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":1646,"title":1647},"\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":1649,"title":1650},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-type-accessibility-and-zoom","Fluid Type, Accessibility and Zoom: The vw-Only Trap",{"path":1652,"title":1653},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-typography-without-javascript","Fluid Typography Without JavaScript: A Precision CSS Reference",{"path":1655,"title":1656},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp","Fluid Typography with clamp(): A Practical Guide for Modern CSS",{"path":1658,"title":1659},"\u002Fmastering-container-queries-responsive-layouts","Mastering Container Queries & Responsive Layouts",{"path":1661,"title":1662},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Faspect-ratio-for-responsive-media","Using aspect-ratio for Responsive Media and Preventing Layout Shift",{"path":1664,"title":1665},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques","Intrinsic Sizing Techniques: Modern CSS Layouts for Responsive UI",{"path":1667,"title":1668},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fmin-max-fit-content-explained","min-content, max-content, and fit-content() Explained",{"path":1670,"title":1671},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fpreventing-flex-and-grid-overflow","The min-width: auto Trap in Flex and Grid Layouts",{"path":1673,"title":1674},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-for-reset-and-tokens","Cascade Layers for Reset and Design Tokens",{"path":1676,"title":1677},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-vs-specificity-hacks","Cascade Layers vs Specificity Hacks: Ordering Instead of Escalating",{"path":1679,"title":1680},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies","Modern CSS Reset Strategies: A Spec-Compliant Foundation",{"path":1682,"title":1683},"\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":1685,"title":1686},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fcontainer-query-data-tables","Container Query Data Tables: Reflowing Tables to Cards",{"path":1688,"title":1689},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fcontainer-query-sidebar-layouts","Container Query Sidebar Layouts That Travel Between Contexts",{"path":1691,"title":1692},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns","Responsive Component Patterns: Architecture & Implementation",{"path":1694,"title":1695},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-forms-with-container-queries","Responsive Forms with Container Queries: Reflow Without Losing the Wiring",{"path":1697,"title":1698},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-navigation-without-media-queries","Responsive Navigation Without Media Queries Using Container Queries",{"path":1700,"title":1701},"\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":1703,"title":1704},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state","Style Queries and Container State: Token-Driven Component Variants",{"path":1706,"title":1707},"\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":1709,"title":1710},"\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",1784566157176]