[{"data":1,"prerenderedAt":1202},["ShallowReactive",2],{"page-\u002Fcss\u002F06-display-and-positioning":3},{"id":4,"title":5,"body":6,"description":1194,"extension":1195,"meta":1196,"navigation":1197,"path":1198,"seo":1199,"stem":1200,"__hash__":1201},"content\u002Fcss\u002F06-display-and-positioning.md","06 — Display, Position & the Containing Block",{"type":7,"value":8,"toc":1172},"minimark",[9,13,50,57,247,261,346,352,452,459,560,568,598,602,672,683,762,769,845,849,917,921,975,979,1059,1063,1116,1168],[10,11,5],"h1",{"id":12},"_06-display-position-the-containing-block",[14,15,16,20,21,25,26,29,30,33,34,37,38,41,42,45,46,49],"p",{},[17,18,19],"code",{},"display"," determines which ",[22,23,24],"em",{},"formatting context"," an element participates in. ",[17,27,28],{},"position"," determines how its box is placed relative to its ",[22,31,32],{},"containing block",". The containing block is not always the parent — ",[17,35,36],{},"absolute"," uses the nearest ",[22,39,40],{},"positioned"," ancestor; ",[17,43,44],{},"fixed"," uses the viewport ",[22,47,48],{},"unless"," a transform\u002Ffilter ancestor intercepts. These two facts explain 90% of positioning bugs.",[51,52,54,56],"h2",{"id":53},"display-the-formatting-context",[17,55,19],{}," — the formatting context",[58,59,61],"code-wrapper",{"language":60},"css",[62,63,67],"pre",{"className":64,"code":65,"language":60,"meta":66,"style":66},"language-css shiki shiki-themes github-light github-dark","\u002F* Each display value creates a formatting context that governs the element and its children. *\u002F\n.block { display: block; }       \u002F* full width, new line, width\u002Fheight\u002Fmargin all work *\u002F\n.inline { display: inline; }    \u002F* content width, flows in line, width\u002Fheight\u002Fvertical-margin IGNORED *\u002F\n.inline-block { display: inline-block; } \u002F* inline flow + block sizing — buttons, badges *\u002F\n.flex { display: flex; }        \u002F* block-level flex container → children become flex items *\u002F\n.grid { display: grid; }        \u002F* block-level grid container → children become grid items *\u002F\n.none { display: none; }        \u002F* removed from layout AND accessibility tree. No space. *\u002F\n.contents { display: contents; } \u002F* the box vanishes; children participate in grandparent's layout *\u002F\n.flow-root { display: flow-root; } \u002F* establishes BFC — contains floats\u002Fmargins, no overflow clipping *\u002F\n","",[17,68,69,78,104,125,146,167,187,207,227],{"__ignoreMap":66},[70,71,74],"span",{"class":72,"line":73},"line",1,[70,75,77],{"class":76},"sdCPZ","\u002F* Each display value creates a formatting context that governs the element and its children. *\u002F\n",[70,79,81,85,89,92,95,98,101],{"class":72,"line":80},2,[70,82,84],{"class":83},"sIsaT",".block",[70,86,88],{"class":87},"ssxIu"," { ",[70,90,19],{"class":91},"snvgF",[70,93,94],{"class":87},": ",[70,96,97],{"class":91},"block",[70,99,100],{"class":87},"; }       ",[70,102,103],{"class":76},"\u002F* full width, new line, width\u002Fheight\u002Fmargin all work *\u002F\n",[70,105,107,110,112,114,116,119,122],{"class":72,"line":106},3,[70,108,109],{"class":83},".inline",[70,111,88],{"class":87},[70,113,19],{"class":91},[70,115,94],{"class":87},[70,117,118],{"class":91},"inline",[70,120,121],{"class":87},"; }    ",[70,123,124],{"class":76},"\u002F* content width, flows in line, width\u002Fheight\u002Fvertical-margin IGNORED *\u002F\n",[70,126,128,131,133,135,137,140,143],{"class":72,"line":127},4,[70,129,130],{"class":83},".inline-block",[70,132,88],{"class":87},[70,134,19],{"class":91},[70,136,94],{"class":87},[70,138,139],{"class":91},"inline-block",[70,141,142],{"class":87},"; } ",[70,144,145],{"class":76},"\u002F* inline flow + block sizing — buttons, badges *\u002F\n",[70,147,149,152,154,156,158,161,164],{"class":72,"line":148},5,[70,150,151],{"class":83},".flex",[70,153,88],{"class":87},[70,155,19],{"class":91},[70,157,94],{"class":87},[70,159,160],{"class":91},"flex",[70,162,163],{"class":87},"; }        ",[70,165,166],{"class":76},"\u002F* block-level flex container → children become flex items *\u002F\n",[70,168,170,173,175,177,179,182,184],{"class":72,"line":169},6,[70,171,172],{"class":83},".grid",[70,174,88],{"class":87},[70,176,19],{"class":91},[70,178,94],{"class":87},[70,180,181],{"class":91},"grid",[70,183,163],{"class":87},[70,185,186],{"class":76},"\u002F* block-level grid container → children become grid items *\u002F\n",[70,188,190,193,195,197,199,202,204],{"class":72,"line":189},7,[70,191,192],{"class":83},".none",[70,194,88],{"class":87},[70,196,19],{"class":91},[70,198,94],{"class":87},[70,200,201],{"class":91},"none",[70,203,163],{"class":87},[70,205,206],{"class":76},"\u002F* removed from layout AND accessibility tree. No space. *\u002F\n",[70,208,210,213,215,217,219,222,224],{"class":72,"line":209},8,[70,211,212],{"class":83},".contents",[70,214,88],{"class":87},[70,216,19],{"class":91},[70,218,94],{"class":87},[70,220,221],{"class":91},"contents",[70,223,142],{"class":87},[70,225,226],{"class":76},"\u002F* the box vanishes; children participate in grandparent's layout *\u002F\n",[70,228,230,233,235,237,239,242,244],{"class":72,"line":229},9,[70,231,232],{"class":83},".flow-root",[70,234,88],{"class":87},[70,236,19],{"class":91},[70,238,94],{"class":87},[70,240,241],{"class":91},"flow-root",[70,243,142],{"class":87},[70,245,246],{"class":76},"\u002F* establishes BFC — contains floats\u002Fmargins, no overflow clipping *\u002F\n",[248,249,251,254,255,254,258],"h3",{"id":250},"display-none-vs-visibility-hidden-vs-opacity-0",[17,252,253],{},"display: none"," vs ",[17,256,257],{},"visibility: hidden",[17,259,260],{},"opacity: 0",[58,262,263],{"language":60},[62,264,266],{"className":64,"code":265,"language":60,"meta":66,"style":66},"\u002F* Three different \"hide\" semantics — pick by what you need: *\u002F\n[hidden] { display: none; }       \u002F* GONE: no space, not in a11y tree, not tabbable, transitions DON'T work *\u002F\n.sr-hidden { visibility: hidden; }\u002F* SPACE reserved, in a11y tree (screen readers MAY read), children can override *\u002F\n.fading { opacity: 0; }           \u002F* SPACE reserved, still interactive (clickable), transitions WORK *\u002F\n\u002F* opacity:0 for animating; display:none for removal; visibility:hidden for \"hidden but space reserved\".\n   visibility is animatable between hidden↔visible but jumps (not interpolable except at 0\u002F1). *\u002F\n",[17,267,268,273,295,315,336,341],{"__ignoreMap":66},[70,269,270],{"class":72,"line":73},[70,271,272],{"class":76},"\u002F* Three different \"hide\" semantics — pick by what you need: *\u002F\n",[70,274,275,278,281,284,286,288,290,292],{"class":72,"line":80},[70,276,277],{"class":87},"[",[70,279,280],{"class":83},"hidden",[70,282,283],{"class":87},"] { ",[70,285,19],{"class":91},[70,287,94],{"class":87},[70,289,201],{"class":91},[70,291,100],{"class":87},[70,293,294],{"class":76},"\u002F* GONE: no space, not in a11y tree, not tabbable, transitions DON'T work *\u002F\n",[70,296,297,300,302,305,307,309,312],{"class":72,"line":106},[70,298,299],{"class":83},".sr-hidden",[70,301,88],{"class":87},[70,303,304],{"class":91},"visibility",[70,306,94],{"class":87},[70,308,280],{"class":91},[70,310,311],{"class":87},"; }",[70,313,314],{"class":76},"\u002F* SPACE reserved, in a11y tree (screen readers MAY read), children can override *\u002F\n",[70,316,317,320,322,325,327,330,333],{"class":72,"line":127},[70,318,319],{"class":83},".fading",[70,321,88],{"class":87},[70,323,324],{"class":91},"opacity",[70,326,94],{"class":87},[70,328,329],{"class":91},"0",[70,331,332],{"class":87},"; }           ",[70,334,335],{"class":76},"\u002F* SPACE reserved, still interactive (clickable), transitions WORK *\u002F\n",[70,337,338],{"class":72,"line":148},[70,339,340],{"class":76},"\u002F* opacity:0 for animating; display:none for removal; visibility:hidden for \"hidden but space reserved\".\n",[70,342,343],{"class":72,"line":169},[70,344,345],{"class":76},"   visibility is animatable between hidden↔visible but jumps (not interpolable except at 0\u002F1). *\u002F\n",[51,347,349,351],{"id":348},"position-the-five-schemes",[17,350,28],{}," — the five schemes",[58,353,354],{"language":60},[62,355,357],{"className":64,"code":356,"language":60,"meta":66,"style":66},".static { position: static; }    \u002F* default: in-flow. top\u002Fleft\u002Fright\u002Fbottom have NO effect. *\u002F\n.relative { position: relative; } \u002F* in-flow, then OFFSET by top\u002Fleft etc. Space preserved at original spot. *\u002F\n.absolute { position: absolute; } \u002F* removed from flow. Containing block = nearest positioned ancestor (or viewport). *\u002F\n.fixed { position: fixed; }       \u002F* removed from flow. Containing block = viewport (⚠️ unless a transform ancestor). *\u002F\n.sticky { position: sticky; }    \u002F* relative until scroll passes top:0 → then fixed at that offset within parent. *\u002F\n",[17,358,359,378,397,415,433],{"__ignoreMap":66},[70,360,361,364,366,368,370,373,375],{"class":72,"line":73},[70,362,363],{"class":83},".static",[70,365,88],{"class":87},[70,367,28],{"class":91},[70,369,94],{"class":87},[70,371,372],{"class":91},"static",[70,374,121],{"class":87},[70,376,377],{"class":76},"\u002F* default: in-flow. top\u002Fleft\u002Fright\u002Fbottom have NO effect. *\u002F\n",[70,379,380,383,385,387,389,392,394],{"class":72,"line":80},[70,381,382],{"class":83},".relative",[70,384,88],{"class":87},[70,386,28],{"class":91},[70,388,94],{"class":87},[70,390,391],{"class":91},"relative",[70,393,142],{"class":87},[70,395,396],{"class":76},"\u002F* in-flow, then OFFSET by top\u002Fleft etc. Space preserved at original spot. *\u002F\n",[70,398,399,402,404,406,408,410,412],{"class":72,"line":106},[70,400,401],{"class":83},".absolute",[70,403,88],{"class":87},[70,405,28],{"class":91},[70,407,94],{"class":87},[70,409,36],{"class":91},[70,411,142],{"class":87},[70,413,414],{"class":76},"\u002F* removed from flow. Containing block = nearest positioned ancestor (or viewport). *\u002F\n",[70,416,417,420,422,424,426,428,430],{"class":72,"line":127},[70,418,419],{"class":83},".fixed",[70,421,88],{"class":87},[70,423,28],{"class":91},[70,425,94],{"class":87},[70,427,44],{"class":91},[70,429,100],{"class":87},[70,431,432],{"class":76},"\u002F* removed from flow. Containing block = viewport (⚠️ unless a transform ancestor). *\u002F\n",[70,434,435,438,440,442,444,447,449],{"class":72,"line":148},[70,436,437],{"class":83},".sticky",[70,439,88],{"class":87},[70,441,28],{"class":91},[70,443,94],{"class":87},[70,445,446],{"class":91},"sticky",[70,448,121],{"class":87},[70,450,451],{"class":76},"\u002F* relative until scroll passes top:0 → then fixed at that offset within parent. *\u002F\n",[248,453,455,458],{"id":454},"position-sticky-the-production-header-pattern",[17,456,457],{},"position: sticky"," — the production header pattern",[58,460,461],{"language":60},[62,462,464],{"className":64,"code":463,"language":60,"meta":66,"style":66},".header {\n  position: sticky;\n  inset-block-start: 0;  \u002F* stick to the top (logical: start = top in horizontal-tb) *\u002F\n  z-index: 10;           \u002F* keep above scrolling content *\u002F\n  background: var(--c-bg); \u002F* opaque — content scrolls UNDER it *\u002F\n}\n\u002F* ⚠️ sticky needs: (1) a parent TALLER than the header (room to scroll), (2) NO ancestor with\n   overflow: hidden\u002Fauto\u002Fscroll — that ancestor becomes the scroll container, and sticky sticks\n   to IT, not the viewport. If your sticky isn't sticking, check ancestor overflow. *\u002F\n",[17,465,466,474,486,501,517,540,545,550,555],{"__ignoreMap":66},[70,467,468,471],{"class":72,"line":73},[70,469,470],{"class":83},".header",[70,472,473],{"class":87}," {\n",[70,475,476,479,481,483],{"class":72,"line":80},[70,477,478],{"class":91},"  position",[70,480,94],{"class":87},[70,482,446],{"class":91},[70,484,485],{"class":87},";\n",[70,487,488,491,493,495,498],{"class":72,"line":106},[70,489,490],{"class":91},"  inset-block-start",[70,492,94],{"class":87},[70,494,329],{"class":91},[70,496,497],{"class":87},";  ",[70,499,500],{"class":76},"\u002F* stick to the top (logical: start = top in horizontal-tb) *\u002F\n",[70,502,503,506,508,511,514],{"class":72,"line":127},[70,504,505],{"class":91},"  z-index",[70,507,94],{"class":87},[70,509,510],{"class":91},"10",[70,512,513],{"class":87},";           ",[70,515,516],{"class":76},"\u002F* keep above scrolling content *\u002F\n",[70,518,519,522,524,527,530,534,537],{"class":72,"line":148},[70,520,521],{"class":91},"  background",[70,523,94],{"class":87},[70,525,526],{"class":91},"var",[70,528,529],{"class":87},"(",[70,531,533],{"class":532},"sCrzJ","--c-bg",[70,535,536],{"class":87},"); ",[70,538,539],{"class":76},"\u002F* opaque — content scrolls UNDER it *\u002F\n",[70,541,542],{"class":72,"line":169},[70,543,544],{"class":87},"}\n",[70,546,547],{"class":72,"line":189},[70,548,549],{"class":76},"\u002F* ⚠️ sticky needs: (1) a parent TALLER than the header (room to scroll), (2) NO ancestor with\n",[70,551,552],{"class":72,"line":209},[70,553,554],{"class":76},"   overflow: hidden\u002Fauto\u002Fscroll — that ancestor becomes the scroll container, and sticky sticks\n",[70,556,557],{"class":72,"line":229},[70,558,559],{"class":76},"   to IT, not the viewport. If your sticky isn't sticking, check ancestor overflow. *\u002F\n",[51,561,563,564,567],{"id":562},"the-containing-block-trap-position-fixed-transform-ancestor","The Containing Block Trap — ",[17,565,566],{},"position: fixed"," + transform ancestor",[14,569,570,571,573,574,576,577,580,581,580,584,580,587,580,590,593,594,597],{},"This is the most common positioning bug in production. ",[17,572,566],{}," is relative to the viewport — ",[22,575,48],{}," an ancestor has ",[17,578,579],{},"transform",", ",[17,582,583],{},"filter",[17,585,586],{},"perspective",[17,588,589],{},"will-change",[17,591,592],{},"backdrop-filter",", or ",[17,595,596],{},"contain: paint",". That ancestor becomes the containing block, and the \"fixed\" element scrolls with it.",[248,599,601],{"id":600},"anti-pattern-transform-on-a-wrapper-breaks-fixed-children","Anti-pattern: transform on a wrapper breaks fixed children",[58,603,604],{"language":60},[62,605,607],{"className":64,"code":606,"language":60,"meta":66,"style":66},"\u002F* ❌ The wrapper has transform (for an animation) → it becomes the containing block for .navbar.\n   .navbar is no longer fixed to the viewport — it scrolls with .wrapper. *\u002F\n.wrapper { transform: translateZ(0); }  \u002F* \"GPU acceleration\" hack — creates containing block + stacking context *\u002F\n.navbar { position: fixed; inset-block-start: 0; }  \u002F* fixed to .wrapper, NOT the viewport *\u002F\n",[17,608,609,614,619,643],{"__ignoreMap":66},[70,610,611],{"class":72,"line":73},[70,612,613],{"class":76},"\u002F* ❌ The wrapper has transform (for an animation) → it becomes the containing block for .navbar.\n",[70,615,616],{"class":72,"line":80},[70,617,618],{"class":76},"   .navbar is no longer fixed to the viewport — it scrolls with .wrapper. *\u002F\n",[70,620,621,624,626,628,630,633,635,637,640],{"class":72,"line":106},[70,622,623],{"class":83},".wrapper",[70,625,88],{"class":87},[70,627,579],{"class":91},[70,629,94],{"class":87},[70,631,632],{"class":91},"translateZ",[70,634,529],{"class":87},[70,636,329],{"class":91},[70,638,639],{"class":87},"); }  ",[70,641,642],{"class":76},"\u002F* \"GPU acceleration\" hack — creates containing block + stacking context *\u002F\n",[70,644,645,648,650,652,654,656,659,662,664,666,669],{"class":72,"line":127},[70,646,647],{"class":83},".navbar",[70,649,88],{"class":87},[70,651,28],{"class":91},[70,653,94],{"class":87},[70,655,44],{"class":91},[70,657,658],{"class":87},"; ",[70,660,661],{"class":91},"inset-block-start",[70,663,94],{"class":87},[70,665,329],{"class":91},[70,667,668],{"class":87},"; }  ",[70,670,671],{"class":76},"\u002F* fixed to .wrapper, NOT the viewport *\u002F\n",[58,673,674],{"language":60},[62,675,677],{"className":64,"code":676,"language":60,"meta":66,"style":66},"\u002F* ✓ Move the fixed element OUTSIDE the transformed ancestor, or remove the transform. *\u002F\n",[17,678,679],{"__ignoreMap":66},[70,680,681],{"class":72,"line":73},[70,682,676],{"class":76},[58,684,686],{"language":685},"html",[62,687,690],{"className":688,"code":689,"language":685,"meta":66,"style":66},"language-html shiki shiki-themes github-light github-dark","\u003Cbody>\n  \u003Cnav class=\"navbar\">...\u003C\u002Fnav>  \u003C!-- outside .wrapper → fixed to viewport -->\n  \u003Cdiv class=\"wrapper\">...\u003C\u002Fdiv>\n\u003C\u002Fbody>\n",[17,691,692,704,733,753],{"__ignoreMap":66},[70,693,694,697,701],{"class":72,"line":73},[70,695,696],{"class":87},"\u003C",[70,698,700],{"class":699},"sk71V","body",[70,702,703],{"class":87},">\n",[70,705,706,709,712,715,718,722,725,727,730],{"class":72,"line":80},[70,707,708],{"class":87},"  \u003C",[70,710,711],{"class":699},"nav",[70,713,714],{"class":83}," class",[70,716,717],{"class":87},"=",[70,719,721],{"class":720},"sJ6F3","\"navbar\"",[70,723,724],{"class":87},">...\u003C\u002F",[70,726,711],{"class":699},[70,728,729],{"class":87},">  ",[70,731,732],{"class":76},"\u003C!-- outside .wrapper → fixed to viewport -->\n",[70,734,735,737,740,742,744,747,749,751],{"class":72,"line":106},[70,736,708],{"class":87},[70,738,739],{"class":699},"div",[70,741,714],{"class":83},[70,743,717],{"class":87},[70,745,746],{"class":720},"\"wrapper\"",[70,748,724],{"class":87},[70,750,739],{"class":699},[70,752,703],{"class":87},[70,754,755,758,760],{"class":72,"line":127},[70,756,757],{"class":87},"\u003C\u002F",[70,759,700],{"class":699},[70,761,703],{"class":87},[51,763,765,768],{"id":764},"inset-the-logical-shorthand",[17,766,767],{},"inset"," — the logical shorthand",[58,770,771],{"language":60},[62,772,774],{"className":64,"code":773,"language":60,"meta":66,"style":66},".cover {\n  position: absolute;\n  inset: 0;              \u002F* shorthand: top:0; right:0; bottom:0; left:0 → fills the containing block *\u002F\n  inset-inline: 0;       \u002F* logical: left\u002Fright in LTR → flips in RTL *\u002F\n  inset-block-start: 0;  \u002F* logical: top in horizontal-tb *\u002F\n}\n\u002F* When all four insets are set and width\u002Fheight are auto, the box stretches to fill the containing block. *\u002F\n",[17,775,776,783,793,808,823,836,840],{"__ignoreMap":66},[70,777,778,781],{"class":72,"line":73},[70,779,780],{"class":83},".cover",[70,782,473],{"class":87},[70,784,785,787,789,791],{"class":72,"line":80},[70,786,478],{"class":91},[70,788,94],{"class":87},[70,790,36],{"class":91},[70,792,485],{"class":87},[70,794,795,798,800,802,805],{"class":72,"line":106},[70,796,797],{"class":91},"  inset",[70,799,94],{"class":87},[70,801,329],{"class":91},[70,803,804],{"class":87},";              ",[70,806,807],{"class":76},"\u002F* shorthand: top:0; right:0; bottom:0; left:0 → fills the containing block *\u002F\n",[70,809,810,813,815,817,820],{"class":72,"line":127},[70,811,812],{"class":91},"  inset-inline",[70,814,94],{"class":87},[70,816,329],{"class":91},[70,818,819],{"class":87},";       ",[70,821,822],{"class":76},"\u002F* logical: left\u002Fright in LTR → flips in RTL *\u002F\n",[70,824,825,827,829,831,833],{"class":72,"line":148},[70,826,490],{"class":91},[70,828,94],{"class":87},[70,830,329],{"class":91},[70,832,497],{"class":87},[70,834,835],{"class":76},"\u002F* logical: top in horizontal-tb *\u002F\n",[70,837,838],{"class":72,"line":169},[70,839,544],{"class":87},[70,841,842],{"class":72,"line":189},[70,843,844],{"class":76},"\u002F* When all four insets are set and width\u002Fheight are auto, the box stretches to fill the containing block. *\u002F\n",[51,846,848],{"id":847},"stacking-context-preview-full-detail-in-chapter-10","Stacking Context — preview (full detail in chapter 10)",[58,850,851],{"language":60},[62,852,854],{"className":64,"code":853,"language":60,"meta":66,"style":66},"\u002F* z-index only works on POSITIONED elements (not static). But many properties create a stacking\n   context WITHOUT position: transform, opacity\u003C1, filter, will-change, position:fixed\u002Fsticky. *\u002F\n.modal { position: fixed; z-index: 1000; }  \u002F* positioned + z-index → new stacking context *\u002F\n.elevated { transform: translateZ(0); }    \u002F* transform alone → new stacking context (z-index: auto) *\u002F\n",[17,855,856,861,866,894],{"__ignoreMap":66},[70,857,858],{"class":72,"line":73},[70,859,860],{"class":76},"\u002F* z-index only works on POSITIONED elements (not static). But many properties create a stacking\n",[70,862,863],{"class":72,"line":80},[70,864,865],{"class":76},"   context WITHOUT position: transform, opacity\u003C1, filter, will-change, position:fixed\u002Fsticky. *\u002F\n",[70,867,868,871,873,875,877,879,881,884,886,889,891],{"class":72,"line":106},[70,869,870],{"class":83},".modal",[70,872,88],{"class":87},[70,874,28],{"class":91},[70,876,94],{"class":87},[70,878,44],{"class":91},[70,880,658],{"class":87},[70,882,883],{"class":91},"z-index",[70,885,94],{"class":87},[70,887,888],{"class":91},"1000",[70,890,668],{"class":87},[70,892,893],{"class":76},"\u002F* positioned + z-index → new stacking context *\u002F\n",[70,895,896,899,901,903,905,907,909,911,914],{"class":72,"line":127},[70,897,898],{"class":83},".elevated",[70,900,88],{"class":87},[70,902,579],{"class":91},[70,904,94],{"class":87},[70,906,632],{"class":91},[70,908,529],{"class":87},[70,910,329],{"class":91},[70,912,913],{"class":87},"); }    ",[70,915,916],{"class":76},"\u002F* transform alone → new stacking context (z-index: auto) *\u002F\n",[51,918,920],{"id":919},"tips-tricks","💡 Tips & Tricks",[922,923,924,944,955,967],"ul",{},[925,926,927,94,931,934,935,937,938,940,941,943],"li",{},[928,929,930],"strong",{},"Idiom",[17,932,933],{},"display: flex","\u002F",[17,936,181],{}," for layouts, ",[17,939,139],{}," only for inline elements needing width\u002Fheight (buttons, badges). Floats are legacy — ",[17,942,241],{}," to clear them if you must use floats for text-wrap.",[925,945,946,94,948,950,951,954],{},[928,947,930],{},[17,949,457],{}," for sticky headers\u002Fsection titles — pure CSS, no JS scroll listeners. Verify no ancestor has ",[17,952,953],{},"overflow: hidden\u002Fauto"," (breaks sticking) and the parent is taller than the sticky element.",[925,956,957,94,959,962,963,966],{},[928,958,930],{},[17,960,961],{},"position: relative"," on a parent to establish a containing block for ",[17,964,965],{},"position: absolute"," children — the absolute child positions relative to the nearest positioned ancestor. Without it, the child escapes to the viewport.",[925,968,969,94,971,974],{},[928,970,930],{},[17,972,973],{},"display: contents"," for semantic wrappers that shouldn't affect layout — the box disappears, children join the grandparent's layout. Useful in grids\u002Fflexbox where a wrapper would break the layout.",[51,976,978],{"id":977},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[922,980,981,1003,1014,1022,1034,1051],{},[925,982,983,94,993,996,997,999,1000,1002],{},[928,984,985,986,934,989,992],{},"Inline elements ignore ",[17,987,988],{},"width",[17,990,991],{},"height","\u002Fvertical margin",[17,994,995],{},"span { width: 100px; }"," does nothing. Use ",[17,998,139],{}," or ",[17,1001,97],{},".",[925,1004,1005,1010,1011,1013],{},[928,1006,1007,1009],{},[17,1008,965],{}," without a positioned ancestor escapes to the viewport"," (initial containing block). Forgetting ",[17,1012,961],{}," on the parent is the #1 absolute-positioning bug.",[925,1015,1016,1021],{},[928,1017,1018,1020],{},[17,1019,566],{}," + transform\u002Ffilter\u002Fperspective\u002Fwill-change ancestor"," → the ancestor becomes the containing block, \"fixed\" scrolls. This is the #1 fixed-positioning bug.",[925,1023,1024,1033],{},[928,1025,1026,1028,1029,1032],{},[17,1027,457],{}," needs a tall parent and no ",[17,1030,1031],{},"overflow"," ancestor"," — if the parent equals the sticky's height, there's no scroll room; if an ancestor scrolls, sticky sticks to it.",[925,1035,1036,94,1044,1047,1048,1050],{},[928,1037,1038,1040,1041],{},[17,1039,883],{}," is ignored on ",[17,1042,1043],{},"position: static",[17,1045,1046],{},"z-index: 10"," on a static element does nothing. Set ",[17,1049,961],{}," (or other) for z-index to apply.",[925,1052,1053,1058],{},[928,1054,1055,1057],{},[17,1056,973],{}," has accessibility quirks"," in older browsers (role may be lost). Test with screen readers if used on semantic elements.",[51,1060,1062],{"id":1061},"spot-the-bug","🧠 Spot the Bug",[58,1064,1065],{"language":60},[62,1066,1068],{"className":64,"code":1067,"language":60,"meta":66,"style":66},".page { transform: scale(1); }\n.navbar { position: fixed; top: 0; }\n",[17,1069,1070,1092],{"__ignoreMap":66},[70,1071,1072,1075,1077,1079,1081,1084,1086,1089],{"class":72,"line":73},[70,1073,1074],{"class":83},".page",[70,1076,88],{"class":87},[70,1078,579],{"class":91},[70,1080,94],{"class":87},[70,1082,1083],{"class":91},"scale",[70,1085,529],{"class":87},[70,1087,1088],{"class":91},"1",[70,1090,1091],{"class":87},"); }\n",[70,1093,1094,1096,1098,1100,1102,1104,1106,1109,1111,1113],{"class":72,"line":80},[70,1095,647],{"class":83},[70,1097,88],{"class":87},[70,1099,28],{"class":91},[70,1101,94],{"class":87},[70,1103,44],{"class":91},[70,1105,658],{"class":87},[70,1107,1108],{"class":91},"top",[70,1110,94],{"class":87},[70,1112,329],{"class":91},[70,1114,1115],{"class":87},"; }\n",[1117,1118,1119,1123],"details",{},[1120,1121,1122],"summary",{},"Answer",[14,1124,1125,1127,1128,1130,1131,1134,1135,1138,1139,1141,1142,1144,1145,1147,1148,1150,1151,1153,1154,934,1156,934,1158,934,1160,934,1162,934,1164,1167],{},[17,1126,1074],{}," wraps everything (including ",[17,1129,647],{},") and has ",[17,1132,1133],{},"transform: scale(1)",". Even ",[17,1136,1137],{},"scale(1)"," (a no-op visually) creates a containing block for ",[17,1140,566],{}," descendants. So ",[17,1143,647],{}," is fixed relative to ",[17,1146,1074],{},", not the viewport — it scrolls with the page. Fix: remove the transform from the wrapper, or move ",[17,1149,647],{}," outside ",[17,1152,1074],{}," in the DOM. Any of ",[17,1155,579],{},[17,1157,583],{},[17,1159,586],{},[17,1161,589],{},[17,1163,592],{},[17,1165,1166],{},"contain:paint"," on an ancestor does this.",[1169,1170,1171],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}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 .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}html pre.shiki code .sk71V, html code.shiki .sk71V{--shiki-default:#22863A;--shiki-github-dark:#85E89D}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}",{"title":66,"searchDepth":80,"depth":80,"links":1173},[1174,1179,1184,1188,1190,1191,1192,1193],{"id":53,"depth":80,"text":1175,"children":1176},"display — the formatting context",[1177],{"id":250,"depth":106,"text":1178},"display: none vs visibility: hidden vs opacity: 0",{"id":348,"depth":80,"text":1180,"children":1181},"position — the five schemes",[1182],{"id":454,"depth":106,"text":1183},"position: sticky — the production header pattern",{"id":562,"depth":80,"text":1185,"children":1186},"The Containing Block Trap — position: fixed + transform ancestor",[1187],{"id":600,"depth":106,"text":601},{"id":764,"depth":80,"text":1189},"inset — the logical shorthand",{"id":847,"depth":80,"text":848},{"id":919,"depth":80,"text":920},{"id":977,"depth":80,"text":978},{"id":1061,"depth":80,"text":1062},"Block\u002Finline\u002Fflex\u002Fgrid formatting contexts, the five position schemes, containing-block resolution (including the transform-ancestor trap that breaks position:fixed), and stacking context basics. Code-first reference.","md",{},true,"\u002Fcss\u002F06-display-and-positioning",{"title":5,"description":1194},"css\u002F06-display-and-positioning","4rTyr_r2EtE08OHX5uZwZvhc3MSWoOtNxjClvlAW370",1789924644820]