[{"data":1,"prerenderedAt":2137},["ShallowReactive",2],{"page-\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002Fsticky-footer-with-flexbox-and-grid\u002F":3,"content-all-pages":1579},{"id":4,"title":5,"body":6,"description":1559,"extension":1560,"meta":1561,"navigation":380,"path":1575,"seo":1576,"stem":1577,"__hash__":1578},"content\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002Fsticky-footer-with-flexbox-and-grid\u002Findex.md","Sticky Footer With Flexbox or Grid: Pinning the Footer on Short Pages",{"type":7,"value":8,"toc":1547},"minimark",[9,13,28,33,45,48,51,55,66,194,200,204,210,872,900,910,929,942,1026,1039,1043,1060,1121,1320,1351,1355,1372,1390,1406,1423,1427,1448,1452,1475,1486,1500,1512,1516,1544],[10,11,5],"h1",{"id":12},"sticky-footer-with-flexbox-or-grid-pinning-the-footer-on-short-pages",[14,15,16,17,22,23,27],"p",{},"A 404 page, an empty search result or a login screen has barely any content, and the footer ends up floating halfway up the viewport with a stripe of blank background below it. The requirement is precise: on a short page the footer should sit at the bottom edge of the viewport; on a long page it should come after the content and scroll away like anything else. This page solves exactly that with a single rule on each of two elements, in both flexbox and grid form, and handles the mobile viewport-height trap that breaks most copies of it. It sits in ",[18,19,21],"a",{"href":20},"\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002F","Flexbox Layout Patterns",", inside the broader ",[18,24,26],{"href":25},"\u002Fmastering-container-queries-responsive-layouts\u002F","Mastering Container Queries & Responsive Layouts"," guide.",[29,30,32],"h2",{"id":31},"why-a-layout-rule-and-not-positioning","Why a layout rule and not positioning",[14,34,35,36,40,41,44],{},"Before flexbox, sticky footers relied on negative margins and a push element whose height had to match the footer's exactly, so a footer that grew a second line of links broke the page. Positioning is the other temptation, and it answers a different question: ",[37,38,39],"code",{},"position: fixed"," keeps the footer on screen permanently, covering the last lines of every long page, and ",[37,42,43],{},"position: sticky"," makes it cling to the viewport while scrolling. Neither is \"at the bottom when there is room, after the content when there is not\".",[14,46,47],{},"The layout approach gets that behaviour for free because it describes the relationship instead of the position: the page is at least as tall as the viewport, and the main region absorbs whatever space is left over. Nothing depends on the footer's height, so the footer can wrap, grow or disappear and the rule still holds.",[14,49,50],{},"There is no accessibility cost. The DOM order stays header, main, footer, landmarks stay in place for screen-reader navigation, and nothing is taken out of flow, so zooming to 400% simply produces a long page with the footer at the end.",[29,52,54],{"id":53},"how-the-free-space-is-shared","How the free space is shared",[14,56,57,58,61,62,65],{},"The mechanism has two parts, and the diagram shows both. The outer container — normally ",[37,59,60],{},"body"," — gets a ",[37,63,64],{},"min-height"," equal to the viewport, which creates free space whenever the content is shorter. Then one child, the main region, is told to take all of that free space.",[67,68,74,75,74,79,74,83,74,91,74,97,74,109,74,118,74,123,74,128,74,132,74,137,74,141,74,144,74,148,74,153,74,157,74,166,74,173,74,176,74,178,74,181,74,184,74,187,74,190],"svg",{"viewBox":69,"role":70,"ariaLabel":71,"xmlns":72,"style":73},"0 0 720 330","img","Two pages compared: on a short page main grows to push the footer to the viewport bottom; on a long page the footer follows the content","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;height:auto;max-width:720px;margin:2rem 0","\n  ",[76,77,78],"title",{},"Short page versus long page",[80,81,82],"desc",{},"On the left a viewport-tall body contains header, a grown main area and a footer at the bottom. On the right the body is taller than the viewport and the footer follows the content below the fold.",[84,85,90],"text",{"textAnchor":86,"x":87,"y":88,"style":89},"middle","360","26","text-anchor:middle;fill:currentColor;font:700 17px sans-serif","min-height creates room; main absorbs it",[84,92,96],{"textAnchor":86,"x":93,"y":94,"style":95},"190","54","text-anchor:middle;fill:currentColor;font:600 13px sans-serif","Short page",[98,99],"rect",{"x":100,"y":101,"width":102,"height":103,"rx":104,"fill":105,"stroke":106,"strokeWidth":107,"opacity":108},"70","64","240","220","8","none","currentColor","1.5","0.55",[98,110],{"x":111,"y":112,"width":113,"height":114,"rx":115,"fill":116,"opacity":117},"82","74","216","30","5","#7aa2ff","0.3",[84,119,122],{"textAnchor":86,"x":93,"y":120,"style":121},"94","text-anchor:middle;fill:currentColor;font:12px ui-monospace,monospace","header",[98,124],{"x":111,"y":125,"width":113,"height":126,"rx":115,"fill":116,"opacity":127},"112","124","0.14",[84,129,131],{"textAnchor":86,"x":93,"y":130,"style":121},"152","main",[84,133,136],{"textAnchor":86,"x":93,"y":134,"style":135},"176","text-anchor:middle;fill:currentColor;font:12px sans-serif","grows into the",[84,138,140],{"textAnchor":86,"x":93,"y":139,"style":135},"194","leftover space",[98,142],{"x":111,"y":143,"width":113,"height":114,"rx":115,"fill":116,"opacity":117},"244",[84,145,147],{"textAnchor":86,"x":93,"y":146,"style":121},"264","footer",[84,149,152],{"textAnchor":86,"x":93,"y":150,"style":151},"306","text-anchor:middle;fill:currentColor;font:12px sans-serif;opacity:0.75","footer meets the viewport edge",[84,154,156],{"textAnchor":86,"x":155,"y":94,"style":95},"530","Long page",[158,159],"path",{"d":160,"fill":105,"stroke":106,"strokeWidth":161,"strokeDashArray":162,"opacity":165},"M410 64 H650 V224 H410 Z","2",[163,164],"6","4","0.8",[84,167,172],{"textAnchor":168,"x":169,"y":170,"style":171},"start","662","150","text-anchor:start;fill:currentColor;font:12px sans-serif","view",[98,174],{"x":175,"y":112,"width":113,"height":114,"rx":115,"fill":116,"opacity":117},"422",[84,177,122],{"textAnchor":86,"x":155,"y":120,"style":121},[98,179],{"x":175,"y":125,"width":113,"height":180,"rx":115,"fill":116,"opacity":127},"140",[84,182,183],{"textAnchor":86,"x":155,"y":134,"style":121},"main (content)",[98,185],{"x":175,"y":186,"width":113,"height":114,"rx":115,"fill":116,"opacity":117},"260",[84,188,147],{"textAnchor":86,"x":155,"y":189,"style":121},"280",[84,191,193],{"textAnchor":86,"x":155,"y":192,"style":151},"314","footer sits below the fold",[14,195,196,197,199],{},"When content is taller than the viewport, there is no free space to share, ",[37,198,64],{}," stops mattering, and the footer lands immediately after the content. The rule is inert on long pages, which is exactly why it is safe to apply site-wide.",[29,201,203],{"id":202},"the-complete-implementation","The complete implementation",[14,205,206,207,209],{},"The document below uses the flexbox form on ",[37,208,60],{},". The alternative grid rule is included as a comment block so the two can be compared line for line.",[211,212,217],"pre",{"className":213,"code":214,"language":215,"meta":216,"style":216},"language-html shiki shiki-themes github-light-high-contrast github-dark-high-contrast","\u003C!doctype html>\n\u003Chtml lang=\"en\">\n\u003Chead>\n\u003Cmeta charset=\"utf-8\">\n\u003Cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\u003Ctitle>Sticky footer\u003C\u002Ftitle>\n\u003Cstyle>\n  \u002F* Remove the default body margin, or min-height plus margin\n     overflows the viewport and adds a permanent scrollbar. *\u002F\n  html, body { margin: 0; }\n\n  body {\n    display: flex;\n    flex-direction: column;\n    \u002F* Two declarations on purpose: browsers without dvh keep the first,\n       browsers with it use the second, which tracks the mobile toolbar. *\u002F\n    min-height: 100vh;\n    min-height: 100dvh;\n    font: 16px\u002F1.6 system-ui, sans-serif;\n  }\n\n  \u002F* The only element that grows. flex: 1 0 auto = grow into free space,\n     never shrink below content, start from content height. *\u002F\n  main {\n    flex: 1 0 auto;\n    padding: 1.5rem;\n  }\n\n  header, footer {\n    padding: 1rem 1.5rem;\n    background: #1e293b;\n    color: #f8fafc;\n  }\n\n  footer a { color: #bfdbfe; }\n\n  \u002F* GRID ALTERNATIVE — replace the body rule above with:\n     body {\n       display: grid;\n       grid-template-rows: auto 1fr auto;\n       min-height: 100vh;\n       min-height: 100dvh;\n     }\n     and delete the main flex rule. The 1fr row plays the role of flex-grow. *\u002F\n\u003C\u002Fstyle>\n\u003C\u002Fhead>\n\u003Cbody>\n  \u003Cheader>Site name\u003C\u002Fheader>\n  \u003Cmain>\n    \u003Ch1>No results\u003C\u002Fh1>\n    \u003Cp>Try a shorter search term.\u003C\u002Fp>\n  \u003C\u002Fmain>\n  \u003Cfooter>\n    \u003Ca href=\"\u002F\">Home\u003C\u002Fa> · \u003Ca href=\"\u002Fcontact\u002F\">Contact\u003C\u002Fa>\n  \u003C\u002Ffooter>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n","html","",[37,218,219,239,259,269,287,312,326,336,343,349,375,382,391,405,418,424,430,447,461,491,497,502,508,514,522,541,556,561,566,578,596,609,622,627,632,653,658,664,670,676,682,688,694,700,706,716,725,734,749,758,773,787,797,806,845,854,863],{"__ignoreMap":216},[220,221,224,228,232,236],"span",{"class":222,"line":223},"line",1,[220,225,227],{"class":226},"suds8","\u003C!",[220,229,231],{"class":230},"sne4z","doctype",[220,233,235],{"class":234},"s-5SL"," html",[220,237,238],{"class":226},">\n",[220,240,242,245,247,250,253,257],{"class":222,"line":241},2,[220,243,244],{"class":226},"\u003C",[220,246,215],{"class":230},[220,248,249],{"class":234}," lang",[220,251,252],{"class":226},"=",[220,254,256],{"class":255},"sT6z2","\"en\"",[220,258,238],{"class":226},[220,260,262,264,267],{"class":222,"line":261},3,[220,263,244],{"class":226},[220,265,266],{"class":230},"head",[220,268,238],{"class":226},[220,270,272,274,277,280,282,285],{"class":222,"line":271},4,[220,273,244],{"class":226},[220,275,276],{"class":230},"meta",[220,278,279],{"class":234}," charset",[220,281,252],{"class":226},[220,283,284],{"class":255},"\"utf-8\"",[220,286,238],{"class":226},[220,288,290,292,294,297,299,302,305,307,310],{"class":222,"line":289},5,[220,291,244],{"class":226},[220,293,276],{"class":230},[220,295,296],{"class":234}," name",[220,298,252],{"class":226},[220,300,301],{"class":255},"\"viewport\"",[220,303,304],{"class":234}," content",[220,306,252],{"class":226},[220,308,309],{"class":255},"\"width=device-width, initial-scale=1\"",[220,311,238],{"class":226},[220,313,315,317,319,322,324],{"class":222,"line":314},6,[220,316,244],{"class":226},[220,318,76],{"class":230},[220,320,321],{"class":226},">Sticky footer\u003C\u002F",[220,323,76],{"class":230},[220,325,238],{"class":226},[220,327,329,331,334],{"class":222,"line":328},7,[220,330,244],{"class":226},[220,332,333],{"class":230},"style",[220,335,238],{"class":226},[220,337,339],{"class":222,"line":338},8,[220,340,342],{"class":341},"sLBg1","  \u002F* Remove the default body margin, or min-height plus margin\n",[220,344,346],{"class":222,"line":345},9,[220,347,348],{"class":341},"     overflows the viewport and adds a permanent scrollbar. *\u002F\n",[220,350,352,355,358,360,363,366,369,372],{"class":222,"line":351},10,[220,353,354],{"class":230},"  html",[220,356,357],{"class":226},", ",[220,359,60],{"class":230},[220,361,362],{"class":226}," { ",[220,364,365],{"class":234},"margin",[220,367,368],{"class":226},": ",[220,370,371],{"class":234},"0",[220,373,374],{"class":226},"; }\n",[220,376,378],{"class":222,"line":377},11,[220,379,381],{"emptyLinePlaceholder":380},true,"\n",[220,383,385,388],{"class":222,"line":384},12,[220,386,387],{"class":230},"  body",[220,389,390],{"class":226}," {\n",[220,392,394,397,399,402],{"class":222,"line":393},13,[220,395,396],{"class":234},"    display",[220,398,368],{"class":226},[220,400,401],{"class":234},"flex",[220,403,404],{"class":226},";\n",[220,406,408,411,413,416],{"class":222,"line":407},14,[220,409,410],{"class":234},"    flex-direction",[220,412,368],{"class":226},[220,414,415],{"class":234},"column",[220,417,404],{"class":226},[220,419,421],{"class":222,"line":420},15,[220,422,423],{"class":341},"    \u002F* Two declarations on purpose: browsers without dvh keep the first,\n",[220,425,427],{"class":222,"line":426},16,[220,428,429],{"class":341},"       browsers with it use the second, which tracks the mobile toolbar. *\u002F\n",[220,431,433,436,438,441,445],{"class":222,"line":432},17,[220,434,435],{"class":234},"    min-height",[220,437,368],{"class":226},[220,439,440],{"class":234},"100",[220,442,444],{"class":443},"sHUrx","vh",[220,446,404],{"class":226},[220,448,450,452,454,456,459],{"class":222,"line":449},18,[220,451,435],{"class":234},[220,453,368],{"class":226},[220,455,440],{"class":234},[220,457,458],{"class":443},"dvh",[220,460,404],{"class":226},[220,462,464,467,469,472,475,478,481,484,486,489],{"class":222,"line":463},19,[220,465,466],{"class":234},"    font",[220,468,368],{"class":226},[220,470,471],{"class":234},"16",[220,473,474],{"class":443},"px",[220,476,477],{"class":226},"\u002F",[220,479,480],{"class":234},"1.6",[220,482,483],{"class":234}," system-ui",[220,485,357],{"class":226},[220,487,488],{"class":234},"sans-serif",[220,490,404],{"class":226},[220,492,494],{"class":222,"line":493},20,[220,495,496],{"class":226},"  }\n",[220,498,500],{"class":222,"line":499},21,[220,501,381],{"emptyLinePlaceholder":380},[220,503,505],{"class":222,"line":504},22,[220,506,507],{"class":341},"  \u002F* The only element that grows. flex: 1 0 auto = grow into free space,\n",[220,509,511],{"class":222,"line":510},23,[220,512,513],{"class":341},"     never shrink below content, start from content height. *\u002F\n",[220,515,517,520],{"class":222,"line":516},24,[220,518,519],{"class":230},"  main",[220,521,390],{"class":226},[220,523,525,528,530,533,536,539],{"class":222,"line":524},25,[220,526,527],{"class":234},"    flex",[220,529,368],{"class":226},[220,531,532],{"class":234},"1",[220,534,535],{"class":234}," 0",[220,537,538],{"class":234}," auto",[220,540,404],{"class":226},[220,542,544,547,549,551,554],{"class":222,"line":543},26,[220,545,546],{"class":234},"    padding",[220,548,368],{"class":226},[220,550,107],{"class":234},[220,552,553],{"class":443},"rem",[220,555,404],{"class":226},[220,557,559],{"class":222,"line":558},27,[220,560,496],{"class":226},[220,562,564],{"class":222,"line":563},28,[220,565,381],{"emptyLinePlaceholder":380},[220,567,569,572,574,576],{"class":222,"line":568},29,[220,570,571],{"class":230},"  header",[220,573,357],{"class":226},[220,575,147],{"class":230},[220,577,390],{"class":226},[220,579,581,583,585,587,589,592,594],{"class":222,"line":580},30,[220,582,546],{"class":234},[220,584,368],{"class":226},[220,586,532],{"class":234},[220,588,553],{"class":443},[220,590,591],{"class":234}," 1.5",[220,593,553],{"class":443},[220,595,404],{"class":226},[220,597,599,602,604,607],{"class":222,"line":598},31,[220,600,601],{"class":234},"    background",[220,603,368],{"class":226},[220,605,606],{"class":234},"#1e293b",[220,608,404],{"class":226},[220,610,612,615,617,620],{"class":222,"line":611},32,[220,613,614],{"class":234},"    color",[220,616,368],{"class":226},[220,618,619],{"class":234},"#f8fafc",[220,621,404],{"class":226},[220,623,625],{"class":222,"line":624},33,[220,626,496],{"class":226},[220,628,630],{"class":222,"line":629},34,[220,631,381],{"emptyLinePlaceholder":380},[220,633,635,638,641,643,646,648,651],{"class":222,"line":634},35,[220,636,637],{"class":230},"  footer",[220,639,640],{"class":230}," a",[220,642,362],{"class":226},[220,644,645],{"class":234},"color",[220,647,368],{"class":226},[220,649,650],{"class":234},"#bfdbfe",[220,652,374],{"class":226},[220,654,656],{"class":222,"line":655},36,[220,657,381],{"emptyLinePlaceholder":380},[220,659,661],{"class":222,"line":660},37,[220,662,663],{"class":341},"  \u002F* GRID ALTERNATIVE — replace the body rule above with:\n",[220,665,667],{"class":222,"line":666},38,[220,668,669],{"class":341},"     body {\n",[220,671,673],{"class":222,"line":672},39,[220,674,675],{"class":341},"       display: grid;\n",[220,677,679],{"class":222,"line":678},40,[220,680,681],{"class":341},"       grid-template-rows: auto 1fr auto;\n",[220,683,685],{"class":222,"line":684},41,[220,686,687],{"class":341},"       min-height: 100vh;\n",[220,689,691],{"class":222,"line":690},42,[220,692,693],{"class":341},"       min-height: 100dvh;\n",[220,695,697],{"class":222,"line":696},43,[220,698,699],{"class":341},"     }\n",[220,701,703],{"class":222,"line":702},44,[220,704,705],{"class":341},"     and delete the main flex rule. The 1fr row plays the role of flex-grow. *\u002F\n",[220,707,709,712,714],{"class":222,"line":708},45,[220,710,711],{"class":226},"\u003C\u002F",[220,713,333],{"class":230},[220,715,238],{"class":226},[220,717,719,721,723],{"class":222,"line":718},46,[220,720,711],{"class":226},[220,722,266],{"class":230},[220,724,238],{"class":226},[220,726,728,730,732],{"class":222,"line":727},47,[220,729,244],{"class":226},[220,731,60],{"class":230},[220,733,238],{"class":226},[220,735,737,740,742,745,747],{"class":222,"line":736},48,[220,738,739],{"class":226},"  \u003C",[220,741,122],{"class":230},[220,743,744],{"class":226},">Site name\u003C\u002F",[220,746,122],{"class":230},[220,748,238],{"class":226},[220,750,752,754,756],{"class":222,"line":751},49,[220,753,739],{"class":226},[220,755,131],{"class":230},[220,757,238],{"class":226},[220,759,761,764,766,769,771],{"class":222,"line":760},50,[220,762,763],{"class":226},"    \u003C",[220,765,10],{"class":230},[220,767,768],{"class":226},">No results\u003C\u002F",[220,770,10],{"class":230},[220,772,238],{"class":226},[220,774,776,778,780,783,785],{"class":222,"line":775},51,[220,777,763],{"class":226},[220,779,14],{"class":230},[220,781,782],{"class":226},">Try a shorter search term.\u003C\u002F",[220,784,14],{"class":230},[220,786,238],{"class":226},[220,788,790,793,795],{"class":222,"line":789},52,[220,791,792],{"class":226},"  \u003C\u002F",[220,794,131],{"class":230},[220,796,238],{"class":226},[220,798,800,802,804],{"class":222,"line":799},53,[220,801,739],{"class":226},[220,803,147],{"class":230},[220,805,238],{"class":226},[220,807,809,811,813,816,818,821,824,826,829,831,833,835,838,841,843],{"class":222,"line":808},54,[220,810,763],{"class":226},[220,812,18],{"class":230},[220,814,815],{"class":234}," href",[220,817,252],{"class":226},[220,819,820],{"class":255},"\"\u002F\"",[220,822,823],{"class":226},">Home\u003C\u002F",[220,825,18],{"class":230},[220,827,828],{"class":226},"> · \u003C",[220,830,18],{"class":230},[220,832,815],{"class":234},[220,834,252],{"class":226},[220,836,837],{"class":255},"\"\u002Fcontact\u002F\"",[220,839,840],{"class":226},">Contact\u003C\u002F",[220,842,18],{"class":230},[220,844,238],{"class":226},[220,846,848,850,852],{"class":222,"line":847},55,[220,849,792],{"class":226},[220,851,147],{"class":230},[220,853,238],{"class":226},[220,855,857,859,861],{"class":222,"line":856},56,[220,858,711],{"class":226},[220,860,60],{"class":230},[220,862,238],{"class":226},[220,864,866,868,870],{"class":222,"line":865},57,[220,867,711],{"class":226},[220,869,215],{"class":230},[220,871,238],{"class":226},[14,873,874,875,878,879,882,883,885,886,888,889,892,893,895,896,899],{},"Two rules deserve a closer look. ",[37,876,877],{},"flex: 1 0 auto"," rather than the more common ",[37,880,881],{},"flex: 1"," matters: ",[37,884,881],{}," sets the basis to zero and allows shrinking, so on a very long page ",[37,887,131],{}," could be squeezed and its content overflow into the footer. A zero shrink factor and an ",[37,890,891],{},"auto"," basis keep the main region at least as tall as its content. And the duplicated ",[37,894,64],{}," is the fallback pattern in its simplest form — an unknown unit invalidates only its own declaration, so older engines keep ",[37,897,898],{},"100vh",".",[29,901,903,904,906,907],{"id":902},"the-key-technique-min-height-never-height","The key technique: ",[37,905,64],{},", never ",[37,908,909],{},"height",[14,911,912,913,917,918,921,922,925,926,928],{},"Everything depends on the outer container being ",[914,915,916],"em",{},"at least"," the viewport height rather than ",[914,919,920],{},"exactly"," it. With ",[37,923,924],{},"height: 100vh"," the body is capped, long content overflows the body's box, and the footer, which is laid out inside the body, sits at the bottom of that capped box — right on top of the overflowing content. ",[37,927,64],{}," removes the cap, so the body grows with its content and the footer always follows the last line.",[14,930,931,932,934,935,938,939,941],{},"The choice of viewport unit is the other half. On mobile Safari and Chrome, ",[37,933,898],{}," is the ",[914,936,937],{},"large"," viewport height — the size with the browser toolbar retracted. When the page first loads the toolbar is showing, so a ",[37,940,898],{}," body is taller than the visible area and the footer starts just below the fold.",[67,943,74,946,74,949,74,952,74,955,74,959,74,964,74,969,74,973,74,977,74,981,74,985,74,990,74,993,74,995,74,998,74,1001,74,1004,74,1007,74,1010,74,1013,74,1016,74,1019,74,1022],{"viewBox":944,"role":70,"ariaLabel":945,"xmlns":72,"style":73},"0 0 720 300","Three phone outlines comparing 100vh, 100svh and 100dvh against a visible toolbar",[76,947,948],{},"Viewport units on a phone with a toolbar",[80,950,951],{},"With the toolbar visible, 100vh extends below the visible area, 100svh fits the small viewport, and 100dvh fits whatever is currently visible.",[84,953,954],{"textAnchor":86,"x":87,"y":88,"style":89},"Which height the footer is measured against",[158,956],{"d":957,"fill":105,"stroke":106,"strokeWidth":161,"opacity":958},"M84 46 H216 Q230 46 230 60 V232 Q230 246 216 246 H84 Q70 246 70 232 V60 Q70 46 84 46 Z","0.7",[98,960],{"x":961,"y":94,"width":962,"height":88,"rx":164,"fill":106,"opacity":963},"78","144","0.18",[84,965,968],{"textAnchor":86,"x":170,"y":966,"style":967},"72","text-anchor:middle;fill:currentColor;font:11px sans-serif","toolbar",[98,970],{"x":961,"y":971,"width":962,"height":93,"rx":164,"fill":116,"opacity":972},"84","0.22",[84,974,898],{"textAnchor":86,"x":170,"y":975,"style":976},"160","text-anchor:middle;fill:currentColor;font:600 13px ui-monospace,monospace",[84,978,980],{"textAnchor":86,"x":170,"y":979,"style":135},"180","spills past",[84,982,984],{"textAnchor":86,"x":170,"y":983,"style":135},"196","the screen",[98,986],{"x":189,"y":987,"width":975,"height":988,"rx":989,"fill":105,"stroke":106,"strokeWidth":161,"opacity":958},"46","200","14",[98,991],{"x":992,"y":94,"width":962,"height":88,"rx":164,"fill":106,"opacity":963},"288",[84,994,968],{"textAnchor":86,"x":87,"y":966,"style":967},[98,996],{"x":992,"y":971,"width":962,"height":997,"rx":164,"fill":116,"opacity":972},"154",[84,999,1000],{"textAnchor":86,"x":87,"y":975,"style":976},"100svh",[84,1002,1003],{"textAnchor":86,"x":87,"y":979,"style":135},"always fits",[98,1005],{"x":1006,"y":987,"width":975,"height":988,"rx":989,"fill":105,"stroke":106,"strokeWidth":161,"opacity":958},"490",[98,1008],{"x":1009,"y":94,"width":962,"height":88,"rx":164,"fill":106,"opacity":963},"498",[84,1011,968],{"textAnchor":86,"x":1012,"y":966,"style":967},"570",[98,1014],{"x":1009,"y":971,"width":962,"height":997,"rx":164,"fill":116,"opacity":1015},"0.34",[84,1017,1018],{"textAnchor":86,"x":1012,"y":975,"style":976},"100dvh",[84,1020,1021],{"textAnchor":86,"x":1012,"y":979,"style":135},"tracks toolbar",[84,1023,1025],{"textAnchor":86,"x":87,"y":1024,"style":151},"292","dvh updates as the toolbar hides; svh is fixed at the smallest possible viewport.",[14,1027,1028,1030,1031,1033,1034,1038],{},[37,1029,1018],{}," is the natural fit for a sticky footer because it is always the visible height: the footer sits on the visible bottom edge whether the toolbar is shown or hidden. The one cost is that the body's minimum height changes as the toolbar animates, which on a short page nudges the footer by the toolbar's height. If that movement bothers you, ",[37,1032,1000],{}," pins the minimum to the smallest viewport and never changes, at the price of a small gap below the footer once the toolbar retracts. The full comparison of the three units lives in ",[18,1035,1037],{"href":1036},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-query-units-cqi-cqb-explained\u002F","Container Query Units: cqi, cqb Explained",", which also covers when container units beat viewport units entirely.",[29,1040,1042],{"id":1041},"variation-an-app-shell-with-a-scrolling-main-region","Variation: an app shell with a scrolling main region",[14,1044,1045,1046,1048,1049,1051,1052,1055,1056,1059],{},"Dashboards and web apps often want the opposite of a document footer: header and footer always visible, and only the middle region scrolling. The same grid template produces it with two changes — an exact ",[37,1047,909],{}," instead of ",[37,1050,64],{}," on the shell, and ",[37,1053,1054],{},"overflow: auto"," plus ",[37,1057,1058],{},"min-height: 0"," on the middle row.",[67,1061,74,1064,74,1067,74,1070,74,1073,74,1077,74,1080,74,1084,74,1087,74,1090,74,1095,74,1098,74,1101,74,1104,74,1110,74,1112,74,1116,74,1118],{"viewBox":1062,"role":70,"ariaLabel":1063,"xmlns":72,"style":73},"0 0 720 260","Comparison of a document layout where the whole page scrolls and an app shell where only main scrolls",[76,1065,1066],{},"Document footer versus app shell",[80,1068,1069],{},"Left, the whole document scrolls and the footer moves with it. Right, the shell is exactly viewport height and a scrollbar appears only on the main region between a fixed header and footer.",[84,1071,1072],{"textAnchor":86,"x":87,"y":88,"style":89},"Who owns the scrollbar",[98,1074],{"x":1075,"y":1076,"width":186,"height":979,"rx":104,"fill":105,"stroke":106,"strokeWidth":107,"opacity":108},"60","44",[98,1078],{"x":966,"y":94,"width":1079,"height":88,"rx":164,"fill":116,"opacity":117},"236",[98,1081],{"x":966,"y":1082,"width":1079,"height":1083,"rx":164,"fill":116,"opacity":127},"86","96",[98,1085],{"x":966,"y":1086,"width":1079,"height":88,"rx":164,"fill":116,"opacity":117},"188",[84,1088,1089],{"textAnchor":86,"x":93,"y":180,"style":121},"min-height: 100dvh",[84,1091,1094],{"textAnchor":86,"x":93,"y":1092,"style":1093},"246","text-anchor:middle;fill:currentColor;font:12px sans-serif;opacity:0.8","document scrolls",[98,1096],{"x":1097,"y":1076,"width":186,"height":979,"rx":104,"fill":105,"stroke":106,"strokeWidth":107,"opacity":108},"400",[98,1099],{"x":1100,"y":94,"width":1079,"height":88,"rx":164,"fill":116,"opacity":117},"412",[98,1102],{"x":1100,"y":1082,"width":1103,"height":1083,"rx":164,"fill":116,"opacity":127},"222",[98,1105],{"x":1106,"y":1107,"width":104,"height":1108,"rx":164,"fill":106,"opacity":1109},"638","90","40","0.5",[98,1111],{"x":1100,"y":1086,"width":1079,"height":88,"rx":164,"fill":116,"opacity":117},[84,1113,1054],{"textAnchor":86,"x":1114,"y":1115,"style":121},"523","130",[84,1117,1058],{"textAnchor":86,"x":1114,"y":170,"style":121},[84,1119,1120],{"textAnchor":86,"x":155,"y":1092,"style":1093},"only main scrolls",[211,1122,1126],{"className":1123,"code":1124,"language":1125,"meta":216,"style":216},"language-css shiki shiki-themes github-light-high-contrast github-dark-high-contrast",".app {\n  display: grid;\n  grid-template-rows: auto 1fr auto;\n  height: 100vh;\n  height: 100dvh;           \u002F* exact, so the shell never scrolls *\u002F\n}\n\n.app > main {\n  min-height: 0;            \u002F* release the automatic minimum so 1fr can shrink *\u002F\n  overflow: auto;           \u002F* the scrollbar lives here, not on the page *\u002F\n  overscroll-behavior: contain;\n}\n\n\u002F* A scrollable region must be reachable by keyboard. *\u002F\n.app > main:focus-visible {\n  outline: 2px solid #2d5bff;\n  outline-offset: -2px;\n}\n","css",[37,1127,1128,1135,1147,1166,1179,1195,1200,1204,1216,1231,1245,1257,1261,1265,1270,1283,1302,1316],{"__ignoreMap":216},[220,1129,1130,1133],{"class":222,"line":223},[220,1131,1132],{"class":234},".app",[220,1134,390],{"class":226},[220,1136,1137,1140,1142,1145],{"class":222,"line":241},[220,1138,1139],{"class":234},"  display",[220,1141,368],{"class":226},[220,1143,1144],{"class":234},"grid",[220,1146,404],{"class":226},[220,1148,1149,1152,1154,1156,1159,1162,1164],{"class":222,"line":261},[220,1150,1151],{"class":234},"  grid-template-rows",[220,1153,368],{"class":226},[220,1155,891],{"class":234},[220,1157,1158],{"class":234}," 1",[220,1160,1161],{"class":443},"fr",[220,1163,538],{"class":234},[220,1165,404],{"class":226},[220,1167,1168,1171,1173,1175,1177],{"class":222,"line":271},[220,1169,1170],{"class":234},"  height",[220,1172,368],{"class":226},[220,1174,440],{"class":234},[220,1176,444],{"class":443},[220,1178,404],{"class":226},[220,1180,1181,1183,1185,1187,1189,1192],{"class":222,"line":289},[220,1182,1170],{"class":234},[220,1184,368],{"class":226},[220,1186,440],{"class":234},[220,1188,458],{"class":443},[220,1190,1191],{"class":226},";           ",[220,1193,1194],{"class":341},"\u002F* exact, so the shell never scrolls *\u002F\n",[220,1196,1197],{"class":222,"line":314},[220,1198,1199],{"class":226},"}\n",[220,1201,1202],{"class":222,"line":328},[220,1203,381],{"emptyLinePlaceholder":380},[220,1205,1206,1208,1211,1214],{"class":222,"line":338},[220,1207,1132],{"class":234},[220,1209,1210],{"class":443}," >",[220,1212,1213],{"class":230}," main",[220,1215,390],{"class":226},[220,1217,1218,1221,1223,1225,1228],{"class":222,"line":345},[220,1219,1220],{"class":234},"  min-height",[220,1222,368],{"class":226},[220,1224,371],{"class":234},[220,1226,1227],{"class":226},";            ",[220,1229,1230],{"class":341},"\u002F* release the automatic minimum so 1fr can shrink *\u002F\n",[220,1232,1233,1236,1238,1240,1242],{"class":222,"line":351},[220,1234,1235],{"class":234},"  overflow",[220,1237,368],{"class":226},[220,1239,891],{"class":234},[220,1241,1191],{"class":226},[220,1243,1244],{"class":341},"\u002F* the scrollbar lives here, not on the page *\u002F\n",[220,1246,1247,1250,1252,1255],{"class":222,"line":377},[220,1248,1249],{"class":234},"  overscroll-behavior",[220,1251,368],{"class":226},[220,1253,1254],{"class":234},"contain",[220,1256,404],{"class":226},[220,1258,1259],{"class":222,"line":384},[220,1260,1199],{"class":226},[220,1262,1263],{"class":222,"line":393},[220,1264,381],{"emptyLinePlaceholder":380},[220,1266,1267],{"class":222,"line":407},[220,1268,1269],{"class":341},"\u002F* A scrollable region must be reachable by keyboard. *\u002F\n",[220,1271,1272,1274,1276,1278,1281],{"class":222,"line":420},[220,1273,1132],{"class":234},[220,1275,1210],{"class":443},[220,1277,1213],{"class":230},[220,1279,1280],{"class":234},":focus-visible",[220,1282,390],{"class":226},[220,1284,1285,1288,1290,1292,1294,1297,1300],{"class":222,"line":426},[220,1286,1287],{"class":234},"  outline",[220,1289,368],{"class":226},[220,1291,161],{"class":234},[220,1293,474],{"class":443},[220,1295,1296],{"class":234}," solid",[220,1298,1299],{"class":234}," #2d5bff",[220,1301,404],{"class":226},[220,1303,1304,1307,1309,1312,1314],{"class":222,"line":432},[220,1305,1306],{"class":234},"  outline-offset",[220,1308,368],{"class":226},[220,1310,1311],{"class":234},"-2",[220,1313,474],{"class":443},[220,1315,404],{"class":226},[220,1317,1318],{"class":222,"line":449},[220,1319,1199],{"class":226},[14,1321,1322,1323,1326,1327,1330,1331,1334,1335,1337,1338,1342,1343,1346,1347,899],{},"Add ",[37,1324,1325],{},"tabindex=\"0\""," and an accessible name such as ",[37,1328,1329],{},"aria-label=\"Messages\""," to that ",[37,1332,1333],{},"\u003Cmain>"," so keyboard users can scroll it; a scroll container with no focusable content is otherwise unreachable, which is an axe-core failure as well as a usability bug. The ",[37,1336,1058],{}," line is the same automatic-minimum release covered in ",[18,1339,1341],{"href":1340},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fpreventing-flex-and-grid-overflow\u002F","Preventing Flex and Grid Overflow","; without it the ",[37,1344,1345],{},"1fr"," row refuses to shrink below its content and the whole shell scrolls instead. When the middle region needs its own internal columns, the shell is a natural parent for the ",[18,1348,1350],{"href":1349},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fholy-grail-layout-with-grid\u002F","Holy Grail Layout With Grid",[29,1352,1354],{"id":1353},"when-a-framework-adds-a-wrapper","When a framework adds a wrapper",[14,1356,1357,1358,1361,1362,1365,1366,1368,1369,1371],{},"The most common way this pattern breaks in production is not the CSS at all but an extra element. Single-page frameworks mount into a root ",[37,1359,1360],{},"\u003Cdiv id=\"app\">"," or ",[37,1363,1364],{},"\u003Cdiv id=\"__nuxt\">",", so ",[37,1367,60],{}," has exactly one child and the header, main and footer are its grandchildren. The flex or grid rule on ",[37,1370,60],{}," now lays out that one wrapper, which is only as tall as its content, and the footer floats again.",[14,1373,1374,1375,1377,1378,1380,1381,1383,1384,1386,1387,1389],{},"There are two fixes, and which one to use depends on how much of the chain you control. The first moves the whole rule down one level: give the wrapper ",[37,1376,1089],{}," and the column layout, and leave ",[37,1379,60],{}," alone. The second passes the height through: make ",[37,1382,60],{}," a column flex container with the viewport minimum, make the wrapper ",[37,1385,877],{}," and itself a column flex container, and then grow ",[37,1388,131],{}," inside it. The second version survives if the framework later adds a second top-level node, such as a portal container for toasts, because each level only claims the space its parent offers.",[14,1391,1392,1393,1396,1397,1399,1400,1361,1402,1405],{},"A related trap is ",[37,1394,1395],{},"display: contents",". Some component libraries set it on wrappers so they do not interfere with layout, and it genuinely works here: an element with ",[37,1398,1395],{}," generates no box, so its children participate directly in the parent's flex or grid layout. The catch is that older engines dropped such elements from the accessibility tree, so reserve it for wrappers that carry no semantics — never for the ",[37,1401,1333],{},[37,1403,1404],{},"\u003Cfooter>"," landmark itself.",[14,1407,1408,1409,1412,1413,1055,1416,1419,1420,1422],{},"Finally, check for a ",[37,1410,1411],{},"height: 100%"," chain inherited from an older stylesheet. Percentage heights resolve against the parent's definite height, so ",[37,1414,1415],{},"html { height: 100% }",[37,1417,1418],{},"body { height: 100% }"," reproduces the capped-height overlap bug described below even when the outer rule uses ",[37,1421,64],{},". Delete those declarations when adopting this pattern; the viewport unit already provides the only height reference the layout needs.",[29,1424,1426],{"id":1425},"browser-support","Browser support",[14,1428,1429,1430,1433,1434,1436,1437,1439,1440,1443,1444,1447],{},"Column flexbox and ",[37,1431,1432],{},"grid-template-rows"," with ",[37,1435,1345],{}," are supported in every current browser; CSS Grid dates from Chrome 57, Firefox 52 and Safari 10.1. The dynamic, small and large viewport units arrived in Chrome and Edge 108, Firefox 101 and Safari 15.4. Because the ",[37,1438,898],{}," declaration comes first, older engines fall back to it automatically — no ",[37,1441,1442],{},"@supports"," block is needed. If you want to scope the unit explicitly, ",[37,1445,1446],{},"@supports (height: 100dvh)"," is a valid guard.",[29,1449,1451],{"id":1450},"faq","FAQ",[14,1453,1454,1462,1463,1465,1466,1468,1469,1471,1472,1474],{},[1455,1456,1457,1458,1461],"strong",{},"Why does ",[37,1459,1460],{},"min-height: 100vh"," leave a gap or scrollbar on mobile?","\nOn mobile browsers ",[37,1464,898],{}," is the height with the address bar retracted, which is taller than the visible area when the bar is showing. Use ",[37,1467,1018],{},", which tracks the bar as it appears and disappears, or ",[37,1470,1000],{}," for the smallest stable height, with ",[37,1473,898],{}," declared first as a fallback.",[14,1476,1477,1485],{},[1455,1478,1479,1480,1361,1482,1484],{},"Should the footer use ",[37,1481,39],{},[37,1483,43],{},"?","\nNeither, for this pattern. A fixed footer is always on screen and covers content; a sticky footer in the positioning sense sticks while scrolling. The layout technique here only pushes the footer down on short pages and lets it scroll normally on long ones.",[14,1487,1488,1491,1492,1495,1496,1499],{},[1455,1489,1490],{},"Is the flexbox or the grid version better?","\nThey produce the same result. Grid with ",[37,1493,1494],{},"grid-template-rows: auto 1fr auto"," states the three rows explicitly and tolerates extra wrapper elements less well; flexbox with ",[37,1497,1498],{},"flex-grow"," on the main element tolerates any number of other children. Pick the one that matches how many direct children the body has.",[14,1501,1502,1505,1506,1508,1509,1511],{},[1455,1503,1504],{},"Why does my footer overlap content when the page is long?","\nBecause something in the chain has a fixed height instead of a minimum height. With ",[37,1507,924],{}," the container cannot grow past the viewport, so long content overflows it and the footer sits on top. Always use ",[37,1510,64],{}," on the outer container.",[29,1513,1515],{"id":1514},"related","Related",[1517,1518,1519,1525,1532,1537],"ul",{},[1520,1521,1522,1524],"li",{},[18,1523,21],{"href":20}," — the parent guide to flex-based page structure.",[1520,1526,1527,1531],{},[18,1528,1530],{"href":1529},"\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002Fflex-wrap-intrinsic-responsive-rows\u002F","Breakpoint-Free Rows With flex-wrap"," — the same free-space sharing, applied along the row axis.",[1520,1533,1534,1536],{},[18,1535,1350],{"href":1349}," — adding sidebars inside the main region.",[1520,1538,1539,1543],{},[18,1540,1542],{"href":1541},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-triggered-reveal-animations\u002F","Scroll-Triggered Reveal Animations"," — animating content as it enters a scrolling main region.",[333,1545,1546],{},"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 pre.shiki code .sLBg1, html code.shiki .sLBg1{--shiki-default:#66707B;--shiki-dark:#BDC4CC}html pre.shiki code .sHUrx, html code.shiki .sHUrx{--shiki-default:#A0111F;--shiki-dark:#FF9492}html .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);}",{"title":216,"searchDepth":241,"depth":241,"links":1548},[1549,1550,1551,1552,1554,1555,1556,1557,1558],{"id":31,"depth":241,"text":32},{"id":53,"depth":241,"text":54},{"id":202,"depth":241,"text":203},{"id":902,"depth":241,"text":1553},"The key technique: min-height, never height",{"id":1041,"depth":241,"text":1042},{"id":1353,"depth":241,"text":1354},{"id":1425,"depth":241,"text":1426},{"id":1450,"depth":241,"text":1451},{"id":1514,"depth":241,"text":1515},"Pin a footer to the bottom of short pages without fixed positioning: the flex-grow and 1fr grid methods, min-height with dvh, and nested app-shell layouts.","md",{"pageTitle":1562,"datePublished":1563,"dateModified":1563,"faq":1564},"Sticky Footer With Flexbox or Grid","2026-09-18",[1565,1568,1571,1573],{"q":1566,"a":1567},"Why does min-height: 100vh leave a gap or scrollbar on mobile?","On mobile browsers 100vh is the height with the address bar retracted, which is taller than the visible area when the bar is showing. Use 100dvh, which tracks the bar as it appears and disappears, or 100svh for the smallest stable height, with 100vh declared first as a fallback.",{"q":1569,"a":1570},"Should the footer use position: fixed or position: sticky?","Neither, for this pattern. A fixed footer is always on screen and covers content; a sticky footer in the positioning sense sticks while scrolling. The layout technique here only pushes the footer down on short pages and lets it scroll normally on long ones.",{"q":1490,"a":1572},"They produce the same result. Grid with grid-template-rows: auto 1fr auto states the three rows explicitly and tolerates extra wrapper elements less well; flexbox with flex-grow on the main element tolerates any number of other children. Pick the one that matches how many direct children the body has.",{"q":1504,"a":1574},"Because something in the chain has a fixed height instead of a minimum height. With height: 100vh the container cannot grow past the viewport, so long content overflows it and the footer sits on top. Always use min-height on the outer container.","\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002Fsticky-footer-with-flexbox-and-grid",{"title":5,"description":1559},"mastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002Fsticky-footer-with-flexbox-and-grid\u002Findex","kvlREZoLAb8ycoqH5PQDRet5I0VbibSoNfyqDXCBejo",[1580,1583,1586,1589,1592,1595,1598,1601,1604,1607,1610,1613,1616,1619,1622,1625,1628,1631,1634,1637,1640,1643,1646,1649,1652,1655,1658,1661,1664,1667,1670,1673,1676,1679,1682,1685,1688,1691,1694,1697,1700,1703,1706,1709,1712,1715,1718,1721,1724,1727,1730,1733,1736,1739,1742,1745,1748,1751,1754,1757,1760,1763,1766,1769,1772,1775,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,1861,1864,1867,1870,1873,1876,1879,1882,1885,1888,1891,1894,1897,1900,1903,1906,1909,1912,1915,1918,1921,1924,1927,1930,1933,1936,1939,1942,1945,1948,1951,1954,1957,1960,1963,1966,1969,1972,1973,1976,1979,1982,1985,1988,1991,1994,1997,1999,2002,2005,2008,2011,2014,2017,2020,2023,2026,2029,2032,2035,2038,2041,2044,2047,2050,2053,2056,2059,2062,2065,2068,2071,2074,2077,2080,2083,2086,2089,2092,2095,2098,2101,2104,2107,2110,2113,2116,2119,2122,2125,2128,2131,2134],{"path":1581,"title":1582},"\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":1584,"title":1585},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fflashing-content-and-seizure-thresholds","Flashing Content and Seizure Thresholds",{"path":1587,"title":1588},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fforced-colors-mode-and-animations","Forced Colors Mode and Animations",{"path":1590,"title":1591},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations","Accessibility in CSS Animations: Patterns, Specs & Best Practices",{"path":1593,"title":1594},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fpause-controls-for-looping-animations","Pause Controls for Looping CSS Animations: Meeting WCAG 2.2.2",{"path":1596,"title":1597},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fprefers-reduced-motion-recipes","prefers-reduced-motion Recipes: A Reduction for Every Common Effect",{"path":1599,"title":1600},"\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":1602,"title":1603},"\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":1605,"title":1606},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fvestibular-safe-animation-patterns","Vestibular-Safe Animation Patterns: Why Some Motion Makes People Sick",{"path":1608,"title":1609},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fwcag-motion-success-criteria","WCAG Motion Success Criteria: What Each One Actually Requires",{"path":1611,"title":1612},"\u002Fcss-only-micro-interactions-animations\u002Fclip-path-and-mask-animations\u002Fanimated-gradient-borders-with-property","Animated Gradient Borders With @property: A Spinning Highlight Without Extra Elements",{"path":1614,"title":1615},"\u002Fcss-only-micro-interactions-animations\u002Fclip-path-and-mask-animations\u002Fclip-path-reveal-animations","Clip-Path Reveal Animations: Wipes, Irises and Corners Without Extra Markup",{"path":1617,"title":1618},"\u002Fcss-only-micro-interactions-animations\u002Fclip-path-and-mask-animations","Clip-Path & Mask Animations: Animating Visibility Instead of Position",{"path":1620,"title":1621},"\u002Fcss-only-micro-interactions-animations\u002Fclip-path-and-mask-animations\u002Fmask-image-fade-edges","Fading Edges With mask-image: Soft Boundaries That Work on Any Background",{"path":1623,"title":1624},"\u002Fcss-only-micro-interactions-animations\u002Fclip-path-and-mask-animations\u002Fmorphing-shapes-with-clip-path-polygon","Morphing Shapes With clip-path: polygon(): Point-Matched Transitions",{"path":1626,"title":1627},"\u002Fcss-only-micro-interactions-animations\u002Fcolor-and-theme-transitions\u002Fanimating-gradients","Animating CSS Gradients: Smooth Colour Motion Without Jumps",{"path":1629,"title":1630},"\u002Fcss-only-micro-interactions-animations\u002Fcolor-and-theme-transitions\u002Fcolor-mix-hover-states","Hover and Active States With color-mix(): One Token, Every Shade",{"path":1632,"title":1633},"\u002Fcss-only-micro-interactions-animations\u002Fcolor-and-theme-transitions","Color & Theme Transitions: Colour as Part of the Motion System",{"path":1635,"title":1636},"\u002Fcss-only-micro-interactions-animations\u002Fcolor-and-theme-transitions\u002Flight-dark-function-for-themes","Light and Dark Themes With light-dark(): One Declaration per Colour",{"path":1638,"title":1639},"\u002Fcss-only-micro-interactions-animations\u002Fcolor-and-theme-transitions\u002Fsmooth-theme-switching-transitions","Smooth Theme Switching: Crossfades, Circular Reveals and No Flash",{"path":1641,"title":1642},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fcontainer-query-hover-affordances","Container Query Hover Affordances: When Narrow Means Persistent, Not Hidden",{"path":1644,"title":1645},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion","Container-Aware Motion: Animation Sized by the Space a Component Actually Has",{"path":1647,"title":1648},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Flayout-change-animations-at-container-breakpoints","Animating Changes at Container Breakpoints",{"path":1650,"title":1651},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fmotion-driven-by-container-style-queries","Motion Driven by Container Style Queries",{"path":1653,"title":1654},"\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":1656,"title":1657},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fsuppressing-motion-in-small-containers","Suppressing Motion in Small Containers: Deliberately Animating Nothing",{"path":1659,"title":1660},"\u002Fcss-only-micro-interactions-animations\u002Fcss-animation-vs-web-animations-api\u002Fcontrolling-css-animations-from-javascript","Controlling CSS Animations From JavaScript",{"path":1662,"title":1663},"\u002Fcss-only-micro-interactions-animations\u002Fcss-animation-vs-web-animations-api","CSS Animation vs the Web Animations API: A Decision Guide",{"path":1665,"title":1666},"\u002Fcss-only-micro-interactions-animations\u002Fcss-animation-vs-web-animations-api\u002Fwaapi-vs-css-for-interruptible-ui","Interruptible UI: CSS Transitions vs WAAPI",{"path":1668,"title":1669},"\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":1671,"title":1672},"\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":1674,"title":1675},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Fcustom-property-fallbacks-and-invalid-values","Custom Property Fallbacks and Invalid Values",{"path":1677,"title":1678},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Ffluid-spacing-tokens-driving-transition-durations","Fluid Spacing Tokens That Drive Transition Durations",{"path":1680,"title":1681},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture","CSS Custom Properties Architecture: Scalable Design Systems & Dynamic UI",{"path":1683,"title":1684},"\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":1686,"title":1687},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Fscoping-custom-properties-to-components","Scoping Custom Properties to Components",{"path":1689,"title":1690},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fcss-transition-timing-functions","CSS Transition Timing Functions: ease, cubic-bezier(), steps() and linear()",{"path":1692,"title":1693},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals","CSS Transition Fundamentals: Architecture, Performance & Patterns",{"path":1695,"title":1696},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Finterrupted-and-reversing-transitions","Interrupted and Reversing Transitions: What Happens Mid-Flight",{"path":1698,"title":1699},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fstarting-style-entry-animations","@starting-style: Animating an Element's Very First Style Change",{"path":1701,"title":1702},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Ftransition-delay-choreography","Choreographing Motion With transition-delay",{"path":1704,"title":1705},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Ftransition-shorthand-and-multiple-properties","The transition Shorthand and Multiple Properties",{"path":1707,"title":1708},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Ftransitioning-display-with-allow-discrete","Transitioning display with transition-behavior: allow-discrete and @starting-style",{"path":1710,"title":1711},"\u002Fcss-only-micro-interactions-animations\u002Fdialog-and-popover-animations\u002Fanimating-dialog-open-and-close","Animating \u003Cdialog> Open and Close: Both Directions, No Library",{"path":1713,"title":1714},"\u002Fcss-only-micro-interactions-animations\u002Fdialog-and-popover-animations\u002Fbackdrop-animations","Animating ::backdrop: Fades and Blurs Behind Dialogs and Popovers",{"path":1716,"title":1717},"\u002Fcss-only-micro-interactions-animations\u002Fdialog-and-popover-animations","Dialog & Popover Animations: Motion for the Top Layer",{"path":1719,"title":1720},"\u002Fcss-only-micro-interactions-animations\u002Fdialog-and-popover-animations\u002Finterpolate-size-for-height-auto-animation","Animating to height: auto With interpolate-size and calc-size()",{"path":1722,"title":1723},"\u002Fcss-only-micro-interactions-animations\u002Fdialog-and-popover-animations\u002Fpopover-entry-and-exit-transitions","Popover Menus That Animate From Their Anchor",{"path":1725,"title":1726},"\u002Fcss-only-micro-interactions-animations\u002Feasing-and-motion-design\u002Fchoosing-animation-durations","Choosing Animation Durations: How Long Motion Should Last",{"path":1728,"title":1729},"\u002Fcss-only-micro-interactions-animations\u002Feasing-and-motion-design\u002Fcubic-bezier-overshoot-and-anticipation","Overshoot and Anticipation With cubic-bezier(): Motion With Character",{"path":1731,"title":1732},"\u002Fcss-only-micro-interactions-animations\u002Feasing-and-motion-design\u002Fentry-vs-exit-easing","Entry vs Exit Easing: Different Curves for Arriving and Leaving",{"path":1734,"title":1735},"\u002Fcss-only-micro-interactions-animations\u002Feasing-and-motion-design","Easing & Motion Design: Making CSS Motion Feel Intentional",{"path":1737,"title":1738},"\u002Fcss-only-micro-interactions-animations\u002Feasing-and-motion-design\u002Flinear-easing-function-for-springs","Spring and Bounce Easing With linear(): Physical Motion Without JavaScript",{"path":1740,"title":1741},"\u002Fcss-only-micro-interactions-animations\u002Feasing-and-motion-design\u002Fsteps-easing-for-sprite-animations","steps() Easing: Sprite Sheets, Typewriters and Other Frame-by-Frame Effects",{"path":1743,"title":1744},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Faccessible-css-only-tooltips","Accessible CSS-Only Tooltips and Hover Cards With  and ",{"path":1746,"title":1747},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Fbutton-press-and-active-states","Button Press and  States",{"path":1749,"title":1750},"\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":1752,"title":1753},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Ffocus-within-form-patterns"," Form Patterns: Styling a Group From the Field Inside It",{"path":1755,"title":1756},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Fhover-intent-delays-with-transition-delay","Hover Intent Delays With transition-delay: Menus That Don't Flicker",{"path":1758,"title":1759},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design","Hover & Focus State Design: Spec-Compliant Patterns for Modern UIs",{"path":1761,"title":1762},"\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":1764,"title":1765},"\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":1767,"title":1768},"\u002Fcss-only-micro-interactions-animations","CSS-Only Micro-Interactions & Animations: Architecture, Performance & Implementation",{"path":1770,"title":1771},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fanimation-composition-and-stacking","Stacking Animations With animation-composition",{"path":1773,"title":1774},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fanimation-fill-mode-explained","animation-fill-mode: What an Animation Applies Before and After It Runs",{"path":1776,"title":1777},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcontainer-query-triggered-keyframe-animations","Container-Query-Triggered Keyframe Animations: Animate Differently per Available Space",{"path":1779,"title":1780},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcss-only-accordions-and-disclosure","CSS-Only Accordions and Disclosure Widgets with details and summary",{"path":1782,"title":1783},"\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":1785,"title":1786},"\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":1788,"title":1789},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns","Keyframe Animation Patterns: Spec-Compliant Architectures for Modern UIs",{"path":1791,"title":1792},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fmulti-step-keyframes-and-per-keyframe-easing","Multi-Step Keyframes and Per-Keyframe Easing",{"path":1794,"title":1795},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fstaggered-list-animations-with-custom-properties","Staggered List Animations Using --i Index Custom Properties",{"path":1797,"title":1798},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fanimating-box-shadow-and-filters-cheaply","Animating box-shadow and Filters Cheaply",{"path":1800,"title":1801},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fcontain-property-for-animation-performance","The contain Property for Animation Performance",{"path":1803,"title":1804},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fcss-triggers-layout-paint-composite","Layout, Paint and Composite: What Triggers What",{"path":1806,"title":1807},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration","Performance & GPU Acceleration in CSS: A Developer’s Blueprint",{"path":1809,"title":1810},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Foptimizing-css-animations-for-60fps","Optimizing CSS Animations for 60fps: Budgeting the Frame",{"path":1812,"title":1813},"\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":1815,"title":1816},"\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":1818,"title":1819},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations","Scroll-Driven Animations: Binding Motion to Scroll Position in Pure CSS",{"path":1821,"title":1822},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-driven-animation-fallbacks","Shipping Scroll-Driven Animations Without Breaking Anything",{"path":1824,"title":1825},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-driven-parallax-effects","Scroll-Driven Parallax Effects in CSS",{"path":1827,"title":1828},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-progress-bar-without-javascript","A Reading Progress Bar Driven by scroll(root)",{"path":1830,"title":1831},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-triggered-reveal-animations","Reveal-on-Scroll with view() and animation-range",{"path":1833,"title":1834},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Ftimeline-scope-for-cross-element-animations","timeline-scope for Cross-Element Animations",{"path":1836,"title":1837},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fview-timeline-and-animation-range","View Timelines and animation-range",{"path":1839,"title":1840},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fcross-document-view-transitions","Cross-Document View Transitions",{"path":1842,"title":1843},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers","View Transitions for CSS Developers: the Pseudo-Element Tree, Snapshots, and Named Elements",{"path":1845,"title":1846},"\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":1848,"title":1849},"\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":1851,"title":1852},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fview-transition-types-and-classes","View Transition Types and Classes",{"path":1854,"title":1855},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fview-transitions-for-list-reordering","View Transitions for List Reordering",{"path":1857,"title":1858},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fview-transitions-with-reduced-motion","Honouring prefers-reduced-motion in View Transitions",{"path":477,"title":1860},"Modern CSS Layouts & Micro-Interactions",{"path":1862,"title":1863},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioned-tooltips","Anchor-Positioned Tooltips: Tethering, Flipping, and Getting the Semantics Right",{"path":1865,"title":1866},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioning-fallbacks","Anchor Positioning Fallbacks: A Graceful Floor for Older Browser Versions",{"path":1868,"title":1869},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-size-for-matching-widths","anchor-size(): Overlays That Match Their Trigger's Size",{"path":1871,"title":1872},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays","CSS Anchor Positioning and Overlays: Tethering Elements Without JavaScript",{"path":1874,"title":1875},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fpopover-attribute-and-css-styling","The popover Attribute: Top-Layer Overlays With No JavaScript",{"path":1877,"title":1878},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fpopover-light-dismiss-and-stacking","Popover Light Dismiss, Nesting and Stacking",{"path":1880,"title":1881},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fposition-area-grid-explained","position-area: The Anchor Placement Grid",{"path":1883,"title":1884},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Fcontainer-query-polyfill-tradeoffs","Container Query Polyfills: What They Cost and When to Skip Them",{"path":1886,"title":1887},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Ffeature-detection-with-supports","Feature Detection with @supports: Syntax, Semantics, and the Traps",{"path":1889,"title":1890},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Fhandling-container-query-fallbacks-for-older-browsers","Handling Container Query Fallbacks for Older Browsers",{"path":1892,"title":1893},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks","Container Query Fallbacks: Spec-Compliant CSS Strategies for Legacy Browsers",{"path":1895,"title":1896},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Fintrinsic-layout-fallbacks-without-queries","Intrinsic Layout Fallbacks: Baselines That Adapt Without Any Query",{"path":1898,"title":1899},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Ftesting-fallbacks-without-old-browsers","Testing CSS Fallbacks Without an Old Browser",{"path":1901,"title":1902},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-queries-inside-css-nesting","Container Queries Inside CSS Nesting: Keeping Responses Next to the Styles They Change",{"path":1904,"title":1905},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-query-range-and-logic-operators","Container Query Range Syntax and Logic Operators",{"path":1907,"title":1908},"\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":1910,"title":1911},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-type-size-vs-inline-size","Choosing container-type: inline-size, size, or normal",{"path":1913,"title":1914},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-vs-media-queries-comparison","Container vs Media Queries: Choosing the Right Reference Box",{"path":1916,"title":1917},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fdebugging-container-queries-in-devtools","Debugging Container Queries in DevTools: Why a Rule Doesn't Match",{"path":1919,"title":1920},"\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":1922,"title":1923},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics","Container Query Syntax Basics",{"path":1925,"title":1926},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fnesting-and-naming-container-queries","Nesting and Naming Container Queries: Targeting the Right Ancestor",{"path":1928,"title":1929},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fauto-fit-minmax-responsive-grids","Responsive Grids with repeat(auto-fit, minmax())",{"path":1931,"title":1932},"\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":1934,"title":1935},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fgrid-auto-flow-dense-packing","grid-auto-flow: dense for Packed Layouts",{"path":1937,"title":1938},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fgrid-template-areas-responsive-layouts","Responsive Layouts With grid-template-areas: Rearranging Regions by Name",{"path":1940,"title":1941},"\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":1943,"title":1944},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts","CSS Grid and Subgrid Layouts for Responsive Interfaces",{"path":1946,"title":1947},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fmasonry-style-layouts-with-grid","Masonry-Style Layouts With the CSS That Ships Today",{"path":1949,"title":1950},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Foverlapping-elements-with-grid-stacking","Overlapping Elements With Grid Stacking: Layers Without position: absolute",{"path":1952,"title":1953},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fsubgrid-vs-nested-grid","Subgrid vs an Independently Nested Grid",{"path":1955,"title":1956},"\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002Fcentering-in-css-every-method","Centering in CSS: Every Modern Method and When Each One Breaks",{"path":1958,"title":1959},"\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002Fflex-basis-vs-width","flex-basis vs width: Which Size a Flex Item Actually Starts From",{"path":1961,"title":1962},"\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002Fflex-grow-and-flex-shrink-explained","flex-grow and flex-shrink Explained",{"path":1964,"title":1965},"\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002Fflex-wrap-intrinsic-responsive-rows","Breakpoint-Free Responsive Rows With flex-wrap and flex-basis",{"path":1967,"title":1968},"\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002Fflexbox-gap-and-spacing","Flexbox gap vs Margins: Spacing Items Without Edge Hacks",{"path":1970,"title":1971},"\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns","Flexbox Layout Patterns: One-Dimensional Layout for Real Components",{"path":1575,"title":5},{"path":1974,"title":1975},"\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":1977,"title":1978},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Fdebugging-clamp-values","Debugging clamp(): Values That Are Ignored, Stuck or Never Fluid",{"path":1980,"title":1981},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-line-height-and-measure","Fluid Line Height and Measure: Keeping Text Readable as It Scales",{"path":1983,"title":1984},"\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":1986,"title":1987},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-type-accessibility-and-zoom","Fluid Type, Accessibility and Zoom: The vw-Only Trap",{"path":1989,"title":1990},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-typography-without-javascript","Fluid Typography Without JavaScript: A Precision CSS Reference",{"path":1992,"title":1993},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp","Fluid Typography with clamp(): A Practical Guide for Modern CSS",{"path":1995,"title":1996},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ftext-wrap-balance-and-pretty","text-wrap: balance and pretty: Better Line Breaks Without Manual Breaks",{"path":1998,"title":26},"\u002Fmastering-container-queries-responsive-layouts",{"path":2000,"title":2001},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Faspect-ratio-for-responsive-media","Using aspect-ratio for Responsive Media and Preventing Layout Shift",{"path":2003,"title":2004},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fcontent-visibility-and-contain-intrinsic-size","content-visibility and contain-intrinsic-size: Rendering Only What Is Near the Screen",{"path":2006,"title":2007},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques","Intrinsic Sizing Techniques: Modern CSS Layouts for Responsive UI",{"path":2009,"title":2010},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Flayout-widths-with-min-max-clamp","Layout Widths With min(), max() and clamp(): Sizing Without Breakpoints",{"path":2012,"title":2013},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fmin-max-fit-content-explained","min-content, max-content, and fit-content() Explained",{"path":2015,"title":2016},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fobject-fit-and-object-position","object-fit and object-position: Images That Fit Any Box",{"path":2018,"title":2019},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fpreventing-flex-and-grid-overflow","The min-width: auto Trap in Flex and Grid Layouts",{"path":2021,"title":2022},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-for-reset-and-tokens","Cascade Layers for Reset and Design Tokens",{"path":2024,"title":2025},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-vs-specificity-hacks","Cascade Layers vs Specificity Hacks: Ordering Instead of Escalating",{"path":2027,"title":2028},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcss-scope-for-component-styles","@scope for Component Styles: Short Selectors That Cannot Leak",{"path":2030,"title":2031},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies","Modern CSS Reset Strategies: A Spec-Compliant Foundation",{"path":2033,"title":2034},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Frevert-layer-and-revert-keywords","initial, inherit, unset, revert and revert-layer: Undoing Styles Correctly",{"path":2036,"title":2037},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fwriting-a-minimal-modern-reset","Writing a Minimal Modern CSS Reset: Every Line Justified",{"path":2039,"title":2040},"\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has\u002Fcontent-aware-card-layouts-with-has","Content-Aware Card Layouts With :has(): One Component, Many Shapes",{"path":2042,"title":2043},"\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has\u002Fempty-and-loading-states-with-has","Empty and Loading States With ()",{"path":2045,"title":2046},"\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has\u002Fform-validation-layouts-with-has","Form Validation Layouts With :has(): Styling Groups From Field State",{"path":2048,"title":2049},"\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has\u002Fhas-selector-performance",":has() Selector Performance: What Is Cheap, What Is Not, and How to Measure",{"path":2051,"title":2052},"\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has\u002Fhas-vs-container-style-queries",":has() vs Container Style Queries: Discovered State and Published State",{"path":2054,"title":2055},"\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has","Parent-Aware Layouts With :has(): Letting Containers React to Their Contents",{"path":2057,"title":2058},"\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has\u002Fquantity-queries-with-has","Quantity Queries With :has(): Layouts That Respond to How Many Items There Are",{"path":2060,"title":2061},"\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":2063,"title":2064},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fcontainer-query-data-tables","Container Query Data Tables: Reflowing Tables to Cards",{"path":2066,"title":2067},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fcontainer-query-sidebar-layouts","Container Query Sidebar Layouts That Travel Between Contexts",{"path":2069,"title":2070},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns","Responsive Component Patterns: Architecture & Implementation",{"path":2072,"title":2073},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-forms-with-container-queries","Responsive Forms with Container Queries: Reflow Without Losing the Wiring",{"path":2075,"title":2076},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-hero-sections-with-container-queries","Responsive Hero Sections With Container Queries",{"path":2078,"title":2079},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-navigation-without-media-queries","Responsive Navigation Without Media Queries Using Container Queries",{"path":2081,"title":2082},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-pricing-tables","Responsive Pricing Tables: Aligned Features, a Clear Recommendation, Any Width",{"path":2084,"title":2085},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Ftabs-that-become-accordions","Tabs That Become an Accordion: One Component, Two Layouts",{"path":2087,"title":2088},"\u002Fmastering-container-queries-responsive-layouts\u002Fscroll-snap-and-overflow-layouts\u002Fcss-only-carousel-with-scroll-snap","A CSS-Only Carousel With Scroll Snap",{"path":2090,"title":2091},"\u002Fmastering-container-queries-responsive-layouts\u002Fscroll-snap-and-overflow-layouts\u002Fhorizontal-scrolling-card-rows","Horizontal Scrolling Card Rows: Swipeable Lists That Stay in Their Lane",{"path":2093,"title":2094},"\u002Fmastering-container-queries-responsive-layouts\u002Fscroll-snap-and-overflow-layouts","Scroll Snap & Overflow Layouts: Designing Components That Scroll on Purpose",{"path":2096,"title":2097},"\u002Fmastering-container-queries-responsive-layouts\u002Fscroll-snap-and-overflow-layouts\u002Foverscroll-behavior-for-nested-scrolling","overscroll-behavior: Taming Nested Scrolling, Pull-to-Refresh and Back-Swipe",{"path":2099,"title":2100},"\u002Fmastering-container-queries-responsive-layouts\u002Fscroll-snap-and-overflow-layouts\u002Fscroll-margin-and-scroll-padding-for-sticky-headers","scroll-margin and scroll-padding: Keeping Targets Clear of Sticky Headers",{"path":2102,"title":2103},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state\u002Fcombining-size-and-style-queries","Combining Size and Style Container Queries",{"path":2105,"title":2106},"\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":2108,"title":2109},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state","Style Queries and Container State: Token-Driven Component Variants",{"path":2111,"title":2112},"\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":2114,"title":2115},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state\u002Fstyle-query-component-variants","Component Variants With Style Queries: One Token, Many Looks",{"path":2117,"title":2118},"\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",{"path":2120,"title":2121},"\u002Fmastering-container-queries-responsive-layouts\u002Fviewport-units-and-mobile-layout\u002Fdvh-svh-lvh-mobile-viewport-units","dvh, svh and lvh: Choosing the Right Mobile Viewport Unit",{"path":2123,"title":2124},"\u002Fmastering-container-queries-responsive-layouts\u002Fviewport-units-and-mobile-layout\u002Ffull-bleed-sections-in-constrained-layouts","Full-Bleed Sections in a Constrained Layout: Breaking Out Without Breaking the Page",{"path":2126,"title":2127},"\u002Fmastering-container-queries-responsive-layouts\u002Fviewport-units-and-mobile-layout","Viewport Units & Mobile Layout: Designing for the Screen You Actually Get",{"path":2129,"title":2130},"\u002Fmastering-container-queries-responsive-layouts\u002Fviewport-units-and-mobile-layout\u002Fsafe-area-insets-for-notched-screens","Safe Area Insets: Designing Around Notches, Corners and Home Indicators",{"path":2132,"title":2133},"\u002Fmastering-container-queries-responsive-layouts\u002Fviewport-units-and-mobile-layout\u002Fviewport-units-vs-container-units","Viewport Units vs Container Units: Choosing the Right Reference Box",{"path":2135,"title":2136},"\u002Fmastering-container-queries-responsive-layouts\u002Fviewport-units-and-mobile-layout\u002Fvirtual-keyboard-and-interactive-widget","Layouts That Survive the Virtual Keyboard",1789717746095]