[{"data":1,"prerenderedAt":2018},["ShallowReactive",2],{"page-\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fcontainer-query-hover-affordances\u002F":3,"content-all-pages":1755},{"id":4,"title":5,"body":6,"description":1737,"extension":1738,"meta":1739,"navigation":479,"path":1751,"seo":1752,"stem":1753,"__hash__":1754},"content\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fcontainer-query-hover-affordances\u002Findex.md","Container Query Hover Affordances: When Narrow Means Persistent, Not Hidden",{"type":7,"value":8,"toc":1728},"minimark",[9,13,28,31,36,47,67,70,73,75,79,82,201,205,448,1283,1293,1304,1306,1310,1332,1340,1360,1362,1366,1373,1600,1608,1610,1614,1638,1640,1644,1651,1662,1675,1681,1683,1687,1724],[10,11,5],"h1",{"id":12},"container-query-hover-affordances-when-narrow-means-persistent-not-hidden",[14,15,16,17,21,22,27],"p",{},"Hover-to-reveal is a space trade: you buy a calmer default view by putting a function behind a pointer gesture. That trade is worth making in a wide card, where the hidden panel has somewhere to expand into and the resting layout genuinely benefits from the quiet. It is a bad trade in a 300px column, where the revealed panel would cover most of the content it describes, and it is no trade at all on a touchscreen, where the gesture that pays for it does not exist. This page is about making the ",[18,19,20],"em",{},"affordance itself"," — not merely its size — a function of the container: a wide instance reveals a detail panel on hover, while the narrow instance of the same component ships a persistent control instead. It belongs to the ",[23,24,26],"a",{"href":25},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002F","container-aware motion"," section, and it is the point where container queries stop adjusting motion and start adjusting interaction design.",[29,30],"hr",{},[32,33,35],"h2",{"id":34},"why-the-container-is-the-right-signal-and-what-it-cannot-tell-you","Why the container is the right signal, and what it cannot tell you",[14,37,38,39,43,44,46],{},"The decision \"should this be hidden behind hover?\" depends on two independent facts. One is whether there is physical room for a reveal that does not destroy the resting layout — a question about the component's box, which ",[40,41,42],"code",{},"@container"," answers exactly. The other is whether the user's input device can hover at all — a question about hardware, which ",[40,45,42],{}," cannot answer and must not be asked to. Conflating them is the classic mistake, and it survives from the media-query era: authors treat \"narrow\" as a proxy for \"touch\", which was never reliable and is now plainly wrong in both directions. A 1200px touchscreen kiosk is wide and cannot hover; a 280px sidebar on a desktop is narrow and can.",[14,48,49,50,53,54,57,58,61,62,66],{},"So the two conditions get expressed with the two features that actually describe them. ",[40,51,52],{},"@container (min-width: …)"," decides whether there is space for a reveal. ",[40,55,56],{},"@media (hover: hover) and (pointer: fine)"," decides whether a reveal can be operated — the semantics of those features, including why ",[40,59,60],{},"any-hover"," behaves differently on hybrid devices, are covered in ",[23,63,65],{"href":64},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Fpointer-and-hover-media-queries\u002F","pointer and hover media queries",". Only where both are true does hiding become defensible.",[14,68,69],{},"The alternative implementation is a script that measures the element and toggles a class. It works, but it puts a functional affordance — whether a control exists in the resting state — behind JavaScript execution and a layout measurement, which means the component has a visibly wrong first paint and a hard dependency on a bundle for something the browser can decide during style computation. The CSS version has neither.",[14,71,72],{},"There is one genuine cost to the CSS approach: both variants exist in the DOM at all times, so you cannot use the query to remove markup, only to restyle it. That is usually fine and occasionally a constraint — if the wide and narrow affordances need different accessible names or different roles, CSS cannot get you there, and a component that truly needs two different accessibility trees needs two different components.",[29,74],{},[32,76,78],{"id":77},"complete-working-implementation","Complete working implementation",[14,80,81],{},"The tile below is one component with one set of markup. Above 340px of container width, a summary overlay is parked below the artwork and slides up on hover or focus. Below 340px, that overlay rule never matches, so the summary is simply a paragraph in normal flow and the call-to-action is a permanently visible, comfortably tappable pill.",[83,84,90,91,90,95,90,99,90,106,90,115,90,119,90,124,90,131,90,134,90,142,90,148,90,153,90,157,90,161,90,165,90,167,90,171,90,174,90,177,90,180,90,185],"svg",{"viewBox":85,"role":86,"ariaLabel":87,"xmlns":88,"style":89},"0 0 720 340","img","A container width condition branching into a persistent control for narrow containers and a hover-revealed panel for wide ones","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;height:auto;max-width:720px;margin:2rem 0","\n  ",[92,93,94],"title",{},"Container width selecting the affordance",[96,97,98],"desc",{},"A container width condition at the top branches into two outcomes: when it does not match, controls are always visible and touch-operable; when it matches, a detail panel is hidden and revealed on hover or focus.",[100,101,105],"text",{"x":102,"y":103,"style":104},"360","28","text-anchor:middle;fill:currentColor;font:700 17px sans-serif","The query picks the affordance, not just the size",[107,108],"rect",{"x":109,"y":110,"width":111,"height":110,"rx":112,"fill":113,"opacity":114},"230","52","260","10","#7aa2ff","0.18",[107,116],{"x":109,"y":110,"width":111,"height":110,"rx":112,"fill":117,"stroke":113,"strokeWidth":118},"none","1.5",[100,120,123],{"x":102,"y":121,"style":122},"84","text-anchor:middle;fill:currentColor;font:12px ui-monospace,monospace","@container (min-width: 340px)",[125,126],"path",{"d":127,"fill":117,"stroke":128,"strokeWidth":129,"markerEnd":130},"M300 104 C 250 128, 200 130, 175 156","currentColor","2","url(#cha)",[125,132],{"d":133,"fill":117,"stroke":128,"strokeWidth":129,"markerEnd":130},"M420 104 C 470 128, 520 130, 545 156",[107,135],{"x":136,"y":137,"width":138,"height":139,"rx":140,"fill":117,"stroke":128,"strokeWidth":118,"opacity":141},"40","162","270","126","12","0.55",[100,143,147],{"x":144,"y":145,"style":146},"175","190","text-anchor:middle;fill:currentColor;font:600 14px sans-serif","no match: narrow",[100,149,152],{"x":144,"y":150,"style":151},"216","text-anchor:middle;fill:currentColor;font:13px sans-serif;opacity:0.8","controls always visible",[100,154,156],{"x":144,"y":155,"style":151},"240","no pointer gesture needed",[100,158,160],{"x":144,"y":159,"style":151},"266","safe on touch",[107,162],{"x":163,"y":137,"width":138,"height":139,"rx":140,"fill":113,"opacity":164},"410","0.12",[107,166],{"x":163,"y":137,"width":138,"height":139,"rx":140,"fill":117,"stroke":113,"strokeWidth":118},[100,168,170],{"x":169,"y":145,"style":146},"545","match: wide",[100,172,173],{"x":169,"y":150,"style":151},"summary parked offscreen",[100,175,176],{"x":169,"y":155,"style":151},"slides up on hover",[100,178,179],{"x":169,"y":159,"style":151},"and on :focus-within",[100,181,184],{"x":102,"y":182,"style":183},"322","text-anchor:middle;fill:currentColor;font:12px sans-serif;opacity:0.6","the hidden variant is the enhancement, never the default",[186,187,188,189,90],"defs",{},"\n    ",[190,191,197,198,188],"marker",{"id":192,"markerWidth":193,"markerHeight":193,"refX":194,"refY":195,"orient":196},"cha","9","7","4","auto","\n      ",[125,199],{"d":200,"fill":128},"M0 0 L8 4 L0 8 z",[202,203],"live-demo",{"name":204},"cmotion-reveal-vs-persistent",[206,207,212],"pre",{"className":208,"code":209,"language":210,"meta":211,"style":211},"language-html shiki shiki-themes github-light-high-contrast github-dark-high-contrast","\u003Cdiv class=\"frame\">\n  \u003Carticle class=\"tile\">\n    \u003Cdiv class=\"tile__art\">\u003Cspan class=\"tile__initials\">KV\u003C\u002Fspan>\n      \u003Cdiv class=\"tile__overlay\">\n        \u003Cp class=\"tile__summary\">Twelve tracks recorded live in a single afternoon.\u003C\u002Fp>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n    \u003Cdiv class=\"tile__foot\">\n      \u003Ch3 class=\"tile__title\">Kestrel Valley\u003C\u002Fh3>\n      \u003Ca class=\"tile__cta\" href=\"#\">Details\u003C\u002Fa>\n    \u003C\u002Fdiv>\n  \u003C\u002Farticle>\n\u003C\u002Fdiv>\n","html","",[40,213,214,241,259,293,310,332,342,352,368,390,419,428,438],{"__ignoreMap":211},[215,216,219,223,227,231,234,238],"span",{"class":217,"line":218},"line",1,[215,220,222],{"class":221},"suds8","\u003C",[215,224,226],{"class":225},"sne4z","div",[215,228,230],{"class":229},"s-5SL"," class",[215,232,233],{"class":221},"=",[215,235,237],{"class":236},"sT6z2","\"frame\"",[215,239,240],{"class":221},">\n",[215,242,244,247,250,252,254,257],{"class":217,"line":243},2,[215,245,246],{"class":221},"  \u003C",[215,248,249],{"class":225},"article",[215,251,230],{"class":229},[215,253,233],{"class":221},[215,255,256],{"class":236},"\"tile\"",[215,258,240],{"class":221},[215,260,262,265,267,269,271,274,277,279,281,283,286,289,291],{"class":217,"line":261},3,[215,263,264],{"class":221},"    \u003C",[215,266,226],{"class":225},[215,268,230],{"class":229},[215,270,233],{"class":221},[215,272,273],{"class":236},"\"tile__art\"",[215,275,276],{"class":221},">\u003C",[215,278,215],{"class":225},[215,280,230],{"class":229},[215,282,233],{"class":221},[215,284,285],{"class":236},"\"tile__initials\"",[215,287,288],{"class":221},">KV\u003C\u002F",[215,290,215],{"class":225},[215,292,240],{"class":221},[215,294,296,299,301,303,305,308],{"class":217,"line":295},4,[215,297,298],{"class":221},"      \u003C",[215,300,226],{"class":225},[215,302,230],{"class":229},[215,304,233],{"class":221},[215,306,307],{"class":236},"\"tile__overlay\"",[215,309,240],{"class":221},[215,311,313,316,318,320,322,325,328,330],{"class":217,"line":312},5,[215,314,315],{"class":221},"        \u003C",[215,317,14],{"class":225},[215,319,230],{"class":229},[215,321,233],{"class":221},[215,323,324],{"class":236},"\"tile__summary\"",[215,326,327],{"class":221},">Twelve tracks recorded live in a single afternoon.\u003C\u002F",[215,329,14],{"class":225},[215,331,240],{"class":221},[215,333,335,338,340],{"class":217,"line":334},6,[215,336,337],{"class":221},"      \u003C\u002F",[215,339,226],{"class":225},[215,341,240],{"class":221},[215,343,345,348,350],{"class":217,"line":344},7,[215,346,347],{"class":221},"    \u003C\u002F",[215,349,226],{"class":225},[215,351,240],{"class":221},[215,353,355,357,359,361,363,366],{"class":217,"line":354},8,[215,356,264],{"class":221},[215,358,226],{"class":225},[215,360,230],{"class":229},[215,362,233],{"class":221},[215,364,365],{"class":236},"\"tile__foot\"",[215,367,240],{"class":221},[215,369,371,373,376,378,380,383,386,388],{"class":217,"line":370},9,[215,372,298],{"class":221},[215,374,375],{"class":225},"h3",[215,377,230],{"class":229},[215,379,233],{"class":221},[215,381,382],{"class":236},"\"tile__title\"",[215,384,385],{"class":221},">Kestrel Valley\u003C\u002F",[215,387,375],{"class":225},[215,389,240],{"class":221},[215,391,393,395,397,399,401,404,407,409,412,415,417],{"class":217,"line":392},10,[215,394,298],{"class":221},[215,396,23],{"class":225},[215,398,230],{"class":229},[215,400,233],{"class":221},[215,402,403],{"class":236},"\"tile__cta\"",[215,405,406],{"class":229}," href",[215,408,233],{"class":221},[215,410,411],{"class":236},"\"#\"",[215,413,414],{"class":221},">Details\u003C\u002F",[215,416,23],{"class":225},[215,418,240],{"class":221},[215,420,422,424,426],{"class":217,"line":421},11,[215,423,347],{"class":221},[215,425,226],{"class":225},[215,427,240],{"class":221},[215,429,431,434,436],{"class":217,"line":430},12,[215,432,433],{"class":221},"  \u003C\u002F",[215,435,249],{"class":225},[215,437,240],{"class":221},[215,439,441,444,446],{"class":217,"line":440},13,[215,442,443],{"class":221},"\u003C\u002F",[215,445,226],{"class":225},[215,447,240],{"class":221},[206,449,453],{"className":450,"code":451,"language":452,"meta":211,"style":211},"language-css shiki shiki-themes github-light-high-contrast github-dark-high-contrast",".frame { container-type: inline-size; container-name: tile; }\n\n.tile {\n  border: 1px solid var(--demo-border);\n  border-radius: 12px;\n  overflow: hidden;\n  background: var(--demo-surface);\n}\n\n.tile__art {\n  position: relative;\n  display: grid;\n  place-items: center;\n  height: 150px;\n  background: var(--demo-accent);\n}\n.tile__initials { font: 700 30px sans-serif; color: var(--demo-bg); }\n\n.tile__foot {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: .75rem;\n  padding: .75rem 1rem;\n}\n.tile__title { margin: 0; font-size: 1rem; color: var(--demo-fg); }\n\n\u002F* NARROW DEFAULT — the summary sits in normal flow, the CTA is a real\n   tappable target, and nothing depends on a pointer that can hover. *\u002F\n.tile__summary {\n  margin: 0;\n  padding: .7rem 1rem;\n  color: var(--demo-muted);\n  font-size: .85rem;\n}\n.tile__cta {\n  padding: .45rem .8rem;\n  border: 1px solid var(--demo-accent);\n  border-radius: 999px;\n  color: var(--demo-accent);\n  text-decoration: none;\n  font-size: .82rem;\n  white-space: nowrap;\n}\n\n\u002F* WIDE — enough room to hide the summary behind a hover overlay. *\u002F\n@container tile (min-width: 340px) {\n  .tile__overlay {\n    position: absolute;\n    inset: auto 0 0 0;\n    background: color-mix(in srgb, var(--demo-bg) 88%, transparent);\n    transform: translateY(100%);\n    transition: transform .28s cubic-bezier(.2,.8,.2,1);\n  }\n  .tile:hover .tile__overlay,\n  .tile:focus-within .tile__overlay { transform: translateY(0); }\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .tile__overlay { transition: none; }\n}\n","css",[40,454,455,475,481,489,520,534,546,563,568,572,579,591,603,615,630,646,651,693,698,706,718,730,743,759,778,783,825,830,837,843,851,863,881,898,913,918,926,945,966,980,995,1007,1021,1034,1039,1044,1050,1058,1066,1079,1098,1142,1162,1201,1207,1219,1242,1247,1252,1261,1278],{"__ignoreMap":211},[215,456,457,460,463,466,469,472],{"class":217,"line":218},[215,458,459],{"class":229},".frame",[215,461,462],{"class":221}," { ",[215,464,465],{"class":229},"container-type",[215,467,468],{"class":221},": inline-size; ",[215,470,471],{"class":229},"container-name",[215,473,474],{"class":221},": tile; }\n",[215,476,477],{"class":217,"line":243},[215,478,480],{"emptyLinePlaceholder":479},true,"\n",[215,482,483,486],{"class":217,"line":261},[215,484,485],{"class":229},".tile",[215,487,488],{"class":221}," {\n",[215,490,491,494,497,500,504,507,510,513,517],{"class":217,"line":295},[215,492,493],{"class":229},"  border",[215,495,496],{"class":221},": ",[215,498,499],{"class":229},"1",[215,501,503],{"class":502},"sHUrx","px",[215,505,506],{"class":229}," solid",[215,508,509],{"class":229}," var",[215,511,512],{"class":221},"(",[215,514,516],{"class":515},"soyes","--demo-border",[215,518,519],{"class":221},");\n",[215,521,522,525,527,529,531],{"class":217,"line":312},[215,523,524],{"class":229},"  border-radius",[215,526,496],{"class":221},[215,528,140],{"class":229},[215,530,503],{"class":502},[215,532,533],{"class":221},";\n",[215,535,536,539,541,544],{"class":217,"line":334},[215,537,538],{"class":229},"  overflow",[215,540,496],{"class":221},[215,542,543],{"class":229},"hidden",[215,545,533],{"class":221},[215,547,548,551,553,556,558,561],{"class":217,"line":344},[215,549,550],{"class":229},"  background",[215,552,496],{"class":221},[215,554,555],{"class":229},"var",[215,557,512],{"class":221},[215,559,560],{"class":515},"--demo-surface",[215,562,519],{"class":221},[215,564,565],{"class":217,"line":354},[215,566,567],{"class":221},"}\n",[215,569,570],{"class":217,"line":370},[215,571,480],{"emptyLinePlaceholder":479},[215,573,574,577],{"class":217,"line":392},[215,575,576],{"class":229},".tile__art",[215,578,488],{"class":221},[215,580,581,584,586,589],{"class":217,"line":421},[215,582,583],{"class":229},"  position",[215,585,496],{"class":221},[215,587,588],{"class":229},"relative",[215,590,533],{"class":221},[215,592,593,596,598,601],{"class":217,"line":430},[215,594,595],{"class":229},"  display",[215,597,496],{"class":221},[215,599,600],{"class":229},"grid",[215,602,533],{"class":221},[215,604,605,608,610,613],{"class":217,"line":440},[215,606,607],{"class":229},"  place-items",[215,609,496],{"class":221},[215,611,612],{"class":229},"center",[215,614,533],{"class":221},[215,616,618,621,623,626,628],{"class":217,"line":617},14,[215,619,620],{"class":229},"  height",[215,622,496],{"class":221},[215,624,625],{"class":229},"150",[215,627,503],{"class":502},[215,629,533],{"class":221},[215,631,633,635,637,639,641,644],{"class":217,"line":632},15,[215,634,550],{"class":229},[215,636,496],{"class":221},[215,638,555],{"class":229},[215,640,512],{"class":221},[215,642,643],{"class":515},"--demo-accent",[215,645,519],{"class":221},[215,647,649],{"class":217,"line":648},16,[215,650,567],{"class":221},[215,652,654,657,659,662,664,667,670,672,675,678,681,683,685,687,690],{"class":217,"line":653},17,[215,655,656],{"class":229},".tile__initials",[215,658,462],{"class":221},[215,660,661],{"class":229},"font",[215,663,496],{"class":221},[215,665,666],{"class":229},"700",[215,668,669],{"class":229}," 30",[215,671,503],{"class":502},[215,673,674],{"class":229}," sans-serif",[215,676,677],{"class":221},"; ",[215,679,680],{"class":229},"color",[215,682,496],{"class":221},[215,684,555],{"class":229},[215,686,512],{"class":221},[215,688,689],{"class":515},"--demo-bg",[215,691,692],{"class":221},"); }\n",[215,694,696],{"class":217,"line":695},18,[215,697,480],{"emptyLinePlaceholder":479},[215,699,701,704],{"class":217,"line":700},19,[215,702,703],{"class":229},".tile__foot",[215,705,488],{"class":221},[215,707,709,711,713,716],{"class":217,"line":708},20,[215,710,595],{"class":229},[215,712,496],{"class":221},[215,714,715],{"class":229},"flex",[215,717,533],{"class":221},[215,719,721,724,726,728],{"class":217,"line":720},21,[215,722,723],{"class":229},"  align-items",[215,725,496],{"class":221},[215,727,612],{"class":229},[215,729,533],{"class":221},[215,731,733,736,738,741],{"class":217,"line":732},22,[215,734,735],{"class":229},"  justify-content",[215,737,496],{"class":221},[215,739,740],{"class":229},"space-between",[215,742,533],{"class":221},[215,744,746,749,751,754,757],{"class":217,"line":745},23,[215,747,748],{"class":229},"  gap",[215,750,496],{"class":221},[215,752,753],{"class":229},".75",[215,755,756],{"class":502},"rem",[215,758,533],{"class":221},[215,760,762,765,767,769,771,774,776],{"class":217,"line":761},24,[215,763,764],{"class":229},"  padding",[215,766,496],{"class":221},[215,768,753],{"class":229},[215,770,756],{"class":502},[215,772,773],{"class":229}," 1",[215,775,756],{"class":502},[215,777,533],{"class":221},[215,779,781],{"class":217,"line":780},25,[215,782,567],{"class":221},[215,784,786,789,791,794,796,799,801,804,806,808,810,812,814,816,818,820,823],{"class":217,"line":785},26,[215,787,788],{"class":229},".tile__title",[215,790,462],{"class":221},[215,792,793],{"class":229},"margin",[215,795,496],{"class":221},[215,797,798],{"class":229},"0",[215,800,677],{"class":221},[215,802,803],{"class":229},"font-size",[215,805,496],{"class":221},[215,807,499],{"class":229},[215,809,756],{"class":502},[215,811,677],{"class":221},[215,813,680],{"class":229},[215,815,496],{"class":221},[215,817,555],{"class":229},[215,819,512],{"class":221},[215,821,822],{"class":515},"--demo-fg",[215,824,692],{"class":221},[215,826,828],{"class":217,"line":827},27,[215,829,480],{"emptyLinePlaceholder":479},[215,831,833],{"class":217,"line":832},28,[215,834,836],{"class":835},"sLBg1","\u002F* NARROW DEFAULT — the summary sits in normal flow, the CTA is a real\n",[215,838,840],{"class":217,"line":839},29,[215,841,842],{"class":835},"   tappable target, and nothing depends on a pointer that can hover. *\u002F\n",[215,844,846,849],{"class":217,"line":845},30,[215,847,848],{"class":229},".tile__summary",[215,850,488],{"class":221},[215,852,854,857,859,861],{"class":217,"line":853},31,[215,855,856],{"class":229},"  margin",[215,858,496],{"class":221},[215,860,798],{"class":229},[215,862,533],{"class":221},[215,864,866,868,870,873,875,877,879],{"class":217,"line":865},32,[215,867,764],{"class":229},[215,869,496],{"class":221},[215,871,872],{"class":229},".7",[215,874,756],{"class":502},[215,876,773],{"class":229},[215,878,756],{"class":502},[215,880,533],{"class":221},[215,882,884,887,889,891,893,896],{"class":217,"line":883},33,[215,885,886],{"class":229},"  color",[215,888,496],{"class":221},[215,890,555],{"class":229},[215,892,512],{"class":221},[215,894,895],{"class":515},"--demo-muted",[215,897,519],{"class":221},[215,899,901,904,906,909,911],{"class":217,"line":900},34,[215,902,903],{"class":229},"  font-size",[215,905,496],{"class":221},[215,907,908],{"class":229},".85",[215,910,756],{"class":502},[215,912,533],{"class":221},[215,914,916],{"class":217,"line":915},35,[215,917,567],{"class":221},[215,919,921,924],{"class":217,"line":920},36,[215,922,923],{"class":229},".tile__cta",[215,925,488],{"class":221},[215,927,929,931,933,936,938,941,943],{"class":217,"line":928},37,[215,930,764],{"class":229},[215,932,496],{"class":221},[215,934,935],{"class":229},".45",[215,937,756],{"class":502},[215,939,940],{"class":229}," .8",[215,942,756],{"class":502},[215,944,533],{"class":221},[215,946,948,950,952,954,956,958,960,962,964],{"class":217,"line":947},38,[215,949,493],{"class":229},[215,951,496],{"class":221},[215,953,499],{"class":229},[215,955,503],{"class":502},[215,957,506],{"class":229},[215,959,509],{"class":229},[215,961,512],{"class":221},[215,963,643],{"class":515},[215,965,519],{"class":221},[215,967,969,971,973,976,978],{"class":217,"line":968},39,[215,970,524],{"class":229},[215,972,496],{"class":221},[215,974,975],{"class":229},"999",[215,977,503],{"class":502},[215,979,533],{"class":221},[215,981,983,985,987,989,991,993],{"class":217,"line":982},40,[215,984,886],{"class":229},[215,986,496],{"class":221},[215,988,555],{"class":229},[215,990,512],{"class":221},[215,992,643],{"class":515},[215,994,519],{"class":221},[215,996,998,1001,1003,1005],{"class":217,"line":997},41,[215,999,1000],{"class":229},"  text-decoration",[215,1002,496],{"class":221},[215,1004,117],{"class":229},[215,1006,533],{"class":221},[215,1008,1010,1012,1014,1017,1019],{"class":217,"line":1009},42,[215,1011,903],{"class":229},[215,1013,496],{"class":221},[215,1015,1016],{"class":229},".82",[215,1018,756],{"class":502},[215,1020,533],{"class":221},[215,1022,1024,1027,1029,1032],{"class":217,"line":1023},43,[215,1025,1026],{"class":229},"  white-space",[215,1028,496],{"class":221},[215,1030,1031],{"class":229},"nowrap",[215,1033,533],{"class":221},[215,1035,1037],{"class":217,"line":1036},44,[215,1038,567],{"class":221},[215,1040,1042],{"class":217,"line":1041},45,[215,1043,480],{"emptyLinePlaceholder":479},[215,1045,1047],{"class":217,"line":1046},46,[215,1048,1049],{"class":835},"\u002F* WIDE — enough room to hide the summary behind a hover overlay. *\u002F\n",[215,1051,1053,1055],{"class":217,"line":1052},47,[215,1054,42],{"class":502},[215,1056,1057],{"class":221}," tile (min-width: 340px) {\n",[215,1059,1061,1064],{"class":217,"line":1060},48,[215,1062,1063],{"class":229},"  .tile__overlay",[215,1065,488],{"class":221},[215,1067,1069,1072,1074,1077],{"class":217,"line":1068},49,[215,1070,1071],{"class":229},"    position",[215,1073,496],{"class":221},[215,1075,1076],{"class":229},"absolute",[215,1078,533],{"class":221},[215,1080,1082,1085,1087,1089,1092,1094,1096],{"class":217,"line":1081},50,[215,1083,1084],{"class":229},"    inset",[215,1086,496],{"class":221},[215,1088,196],{"class":229},[215,1090,1091],{"class":229}," 0",[215,1093,1091],{"class":229},[215,1095,1091],{"class":229},[215,1097,533],{"class":221},[215,1099,1101,1104,1106,1109,1111,1114,1117,1120,1122,1124,1126,1129,1132,1135,1137,1140],{"class":217,"line":1100},51,[215,1102,1103],{"class":229},"    background",[215,1105,496],{"class":221},[215,1107,1108],{"class":229},"color-mix",[215,1110,512],{"class":221},[215,1112,1113],{"class":515},"in",[215,1115,1116],{"class":229}," srgb",[215,1118,1119],{"class":221},", ",[215,1121,555],{"class":229},[215,1123,512],{"class":221},[215,1125,689],{"class":515},[215,1127,1128],{"class":221},") ",[215,1130,1131],{"class":229},"88",[215,1133,1134],{"class":502},"%",[215,1136,1119],{"class":221},[215,1138,1139],{"class":229},"transparent",[215,1141,519],{"class":221},[215,1143,1145,1148,1150,1153,1155,1158,1160],{"class":217,"line":1144},52,[215,1146,1147],{"class":229},"    transform",[215,1149,496],{"class":221},[215,1151,1152],{"class":229},"translateY",[215,1154,512],{"class":221},[215,1156,1157],{"class":229},"100",[215,1159,1134],{"class":502},[215,1161,519],{"class":221},[215,1163,1165,1168,1171,1174,1177,1180,1182,1185,1188,1191,1193,1195,1197,1199],{"class":217,"line":1164},53,[215,1166,1167],{"class":229},"    transition",[215,1169,1170],{"class":221},": transform ",[215,1172,1173],{"class":229},".28",[215,1175,1176],{"class":502},"s",[215,1178,1179],{"class":229}," cubic-bezier",[215,1181,512],{"class":221},[215,1183,1184],{"class":229},".2",[215,1186,1187],{"class":221},",",[215,1189,1190],{"class":229},".8",[215,1192,1187],{"class":221},[215,1194,1184],{"class":229},[215,1196,1187],{"class":221},[215,1198,499],{"class":229},[215,1200,519],{"class":221},[215,1202,1204],{"class":217,"line":1203},54,[215,1205,1206],{"class":221},"  }\n",[215,1208,1210,1213,1216],{"class":217,"line":1209},55,[215,1211,1212],{"class":229},"  .tile:hover",[215,1214,1215],{"class":229}," .tile__overlay",[215,1217,1218],{"class":221},",\n",[215,1220,1222,1225,1227,1229,1232,1234,1236,1238,1240],{"class":217,"line":1221},56,[215,1223,1224],{"class":229},"  .tile:focus-within",[215,1226,1215],{"class":229},[215,1228,462],{"class":221},[215,1230,1231],{"class":229},"transform",[215,1233,496],{"class":221},[215,1235,1152],{"class":229},[215,1237,512],{"class":221},[215,1239,798],{"class":229},[215,1241,692],{"class":221},[215,1243,1245],{"class":217,"line":1244},57,[215,1246,567],{"class":221},[215,1248,1250],{"class":217,"line":1249},58,[215,1251,480],{"emptyLinePlaceholder":479},[215,1253,1255,1258],{"class":217,"line":1254},59,[215,1256,1257],{"class":502},"@media",[215,1259,1260],{"class":221}," (prefers-reduced-motion: reduce) {\n",[215,1262,1264,1266,1268,1271,1273,1275],{"class":217,"line":1263},60,[215,1265,1063],{"class":229},[215,1267,462],{"class":221},[215,1269,1270],{"class":229},"transition",[215,1272,496],{"class":221},[215,1274,117],{"class":229},[215,1276,1277],{"class":221},"; }\n",[215,1279,1281],{"class":217,"line":1280},61,[215,1282,567],{"class":221},[1284,1285,1286],"blockquote",{},[14,1287,1288,1289,1292],{},"The ",[40,1290,1291],{},"--demo-*"," values above are the theme variables supplied by the demo frame, so the\nexample follows light and dark mode here. Substitute your own colour tokens when you\ncopy it.",[14,1294,1295,1296,1299,1300,1303],{},"Notice what is ",[18,1297,1298],{},"not"," in the narrow branch: there is no ",[40,1301,1302],{},"@container (max-width: 339px)"," block anywhere. The narrow variant is the base cascade, and the wide variant is additive. That inversion is deliberate and is discussed below.",[29,1305],{},[32,1307,1309],{"id":1308},"the-key-technique-hiding-is-the-enhancement-showing-is-the-default","The key technique: hiding is the enhancement, showing is the default",[14,1311,1312,1313,1316,1317,1320,1321,1324,1325,1328,1329,1331],{},"The instinct is to write the rich version first — overlay absolutely positioned, translated out of view — and then add a ",[40,1314,1315],{},"max-width"," query that un-hides it for narrow containers. Do that and every failure mode becomes a functional one. An engine that does not support container queries ignores ",[18,1318,1319],{},"both"," blocks, leaving the summary parked at ",[40,1322,1323],{},"translateY(100%)"," under ",[40,1326,1327],{},"overflow: hidden",", permanently invisible with no way to retrieve it. A typo in the container name produces the same result. So does a stylesheet that loads before the container's ",[40,1330,465],{}," is applied by a later rule.",[14,1333,1334,1335,1339],{},"Writing it the other way round makes every one of those failures cosmetic. If the query never matches — unsupported engine, wrong name, no container established — the reader gets a tile with a visible summary and a visible button. That is a less elegant component, not a broken one. This is the same progressive-enhancement ordering used for layout fallbacks in ",[23,1336,1338],{"href":1337},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Fhandling-container-query-fallbacks-for-older-browsers\u002F","handling container query fallbacks for older browsers",", applied to interaction instead of geometry: put the guaranteed-functional state in the cascade's base, and let the query add capability rather than restore it.",[14,1341,1342,1343,1346,1347,1350,1351,1354,1355,1359],{},"The second half of the technique is ",[40,1344,1345],{},":focus-within",". The reveal selector lists ",[40,1348,1349],{},".tile:hover"," and ",[40,1352,1353],{},".tile:focus-within"," together, so a keyboard user tabbing to a link inside the overlay brings the overlay up. Omit it and the focused control keeps its focus ring, but the ring is drawn inside a box that has been translated out of the visible area — a WCAG 2.4.11 focus-visibility failure that is invisible during mouse testing and only appears when someone actually tabs the page. The broader pattern of driving container state from descendant focus is developed in ",[23,1356,1358],{"href":1357},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Ffocus-within-form-patterns\u002F","focus-within form patterns",".",[29,1361],{},[32,1363,1365],{"id":1364},"variation-adding-the-input-capability-condition","Variation: adding the input-capability condition",[14,1367,1368,1369,1372],{},"Container width and hover capability are separate axes, and on a wide touchscreen you want the narrow behaviour despite the width. Nesting the pointer media query inside the container query expresses that precisely: hide only when there is room ",[18,1370,1371],{},"and"," the pointer can hover.",[206,1374,1376],{"className":450,"code":1375,"language":452,"meta":211,"style":211},"@container tile (min-width: 340px) {\n  \u002F* Only devices with a hovering, precise pointer get the hidden overlay. *\u002F\n  @media (hover: hover) and (pointer: fine) {\n    .tile__overlay {\n      position: absolute;\n      inset: auto 0 0 0;\n      transform: translateY(100%);\n      transition: transform .28s cubic-bezier(.2, .8, .2, 1);\n    }\n    .tile:hover .tile__overlay,\n    .tile:focus-within .tile__overlay { transform: translateY(0); }\n  }\n}\n\n\u002F* A coarse pointer keeps the persistent control, and gets a target\n   large enough to hit reliably. *\u002F\n@media (pointer: coarse) {\n  .tile__cta { min-block-size: 44px; display: inline-flex; align-items: center; }\n}\n",[40,1377,1378,1384,1389,1411,1418,1429,1446,1463,1494,1499,1508,1529,1533,1537,1541,1546,1551,1558,1596],{"__ignoreMap":211},[215,1379,1380,1382],{"class":217,"line":218},[215,1381,42],{"class":502},[215,1383,1057],{"class":221},[215,1385,1386],{"class":217,"line":243},[215,1387,1388],{"class":835},"  \u002F* Only devices with a hovering, precise pointer get the hidden overlay. *\u002F\n",[215,1390,1391,1394,1397,1400,1402,1404,1406,1408],{"class":217,"line":261},[215,1392,1393],{"class":502},"  @media",[215,1395,1396],{"class":221}," (",[215,1398,1399],{"class":229},"hover",[215,1401,496],{"class":221},[215,1403,1399],{"class":229},[215,1405,1128],{"class":221},[215,1407,1371],{"class":502},[215,1409,1410],{"class":221}," (pointer: fine) {\n",[215,1412,1413,1416],{"class":217,"line":295},[215,1414,1415],{"class":229},"    .tile__overlay",[215,1417,488],{"class":221},[215,1419,1420,1423,1425,1427],{"class":217,"line":312},[215,1421,1422],{"class":229},"      position",[215,1424,496],{"class":221},[215,1426,1076],{"class":229},[215,1428,533],{"class":221},[215,1430,1431,1434,1436,1438,1440,1442,1444],{"class":217,"line":334},[215,1432,1433],{"class":229},"      inset",[215,1435,496],{"class":221},[215,1437,196],{"class":229},[215,1439,1091],{"class":229},[215,1441,1091],{"class":229},[215,1443,1091],{"class":229},[215,1445,533],{"class":221},[215,1447,1448,1451,1453,1455,1457,1459,1461],{"class":217,"line":344},[215,1449,1450],{"class":229},"      transform",[215,1452,496],{"class":221},[215,1454,1152],{"class":229},[215,1456,512],{"class":221},[215,1458,1157],{"class":229},[215,1460,1134],{"class":502},[215,1462,519],{"class":221},[215,1464,1465,1468,1470,1472,1474,1476,1478,1480,1482,1484,1486,1488,1490,1492],{"class":217,"line":354},[215,1466,1467],{"class":229},"      transition",[215,1469,1170],{"class":221},[215,1471,1173],{"class":229},[215,1473,1176],{"class":502},[215,1475,1179],{"class":229},[215,1477,512],{"class":221},[215,1479,1184],{"class":229},[215,1481,1119],{"class":221},[215,1483,1190],{"class":229},[215,1485,1119],{"class":221},[215,1487,1184],{"class":229},[215,1489,1119],{"class":221},[215,1491,499],{"class":229},[215,1493,519],{"class":221},[215,1495,1496],{"class":217,"line":370},[215,1497,1498],{"class":221},"    }\n",[215,1500,1501,1504,1506],{"class":217,"line":392},[215,1502,1503],{"class":229},"    .tile:hover",[215,1505,1215],{"class":229},[215,1507,1218],{"class":221},[215,1509,1510,1513,1515,1517,1519,1521,1523,1525,1527],{"class":217,"line":421},[215,1511,1512],{"class":229},"    .tile:focus-within",[215,1514,1215],{"class":229},[215,1516,462],{"class":221},[215,1518,1231],{"class":229},[215,1520,496],{"class":221},[215,1522,1152],{"class":229},[215,1524,512],{"class":221},[215,1526,798],{"class":229},[215,1528,692],{"class":221},[215,1530,1531],{"class":217,"line":430},[215,1532,1206],{"class":221},[215,1534,1535],{"class":217,"line":440},[215,1536,567],{"class":221},[215,1538,1539],{"class":217,"line":617},[215,1540,480],{"emptyLinePlaceholder":479},[215,1542,1543],{"class":217,"line":632},[215,1544,1545],{"class":835},"\u002F* A coarse pointer keeps the persistent control, and gets a target\n",[215,1547,1548],{"class":217,"line":648},[215,1549,1550],{"class":835},"   large enough to hit reliably. *\u002F\n",[215,1552,1553,1555],{"class":217,"line":653},[215,1554,1257],{"class":502},[215,1556,1557],{"class":221}," (pointer: coarse) {\n",[215,1559,1560,1563,1565,1568,1570,1573,1575,1577,1580,1582,1585,1587,1590,1592,1594],{"class":217,"line":695},[215,1561,1562],{"class":229},"  .tile__cta",[215,1564,462],{"class":221},[215,1566,1567],{"class":229},"min-block-size",[215,1569,496],{"class":221},[215,1571,1572],{"class":229},"44",[215,1574,503],{"class":502},[215,1576,677],{"class":221},[215,1578,1579],{"class":229},"display",[215,1581,496],{"class":221},[215,1583,1584],{"class":229},"inline-flex",[215,1586,677],{"class":221},[215,1588,1589],{"class":229},"align-items",[215,1591,496],{"class":221},[215,1593,612],{"class":229},[215,1595,1277],{"class":221},[215,1597,1598],{"class":217,"line":700},[215,1599,567],{"class":221},[14,1601,1602,1603,1607],{},"The 44px minimum is not arbitrary padding — it is the target size floor discussed in ",[23,1604,1606],{"href":1605},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Ftarget-size-and-pointer-accessibility\u002F","target size and pointer accessibility",", and it matters most in exactly the case this page creates: a persistent control in a narrow component, where the temptation to shrink it to fit is strongest.",[29,1609],{},[32,1611,1613],{"id":1612},"browser-support","Browser support",[14,1615,1616,1617,1619,1620,1350,1622,1625,1626,1629,1630,1633,1634,1637],{},"Every mechanism here is broadly interoperable. Size container queries are available in Chrome and Edge 105+, Safari 16+, and Firefox 110+. ",[40,1618,1345],{}," is older and universal across evergreen engines. The ",[40,1621,1399],{},[40,1623,1624],{},"pointer"," media features have shipped everywhere relevant for years. The one newer convenience is ",[40,1627,1628],{},"color-mix()",", used for the overlay backdrop, which needs Chrome and Edge 111+, Safari 16.2+, and Firefox 113+; swap it for a plain ",[40,1631,1632],{},"rgb(… \u002F .88)"," value if you support older builds, since it is purely cosmetic. Because the persistent variant is the cascade default, no ",[40,1635,1636],{},"@supports"," gate is required — an engine that understands none of the query syntax renders the fully usable narrow layout at every width.",[29,1639],{},[32,1641,1643],{"id":1642},"faq","FAQ",[14,1645,1646,1650],{},[1647,1648,1649],"strong",{},"Why change the affordance instead of just shrinking the hover panel?","\nA smaller hover panel is still a hover panel, so it still fails for touch users and still hides the function behind a pointer gesture. Below a certain width there is no room for a reveal that does not cover the content it belongs to, so the correct answer is a control that is simply always visible.",[14,1652,1653,1656,1657,1350,1659,1661],{},[1647,1654,1655],{},"Does a container query know whether the device supports hover?","\nNo. Container queries measure space only. Pair them with the ",[40,1658,1624],{},[40,1660,1399],{}," media features, which describe the input device, and treat the two as independent conditions that both have to be satisfied before hiding anything behind hover.",[14,1663,1664,1667,1668,1670,1671,1674],{},[1647,1665,1666],{},"How do I keep keyboard users from losing a hover-revealed control?","\nAdd ",[40,1669,1345],{}," alongside ",[40,1672,1673],{},":hover"," on every reveal selector so tabbing into the hidden element opens the container. Without it the focused control stays inside a clipped or zero-height box and the focus indicator is invisible.",[14,1676,1677,1680],{},[1647,1678,1679],{},"Which variant should be the default in the stylesheet?","\nThe always-visible one. Write the persistent control as the base style and add the hover reveal inside the container query, so any engine that does not evaluate the query still renders a fully functional component rather than a permanently hidden one.",[29,1682],{},[32,1684,1686],{"id":1685},"related","Related",[1688,1689,1690,1697,1704,1711,1717],"ul",{},[1691,1692,1693,1696],"li",{},[23,1694,1695],{"href":25},"Container-Aware Motion"," — the parent section on motion sized to the component's own box.",[1691,1698,1699,1703],{},[23,1700,1702],{"href":1701},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fmotion-that-scales-with-container-size\u002F","Motion That Scales with Container Size"," — the continuous counterpart to this page's discrete switch.",[1691,1705,1706,1710],{},[23,1707,1709],{"href":1708},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Fsmooth-hover-effects-without-javascript\u002F","Smooth Hover Effects Without JavaScript"," — the hover-state craft this pattern chooses when to apply.",[1691,1712,1713,1716],{},[23,1714,1715],{"href":64},"Pointer and Hover Media Queries"," — detecting input capability as a separate axis from space.",[1691,1718,1719,1723],{},[23,1720,1722],{"href":1721},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fbuilding-responsive-cards-with-container-queries\u002F","Building Responsive Cards with Container Queries"," — the cross-area layout work behind the same component.",[1725,1726,1727],"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 .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}html pre.shiki code .sLBg1, html code.shiki .sLBg1{--shiki-default:#66707B;--shiki-dark:#BDC4CC}",{"title":211,"searchDepth":243,"depth":243,"links":1729},[1730,1731,1732,1733,1734,1735,1736],{"id":34,"depth":243,"text":35},{"id":77,"depth":243,"text":78},{"id":1308,"depth":243,"text":1309},{"id":1364,"depth":243,"text":1365},{"id":1612,"depth":243,"text":1613},{"id":1642,"depth":243,"text":1643},{"id":1685,"depth":243,"text":1686},"Swap a hover-to-reveal panel for a persistent, always-visible control when a component is narrow, using @container so the affordance itself changes with space.","md",{"pageTitle":1740,"datePublished":1741,"dateModified":1741,"faq":1742},"Container Query Hover Affordances","2026-07-20",[1743,1745,1747,1749],{"q":1649,"a":1744},"A smaller hover panel is still a hover panel, so it still fails for touch users and still hides the function behind a pointer gesture. Below a certain width there is no room for a reveal that does not cover the content it belongs to, so the correct answer is a control that is simply always visible.",{"q":1655,"a":1746},"No. Container queries measure space only. Pair them with the pointer and hover media features, which describe the input device, and treat the two as independent conditions that both have to be satisfied before hiding anything behind hover.",{"q":1666,"a":1748},"Add :focus-within alongside :hover on every reveal selector so tabbing into the hidden element opens the container. Without it the focused control stays inside a clipped or zero-height box and the focus indicator is invisible.",{"q":1679,"a":1750},"The always-visible one. Write the persistent control as the base style and add the hover reveal inside the container query, so any engine that does not evaluate the query still renders a fully functional component rather than a permanently hidden one.","\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fcontainer-query-hover-affordances",{"title":5,"description":1737},"css-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fcontainer-query-hover-affordances\u002Findex","8WnVQtdueYqL_9a8N7LPsJlLxj7AN8j6DIU2AuNluEA",[1756,1759,1762,1765,1768,1771,1774,1777,1778,1781,1784,1787,1790,1793,1796,1799,1802,1805,1808,1811,1814,1817,1820,1823,1826,1829,1832,1835,1838,1841,1844,1847,1850,1853,1856,1859,1862,1865,1868,1871,1874,1877,1880,1883,1886,1889,1892,1895,1898,1901,1904,1907,1910,1913,1916,1919,1922,1925,1928,1931,1934,1937,1940,1943,1946,1949,1952,1955,1958,1961,1964,1967,1970,1973,1976,1979,1982,1985,1988,1991,1994,1997,2000,2003,2006,2009,2012,2015],{"path":1757,"title":1758},"\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":1760,"title":1761},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations","Accessibility in CSS Animations: Patterns, Specs & Best Practices",{"path":1763,"title":1764},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fprefers-reduced-motion-recipes","prefers-reduced-motion Recipes: A Reduction for Every Common Effect",{"path":1766,"title":1767},"\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":1769,"title":1770},"\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":1772,"title":1773},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fvestibular-safe-animation-patterns","Vestibular-Safe Animation Patterns: Why Some Motion Makes People Sick",{"path":1775,"title":1776},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fwcag-motion-success-criteria","WCAG Motion Success Criteria: What Each One Actually Requires",{"path":1751,"title":5},{"path":1779,"title":1780},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion","Container-Aware Motion: Animation Sized by the Space a Component Actually Has",{"path":1782,"title":1783},"\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":1785,"title":1786},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fsuppressing-motion-in-small-containers","Suppressing Motion in Small Containers: Deliberately Animating Nothing",{"path":1788,"title":1789},"\u002Fcss-only-micro-interactions-animations\u002Fcss-animation-vs-web-animations-api","CSS Animation vs the Web Animations API: A Decision Guide",{"path":1791,"title":1792},"\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":1794,"title":1795},"\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":1797,"title":1798},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Ffluid-spacing-tokens-driving-transition-durations","Fluid Spacing Tokens That Drive Transition Durations",{"path":1800,"title":1801},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture","CSS Custom Properties Architecture: Scalable Design Systems & Dynamic UI",{"path":1803,"title":1804},"\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":1806,"title":1807},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fcss-transition-timing-functions","CSS Transition Timing Functions: ease, cubic-bezier(), steps() and linear()",{"path":1809,"title":1810},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals","CSS Transition Fundamentals: Architecture, Performance & Patterns",{"path":1812,"title":1813},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fstarting-style-entry-animations","@starting-style: Animating an Element's Very First Style Change",{"path":1815,"title":1816},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Ftransitioning-display-with-allow-discrete","Transitioning display with transition-behavior: allow-discrete and @starting-style",{"path":1818,"title":1819},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Faccessible-css-only-tooltips","Accessible CSS-Only Tooltips and Hover Cards With  and ",{"path":1821,"title":1822},"\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":1824,"title":1825},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Ffocus-within-form-patterns"," Form Patterns: Styling a Group From the Field Inside It",{"path":1827,"title":1828},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design","Hover & Focus State Design: Spec-Compliant Patterns for Modern UIs",{"path":1830,"title":1831},"\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":1833,"title":1834},"\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":1836,"title":1837},"\u002Fcss-only-micro-interactions-animations","CSS-Only Micro-Interactions & Animations: Architecture, Performance & Implementation",{"path":1839,"title":1840},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcontainer-query-triggered-keyframe-animations","Container-Query-Triggered Keyframe Animations: Animate Differently per Available Space",{"path":1842,"title":1843},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcss-only-accordions-and-disclosure","CSS-Only Accordions and Disclosure Widgets with details and summary",{"path":1845,"title":1846},"\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":1848,"title":1849},"\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":1851,"title":1852},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns","Keyframe Animation Patterns: Spec-Compliant Architectures for Modern UIs",{"path":1854,"title":1855},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fstaggered-list-animations-with-custom-properties","Staggered List Animations Using --i Index Custom Properties",{"path":1857,"title":1858},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration","Performance & GPU Acceleration in CSS: A Developer’s Blueprint",{"path":1860,"title":1861},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Foptimizing-css-animations-for-60fps","Optimizing CSS Animations for 60fps: Budgeting the Frame",{"path":1863,"title":1864},"\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":1866,"title":1867},"\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":1869,"title":1870},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations","Scroll-Driven Animations: Binding Motion to Scroll Position in Pure CSS",{"path":1872,"title":1873},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-driven-animation-fallbacks","Shipping Scroll-Driven Animations Without Breaking Anything",{"path":1875,"title":1876},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-progress-bar-without-javascript","A Reading Progress Bar Driven by scroll(root)",{"path":1878,"title":1879},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-triggered-reveal-animations","Reveal-on-Scroll with view() and animation-range",{"path":1881,"title":1882},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers","View Transitions for CSS Developers: the Pseudo-Element Tree, Snapshots, and Named Elements",{"path":1884,"title":1885},"\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":1887,"title":1888},"\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":1890,"title":1891},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fview-transitions-with-reduced-motion","Honouring prefers-reduced-motion in View Transitions",{"path":1893,"title":1894},"\u002F","Modern CSS Layouts & Micro-Interactions",{"path":1896,"title":1897},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioned-tooltips","Anchor-Positioned Tooltips: Tethering, Flipping, and Getting the Semantics Right",{"path":1899,"title":1900},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioning-fallbacks","Anchor Positioning Fallbacks: A Graceful Floor for Older Browser Versions",{"path":1902,"title":1903},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays","CSS Anchor Positioning and Overlays: Tethering Elements Without JavaScript",{"path":1905,"title":1906},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fpopover-attribute-and-css-styling","The popover Attribute: Top-Layer Overlays With No JavaScript",{"path":1908,"title":1909},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Ffeature-detection-with-supports","Feature Detection with @supports: Syntax, Semantics, and the Traps",{"path":1911,"title":1912},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Fhandling-container-query-fallbacks-for-older-browsers","Handling Container Query Fallbacks for Older Browsers",{"path":1914,"title":1915},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks","Container Query Fallbacks: Spec-Compliant CSS Strategies for Legacy Browsers",{"path":1917,"title":1918},"\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":1920,"title":1921},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-type-size-vs-inline-size","Choosing container-type: inline-size, size, or normal",{"path":1923,"title":1924},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-vs-media-queries-comparison","Container vs Media Queries: Choosing the Right Reference Box",{"path":1926,"title":1927},"\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":1929,"title":1930},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics","Container Query Syntax Basics",{"path":1932,"title":1933},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fnesting-and-naming-container-queries","Nesting and Naming Container Queries: Targeting the Right Ancestor",{"path":1935,"title":1936},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fauto-fit-minmax-responsive-grids","Responsive Grids with repeat(auto-fit, minmax())",{"path":1938,"title":1939},"\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":1941,"title":1942},"\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":1944,"title":1945},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts","CSS Grid and Subgrid Layouts for Responsive Interfaces",{"path":1947,"title":1948},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fsubgrid-vs-nested-grid","Subgrid vs an Independently Nested Grid",{"path":1950,"title":1951},"\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":1953,"title":1954},"\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":1956,"title":1957},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-type-accessibility-and-zoom","Fluid Type, Accessibility and Zoom: The vw-Only Trap",{"path":1959,"title":1960},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-typography-without-javascript","Fluid Typography Without JavaScript: A Precision CSS Reference",{"path":1962,"title":1963},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp","Fluid Typography with clamp(): A Practical Guide for Modern CSS",{"path":1965,"title":1966},"\u002Fmastering-container-queries-responsive-layouts","Mastering Container Queries & Responsive Layouts",{"path":1968,"title":1969},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Faspect-ratio-for-responsive-media","Using aspect-ratio for Responsive Media and Preventing Layout Shift",{"path":1971,"title":1972},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques","Intrinsic Sizing Techniques: Modern CSS Layouts for Responsive UI",{"path":1974,"title":1975},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fmin-max-fit-content-explained","min-content, max-content, and fit-content() Explained",{"path":1977,"title":1978},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fpreventing-flex-and-grid-overflow","The min-width: auto Trap in Flex and Grid Layouts",{"path":1980,"title":1981},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-for-reset-and-tokens","Cascade Layers for Reset and Design Tokens",{"path":1983,"title":1984},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-vs-specificity-hacks","Cascade Layers vs Specificity Hacks: Ordering Instead of Escalating",{"path":1986,"title":1987},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies","Modern CSS Reset Strategies: A Spec-Compliant Foundation",{"path":1989,"title":1990},"\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":1992,"title":1993},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fcontainer-query-data-tables","Container Query Data Tables: Reflowing Tables to Cards",{"path":1995,"title":1996},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fcontainer-query-sidebar-layouts","Container Query Sidebar Layouts That Travel Between Contexts",{"path":1998,"title":1999},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns","Responsive Component Patterns: Architecture & Implementation",{"path":2001,"title":2002},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-forms-with-container-queries","Responsive Forms with Container Queries: Reflow Without Losing the Wiring",{"path":2004,"title":2005},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-navigation-without-media-queries","Responsive Navigation Without Media Queries Using Container Queries",{"path":2007,"title":2008},"\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":2010,"title":2011},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state","Style Queries and Container State: Token-Driven Component Variants",{"path":2013,"title":2014},"\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":2016,"title":2017},"\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",1784566157491]