[{"data":1,"prerenderedAt":1807},["ShallowReactive",2],{"page-\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fpopover-attribute-and-css-styling\u002F":3,"content-all-pages":1544},{"id":4,"title":5,"body":6,"description":1525,"extension":1526,"meta":1527,"navigation":375,"path":1540,"seo":1541,"stem":1542,"__hash__":1543},"content\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fpopover-attribute-and-css-styling\u002Findex.md","The popover Attribute: Top-Layer Overlays With No JavaScript",{"type":7,"value":8,"toc":1514},"minimark",[9,13,58,63,66,132,138,141,156,160,167,272,292,316,320,326,330,506,1126,1152,1159,1164,1171,1177,1187,1191,1194,1265,1277,1284,1385,1389,1410,1414,1429,1446,1458,1470,1474,1510],[10,11,5],"h1",{"id":12},"the-popover-attribute-top-layer-overlays-with-no-javascript",[14,15,16,17,21,22,26,27,30,31,35,36,39,40,45,46,49,50,53,54,57],"p",{},"Overlay components have a reputation for being the buggiest thing in any component library, and the reputation is earned. A dropdown clipped by an ancestor's ",[18,19,20],"code",{},"overflow: hidden",". A modal that sits ",[23,24,25],"em",{},"behind"," a sticky header because a parent created a stacking context. An outside-click handler bound to ",[18,28,29],{},"document"," that fights with a stopPropagation call three components away. An ",[32,33,34],"kbd",{},"Escape"," listener that closes two panels at once. None of that is essential complexity — it is all consequence of building overlays inside the normal document. The ",[18,37,38],{},"popover"," attribute moves them out of it. This page, part of the ",[41,42,44],"a",{"href":43},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002F","CSS anchor positioning and overlays"," section, covers what the attribute gives you for free, how ",[18,47,48],{},"::backdrop"," works, and how to animate entry and exit with ",[18,51,52],{},"@starting-style"," and ",[18,55,56],{},"transition-behavior: allow-discrete"," — all in HTML and CSS, with no script anywhere.",[59,60,62],"h2",{"id":61},"why-this-instead-of-a-hand-rolled-overlay","Why this instead of a hand-rolled overlay",[14,64,65],{},"Two attributes replace a component's worth of behaviour:",[67,68,73],"pre",{"className":69,"code":70,"language":71,"meta":72,"style":72},"language-html shiki shiki-themes github-light-high-contrast github-dark-high-contrast","\u003Cbutton popovertarget=\"panel\">Open\u003C\u002Fbutton>\n\u003Cdiv id=\"panel\" popover>Hello\u003C\u002Fdiv>\n","html","",[18,74,75,107],{"__ignoreMap":72},[76,77,80,84,88,92,95,99,102,104],"span",{"class":78,"line":79},"line",1,[76,81,83],{"class":82},"suds8","\u003C",[76,85,87],{"class":86},"sne4z","button",[76,89,91],{"class":90},"s-5SL"," popovertarget",[76,93,94],{"class":82},"=",[76,96,98],{"class":97},"sT6z2","\"panel\"",[76,100,101],{"class":82},">Open\u003C\u002F",[76,103,87],{"class":86},[76,105,106],{"class":82},">\n",[76,108,110,112,115,118,120,122,125,128,130],{"class":78,"line":109},2,[76,111,83],{"class":82},[76,113,114],{"class":86},"div",[76,116,117],{"class":90}," id",[76,119,94],{"class":82},[76,121,98],{"class":97},[76,123,124],{"class":90}," popover",[76,126,127],{"class":82},">Hello\u003C\u002F",[76,129,114],{"class":86},[76,131,106],{"class":82},[14,133,134,135,137],{},"That markup already gives you a toggle button, an element promoted to the top layer when shown, light dismiss on an outside click, close on ",[32,136,34],{},", focus returned to the invoking button on close, and an implicit relationship between the button and the panel exposed to assistive technology. It also gives you correct behaviour in cases people usually forget: opening a second popover closes the first, unless the second is nested inside it; and the browser's dismissal handling knows about the top-layer stack, so nested popovers unwind one level at a time rather than all at once.",[14,139,140],{},"The reason to prefer this to a bespoke implementation is not that the code is shorter. It is that the tricky parts are handled by the same engine that owns focus, the stacking order, and the event loop. An outside-click handler in JavaScript is an approximation of light dismiss; the browser's version is the definition of it.",[14,142,143,144,147,148,151,152,155],{},"When ",[23,145,146],{},"not"," to use it: anything requiring a decision before the user proceeds. Popovers are non-modal by design — content behind them remains interactive and focus is not trapped. For a confirmation prompt or a blocking form, use ",[18,149,150],{},"\u003Cdialog>"," with ",[18,153,154],{},"showModal()",", which does trap focus and marks the rest of the page inert.",[59,157,159],{"id":158},"the-three-states-and-the-two-discrete-properties","The three states, and the two discrete properties",[14,161,162,163,166],{},"Everything about styling a popover follows from one fact: a hidden popover is ",[18,164,165],{},"display: none",". It is not transparent, not scaled to zero, not moved off-screen — it does not generate a box at all. That is what makes it cheap and what makes animating it awkward, because there is no box to animate from.",[168,169,175,176,175,180,175,184,175,191,175,203,175,208,175,213,175,218,175,221,175,225,175,229,175,233,175,236,175,239,175,243,175,246,175,250,175,252,175,255,175,261,175,267],"svg",{"viewBox":170,"role":171,"ariaLabel":172,"xmlns":173,"style":174},"0 0 720 300","img","A popover moves from display none through a starting-style frame to the open state, then back out over a discrete transition","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;height:auto;max-width:720px;margin:2rem 0","\n  ",[177,178,179],"title",{},"Popover lifecycle across the discrete boundary",[181,182,183],"desc",{},"Four stages: hidden with display none, the starting-style frame, the open state in the top layer, and the exit kept alive by allow-discrete.",[185,186,190],"text",{"x":187,"y":188,"style":189},"360","30","text-anchor:middle;fill:currentColor;font:700 17px sans-serif","Where each CSS feature acts in the lifecycle",[192,193],"rect",{"x":194,"y":195,"width":196,"height":197,"rx":198,"fill":199,"stroke":200,"strokeWidth":201,"opacity":202},"25","76","160","96","9","none","currentColor","1.5","0.5",[185,204,165],{"x":205,"y":206,"style":207},"105","112","text-anchor:middle;fill:currentColor;font:12px ui-monospace,monospace",[185,209,212],{"x":205,"y":210,"style":211},"140","text-anchor:middle;fill:currentColor;font:11px sans-serif;opacity:0.7","closed, no box",[192,214],{"x":215,"y":195,"width":196,"height":197,"rx":198,"fill":216,"opacity":217},"200","#7aa2ff","0.18",[185,219,52],{"x":220,"y":206,"style":207},"280",[185,222,224],{"x":220,"y":210,"style":223},"text-anchor:middle;fill:currentColor;font:11px sans-serif;opacity:0.75","the first frame",[192,226],{"x":227,"y":195,"width":196,"height":197,"rx":198,"fill":216,"opacity":228},"375","0.32",[185,230,232],{"x":231,"y":206,"style":207},"455",":popover-open",[185,234,235],{"x":231,"y":210,"style":223},"top layer",[192,237],{"x":238,"y":195,"width":196,"height":197,"rx":198,"fill":216,"opacity":217},"550",[185,240,242],{"x":241,"y":206,"style":207},"630","allow-discrete",[185,244,245],{"x":241,"y":210,"style":223},"exit kept alive",[78,247],{"x1":248,"y1":249,"x2":215,"y2":249,"stroke":200,"strokeWidth":201},"185","124",[78,251],{"x1":187,"y1":249,"x2":227,"y2":249,"stroke":200,"strokeWidth":201},[78,253],{"x1":254,"y1":249,"x2":238,"y2":249,"stroke":200,"strokeWidth":201},"535",[192,256],{"x":194,"y":215,"width":257,"height":258,"rx":259,"fill":216,"opacity":260},"685","34","6","0.12",[185,262,266],{"x":263,"y":264,"style":265},"367","222","text-anchor:middle;fill:currentColor;font:12px sans-serif","::backdrop paints beneath the element for the whole open period",[185,268,271],{"x":187,"y":269,"style":270},"268","text-anchor:middle;fill:currentColor;font:12px sans-serif;opacity:0.7","display and overlay are discrete; both need allow-discrete to survive the exit",[14,273,274,275,277,278,53,281,284,285,288,289,291],{},"The open state is selectable with ",[18,276,232],{},", which matches only while the element is showing. The two properties that change across the boundary — ",[18,279,280],{},"display",[18,282,283],{},"overlay"," — are ",[23,286,287],{},"discrete",": they have no intermediate values, so by default they flip at the very start of a transition. That is fine going in and catastrophic coming out, because on close the element hits ",[18,290,165],{}," on frame one and there is nothing left to fade.",[14,293,294,296,297,300,301,303,304,306,307,309,310,312,313,315],{},[18,295,56],{}," changes the flip point for those properties to the ",[23,298,299],{},"end"," of the transition instead of the start. ",[18,302,52],{}," supplies the missing \"before\" value for the entry, since an element appearing from ",[18,305,165],{}," has no previous computed style to interpolate from. You need both, and you need ",[18,308,283],{}," in the list as well as ",[18,311,280],{}," — ",[18,314,283],{}," is the property that represents top-layer membership, and if it is left out the panel drops behind other content the instant it starts closing.",[59,317,319],{"id":318},"complete-working-implementation","Complete working implementation",[14,321,322,323,325],{},"Open the panel below, then click outside it or press ",[32,324,34],{},". Nothing in the frame is scripted.",[327,328],"live-demo",{"name":329},"anchor-popover-backdrop",[67,331,333],{"className":69,"code":332,"language":71,"meta":72,"style":72},"\u003Cbutton type=\"button\" popovertarget=\"menu\" class=\"pop-btn\">Open panel\u003C\u002Fbutton>\n\n\u003Cdiv id=\"menu\" popover class=\"pop\">\n  \u003Ch3 class=\"pop__title\">Export\u003C\u002Fh3>\n  \u003Cp class=\"pop__body\">Click anywhere outside this panel, or press Escape, to dismiss it.\u003C\u002Fp>\n  \u003Cbutton type=\"button\" popovertarget=\"menu\" popovertargetaction=\"hide\" class=\"pop-btn\">\n    Close\n  \u003C\u002Fbutton>\n\u003C\u002Fdiv>\n",[18,334,335,371,377,401,424,445,480,486,496],{"__ignoreMap":72},[76,336,337,339,341,344,346,349,351,353,356,359,361,364,367,369],{"class":78,"line":79},[76,338,83],{"class":82},[76,340,87],{"class":86},[76,342,343],{"class":90}," type",[76,345,94],{"class":82},[76,347,348],{"class":97},"\"button\"",[76,350,91],{"class":90},[76,352,94],{"class":82},[76,354,355],{"class":97},"\"menu\"",[76,357,358],{"class":90}," class",[76,360,94],{"class":82},[76,362,363],{"class":97},"\"pop-btn\"",[76,365,366],{"class":82},">Open panel\u003C\u002F",[76,368,87],{"class":86},[76,370,106],{"class":82},[76,372,373],{"class":78,"line":109},[76,374,376],{"emptyLinePlaceholder":375},true,"\n",[76,378,380,382,384,386,388,390,392,394,396,399],{"class":78,"line":379},3,[76,381,83],{"class":82},[76,383,114],{"class":86},[76,385,117],{"class":90},[76,387,94],{"class":82},[76,389,355],{"class":97},[76,391,124],{"class":90},[76,393,358],{"class":90},[76,395,94],{"class":82},[76,397,398],{"class":97},"\"pop\"",[76,400,106],{"class":82},[76,402,404,407,410,412,414,417,420,422],{"class":78,"line":403},4,[76,405,406],{"class":82},"  \u003C",[76,408,409],{"class":86},"h3",[76,411,358],{"class":90},[76,413,94],{"class":82},[76,415,416],{"class":97},"\"pop__title\"",[76,418,419],{"class":82},">Export\u003C\u002F",[76,421,409],{"class":86},[76,423,106],{"class":82},[76,425,427,429,431,433,435,438,441,443],{"class":78,"line":426},5,[76,428,406],{"class":82},[76,430,14],{"class":86},[76,432,358],{"class":90},[76,434,94],{"class":82},[76,436,437],{"class":97},"\"pop__body\"",[76,439,440],{"class":82},">Click anywhere outside this panel, or press Escape, to dismiss it.\u003C\u002F",[76,442,14],{"class":86},[76,444,106],{"class":82},[76,446,448,450,452,454,456,458,460,462,464,467,469,472,474,476,478],{"class":78,"line":447},6,[76,449,406],{"class":82},[76,451,87],{"class":86},[76,453,343],{"class":90},[76,455,94],{"class":82},[76,457,348],{"class":97},[76,459,91],{"class":90},[76,461,94],{"class":82},[76,463,355],{"class":97},[76,465,466],{"class":90}," popovertargetaction",[76,468,94],{"class":82},[76,470,471],{"class":97},"\"hide\"",[76,473,358],{"class":90},[76,475,94],{"class":82},[76,477,363],{"class":97},[76,479,106],{"class":82},[76,481,483],{"class":78,"line":482},7,[76,484,485],{"class":82},"    Close\n",[76,487,489,492,494],{"class":78,"line":488},8,[76,490,491],{"class":82},"  \u003C\u002F",[76,493,87],{"class":86},[76,495,106],{"class":82},[76,497,499,502,504],{"class":78,"line":498},9,[76,500,501],{"class":82},"\u003C\u002F",[76,503,114],{"class":86},[76,505,106],{"class":82},[67,507,511],{"className":508,"code":509,"language":510,"meta":72,"style":72},"language-css shiki shiki-themes github-light-high-contrast github-dark-high-contrast",".pop {\n  max-width: 20rem;\n  padding: 1rem;\n  border: 1px solid #d3d8e0;\n  border-radius: 0.75rem;\n  background: #fff;\n\n  \u002F* Closed appearance. The element is display:none here, so these values\n     only matter as the target the exit transition runs towards. *\u002F\n  opacity: 0;\n  translate: 0 -6px;\n\n  \u002F* display and overlay must both carry allow-discrete or the exit is\n     cut off on frame one. *\u002F\n  transition:\n    opacity 0.2s ease,\n    translate 0.2s ease,\n    overlay 0.2s allow-discrete,\n    display 0.2s allow-discrete;\n}\n\n\u002F* Open appearance. :popover-open matches only while the panel is showing. *\u002F\n.pop:popover-open {\n  opacity: 1;\n  translate: 0 0;\n}\n\n\u002F* The frame before the open state exists. Without this the panel would\n   simply appear at full opacity — there is no prior value to animate from. *\u002F\n@starting-style {\n  .pop:popover-open {\n    opacity: 0;\n    translate: 0 -6px;\n  }\n}\n\n\u002F* Every top-layer element gets a ::backdrop, rendered directly beneath it. *\u002F\n.pop::backdrop {\n  background: rgb(0 0 0 \u002F 0.45);\n  opacity: 0;\n  transition:\n    opacity 0.2s ease,\n    overlay 0.2s allow-discrete,\n    display 0.2s allow-discrete;\n}\n\n.pop:popover-open::backdrop { opacity: 1; }\n\n@starting-style {\n  .pop:popover-open::backdrop { opacity: 0; }\n}\n\n.pop-btn {\n  font: inherit;\n  padding: 0.5rem 0.9rem;\n  border: 1px solid #d3d8e0;\n  border-radius: 0.5rem;\n  background: #fff;\n}\n","css",[18,512,513,521,539,553,573,587,599,603,609,614,627,644,649,655,661,670,688,702,716,729,735,740,746,759,770,784,789,794,800,806,813,825,837,853,859,864,869,875,883,911,922,929,942,953,964,969,974,998,1003,1010,1031,1036,1041,1049,1062,1080,1097,1110,1121],{"__ignoreMap":72},[76,514,515,518],{"class":78,"line":79},[76,516,517],{"class":90},".pop",[76,519,520],{"class":82}," {\n",[76,522,523,526,529,532,536],{"class":78,"line":109},[76,524,525],{"class":90},"  max-width",[76,527,528],{"class":82},": ",[76,530,531],{"class":90},"20",[76,533,535],{"class":534},"sHUrx","rem",[76,537,538],{"class":82},";\n",[76,540,541,544,546,549,551],{"class":78,"line":379},[76,542,543],{"class":90},"  padding",[76,545,528],{"class":82},[76,547,548],{"class":90},"1",[76,550,535],{"class":534},[76,552,538],{"class":82},[76,554,555,558,560,562,565,568,571],{"class":78,"line":403},[76,556,557],{"class":90},"  border",[76,559,528],{"class":82},[76,561,548],{"class":90},[76,563,564],{"class":534},"px",[76,566,567],{"class":90}," solid",[76,569,570],{"class":90}," #d3d8e0",[76,572,538],{"class":82},[76,574,575,578,580,583,585],{"class":78,"line":426},[76,576,577],{"class":90},"  border-radius",[76,579,528],{"class":82},[76,581,582],{"class":90},"0.75",[76,584,535],{"class":534},[76,586,538],{"class":82},[76,588,589,592,594,597],{"class":78,"line":447},[76,590,591],{"class":90},"  background",[76,593,528],{"class":82},[76,595,596],{"class":90},"#fff",[76,598,538],{"class":82},[76,600,601],{"class":78,"line":482},[76,602,376],{"emptyLinePlaceholder":375},[76,604,605],{"class":78,"line":488},[76,606,608],{"class":607},"sLBg1","  \u002F* Closed appearance. The element is display:none here, so these values\n",[76,610,611],{"class":78,"line":498},[76,612,613],{"class":607},"     only matter as the target the exit transition runs towards. *\u002F\n",[76,615,617,620,622,625],{"class":78,"line":616},10,[76,618,619],{"class":90},"  opacity",[76,621,528],{"class":82},[76,623,624],{"class":90},"0",[76,626,538],{"class":82},[76,628,630,633,635,637,640,642],{"class":78,"line":629},11,[76,631,632],{"class":90},"  translate",[76,634,528],{"class":82},[76,636,624],{"class":90},[76,638,639],{"class":90}," -6",[76,641,564],{"class":534},[76,643,538],{"class":82},[76,645,647],{"class":78,"line":646},12,[76,648,376],{"emptyLinePlaceholder":375},[76,650,652],{"class":78,"line":651},13,[76,653,654],{"class":607},"  \u002F* display and overlay must both carry allow-discrete or the exit is\n",[76,656,658],{"class":78,"line":657},14,[76,659,660],{"class":607},"     cut off on frame one. *\u002F\n",[76,662,664,667],{"class":78,"line":663},15,[76,665,666],{"class":90},"  transition",[76,668,669],{"class":82},":\n",[76,671,673,676,679,682,685],{"class":78,"line":672},16,[76,674,675],{"class":82},"    opacity ",[76,677,678],{"class":90},"0.2",[76,680,681],{"class":534},"s",[76,683,684],{"class":90}," ease",[76,686,687],{"class":82},",\n",[76,689,691,694,696,698,700],{"class":78,"line":690},17,[76,692,693],{"class":82},"    translate ",[76,695,678],{"class":90},[76,697,681],{"class":534},[76,699,684],{"class":90},[76,701,687],{"class":82},[76,703,705,708,711,713],{"class":78,"line":704},18,[76,706,707],{"class":90},"    overlay",[76,709,710],{"class":90}," 0.2",[76,712,681],{"class":534},[76,714,715],{"class":82}," allow-discrete,\n",[76,717,719,722,724,726],{"class":78,"line":718},19,[76,720,721],{"class":82},"    display ",[76,723,678],{"class":90},[76,725,681],{"class":534},[76,727,728],{"class":82}," allow-discrete;\n",[76,730,732],{"class":78,"line":731},20,[76,733,734],{"class":82},"}\n",[76,736,738],{"class":78,"line":737},21,[76,739,376],{"emptyLinePlaceholder":375},[76,741,743],{"class":78,"line":742},22,[76,744,745],{"class":607},"\u002F* Open appearance. :popover-open matches only while the panel is showing. *\u002F\n",[76,747,749,751,754,757],{"class":78,"line":748},23,[76,750,517],{"class":90},[76,752,753],{"class":82},":",[76,755,756],{"class":86},"popover-open",[76,758,520],{"class":82},[76,760,762,764,766,768],{"class":78,"line":761},24,[76,763,619],{"class":90},[76,765,528],{"class":82},[76,767,548],{"class":90},[76,769,538],{"class":82},[76,771,773,775,777,779,782],{"class":78,"line":772},25,[76,774,632],{"class":90},[76,776,528],{"class":82},[76,778,624],{"class":90},[76,780,781],{"class":90}," 0",[76,783,538],{"class":82},[76,785,787],{"class":78,"line":786},26,[76,788,734],{"class":82},[76,790,792],{"class":78,"line":791},27,[76,793,376],{"emptyLinePlaceholder":375},[76,795,797],{"class":78,"line":796},28,[76,798,799],{"class":607},"\u002F* The frame before the open state exists. Without this the panel would\n",[76,801,803],{"class":78,"line":802},29,[76,804,805],{"class":607},"   simply appear at full opacity — there is no prior value to animate from. *\u002F\n",[76,807,809,811],{"class":78,"line":808},30,[76,810,52],{"class":534},[76,812,520],{"class":82},[76,814,816,819,821,823],{"class":78,"line":815},31,[76,817,818],{"class":90},"  .pop",[76,820,753],{"class":82},[76,822,756],{"class":86},[76,824,520],{"class":82},[76,826,828,831,833,835],{"class":78,"line":827},32,[76,829,830],{"class":90},"    opacity",[76,832,528],{"class":82},[76,834,624],{"class":90},[76,836,538],{"class":82},[76,838,840,843,845,847,849,851],{"class":78,"line":839},33,[76,841,842],{"class":90},"    translate",[76,844,528],{"class":82},[76,846,624],{"class":90},[76,848,639],{"class":90},[76,850,564],{"class":534},[76,852,538],{"class":82},[76,854,856],{"class":78,"line":855},34,[76,857,858],{"class":82},"  }\n",[76,860,862],{"class":78,"line":861},35,[76,863,734],{"class":82},[76,865,867],{"class":78,"line":866},36,[76,868,376],{"emptyLinePlaceholder":375},[76,870,872],{"class":78,"line":871},37,[76,873,874],{"class":607},"\u002F* Every top-layer element gets a ::backdrop, rendered directly beneath it. *\u002F\n",[76,876,878,881],{"class":78,"line":877},38,[76,879,880],{"class":90},".pop::backdrop",[76,882,520],{"class":82},[76,884,886,888,890,893,896,898,900,902,905,908],{"class":78,"line":885},39,[76,887,591],{"class":90},[76,889,528],{"class":82},[76,891,892],{"class":90},"rgb",[76,894,895],{"class":82},"(",[76,897,624],{"class":90},[76,899,781],{"class":90},[76,901,781],{"class":90},[76,903,904],{"class":82}," \u002F ",[76,906,907],{"class":90},"0.45",[76,909,910],{"class":82},");\n",[76,912,914,916,918,920],{"class":78,"line":913},40,[76,915,619],{"class":90},[76,917,528],{"class":82},[76,919,624],{"class":90},[76,921,538],{"class":82},[76,923,925,927],{"class":78,"line":924},41,[76,926,666],{"class":90},[76,928,669],{"class":82},[76,930,932,934,936,938,940],{"class":78,"line":931},42,[76,933,675],{"class":82},[76,935,678],{"class":90},[76,937,681],{"class":534},[76,939,684],{"class":90},[76,941,687],{"class":82},[76,943,945,947,949,951],{"class":78,"line":944},43,[76,946,707],{"class":90},[76,948,710],{"class":90},[76,950,681],{"class":534},[76,952,715],{"class":82},[76,954,956,958,960,962],{"class":78,"line":955},44,[76,957,721],{"class":82},[76,959,678],{"class":90},[76,961,681],{"class":534},[76,963,728],{"class":82},[76,965,967],{"class":78,"line":966},45,[76,968,734],{"class":82},[76,970,972],{"class":78,"line":971},46,[76,973,376],{"emptyLinePlaceholder":375},[76,975,977,979,981,983,985,988,991,993,995],{"class":78,"line":976},47,[76,978,517],{"class":90},[76,980,753],{"class":82},[76,982,756],{"class":86},[76,984,48],{"class":90},[76,986,987],{"class":82}," { ",[76,989,990],{"class":90},"opacity",[76,992,528],{"class":82},[76,994,548],{"class":90},[76,996,997],{"class":82},"; }\n",[76,999,1001],{"class":78,"line":1000},48,[76,1002,376],{"emptyLinePlaceholder":375},[76,1004,1006,1008],{"class":78,"line":1005},49,[76,1007,52],{"class":534},[76,1009,520],{"class":82},[76,1011,1013,1015,1017,1019,1021,1023,1025,1027,1029],{"class":78,"line":1012},50,[76,1014,818],{"class":90},[76,1016,753],{"class":82},[76,1018,756],{"class":86},[76,1020,48],{"class":90},[76,1022,987],{"class":82},[76,1024,990],{"class":90},[76,1026,528],{"class":82},[76,1028,624],{"class":90},[76,1030,997],{"class":82},[76,1032,1034],{"class":78,"line":1033},51,[76,1035,734],{"class":82},[76,1037,1039],{"class":78,"line":1038},52,[76,1040,376],{"emptyLinePlaceholder":375},[76,1042,1044,1047],{"class":78,"line":1043},53,[76,1045,1046],{"class":90},".pop-btn",[76,1048,520],{"class":82},[76,1050,1052,1055,1057,1060],{"class":78,"line":1051},54,[76,1053,1054],{"class":90},"  font",[76,1056,528],{"class":82},[76,1058,1059],{"class":90},"inherit",[76,1061,538],{"class":82},[76,1063,1065,1067,1069,1071,1073,1076,1078],{"class":78,"line":1064},55,[76,1066,543],{"class":90},[76,1068,528],{"class":82},[76,1070,202],{"class":90},[76,1072,535],{"class":534},[76,1074,1075],{"class":90}," 0.9",[76,1077,535],{"class":534},[76,1079,538],{"class":82},[76,1081,1083,1085,1087,1089,1091,1093,1095],{"class":78,"line":1082},56,[76,1084,557],{"class":90},[76,1086,528],{"class":82},[76,1088,548],{"class":90},[76,1090,564],{"class":534},[76,1092,567],{"class":90},[76,1094,570],{"class":90},[76,1096,538],{"class":82},[76,1098,1100,1102,1104,1106,1108],{"class":78,"line":1099},57,[76,1101,577],{"class":90},[76,1103,528],{"class":82},[76,1105,202],{"class":90},[76,1107,535],{"class":534},[76,1109,538],{"class":82},[76,1111,1113,1115,1117,1119],{"class":78,"line":1112},58,[76,1114,591],{"class":90},[76,1116,528],{"class":82},[76,1118,596],{"class":90},[76,1120,538],{"class":82},[76,1122,1124],{"class":78,"line":1123},59,[76,1125,734],{"class":82},[14,1127,1128,1129,1132,1133,1136,1137,1140,1141,1143,1144,1147,1148,1151],{},"Note the second ",[18,1130,1131],{},"popovertarget"," on the close button, paired with ",[18,1134,1135],{},"popovertargetaction=\"hide\"",". Without the action attribute the button would ",[23,1138,1139],{},"toggle",", which on an already-open popover works but reads ambiguously; being explicit means the same button can never accidentally reopen a panel that some other interaction just closed. The available actions are ",[18,1142,1139],{}," (the default), ",[18,1145,1146],{},"show",", and ",[18,1149,1150],{},"hide",".",[59,1153,1155,1156,1158],{"id":1154},"the-technique-backdrop-is-a-sibling-of-the-top-layer-not-of-the-page","The technique: ",[18,1157,48],{}," is a sibling of the top layer, not of the page",[14,1160,1161,1163],{},[18,1162,48],{}," is easy to misread as \"a dimming div the browser inserts for you.\" It is more specific than that, and the specifics decide what you can do with it.",[14,1165,1166,1167,1170],{},"It is generated for every element in the top layer, and it paints immediately below that element and above everything else in the document. It is not a child of the popover and it is not a child of the body — it sits in the top layer alongside its originating element, which is why no ",[18,1168,1169],{},"z-index"," anywhere in your stylesheet can get above or between them. It inherits nothing from the popover, so it needs its own transition declarations rather than picking them up from the parent rule; this is the single most common reason a panel fades nicely while its backdrop snaps off.",[14,1172,1173,1174,1176],{},"It also does not intercept anything you need to handle. Light dismiss is implemented by the browser at the popover level, not by a click on the backdrop, so you get outside-click dismissal whether or not you style ",[18,1175,48],{}," at all — and styling it does not break that behaviour the way an inserted overlay div would.",[14,1178,1179,1180,1183,1184,1186],{},"One practical consequence: because a ",[18,1181,1182],{},"popover=\"auto\""," element is non-modal, a dark backdrop over the whole viewport can be actively misleading. It looks modal, but clicks still reach the content behind it and screen reader users can still navigate there. Reserve a full dimming backdrop for genuinely modal ",[18,1185,150],{}," elements, and use something lighter — a subtle scrim, or nothing at all — for popovers.",[59,1188,1190],{"id":1189},"variation-an-auto-popover-versus-a-manual-one","Variation: an auto popover versus a manual one",[14,1192,1193],{},"The attribute's value changes the dismissal model, and picking the wrong one produces bugs that look like framework problems.",[67,1195,1197],{"className":69,"code":1196,"language":71,"meta":72,"style":72},"\u003C!-- Default. Light dismiss + Escape; opening this closes other auto popovers. -->\n\u003Cdiv id=\"menu\" popover=\"auto\">…\u003C\u002Fdiv>\n\n\u003C!-- No light dismiss, no Escape, no auto-close of siblings. -->\n\u003Cdiv id=\"toast\" popover=\"manual\">…\u003C\u002Fdiv>\n",[18,1198,1199,1204,1230,1234,1239],{"__ignoreMap":72},[76,1200,1201],{"class":78,"line":79},[76,1202,1203],{"class":607},"\u003C!-- Default. Light dismiss + Escape; opening this closes other auto popovers. -->\n",[76,1205,1206,1208,1210,1212,1214,1216,1218,1220,1223,1226,1228],{"class":78,"line":109},[76,1207,83],{"class":82},[76,1209,114],{"class":86},[76,1211,117],{"class":90},[76,1213,94],{"class":82},[76,1215,355],{"class":97},[76,1217,124],{"class":90},[76,1219,94],{"class":82},[76,1221,1222],{"class":97},"\"auto\"",[76,1224,1225],{"class":82},">…\u003C\u002F",[76,1227,114],{"class":86},[76,1229,106],{"class":82},[76,1231,1232],{"class":78,"line":379},[76,1233,376],{"emptyLinePlaceholder":375},[76,1235,1236],{"class":78,"line":403},[76,1237,1238],{"class":607},"\u003C!-- No light dismiss, no Escape, no auto-close of siblings. -->\n",[76,1240,1241,1243,1245,1247,1249,1252,1254,1256,1259,1261,1263],{"class":78,"line":426},[76,1242,83],{"class":82},[76,1244,114],{"class":86},[76,1246,117],{"class":90},[76,1248,94],{"class":82},[76,1250,1251],{"class":97},"\"toast\"",[76,1253,124],{"class":90},[76,1255,94],{"class":82},[76,1257,1258],{"class":97},"\"manual\"",[76,1260,1225],{"class":82},[76,1262,114],{"class":86},[76,1264,106],{"class":82},[14,1266,1267,1269,1270,1272,1273,1276],{},[18,1268,1182],{}," — which is what the bare ",[18,1271,38],{}," attribute means — participates in a dismissal stack. Opening one auto popover closes any other open auto popover that is not one of its ancestors, so nested submenus work but two unrelated dropdowns can never be open at once. That is the right model for menus, and exactly the wrong model for a stack of notification toasts, where ",[18,1274,1275],{},"popover=\"manual\""," keeps each one alive until something explicitly hides it.",[14,1278,1279,1280,1283],{},"For reduced-motion users, drop the movement but keep the discrete transitions in place — the fade duration is what keeps the exit visible at all, so removing the whole ",[18,1281,1282],{},"transition"," declaration would make the panel vanish abruptly rather than gently:",[67,1285,1287],{"className":508,"code":1286,"language":510,"meta":72,"style":72},"@media (prefers-reduced-motion: reduce) {\n  .pop {\n    translate: none;\n    transition:\n      opacity 0.1s linear,\n      overlay 0.1s allow-discrete,\n      display 0.1s allow-discrete;\n  }\n  .pop:popover-open { translate: none; }\n}\n",[18,1288,1289,1297,1303,1313,1320,1335,1347,1358,1362,1381],{"__ignoreMap":72},[76,1290,1291,1294],{"class":78,"line":79},[76,1292,1293],{"class":534},"@media",[76,1295,1296],{"class":82}," (prefers-reduced-motion: reduce) {\n",[76,1298,1299,1301],{"class":78,"line":109},[76,1300,818],{"class":90},[76,1302,520],{"class":82},[76,1304,1305,1307,1309,1311],{"class":78,"line":379},[76,1306,842],{"class":90},[76,1308,528],{"class":82},[76,1310,199],{"class":90},[76,1312,538],{"class":82},[76,1314,1315,1318],{"class":78,"line":403},[76,1316,1317],{"class":90},"    transition",[76,1319,669],{"class":82},[76,1321,1322,1325,1328,1330,1333],{"class":78,"line":426},[76,1323,1324],{"class":82},"      opacity ",[76,1326,1327],{"class":90},"0.1",[76,1329,681],{"class":534},[76,1331,1332],{"class":90}," linear",[76,1334,687],{"class":82},[76,1336,1337,1340,1343,1345],{"class":78,"line":447},[76,1338,1339],{"class":90},"      overlay",[76,1341,1342],{"class":90}," 0.1",[76,1344,681],{"class":534},[76,1346,715],{"class":82},[76,1348,1349,1352,1354,1356],{"class":78,"line":482},[76,1350,1351],{"class":82},"      display ",[76,1353,1327],{"class":90},[76,1355,681],{"class":534},[76,1357,728],{"class":82},[76,1359,1360],{"class":78,"line":488},[76,1361,858],{"class":82},[76,1363,1364,1366,1368,1370,1372,1375,1377,1379],{"class":78,"line":498},[76,1365,818],{"class":90},[76,1367,753],{"class":82},[76,1369,756],{"class":86},[76,1371,987],{"class":82},[76,1373,1374],{"class":90},"translate",[76,1376,528],{"class":82},[76,1378,199],{"class":90},[76,1380,997],{"class":82},[76,1382,1383],{"class":78,"line":616},[76,1384,734],{"class":82},[59,1386,1388],{"id":1387},"browser-support","Browser support",[14,1390,1391,1392,1394,1395,1397,1398,1400,1401,1404,1405,1409],{},"The ",[18,1393,38],{}," attribute is supported in Chrome 114+, Edge 114+, Safari 17+, and Firefox 125+ — the oldest and most widely deployed piece of the overlay stack. ",[18,1396,56],{}," landed in Chrome 117+, Edge 117+, Safari 17.4+, and Firefox 129+; ",[18,1399,52],{}," matches it everywhere except Safari, where it arrived one release later in 17.5. In an engine that lacks the animation half, a popover still opens and closes correctly — it simply appears and disappears instantly, which is an acceptable degradation and needs no ",[18,1402,1403],{},"@supports"," guard. The placement rules that tether the panel to its button depend on anchor positioning, which is also available in every current engine (Chrome\u002FEdge 125+, Safari 26+, Firefox 147+) but shipped recently enough to be worth guarding for older versions; ",[41,1406,1408],{"href":1407},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioning-fallbacks\u002F","anchor positioning fallbacks"," covers how to layer that on.",[59,1411,1413],{"id":1412},"faq","FAQ",[14,1415,1416,1425,1426,1428],{},[1417,1418,1419,1420,53,1422,1424],"strong",{},"What is the difference between ",[18,1421,1182],{},[18,1423,1275],{},"?","\nAn auto popover light-dismisses on an outside click or ",[32,1427,34],{}," and closes any other auto popover that is not its ancestor. A manual popover does neither, so it stays open until something explicitly toggles it and it can coexist with other open popovers.",[14,1430,1431,1434,1435,53,1437,1439,1440,1442,1443,1445],{},[1417,1432,1433],{},"Why does my popover disappear instantly instead of fading out?","\nBecause ",[18,1436,280],{},[18,1438,283],{}," are discrete properties. Without ",[18,1441,56],{}," on both, the element flips to ",[18,1444,165],{}," and leaves the top layer on the first frame of the exit, so there is nothing left to fade.",[14,1447,1448,1451,1452,1454,1455,1457],{},[1417,1449,1450],{},"Does a popover trap focus like a modal dialog?","\nNo, and that is intentional. Popovers are non-modal, so focus can leave them and content behind them stays interactive. Use a ",[18,1453,150],{}," element opened with ",[18,1456,154],{}," for anything that requires a decision before the user continues.",[14,1459,1460,1463,1464,1466,1467,1469],{},[1417,1461,1462],{},"Can I style the area behind a popover?","\nYes, through the ",[18,1465,48],{}," pseudo-element, which every top-layer element gets. It renders directly beneath the popover and above everything else, and it can be transitioned as long as ",[18,1468,242],{}," is included so it survives the exit.",[59,1471,1473],{"id":1472},"related","Related",[1475,1476,1477,1483,1490,1496,1503],"ul",{},[1478,1479,1480,1482],"li",{},[41,1481,44],{"href":43}," — the parent guide, including how the top layer and anchoring combine.",[1478,1484,1485,1489],{},[41,1486,1488],{"href":1487},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioned-tooltips\u002F","Anchor positioned tooltips"," — the lighter component for passive hints.",[1478,1491,1492,1495],{},[41,1493,1494],{"href":1407},"Anchor positioning fallbacks"," — tethering the panel on browser versions older than the anchor ship dates.",[1478,1497,1498,1502],{},[41,1499,1501],{"href":1500},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Ftransitioning-display-with-allow-discrete\u002F","Transitioning display with allow-discrete"," — cross-area: the discrete transition rules in full.",[1478,1504,1505,1509],{},[41,1506,1508],{"href":1507},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fstarting-style-entry-animations\u002F","@starting-style entry animations"," — cross-area: more patterns for elements appearing from nothing.",[1511,1512,1513],"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 .sLBg1, html code.shiki .sLBg1{--shiki-default:#66707B;--shiki-dark:#BDC4CC}",{"title":72,"searchDepth":109,"depth":109,"links":1515},[1516,1517,1518,1519,1521,1522,1523,1524],{"id":61,"depth":109,"text":62},{"id":158,"depth":109,"text":159},{"id":318,"depth":109,"text":319},{"id":1154,"depth":109,"text":1520},"The technique: ::backdrop is a sibling of the top layer, not of the page",{"id":1189,"depth":109,"text":1190},{"id":1387,"depth":109,"text":1388},{"id":1412,"depth":109,"text":1413},{"id":1472,"depth":109,"text":1473},"Use the native popover attribute for light-dismiss overlays in the top layer, then style ::backdrop and animate entry and exit with @starting-style, no JS.","md",{"pageTitle":1528,"datePublished":1529,"dateModified":1529,"faq":1530},"The popover Attribute, Styled in CSS","2026-07-20",[1531,1534,1536,1538],{"q":1532,"a":1533},"What is the difference between popover=auto and popover=manual?","An auto popover light-dismisses on an outside click or Escape and closes any other auto popover that is not its ancestor. A manual popover does neither, so it stays open until something explicitly toggles it and it can coexist with other open popovers.",{"q":1433,"a":1535},"Because display and overlay are discrete properties. Without transition-behavior allow-discrete on both, the element flips to display none and leaves the top layer on the first frame of the exit, so there is nothing left to fade.",{"q":1450,"a":1537},"No, and that is intentional. Popovers are non-modal, so focus can leave them and content behind them stays interactive. Use a dialog element opened with showModal for anything that requires a decision before the user continues.",{"q":1462,"a":1539},"Yes, through the ::backdrop pseudo-element, which every top-layer element gets. It renders directly beneath the popover and above everything else, and it can be transitioned as long as allow-discrete is included so it survives the exit.","\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fpopover-attribute-and-css-styling",{"title":5,"description":1525},"mastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fpopover-attribute-and-css-styling\u002Findex","JMfnQyFTLpbiJEIY7TVAY2CDfYALkNyRoJKagbQ4r0c",[1545,1548,1551,1554,1557,1560,1563,1566,1569,1572,1575,1578,1581,1584,1587,1590,1593,1596,1599,1602,1605,1608,1611,1614,1617,1620,1623,1626,1629,1632,1635,1638,1641,1644,1647,1650,1653,1656,1659,1662,1665,1668,1671,1674,1677,1680,1683,1686,1689,1692,1695,1696,1699,1702,1705,1708,1711,1714,1717,1720,1723,1726,1729,1732,1735,1738,1741,1744,1747,1750,1753,1756,1759,1762,1765,1768,1771,1774,1777,1780,1783,1786,1789,1792,1795,1798,1801,1804],{"path":1546,"title":1547},"\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":1549,"title":1550},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations","Accessibility in CSS Animations: Patterns, Specs & Best Practices",{"path":1552,"title":1553},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fprefers-reduced-motion-recipes","prefers-reduced-motion Recipes: A Reduction for Every Common Effect",{"path":1555,"title":1556},"\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":1558,"title":1559},"\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":1561,"title":1562},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fvestibular-safe-animation-patterns","Vestibular-Safe Animation Patterns: Why Some Motion Makes People Sick",{"path":1564,"title":1565},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fwcag-motion-success-criteria","WCAG Motion Success Criteria: What Each One Actually Requires",{"path":1567,"title":1568},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fcontainer-query-hover-affordances","Container Query Hover Affordances: When Narrow Means Persistent, Not Hidden",{"path":1570,"title":1571},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion","Container-Aware Motion: Animation Sized by the Space a Component Actually Has",{"path":1573,"title":1574},"\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":1576,"title":1577},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fsuppressing-motion-in-small-containers","Suppressing Motion in Small Containers: Deliberately Animating Nothing",{"path":1579,"title":1580},"\u002Fcss-only-micro-interactions-animations\u002Fcss-animation-vs-web-animations-api","CSS Animation vs the Web Animations API: A Decision Guide",{"path":1582,"title":1583},"\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":1585,"title":1586},"\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":1588,"title":1589},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Ffluid-spacing-tokens-driving-transition-durations","Fluid Spacing Tokens That Drive Transition Durations",{"path":1591,"title":1592},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture","CSS Custom Properties Architecture: Scalable Design Systems & Dynamic UI",{"path":1594,"title":1595},"\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":1597,"title":1598},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fcss-transition-timing-functions","CSS Transition Timing Functions: ease, cubic-bezier(), steps() and linear()",{"path":1600,"title":1601},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals","CSS Transition Fundamentals: Architecture, Performance & Patterns",{"path":1603,"title":1604},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fstarting-style-entry-animations","@starting-style: Animating an Element's Very First Style Change",{"path":1606,"title":1607},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Ftransitioning-display-with-allow-discrete","Transitioning display with transition-behavior: allow-discrete and @starting-style",{"path":1609,"title":1610},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Faccessible-css-only-tooltips","Accessible CSS-Only Tooltips and Hover Cards With  and ",{"path":1612,"title":1613},"\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":1615,"title":1616},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Ffocus-within-form-patterns"," Form Patterns: Styling a Group From the Field Inside It",{"path":1618,"title":1619},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design","Hover & Focus State Design: Spec-Compliant Patterns for Modern UIs",{"path":1621,"title":1622},"\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":1624,"title":1625},"\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":1627,"title":1628},"\u002Fcss-only-micro-interactions-animations","CSS-Only Micro-Interactions & Animations: Architecture, Performance & Implementation",{"path":1630,"title":1631},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcontainer-query-triggered-keyframe-animations","Container-Query-Triggered Keyframe Animations: Animate Differently per Available Space",{"path":1633,"title":1634},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcss-only-accordions-and-disclosure","CSS-Only Accordions and Disclosure Widgets with details and summary",{"path":1636,"title":1637},"\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":1639,"title":1640},"\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":1642,"title":1643},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns","Keyframe Animation Patterns: Spec-Compliant Architectures for Modern UIs",{"path":1645,"title":1646},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fstaggered-list-animations-with-custom-properties","Staggered List Animations Using --i Index Custom Properties",{"path":1648,"title":1649},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration","Performance & GPU Acceleration in CSS: A Developer’s Blueprint",{"path":1651,"title":1652},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Foptimizing-css-animations-for-60fps","Optimizing CSS Animations for 60fps: Budgeting the Frame",{"path":1654,"title":1655},"\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":1657,"title":1658},"\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":1660,"title":1661},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations","Scroll-Driven Animations: Binding Motion to Scroll Position in Pure CSS",{"path":1663,"title":1664},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-driven-animation-fallbacks","Shipping Scroll-Driven Animations Without Breaking Anything",{"path":1666,"title":1667},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-progress-bar-without-javascript","A Reading Progress Bar Driven by scroll(root)",{"path":1669,"title":1670},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-triggered-reveal-animations","Reveal-on-Scroll with view() and animation-range",{"path":1672,"title":1673},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers","View Transitions for CSS Developers: the Pseudo-Element Tree, Snapshots, and Named Elements",{"path":1675,"title":1676},"\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":1678,"title":1679},"\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":1681,"title":1682},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fview-transitions-with-reduced-motion","Honouring prefers-reduced-motion in View Transitions",{"path":1684,"title":1685},"\u002F","Modern CSS Layouts & Micro-Interactions",{"path":1687,"title":1688},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioned-tooltips","Anchor-Positioned Tooltips: Tethering, Flipping, and Getting the Semantics Right",{"path":1690,"title":1691},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioning-fallbacks","Anchor Positioning Fallbacks: A Graceful Floor for Older Browser Versions",{"path":1693,"title":1694},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays","CSS Anchor Positioning and Overlays: Tethering Elements Without JavaScript",{"path":1540,"title":5},{"path":1697,"title":1698},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Ffeature-detection-with-supports","Feature Detection with @supports: Syntax, Semantics, and the Traps",{"path":1700,"title":1701},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Fhandling-container-query-fallbacks-for-older-browsers","Handling Container Query Fallbacks for Older Browsers",{"path":1703,"title":1704},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks","Container Query Fallbacks: Spec-Compliant CSS Strategies for Legacy Browsers",{"path":1706,"title":1707},"\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":1709,"title":1710},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-type-size-vs-inline-size","Choosing container-type: inline-size, size, or normal",{"path":1712,"title":1713},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-vs-media-queries-comparison","Container vs Media Queries: Choosing the Right Reference Box",{"path":1715,"title":1716},"\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":1718,"title":1719},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics","Container Query Syntax Basics",{"path":1721,"title":1722},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fnesting-and-naming-container-queries","Nesting and Naming Container Queries: Targeting the Right Ancestor",{"path":1724,"title":1725},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fauto-fit-minmax-responsive-grids","Responsive Grids with repeat(auto-fit, minmax())",{"path":1727,"title":1728},"\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":1730,"title":1731},"\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":1733,"title":1734},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts","CSS Grid and Subgrid Layouts for Responsive Interfaces",{"path":1736,"title":1737},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fsubgrid-vs-nested-grid","Subgrid vs an Independently Nested Grid",{"path":1739,"title":1740},"\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":1742,"title":1743},"\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":1745,"title":1746},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-type-accessibility-and-zoom","Fluid Type, Accessibility and Zoom: The vw-Only Trap",{"path":1748,"title":1749},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-typography-without-javascript","Fluid Typography Without JavaScript: A Precision CSS Reference",{"path":1751,"title":1752},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp","Fluid Typography with clamp(): A Practical Guide for Modern CSS",{"path":1754,"title":1755},"\u002Fmastering-container-queries-responsive-layouts","Mastering Container Queries & Responsive Layouts",{"path":1757,"title":1758},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Faspect-ratio-for-responsive-media","Using aspect-ratio for Responsive Media and Preventing Layout Shift",{"path":1760,"title":1761},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques","Intrinsic Sizing Techniques: Modern CSS Layouts for Responsive UI",{"path":1763,"title":1764},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fmin-max-fit-content-explained","min-content, max-content, and fit-content() Explained",{"path":1766,"title":1767},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fpreventing-flex-and-grid-overflow","The min-width: auto Trap in Flex and Grid Layouts",{"path":1769,"title":1770},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-for-reset-and-tokens","Cascade Layers for Reset and Design Tokens",{"path":1772,"title":1773},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-vs-specificity-hacks","Cascade Layers vs Specificity Hacks: Ordering Instead of Escalating",{"path":1775,"title":1776},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies","Modern CSS Reset Strategies: A Spec-Compliant Foundation",{"path":1778,"title":1779},"\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":1781,"title":1782},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fcontainer-query-data-tables","Container Query Data Tables: Reflowing Tables to Cards",{"path":1784,"title":1785},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fcontainer-query-sidebar-layouts","Container Query Sidebar Layouts That Travel Between Contexts",{"path":1787,"title":1788},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns","Responsive Component Patterns: Architecture & Implementation",{"path":1790,"title":1791},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-forms-with-container-queries","Responsive Forms with Container Queries: Reflow Without Losing the Wiring",{"path":1793,"title":1794},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-navigation-without-media-queries","Responsive Navigation Without Media Queries Using Container Queries",{"path":1796,"title":1797},"\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":1799,"title":1800},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state","Style Queries and Container State: Token-Driven Component Variants",{"path":1802,"title":1803},"\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":1805,"title":1806},"\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",1784566157143]