[{"data":1,"prerenderedAt":2074},["ShallowReactive",2],{"page-\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has\u002Fhas-selector-performance":3,"content-all-pages":1516},{"id":4,"title":5,"body":6,"description":1494,"extension":1495,"meta":1496,"navigation":504,"path":1512,"seo":1513,"stem":1514,"__hash__":1515},"content\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has\u002Fhas-selector-performance\u002Findex.md",":has() Selector Performance: What Is Cheap, What Is Not, and How to Measure",{"type":7,"value":8,"toc":1482},"minimark",[9,18,43,48,79,89,93,109,231,241,245,248,937,946,950,953,1031,1034,1107,1111,1114,1201,1223,1234,1241,1249,1354,1363,1367,1372,1376,1394,1409,1426,1438,1442,1479],[10,11,13,17],"h1",{"id":12},"has-selector-performance-what-is-cheap-what-is-not-and-how-to-measure",[14,15,16],"code",{},":has()"," Selector Performance: What Is Cheap, What Is Not, and How to Measure",[19,20,21,22,24,25,27,28,37,38,42],"p",{},"For twenty years the stated reason CSS had no parent selector was performance: browsers match selectors right to left, from the element outward, and a selector that depends on descendants would force them to re-examine ancestors every time anything inside changed. ",[14,23,16],{}," shipped anyway because engine teams found ways to make that re-examination targeted. It is fast in ordinary use — but \"ordinary use\" has limits, and a few patterns can turn a hover into a full-document style recalculation. This page explains how invalidation works, which shapes of ",[14,26,16],{}," stay cheap, and how to verify a suspicious rule in DevTools. It belongs to ",[29,30,32,33,36],"a",{"href":31},"\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has\u002F","Parent-Aware Layouts With ",[34,35],"has",{},"()",", part of the ",[29,39,41],{"href":40},"\u002Fmastering-container-queries-responsive-layouts\u002F","Mastering Container Queries & Responsive Layouts"," guide.",[44,45,47],"h2",{"id":46},"why-the-worry-existed","Why the worry existed",[19,49,50,51,54,55,58,59,63,64,67,68,71,72,74,75,78],{},"Selector matching runs right to left. For ",[14,52,53],{},".card .title",", the engine starts at each element that could be ",[14,56,57],{},".title"," and walks ",[60,61,62],"em",{},"up"," looking for a ",[14,65,66],{},".card"," ancestor. Ancestors are few and walking up is cheap. A relational selector reverses that: for ",[14,69,70],{},".card:has(.title)",", the subject is ",[14,73,66],{},", and deciding whether it matches means looking ",[60,76,77],{},"down"," into a subtree that may contain thousands of elements.",[19,80,81,82,85,86,88],{},"Matching once is not the real problem — pages are styled once and the cost is bounded. The problem is ",[60,83,84],{},"invalidation",". When the DOM or an element's state changes, the engine must work out which elements' styles might now be different. For ordinary selectors, a change to an element can only affect that element, its descendants, and sometimes its siblings. With ",[14,87,16],{},", a change deep in a subtree can affect ancestors all the way up to the root. Without care, every class toggle anywhere would force a style recalculation of everything above it.",[44,90,92],{"id":91},"how-engines-keep-it-targeted","How engines keep it targeted",[19,94,95,96,98,99,102,103,105,106,108],{},"The engines solve this with bookkeeping at stylesheet-parse time. For every ",[14,97,16],{}," in the stylesheet, they record which simple selectors appear in its argument — the classes, attributes, pseudo-classes and element types. When something changes, they first ask a cheap question: could this change affect ",[60,100,101],{},"any"," ",[14,104,16],{}," argument? A class that appears in no argument is ignored completely. Only if the changed feature is relevant do they walk up the ancestors looking for elements whose ",[14,107,16],{}," might now match differently, and they mark only those for recalculation.",[110,111,117,118,117,122,117,126,117,134,117,146,117,152,117,157,117,163,117,168,117,172,117,176,117,180,117,186,117,189,117,193,117,196,117,200,117,207,117,210,117,213,117,217,117,221,117,227],"svg",{"viewBox":112,"role":113,"ariaLabel":114,"xmlns":115,"style":116},"0 0 720 320","img","Invalidation flow: a DOM change is filtered against features used in has arguments, then only candidate ancestors are rechecked","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;height:auto;max-width:720px;margin:2rem 0","\n  ",[119,120,121],"title",{},"How a change reaches a :has() rule",[123,124,125],"desc",{},"A change to an element's class or state is first compared with the set of features used inside has arguments. Irrelevant changes stop there. Relevant ones walk up to ancestors that are has anchors, which are marked for style recalculation along with what they affect.",[127,128,133],"text",{"textAnchor":129,"x":130,"y":131,"style":132},"middle","360","26","text-anchor:middle;fill:currentColor;font:700 17px sans-serif","Most changes never reach a :has() rule",[135,136],"rect",{"x":137,"y":138,"width":139,"height":140,"rx":141,"fill":142,"stroke":143,"strokeWidth":144,"opacity":145},"30","54","170","70","10","none","currentColor","1.5","0.6",[127,147,151],{"textAnchor":129,"x":148,"y":149,"style":150},"115","84","text-anchor:middle;fill:currentColor;font:600 13px sans-serif","DOM change",[127,153,156],{"textAnchor":129,"x":148,"y":154,"style":155},"106","text-anchor:middle;fill:currentColor;font:12px ui-monospace,monospace",".is-open added",[158,159],"line",{"x1":160,"y1":161,"x2":162,"y2":161,"stroke":143,"strokeWidth":144,"opacity":145},"200","89","240",[135,164],{"x":162,"y":138,"width":165,"height":140,"rx":141,"fill":166,"opacity":167},"220","#7aa2ff","0.2",[127,169,171],{"textAnchor":129,"x":170,"y":149,"style":150},"350","In any :has() argument?",[127,173,175],{"textAnchor":129,"x":170,"y":154,"style":174},"text-anchor:middle;fill:currentColor;font:12px sans-serif","feature set lookup",[158,177],{"x1":178,"y1":161,"x2":179,"y2":161,"stroke":143,"strokeWidth":144,"opacity":145},"460","500",[127,181,185],{"textAnchor":129,"x":182,"y":183,"style":184},"480","80","text-anchor:middle;fill:currentColor;font:11px sans-serif","no",[135,187],{"x":179,"y":138,"width":188,"height":140,"rx":141,"fill":142,"stroke":143,"strokeWidth":144,"opacity":145},"190",[127,190,192],{"textAnchor":129,"x":191,"y":149,"style":150},"595","Stop",[127,194,195],{"textAnchor":129,"x":191,"y":154,"style":174},"no :has() work at all",[158,197],{"x1":170,"y1":198,"x2":170,"y2":199,"stroke":143,"strokeWidth":144,"opacity":145},"124","160",[127,201,206],{"textAnchor":202,"x":203,"y":204,"style":205},"start","362","146","text-anchor:start;fill:currentColor;font:11px sans-serif","yes",[135,208],{"x":160,"y":199,"width":209,"height":140,"rx":141,"fill":166,"opacity":167},"300",[127,211,212],{"textAnchor":129,"x":170,"y":188,"style":150},"Walk up to :has() anchors",[127,214,216],{"textAnchor":129,"x":170,"y":215,"style":174},"212","only ancestors that could match",[158,218],{"x1":170,"y1":219,"x2":170,"y2":220,"stroke":143,"strokeWidth":144,"opacity":145},"230","256",[135,222],{"x":223,"y":220,"width":224,"height":225,"rx":141,"fill":166,"opacity":226},"150","400","50","0.38",[127,228,230],{"textAnchor":129,"x":170,"y":229,"style":150},"286","Recalculate those anchors and their dependants",[19,232,233,234,236,237,240],{},"That design has a clear consequence for authors. The cost of a ",[14,235,16],{}," rule is not paid when it matches; it is paid when ",[60,238,239],{},"something that appears in its argument changes",". A rule whose argument names a rarely changing feature is essentially free. A rule whose argument names something that changes on every mouse move is paid on every mouse move — and how much it costs then depends on how broad the anchor is.",[44,242,244],{"id":243},"the-complete-implementation-cheap-and-expensive-side-by-side","The complete implementation: cheap and expensive side by side",[19,246,247],{},"The stylesheet below contains pairs of rules that produce similar visual results with very different invalidation costs. It is annotated rule by rule.",[249,250,255],"pre",{"className":251,"code":252,"language":253,"meta":254,"style":254},"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\u003Ctitle>:has() cost comparison\u003C\u002Ftitle>\n\u003Cstyle>\n  body { font: 15px\u002F1.5 system-ui, sans-serif; margin: 1.5rem; }\n  .list { display: grid; gap: 0.25rem; max-width: 24rem; padding: 0; list-style: none; }\n  .list li { padding: 0.4rem 0.6rem; border-radius: 6px; }\n\n  \u002F* EXPENSIVE: the anchor is the whole document and the argument is :hover,\n     which changes constantly. Every hover change anywhere inside body may\n     affect body's match, so style is invalidated from the root down. *\u002F\n  body:has(.list li:hover) .toolbar { opacity: 0.6; }\n\n  \u002F* CHEAP: same visual intent, anchor narrowed to the component and the\n     argument scoped to direct children. A hover only re-checks this .list. *\u002F\n  .panel:has(> .list > li:hover) > .toolbar { opacity: 0.6; }\n\n  \u002F* CHEAP even at the root: the argument changes rarely. Opening a dialog\n     happens a handful of times per session, so a document-wide recalc\n     at that moment is fine. *\u002F\n  :root:has(dialog[open]) { overflow: hidden; }\n\n  \u002F* RISKY: a universal subject means every element is an anchor candidate.\n     Always give :has() a specific subject. *\u002F\n  \u002F* *:has(> img) { outline: 1px solid red; }   -- avoid *\u002F\n  figure:has(> img) { margin-inline: 0; }\n\n  \u002F* PREFER a direct-child argument when that is what you mean. It is\n     both clearer and gives the engine a shorter walk. *\u002F\n  .card:has(> .card__media) { grid-template-rows: auto 1fr; }\n\u003C\u002Fstyle>\n\u003C\u002Fhead>\n\u003Cbody>\n  \u003Csection class=\"panel\">\n    \u003Cdiv class=\"toolbar\">Toolbar\u003C\u002Fdiv>\n    \u003Cul class=\"list\">\n      \u003Cli>First item\u003C\u002Fli>\n      \u003Cli>Second item\u003C\u002Fli>\n      \u003Cli>Third item\u003C\u002Fli>\n    \u003C\u002Ful>\n  \u003C\u002Fsection>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n","html","",[14,256,257,276,296,306,324,338,348,400,461,499,506,513,519,525,561,566,572,578,616,621,627,633,639,669,674,680,686,692,719,724,730,736,767,777,786,796,815,838,855,871,885,899,909,919,928],{"__ignoreMap":254},[258,259,261,265,269,273],"span",{"class":158,"line":260},1,[258,262,264],{"class":263},"suds8","\u003C!",[258,266,268],{"class":267},"sne4z","doctype",[258,270,272],{"class":271},"s-5SL"," html",[258,274,275],{"class":263},">\n",[258,277,279,282,284,287,290,294],{"class":158,"line":278},2,[258,280,281],{"class":263},"\u003C",[258,283,253],{"class":267},[258,285,286],{"class":271}," lang",[258,288,289],{"class":263},"=",[258,291,293],{"class":292},"sT6z2","\"en\"",[258,295,275],{"class":263},[258,297,299,301,304],{"class":158,"line":298},3,[258,300,281],{"class":263},[258,302,303],{"class":267},"head",[258,305,275],{"class":263},[258,307,309,311,314,317,319,322],{"class":158,"line":308},4,[258,310,281],{"class":263},[258,312,313],{"class":267},"meta",[258,315,316],{"class":271}," charset",[258,318,289],{"class":263},[258,320,321],{"class":292},"\"utf-8\"",[258,323,275],{"class":263},[258,325,327,329,331,334,336],{"class":158,"line":326},5,[258,328,281],{"class":263},[258,330,119],{"class":267},[258,332,333],{"class":263},">:has() cost comparison\u003C\u002F",[258,335,119],{"class":267},[258,337,275],{"class":263},[258,339,341,343,346],{"class":158,"line":340},6,[258,342,281],{"class":263},[258,344,345],{"class":267},"style",[258,347,275],{"class":263},[258,349,351,354,357,360,363,366,370,373,375,378,381,384,387,390,392,394,397],{"class":158,"line":350},7,[258,352,353],{"class":267},"  body",[258,355,356],{"class":263}," { ",[258,358,359],{"class":271},"font",[258,361,362],{"class":263},": ",[258,364,365],{"class":271},"15",[258,367,369],{"class":368},"sHUrx","px",[258,371,372],{"class":263},"\u002F",[258,374,144],{"class":271},[258,376,377],{"class":271}," system-ui",[258,379,380],{"class":263},", ",[258,382,383],{"class":271},"sans-serif",[258,385,386],{"class":263},"; ",[258,388,389],{"class":271},"margin",[258,391,362],{"class":263},[258,393,144],{"class":271},[258,395,396],{"class":368},"rem",[258,398,399],{"class":263},"; }\n",[258,401,403,406,408,411,413,416,418,421,423,426,428,430,433,435,438,440,442,445,447,450,452,455,457,459],{"class":158,"line":402},8,[258,404,405],{"class":271},"  .list",[258,407,356],{"class":263},[258,409,410],{"class":271},"display",[258,412,362],{"class":263},[258,414,415],{"class":271},"grid",[258,417,386],{"class":263},[258,419,420],{"class":271},"gap",[258,422,362],{"class":263},[258,424,425],{"class":271},"0.25",[258,427,396],{"class":368},[258,429,386],{"class":263},[258,431,432],{"class":271},"max-width",[258,434,362],{"class":263},[258,436,437],{"class":271},"24",[258,439,396],{"class":368},[258,441,386],{"class":263},[258,443,444],{"class":271},"padding",[258,446,362],{"class":263},[258,448,449],{"class":271},"0",[258,451,386],{"class":263},[258,453,454],{"class":271},"list-style",[258,456,362],{"class":263},[258,458,142],{"class":271},[258,460,399],{"class":263},[258,462,464,466,469,471,473,475,478,480,483,485,487,490,492,495,497],{"class":158,"line":463},9,[258,465,405],{"class":271},[258,467,468],{"class":267}," li",[258,470,356],{"class":263},[258,472,444],{"class":271},[258,474,362],{"class":263},[258,476,477],{"class":271},"0.4",[258,479,396],{"class":368},[258,481,482],{"class":271}," 0.6",[258,484,396],{"class":368},[258,486,386],{"class":263},[258,488,489],{"class":271},"border-radius",[258,491,362],{"class":263},[258,493,494],{"class":271},"6",[258,496,369],{"class":368},[258,498,399],{"class":263},[258,500,502],{"class":158,"line":501},10,[258,503,505],{"emptyLinePlaceholder":504},true,"\n",[258,507,509],{"class":158,"line":508},11,[258,510,512],{"class":511},"sLBg1","  \u002F* EXPENSIVE: the anchor is the whole document and the argument is :hover,\n",[258,514,516],{"class":158,"line":515},12,[258,517,518],{"class":511},"     which changes constantly. Every hover change anywhere inside body may\n",[258,520,522],{"class":158,"line":521},13,[258,523,524],{"class":511},"     affect body's match, so style is invalidated from the root down. *\u002F\n",[258,526,528,530,533,536,539,541,544,547,550,552,555,557,559],{"class":158,"line":527},14,[258,529,353],{"class":267},[258,531,532],{"class":271},":has",[258,534,535],{"class":263},"(",[258,537,538],{"class":271},".list",[258,540,468],{"class":267},[258,542,543],{"class":271},":hover",[258,545,546],{"class":263},") ",[258,548,549],{"class":271},".toolbar",[258,551,356],{"class":263},[258,553,554],{"class":271},"opacity",[258,556,362],{"class":263},[258,558,145],{"class":271},[258,560,399],{"class":263},[258,562,564],{"class":158,"line":563},15,[258,565,505],{"emptyLinePlaceholder":504},[258,567,569],{"class":158,"line":568},16,[258,570,571],{"class":511},"  \u002F* CHEAP: same visual intent, anchor narrowed to the component and the\n",[258,573,575],{"class":158,"line":574},17,[258,576,577],{"class":511},"     argument scoped to direct children. A hover only re-checks this .list. *\u002F\n",[258,579,581,584,586,589,592,595,597,599,601,603,606,608,610,612,614],{"class":158,"line":580},18,[258,582,583],{"class":271},"  .panel:has",[258,585,535],{"class":263},[258,587,588],{"class":368},">",[258,590,591],{"class":271}," .list",[258,593,594],{"class":368}," >",[258,596,468],{"class":267},[258,598,543],{"class":271},[258,600,546],{"class":263},[258,602,588],{"class":368},[258,604,605],{"class":271}," .toolbar",[258,607,356],{"class":263},[258,609,554],{"class":271},[258,611,362],{"class":263},[258,613,145],{"class":271},[258,615,399],{"class":263},[258,617,619],{"class":158,"line":618},19,[258,620,505],{"emptyLinePlaceholder":504},[258,622,624],{"class":158,"line":623},20,[258,625,626],{"class":511},"  \u002F* CHEAP even at the root: the argument changes rarely. Opening a dialog\n",[258,628,630],{"class":158,"line":629},21,[258,631,632],{"class":511},"     happens a handful of times per session, so a document-wide recalc\n",[258,634,636],{"class":158,"line":635},22,[258,637,638],{"class":511},"     at that moment is fine. *\u002F\n",[258,640,642,645,647,650,653,656,659,662,664,667],{"class":158,"line":641},23,[258,643,644],{"class":271},"  :root:has",[258,646,535],{"class":263},[258,648,649],{"class":267},"dialog",[258,651,652],{"class":263},"[",[258,654,655],{"class":271},"open",[258,657,658],{"class":263},"]) { ",[258,660,661],{"class":271},"overflow",[258,663,362],{"class":263},[258,665,666],{"class":271},"hidden",[258,668,399],{"class":263},[258,670,672],{"class":158,"line":671},24,[258,673,505],{"emptyLinePlaceholder":504},[258,675,677],{"class":158,"line":676},25,[258,678,679],{"class":511},"  \u002F* RISKY: a universal subject means every element is an anchor candidate.\n",[258,681,683],{"class":158,"line":682},26,[258,684,685],{"class":511},"     Always give :has() a specific subject. *\u002F\n",[258,687,689],{"class":158,"line":688},27,[258,690,691],{"class":511},"  \u002F* *:has(> img) { outline: 1px solid red; }   -- avoid *\u002F\n",[258,693,695,698,700,702,704,707,710,713,715,717],{"class":158,"line":694},28,[258,696,697],{"class":267},"  figure",[258,699,532],{"class":271},[258,701,535],{"class":263},[258,703,588],{"class":368},[258,705,706],{"class":267}," img",[258,708,709],{"class":263},") { ",[258,711,712],{"class":271},"margin-inline",[258,714,362],{"class":263},[258,716,449],{"class":271},[258,718,399],{"class":263},[258,720,722],{"class":158,"line":721},29,[258,723,505],{"emptyLinePlaceholder":504},[258,725,727],{"class":158,"line":726},30,[258,728,729],{"class":511},"  \u002F* PREFER a direct-child argument when that is what you mean. It is\n",[258,731,733],{"class":158,"line":732},31,[258,734,735],{"class":511},"     both clearer and gives the engine a shorter walk. *\u002F\n",[258,737,739,742,744,746,749,751,754,756,759,762,765],{"class":158,"line":738},32,[258,740,741],{"class":271},"  .card:has",[258,743,535],{"class":263},[258,745,588],{"class":368},[258,747,748],{"class":271}," .card__media",[258,750,709],{"class":263},[258,752,753],{"class":271},"grid-template-rows",[258,755,362],{"class":263},[258,757,758],{"class":271},"auto",[258,760,761],{"class":271}," 1",[258,763,764],{"class":368},"fr",[258,766,399],{"class":263},[258,768,770,773,775],{"class":158,"line":769},33,[258,771,772],{"class":263},"\u003C\u002F",[258,774,345],{"class":267},[258,776,275],{"class":263},[258,778,780,782,784],{"class":158,"line":779},34,[258,781,772],{"class":263},[258,783,303],{"class":267},[258,785,275],{"class":263},[258,787,789,791,794],{"class":158,"line":788},35,[258,790,281],{"class":263},[258,792,793],{"class":267},"body",[258,795,275],{"class":263},[258,797,799,802,805,808,810,813],{"class":158,"line":798},36,[258,800,801],{"class":263},"  \u003C",[258,803,804],{"class":267},"section",[258,806,807],{"class":271}," class",[258,809,289],{"class":263},[258,811,812],{"class":292},"\"panel\"",[258,814,275],{"class":263},[258,816,818,821,824,826,828,831,834,836],{"class":158,"line":817},37,[258,819,820],{"class":263},"    \u003C",[258,822,823],{"class":267},"div",[258,825,807],{"class":271},[258,827,289],{"class":263},[258,829,830],{"class":292},"\"toolbar\"",[258,832,833],{"class":263},">Toolbar\u003C\u002F",[258,835,823],{"class":267},[258,837,275],{"class":263},[258,839,841,843,846,848,850,853],{"class":158,"line":840},38,[258,842,820],{"class":263},[258,844,845],{"class":267},"ul",[258,847,807],{"class":271},[258,849,289],{"class":263},[258,851,852],{"class":292},"\"list\"",[258,854,275],{"class":263},[258,856,858,861,864,867,869],{"class":158,"line":857},39,[258,859,860],{"class":263},"      \u003C",[258,862,863],{"class":267},"li",[258,865,866],{"class":263},">First item\u003C\u002F",[258,868,863],{"class":267},[258,870,275],{"class":263},[258,872,874,876,878,881,883],{"class":158,"line":873},40,[258,875,860],{"class":263},[258,877,863],{"class":267},[258,879,880],{"class":263},">Second item\u003C\u002F",[258,882,863],{"class":267},[258,884,275],{"class":263},[258,886,888,890,892,895,897],{"class":158,"line":887},41,[258,889,860],{"class":263},[258,891,863],{"class":267},[258,893,894],{"class":263},">Third item\u003C\u002F",[258,896,863],{"class":267},[258,898,275],{"class":263},[258,900,902,905,907],{"class":158,"line":901},42,[258,903,904],{"class":263},"    \u003C\u002F",[258,906,845],{"class":267},[258,908,275],{"class":263},[258,910,912,915,917],{"class":158,"line":911},43,[258,913,914],{"class":263},"  \u003C\u002F",[258,916,804],{"class":267},[258,918,275],{"class":263},[258,920,922,924,926],{"class":158,"line":921},44,[258,923,772],{"class":263},[258,925,793],{"class":267},[258,927,275],{"class":263},[258,929,931,933,935],{"class":158,"line":930},45,[258,932,772],{"class":263},[258,934,253],{"class":267},[258,936,275],{"class":263},[19,938,939,940,942,943,945],{},"The first two rules are the heart of the matter. Both dim a toolbar while any list item is hovered. The first anchors on ",[14,941,793],{},", so each hover change is potentially relevant to the document root, and the resulting style invalidation can cascade through everything ",[14,944,793],{}," contains. The second anchors on the panel that actually contains both the list and the toolbar, so each hover change walks up at most two levels and recalculates one small subtree.",[44,947,949],{"id":948},"the-key-technique-narrow-the-anchor-stabilise-the-argument","The key technique: narrow the anchor, stabilise the argument",[19,951,952],{},"Cost is a product of two things — how often the argument changes, and how much style depends on the anchor. The chart below plots common patterns on those two axes. Anything in the top-right quadrant deserves a second look.",[110,954,117,957,117,960,117,963,117,966,117,971,117,975,117,978,117,984,117,989,117,993,117,996,117,1002,117,1008,117,1012,117,1014,117,1017,117,1021,117,1026,117,1028],{"viewBox":955,"role":113,"ariaLabel":956,"xmlns":115,"style":116},"0 0 720 360","Two-axis chart of has patterns by anchor breadth and argument volatility, with the costly quadrant highlighted",[119,958,959],{},"Anchor breadth versus argument volatility",[123,961,962],{},"Horizontal axis runs from narrow to broad anchors, vertical from stable to volatile arguments. Root with dialog open sits bottom right, component with hover sits top left, and body with hover sits top right in the costly quadrant.",[127,964,965],{"textAnchor":129,"x":130,"y":131,"style":132},"Where a :has() rule's cost comes from",[135,967],{"x":968,"y":225,"width":209,"height":969,"rx":494,"fill":166,"opacity":970},"380","130","0.28",[158,972],{"x1":183,"y1":973,"x2":974,"y2":973,"stroke":143,"strokeWidth":144,"opacity":145},"310","690",[158,976],{"x1":183,"y1":977,"x2":183,"y2":973,"stroke":143,"strokeWidth":144,"opacity":145},"44",[127,979,983],{"textAnchor":980,"x":974,"y":981,"style":982},"end","332","text-anchor:end;fill:currentColor;font:12px sans-serif","broad anchor",[127,985,988],{"textAnchor":202,"x":986,"y":981,"style":987},"90","text-anchor:start;fill:currentColor;font:12px sans-serif","narrow anchor",[127,990,992],{"textAnchor":980,"x":140,"y":991,"style":982},"60","volatile",[127,994,995],{"textAnchor":980,"x":140,"y":209,"style":982},"stable",[127,997,1001],{"textAnchor":129,"x":998,"y":999,"style":1000},"530","72","text-anchor:middle;fill:currentColor;font:600 12px sans-serif","review these",[1003,1004],"circle",{"cx":1005,"cy":1006,"r":1007,"fill":143},"560","116","7",[127,1009,1011],{"textAnchor":129,"x":1010,"y":204,"style":155},"550","body:has(li:hover)",[1003,1013],{"cx":188,"cy":1006,"r":1007,"fill":143},[127,1015,1016],{"textAnchor":129,"x":160,"y":204,"style":155},".panel:has(li:hover)",[1003,1018],{"cx":1019,"cy":1020,"r":1007,"fill":143},"590","250",[127,1022,1025],{"textAnchor":129,"x":1023,"y":1024,"style":155},"540","280",":root:has(dialog[open])",[1003,1027],{"cx":188,"cy":1020,"r":1007,"fill":143},[127,1029,1030],{"textAnchor":129,"x":160,"y":1024,"style":155},".card:has(> img)",[19,1032,1033],{},"Practical rules follow directly:",[845,1035,1036,1053,1066,1077,1095],{},[863,1037,1038,1045,1046,1049,1050,1052],{},[1039,1040,1041,1042,1044],"strong",{},"Give every ",[14,1043,16],{}," a specific subject."," A class or element type, never ",[14,1047,1048],{},"*"," and rarely ",[14,1051,793],{},". The subject determines which elements are candidates.",[863,1054,1055,102,1058,1061,1062,1065],{},[1039,1056,1057],{},"Scope the argument with a combinator.",[14,1059,1060],{},":has(> x)"," or ",[14,1063,1064],{},":has(+ x)"," when that is what you mean. It prevents accidental matches from nested components and shortens the walk.",[863,1067,1068,102,1071,380,1073,1076],{},[1039,1069,1070],{},"Use document-level anchors only for stable state.",[14,1072,1025],{},[14,1074,1075],{},":root:has(#dark-mode:checked)"," and similar page-mode switches change a few times per session.",[863,1078,1079,102,1082,380,1084,1087,1088,1091,1092,1094],{},[1039,1080,1081],{},"Avoid volatile pseudo-classes under broad anchors.",[14,1083,543],{},[14,1085,1086],{},":focus"," and ",[14,1089,1090],{},":active"," change constantly; keep their ",[14,1093,16],{}," anchors close to the element that changes.",[863,1096,1097,102,1103,1106],{},[1039,1098,1099,1100,1102],{},"Beware of ",[14,1101,16],{}," combined with sibling selectors.",[14,1104,1105],{},".a:has(~ .b)"," makes every later sibling relevant to every earlier one, which is fine in a short list and unpleasant in a list of thousands.",[44,1108,1110],{"id":1109},"measuring-instead-of-guessing","Measuring instead of guessing",[19,1112,1113],{},"Rules of thumb only get you so far; profile when a page feels slow. The workflow below uses Chrome's Performance panel, which exposes per-selector timing.",[110,1115,117,1118,117,1121,117,1124,117,1127,117,1133,117,1138,117,1141,117,1144,117,1147,117,1150,117,1154,117,1157,117,1160,117,1163,117,1167,117,1170,117,1173,117,1176,117,1180,117,1184,117,1187,117,1190,117,1193,117,1197],{"viewBox":1116,"role":113,"ariaLabel":1117,"xmlns":115,"style":116},"0 0 720 250","Four-step profiling workflow for a slow has rule",[119,1119,1120],{},"Profiling a :has() rule",[123,1122,1123],{},"Enable selector statistics, record the interaction, select the Recalculate Style event, and sort the selector table by elapsed time to find the costly rule.",[127,1125,1126],{"textAnchor":129,"x":130,"y":131,"style":132},"From a janky hover to the guilty selector",[135,1128],{"x":1129,"y":1130,"width":199,"height":1131,"rx":141,"fill":166,"opacity":1132},"20","56","110","0.18",[127,1134,1137],{"textAnchor":129,"x":1135,"y":149,"style":1136},"100","text-anchor:middle;fill:currentColor;font:700 14px sans-serif","1. Enable",[127,1139,1140],{"textAnchor":129,"x":1135,"y":1131,"style":174},"selector stats",[127,1142,1143],{"textAnchor":129,"x":1135,"y":969,"style":174},"in capture",[127,1145,1146],{"textAnchor":129,"x":1135,"y":223,"style":174},"settings",[135,1148],{"x":1149,"y":1130,"width":199,"height":1131,"rx":141,"fill":166,"opacity":1132},"196",[127,1151,1153],{"textAnchor":129,"x":1152,"y":149,"style":1136},"276","2. Record",[127,1155,1156],{"textAnchor":129,"x":1152,"y":1131,"style":174},"the exact",[127,1158,1159],{"textAnchor":129,"x":1152,"y":969,"style":174},"interaction",[135,1161],{"x":1162,"y":1130,"width":199,"height":1131,"rx":141,"fill":166,"opacity":1132},"372",[127,1164,1166],{"textAnchor":129,"x":1165,"y":149,"style":1136},"452","3. Select",[127,1168,1169],{"textAnchor":129,"x":1165,"y":1131,"style":174},"a long",[127,1171,1172],{"textAnchor":129,"x":1165,"y":969,"style":174},"Recalculate",[127,1174,1175],{"textAnchor":129,"x":1165,"y":223,"style":174},"Style event",[135,1177],{"x":1178,"y":1130,"width":199,"height":1131,"rx":141,"fill":166,"opacity":1179},"548","0.34",[127,1181,1183],{"textAnchor":129,"x":1182,"y":149,"style":1136},"628","4. Sort",[127,1185,1186],{"textAnchor":129,"x":1182,"y":1131,"style":174},"selector table",[127,1188,1189],{"textAnchor":129,"x":1182,"y":969,"style":174},"by elapsed",[127,1191,1192],{"textAnchor":129,"x":1182,"y":223,"style":174},"time",[127,1194,1196],{"textAnchor":129,"x":130,"y":1195,"style":174},"206","Watch \"match attempts\": a :has() tested against thousands of",[127,1198,1200],{"textAnchor":129,"x":130,"y":1199,"style":174},"226","elements per hover is the pattern to narrow.",[1202,1203,1204,1207,1210,1217],"ol",{},[863,1205,1206],{},"In Chrome or Edge DevTools, open the Performance panel, open its capture settings, and enable the selector statistics option. It adds overhead, so turn it off afterwards.",[863,1208,1209],{},"Record while performing the exact interaction that feels slow — hovering down a list, typing in a field, toggling a panel.",[863,1211,1212,1213,1216],{},"In the flame chart, find the purple ",[60,1214,1215],{},"Recalculate Style"," events and select a long one. The summary shows how many elements were affected.",[863,1218,1219,1220,1222],{},"Open the Selector Stats tab for that event and sort by elapsed time. Each row shows a selector, how long it took, how many match attempts were made, and how many matched. A ",[14,1221,16],{}," rule with enormous match attempts and few matches is the one to narrow.",[19,1224,1225,1226,1228,1229,1233],{},"Firefox's profiler shows style recalculation cost as well, without per-selector breakdown; if the style phase is large after a change and removing one ",[14,1227,16],{}," rule shrinks it, you have your answer. The broader animation-profiling workflow is covered in ",[29,1230,1232],{"href":1231},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fprofiling-animations-in-devtools\u002F","Profiling Animations in DevTools",".",[44,1235,1237,1238,1240],{"id":1236},"variation-replacing-a-hot-has-with-a-container-style-query","Variation: replacing a hot ",[14,1239,16],{}," with a container style query",[19,1242,1243,1244,1248],{},"When a broad anchor genuinely needs state from deep inside — a page layout that changes when a sidebar panel is expanded, say — and the state changes often, consider moving the state into a custom property and reading it with a ",[29,1245,1247],{"href":1246},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state\u002F","style query",". The component that owns the state sets a property on itself, the layout container reads it, and the relationship is explicit rather than discovered by selector walking.",[249,1250,1254],{"className":1251,"code":1252,"language":1253,"meta":254,"style":254},"language-css shiki shiki-themes github-light-high-contrast github-dark-high-contrast","\u002F* The panel that owns the state publishes it as a custom property... *\u002F\n.sidebar { container-name: shell; }\n.sidebar:has(> details[open]) { --sidebar-state: expanded; }\n\n\u002F* ...and descendants of the container read it with a style query.\n   The :has() is anchored narrowly on .sidebar, and only the\n   container's subtree consults the published value. *\u002F\n@container shell style(--sidebar-state: expanded) {\n  .sidebar__nav { grid-template-columns: 1fr; }\n}\n","css",[14,1255,1256,1261,1274,1303,1307,1312,1317,1322,1330,1349],{"__ignoreMap":254},[258,1257,1258],{"class":158,"line":260},[258,1259,1260],{"class":511},"\u002F* The panel that owns the state publishes it as a custom property... *\u002F\n",[258,1262,1263,1266,1268,1271],{"class":158,"line":278},[258,1264,1265],{"class":271},".sidebar",[258,1267,356],{"class":263},[258,1269,1270],{"class":271},"container-name",[258,1272,1273],{"class":263},": shell; }\n",[258,1275,1276,1279,1281,1283,1286,1288,1290,1292,1296,1298,1301],{"class":158,"line":298},[258,1277,1278],{"class":271},".sidebar:has",[258,1280,535],{"class":263},[258,1282,588],{"class":368},[258,1284,1285],{"class":267}," details",[258,1287,652],{"class":263},[258,1289,655],{"class":271},[258,1291,658],{"class":263},[258,1293,1295],{"class":1294},"soyes","--sidebar-state",[258,1297,362],{"class":263},[258,1299,1300],{"class":271},"expanded",[258,1302,399],{"class":263},[258,1304,1305],{"class":158,"line":308},[258,1306,505],{"emptyLinePlaceholder":504},[258,1308,1309],{"class":158,"line":326},[258,1310,1311],{"class":511},"\u002F* ...and descendants of the container read it with a style query.\n",[258,1313,1314],{"class":158,"line":340},[258,1315,1316],{"class":511},"   The :has() is anchored narrowly on .sidebar, and only the\n",[258,1318,1319],{"class":158,"line":350},[258,1320,1321],{"class":511},"   container's subtree consults the published value. *\u002F\n",[258,1323,1324,1327],{"class":158,"line":402},[258,1325,1326],{"class":368},"@container",[258,1328,1329],{"class":263}," shell style(--sidebar-state: expanded) {\n",[258,1331,1332,1335,1337,1340,1342,1345,1347],{"class":158,"line":463},[258,1333,1334],{"class":271},"  .sidebar__nav",[258,1336,356],{"class":263},[258,1338,1339],{"class":271},"grid-template-columns",[258,1341,362],{"class":263},[258,1343,1344],{"class":271},"1",[258,1346,764],{"class":368},[258,1348,399],{"class":263},[258,1350,1351],{"class":158,"line":501},[258,1352,1353],{"class":263},"}\n",[19,1355,1356,1357,1233],{},"Whether this is actually faster depends on the page, so measure both. The architectural benefit is certain, though: the state has a name, and anyone reading the stylesheet can see which component publishes it. The trade-offs between the two mechanisms are laid out in ",[29,1358,1360,1362],{"href":1359},"\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has\u002Fhas-vs-container-style-queries\u002F",[34,1361],{},"() vs Container Style Queries",[44,1364,1366],{"id":1365},"browser-support","Browser support",[19,1368,1369,1371],{},[14,1370,16],{}," is supported in Chrome and Edge 105+, Firefox 121+ and Safari 15.4+, and all three engines implement targeted invalidation of the kind described here. Selector statistics in the Performance panel is a Chromium DevTools feature. Style queries for custom properties, used in the variation, are supported in Chrome and Edge 111+, Firefox 151+ and Safari 18+.",[44,1373,1375],{"id":1374},"faq","FAQ",[19,1377,1378,1384,1385,1387,1388,1061,1390,1393],{},[1039,1379,1380,1381,1383],{},"Is ",[14,1382,16],{}," slow?","\nNot in normal use. Engines track which elements could be affected by a ",[14,1386,16],{}," argument and only recheck those when something relevant changes. It becomes expensive when the anchor is very broad, such as ",[14,1389,793],{},[14,1391,1392],{},":root",", and the argument matches something that changes often, because then every change forces a recheck over a large subtree.",[19,1395,1396,1405,1406,1408],{},[1039,1397,1380,1398,1061,1401,1404],{},[14,1399,1400],{},"body:has()",[14,1402,1403],{},":root:has()"," a bad idea?","\nIt is fine for state that changes rarely, such as a dialog being open or a theme checkbox being checked. It is a poor choice for state that changes constantly, such as ",[14,1407,543],{}," inside a long list, because every hover change then invalidates style for the whole document.",[19,1410,1411,1417,1418,1421,1422,1425],{},[1039,1412,1413,1414,1416],{},"Does the child combinator make ",[14,1415,16],{}," faster?","\nUsually. ",[14,1419,1420],{},":has(> .x)"," only needs to look at direct children, while ",[14,1423,1424],{},":has(.x)"," must consider the whole subtree. Engines optimise both, but a narrower argument means fewer elements to recheck and less chance of accidental matches deep inside nested components.",[19,1427,1428,1434,1435,1437],{},[1039,1429,1430,1431,1433],{},"How do I measure whether a ",[14,1432,16],{}," rule is causing jank?","\nRecord a Performance profile while triggering the state change and look at the Recalculate Style events. Chrome's selector statistics option lists the selectors that took the most time and how many elements they were tested against, which pinpoints an expensive ",[14,1436,16],{}," directly.",[44,1439,1441],{"id":1440},"related","Related",[845,1443,1444,1451,1460,1467,1472],{},[863,1445,1446,1450],{},[29,1447,32,1448,36],{"href":31},[34,1449],{}," — the parent guide on relational selectors.",[863,1452,1453,1459],{},[29,1454,1456,1457,36],{"href":1455},"\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has\u002Fquantity-queries-with-has\u002F","Quantity Queries With ",[34,1458],{}," — a stable-argument pattern that is always cheap.",[863,1461,1462,1466],{},[29,1463,1464,1362],{"href":1359},[34,1465],{}," — when published state beats discovered state.",[863,1468,1469,1471],{},[29,1470,1232],{"href":1231}," — the same panel, used for motion.",[863,1473,1474,1478],{},[29,1475,1477],{"href":1476},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fwill-change-and-the-compositor-thread\u002F","Will-Change and the Compositor Thread"," — what happens after style recalculation.",[345,1480,1481],{},"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 .sHUrx, html code.shiki .sHUrx{--shiki-default:#A0111F;--shiki-dark:#FF9492}html pre.shiki code .sLBg1, html code.shiki .sLBg1{--shiki-default:#66707B;--shiki-dark:#BDC4CC}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .soyes, html code.shiki .soyes{--shiki-default:#702C00;--shiki-dark:#FFB757}",{"title":254,"searchDepth":278,"depth":278,"links":1483},[1484,1485,1486,1487,1488,1489,1491,1492,1493],{"id":46,"depth":278,"text":47},{"id":91,"depth":278,"text":92},{"id":243,"depth":278,"text":244},{"id":948,"depth":278,"text":949},{"id":1109,"depth":278,"text":1110},{"id":1236,"depth":278,"text":1490},"Variation: replacing a hot :has() with a container style query",{"id":1365,"depth":278,"text":1366},{"id":1374,"depth":278,"text":1375},{"id":1440,"depth":278,"text":1441},"How engines invalidate :has(), which relational selectors are cheap and which force wide style recalculation, and how to measure the cost in DevTools.","md",{"pageTitle":1497,"datePublished":1498,"dateModified":1498,"faq":1499},":has() Selector Performance in Practice","2026-09-18",[1500,1503,1506,1509],{"q":1501,"a":1502},"Is :has() slow?","Not in normal use. Engines track which elements could be affected by a :has() argument and only recheck those when something relevant changes. It becomes expensive when the anchor is very broad, such as body or :root, and the argument matches something that changes often, because then every change forces a recheck over a large subtree.",{"q":1504,"a":1505},"Is body:has() or :root:has() a bad idea?","It is fine for state that changes rarely, such as a dialog being open or a theme checkbox being checked. It is a poor choice for state that changes constantly, such as :hover inside a long list, because every hover change then invalidates style for the whole document.",{"q":1507,"a":1508},"Does the child combinator make :has() faster?","Usually. :has(> .x) only needs to look at direct children, while :has(.x) must consider the whole subtree. Engines optimise both, but a narrower argument means fewer elements to recheck and less chance of accidental matches deep inside nested components.",{"q":1510,"a":1511},"How do I measure whether a :has() rule is causing jank?","Record a Performance profile while triggering the state change and look at the Recalculate Style events. Chrome's selector statistics option lists the selectors that took the most time and how many elements they were tested against, which pinpoints an expensive :has() directly.","\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has\u002Fhas-selector-performance",{"title":5,"description":1494},"mastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has\u002Fhas-selector-performance\u002Findex","1bz-8LCzcsGDJp1-s87bLD1mX63aSOLf94Gjv5EE50g",[1517,1520,1523,1526,1529,1532,1535,1538,1541,1544,1547,1550,1553,1556,1559,1562,1565,1568,1571,1574,1577,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,1798,1801,1804,1807,1810,1813,1816,1819,1822,1825,1828,1831,1834,1837,1840,1843,1846,1849,1852,1855,1858,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,1938,1941,1944,1947,1950,1953,1956,1959,1962,1965,1968,1971,1974,1977,1980,1983,1986,1987,1990,1993,1996,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],{"path":1518,"title":1519},"\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":1521,"title":1522},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fflashing-content-and-seizure-thresholds","Flashing Content and Seizure Thresholds",{"path":1524,"title":1525},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fforced-colors-mode-and-animations","Forced Colors Mode and Animations",{"path":1527,"title":1528},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations","Accessibility in CSS Animations: Patterns, Specs & Best Practices",{"path":1530,"title":1531},"\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":1533,"title":1534},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fprefers-reduced-motion-recipes","prefers-reduced-motion Recipes: A Reduction for Every Common Effect",{"path":1536,"title":1537},"\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":1539,"title":1540},"\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":1542,"title":1543},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fvestibular-safe-animation-patterns","Vestibular-Safe Animation Patterns: Why Some Motion Makes People Sick",{"path":1545,"title":1546},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fwcag-motion-success-criteria","WCAG Motion Success Criteria: What Each One Actually Requires",{"path":1548,"title":1549},"\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":1551,"title":1552},"\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":1554,"title":1555},"\u002Fcss-only-micro-interactions-animations\u002Fclip-path-and-mask-animations","Clip-Path & Mask Animations: Animating Visibility Instead of Position",{"path":1557,"title":1558},"\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":1560,"title":1561},"\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":1563,"title":1564},"\u002Fcss-only-micro-interactions-animations\u002Fcolor-and-theme-transitions\u002Fanimating-gradients","Animating CSS Gradients: Smooth Colour Motion Without Jumps",{"path":1566,"title":1567},"\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":1569,"title":1570},"\u002Fcss-only-micro-interactions-animations\u002Fcolor-and-theme-transitions","Color & Theme Transitions: Colour as Part of the Motion System",{"path":1572,"title":1573},"\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":1575,"title":1576},"\u002Fcss-only-micro-interactions-animations\u002Fcolor-and-theme-transitions\u002Fsmooth-theme-switching-transitions","Smooth Theme Switching: Crossfades, Circular Reveals and No Flash",{"path":1578,"title":1579},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fcontainer-query-hover-affordances","Container Query Hover Affordances: When Narrow Means Persistent, Not Hidden",{"path":1581,"title":1582},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion","Container-Aware Motion: Animation Sized by the Space a Component Actually Has",{"path":1584,"title":1585},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Flayout-change-animations-at-container-breakpoints","Animating Changes at Container Breakpoints",{"path":1587,"title":1588},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fmotion-driven-by-container-style-queries","Motion Driven by Container Style Queries",{"path":1590,"title":1591},"\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":1593,"title":1594},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fsuppressing-motion-in-small-containers","Suppressing Motion in Small Containers: Deliberately Animating Nothing",{"path":1596,"title":1597},"\u002Fcss-only-micro-interactions-animations\u002Fcss-animation-vs-web-animations-api\u002Fcontrolling-css-animations-from-javascript","Controlling CSS Animations From JavaScript",{"path":1599,"title":1600},"\u002Fcss-only-micro-interactions-animations\u002Fcss-animation-vs-web-animations-api","CSS Animation vs the Web Animations API: A Decision Guide",{"path":1602,"title":1603},"\u002Fcss-only-micro-interactions-animations\u002Fcss-animation-vs-web-animations-api\u002Fwaapi-vs-css-for-interruptible-ui","Interruptible UI: CSS Transitions vs WAAPI",{"path":1605,"title":1606},"\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":1608,"title":1609},"\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":1611,"title":1612},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Fcustom-property-fallbacks-and-invalid-values","Custom Property Fallbacks and Invalid Values",{"path":1614,"title":1615},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Ffluid-spacing-tokens-driving-transition-durations","Fluid Spacing Tokens That Drive Transition Durations",{"path":1617,"title":1618},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture","CSS Custom Properties Architecture: Scalable Design Systems & Dynamic UI",{"path":1620,"title":1621},"\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":1623,"title":1624},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Fscoping-custom-properties-to-components","Scoping Custom Properties to Components",{"path":1626,"title":1627},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fcss-transition-timing-functions","CSS Transition Timing Functions: ease, cubic-bezier(), steps() and linear()",{"path":1629,"title":1630},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals","CSS Transition Fundamentals: Architecture, Performance & Patterns",{"path":1632,"title":1633},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Finterrupted-and-reversing-transitions","Interrupted and Reversing Transitions: What Happens Mid-Flight",{"path":1635,"title":1636},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fstarting-style-entry-animations","@starting-style: Animating an Element's Very First Style Change",{"path":1638,"title":1639},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Ftransition-delay-choreography","Choreographing Motion With transition-delay",{"path":1641,"title":1642},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Ftransition-shorthand-and-multiple-properties","The transition Shorthand and Multiple Properties",{"path":1644,"title":1645},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Ftransitioning-display-with-allow-discrete","Transitioning display with transition-behavior: allow-discrete and @starting-style",{"path":1647,"title":1648},"\u002Fcss-only-micro-interactions-animations\u002Fdialog-and-popover-animations\u002Fanimating-dialog-open-and-close","Animating \u003Cdialog> Open and Close: Both Directions, No Library",{"path":1650,"title":1651},"\u002Fcss-only-micro-interactions-animations\u002Fdialog-and-popover-animations\u002Fbackdrop-animations","Animating ::backdrop: Fades and Blurs Behind Dialogs and Popovers",{"path":1653,"title":1654},"\u002Fcss-only-micro-interactions-animations\u002Fdialog-and-popover-animations","Dialog & Popover Animations: Motion for the Top Layer",{"path":1656,"title":1657},"\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":1659,"title":1660},"\u002Fcss-only-micro-interactions-animations\u002Fdialog-and-popover-animations\u002Fpopover-entry-and-exit-transitions","Popover Menus That Animate From Their Anchor",{"path":1662,"title":1663},"\u002Fcss-only-micro-interactions-animations\u002Feasing-and-motion-design\u002Fchoosing-animation-durations","Choosing Animation Durations: How Long Motion Should Last",{"path":1665,"title":1666},"\u002Fcss-only-micro-interactions-animations\u002Feasing-and-motion-design\u002Fcubic-bezier-overshoot-and-anticipation","Overshoot and Anticipation With cubic-bezier(): Motion With Character",{"path":1668,"title":1669},"\u002Fcss-only-micro-interactions-animations\u002Feasing-and-motion-design\u002Fentry-vs-exit-easing","Entry vs Exit Easing: Different Curves for Arriving and Leaving",{"path":1671,"title":1672},"\u002Fcss-only-micro-interactions-animations\u002Feasing-and-motion-design","Easing & Motion Design: Making CSS Motion Feel Intentional",{"path":1674,"title":1675},"\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":1677,"title":1678},"\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":1680,"title":1681},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Faccessible-css-only-tooltips","Accessible CSS-Only Tooltips and Hover Cards With  and ",{"path":1683,"title":1684},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Fbutton-press-and-active-states","Button Press and  States",{"path":1686,"title":1687},"\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":1689,"title":1690},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Ffocus-within-form-patterns"," Form Patterns: Styling a Group From the Field Inside It",{"path":1692,"title":1693},"\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":1695,"title":1696},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design","Hover & Focus State Design: Spec-Compliant Patterns for Modern UIs",{"path":1698,"title":1699},"\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":1701,"title":1702},"\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":1704,"title":1705},"\u002Fcss-only-micro-interactions-animations","CSS-Only Micro-Interactions & Animations: Architecture, Performance & Implementation",{"path":1707,"title":1708},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fanimation-composition-and-stacking","Stacking Animations With animation-composition",{"path":1710,"title":1711},"\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":1713,"title":1714},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcontainer-query-triggered-keyframe-animations","Container-Query-Triggered Keyframe Animations: Animate Differently per Available Space",{"path":1716,"title":1717},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcss-only-accordions-and-disclosure","CSS-Only Accordions and Disclosure Widgets with details and summary",{"path":1719,"title":1720},"\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":1722,"title":1723},"\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":1725,"title":1726},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns","Keyframe Animation Patterns: Spec-Compliant Architectures for Modern UIs",{"path":1728,"title":1729},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fmulti-step-keyframes-and-per-keyframe-easing","Multi-Step Keyframes and Per-Keyframe Easing",{"path":1731,"title":1732},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fstaggered-list-animations-with-custom-properties","Staggered List Animations Using --i Index Custom Properties",{"path":1734,"title":1735},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fanimating-box-shadow-and-filters-cheaply","Animating box-shadow and Filters Cheaply",{"path":1737,"title":1738},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fcontain-property-for-animation-performance","The contain Property for Animation Performance",{"path":1740,"title":1741},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fcss-triggers-layout-paint-composite","Layout, Paint and Composite: What Triggers What",{"path":1743,"title":1744},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration","Performance & GPU Acceleration in CSS: A Developer’s Blueprint",{"path":1746,"title":1747},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Foptimizing-css-animations-for-60fps","Optimizing CSS Animations for 60fps: Budgeting the Frame",{"path":1749,"title":1750},"\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":1752,"title":1753},"\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":1755,"title":1756},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations","Scroll-Driven Animations: Binding Motion to Scroll Position in Pure CSS",{"path":1758,"title":1759},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-driven-animation-fallbacks","Shipping Scroll-Driven Animations Without Breaking Anything",{"path":1761,"title":1762},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-driven-parallax-effects","Scroll-Driven Parallax Effects in CSS",{"path":1764,"title":1765},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-progress-bar-without-javascript","A Reading Progress Bar Driven by scroll(root)",{"path":1767,"title":1768},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-triggered-reveal-animations","Reveal-on-Scroll with view() and animation-range",{"path":1770,"title":1771},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Ftimeline-scope-for-cross-element-animations","timeline-scope for Cross-Element Animations",{"path":1773,"title":1774},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fview-timeline-and-animation-range","View Timelines and animation-range",{"path":1776,"title":1777},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fcross-document-view-transitions","Cross-Document View Transitions",{"path":1779,"title":1780},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers","View Transitions for CSS Developers: the Pseudo-Element Tree, Snapshots, and Named Elements",{"path":1782,"title":1783},"\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":1785,"title":1786},"\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":1788,"title":1789},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fview-transition-types-and-classes","View Transition Types and Classes",{"path":1791,"title":1792},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fview-transitions-for-list-reordering","View Transitions for List Reordering",{"path":1794,"title":1795},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fview-transitions-with-reduced-motion","Honouring prefers-reduced-motion in View Transitions",{"path":372,"title":1797},"Modern CSS Layouts & Micro-Interactions",{"path":1799,"title":1800},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioned-tooltips","Anchor-Positioned Tooltips: Tethering, Flipping, and Getting the Semantics Right",{"path":1802,"title":1803},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioning-fallbacks","Anchor Positioning Fallbacks: A Graceful Floor for Older Browser Versions",{"path":1805,"title":1806},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-size-for-matching-widths","anchor-size(): Overlays That Match Their Trigger's Size",{"path":1808,"title":1809},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays","CSS Anchor Positioning and Overlays: Tethering Elements Without JavaScript",{"path":1811,"title":1812},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fpopover-attribute-and-css-styling","The popover Attribute: Top-Layer Overlays With No JavaScript",{"path":1814,"title":1815},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fpopover-light-dismiss-and-stacking","Popover Light Dismiss, Nesting and Stacking",{"path":1817,"title":1818},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fposition-area-grid-explained","position-area: The Anchor Placement Grid",{"path":1820,"title":1821},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Fcontainer-query-polyfill-tradeoffs","Container Query Polyfills: What They Cost and When to Skip Them",{"path":1823,"title":1824},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Ffeature-detection-with-supports","Feature Detection with @supports: Syntax, Semantics, and the Traps",{"path":1826,"title":1827},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Fhandling-container-query-fallbacks-for-older-browsers","Handling Container Query Fallbacks for Older Browsers",{"path":1829,"title":1830},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks","Container Query Fallbacks: Spec-Compliant CSS Strategies for Legacy Browsers",{"path":1832,"title":1833},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Fintrinsic-layout-fallbacks-without-queries","Intrinsic Layout Fallbacks: Baselines That Adapt Without Any Query",{"path":1835,"title":1836},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Ftesting-fallbacks-without-old-browsers","Testing CSS Fallbacks Without an Old Browser",{"path":1838,"title":1839},"\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":1841,"title":1842},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-query-range-and-logic-operators","Container Query Range Syntax and Logic Operators",{"path":1844,"title":1845},"\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":1847,"title":1848},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-type-size-vs-inline-size","Choosing container-type: inline-size, size, or normal",{"path":1850,"title":1851},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-vs-media-queries-comparison","Container vs Media Queries: Choosing the Right Reference Box",{"path":1853,"title":1854},"\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":1856,"title":1857},"\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":1859,"title":1860},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics","Container Query Syntax Basics",{"path":1862,"title":1863},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fnesting-and-naming-container-queries","Nesting and Naming Container Queries: Targeting the Right Ancestor",{"path":1865,"title":1866},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fauto-fit-minmax-responsive-grids","Responsive Grids with repeat(auto-fit, minmax())",{"path":1868,"title":1869},"\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":1871,"title":1872},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fgrid-auto-flow-dense-packing","grid-auto-flow: dense for Packed Layouts",{"path":1874,"title":1875},"\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":1877,"title":1878},"\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":1880,"title":1881},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts","CSS Grid and Subgrid Layouts for Responsive Interfaces",{"path":1883,"title":1884},"\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":1886,"title":1887},"\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":1889,"title":1890},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fsubgrid-vs-nested-grid","Subgrid vs an Independently Nested Grid",{"path":1892,"title":1893},"\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":1895,"title":1896},"\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":1898,"title":1899},"\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002Fflex-grow-and-flex-shrink-explained","flex-grow and flex-shrink Explained",{"path":1901,"title":1902},"\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002Fflex-wrap-intrinsic-responsive-rows","Breakpoint-Free Responsive Rows With flex-wrap and flex-basis",{"path":1904,"title":1905},"\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002Fflexbox-gap-and-spacing","Flexbox gap vs Margins: Spacing Items Without Edge Hacks",{"path":1907,"title":1908},"\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns","Flexbox Layout Patterns: One-Dimensional Layout for Real Components",{"path":1910,"title":1911},"\u002Fmastering-container-queries-responsive-layouts\u002Fflexbox-layout-patterns\u002Fsticky-footer-with-flexbox-and-grid","Sticky Footer With Flexbox or Grid: Pinning the Footer on Short Pages",{"path":1913,"title":1914},"\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":1916,"title":1917},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Fdebugging-clamp-values","Debugging clamp(): Values That Are Ignored, Stuck or Never Fluid",{"path":1919,"title":1920},"\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":1922,"title":1923},"\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":1925,"title":1926},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-type-accessibility-and-zoom","Fluid Type, Accessibility and Zoom: The vw-Only Trap",{"path":1928,"title":1929},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-typography-without-javascript","Fluid Typography Without JavaScript: A Precision CSS Reference",{"path":1931,"title":1932},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp","Fluid Typography with clamp(): A Practical Guide for Modern CSS",{"path":1934,"title":1935},"\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":1937,"title":41},"\u002Fmastering-container-queries-responsive-layouts",{"path":1939,"title":1940},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Faspect-ratio-for-responsive-media","Using aspect-ratio for Responsive Media and Preventing Layout Shift",{"path":1942,"title":1943},"\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":1945,"title":1946},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques","Intrinsic Sizing Techniques: Modern CSS Layouts for Responsive UI",{"path":1948,"title":1949},"\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":1951,"title":1952},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fmin-max-fit-content-explained","min-content, max-content, and fit-content() Explained",{"path":1954,"title":1955},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fobject-fit-and-object-position","object-fit and object-position: Images That Fit Any Box",{"path":1957,"title":1958},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fpreventing-flex-and-grid-overflow","The min-width: auto Trap in Flex and Grid Layouts",{"path":1960,"title":1961},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-for-reset-and-tokens","Cascade Layers for Reset and Design Tokens",{"path":1963,"title":1964},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-vs-specificity-hacks","Cascade Layers vs Specificity Hacks: Ordering Instead of Escalating",{"path":1966,"title":1967},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcss-scope-for-component-styles","@scope for Component Styles: Short Selectors That Cannot Leak",{"path":1969,"title":1970},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies","Modern CSS Reset Strategies: A Spec-Compliant Foundation",{"path":1972,"title":1973},"\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":1975,"title":1976},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fwriting-a-minimal-modern-reset","Writing a Minimal Modern CSS Reset: Every Line Justified",{"path":1978,"title":1979},"\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":1981,"title":1982},"\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has\u002Fempty-and-loading-states-with-has","Empty and Loading States With ()",{"path":1984,"title":1985},"\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":1512,"title":5},{"path":1988,"title":1989},"\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":1991,"title":1992},"\u002Fmastering-container-queries-responsive-layouts\u002Fparent-aware-layouts-with-has","Parent-Aware Layouts With :has(): Letting Containers React to Their Contents",{"path":1994,"title":1995},"\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":1997,"title":1998},"\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":2000,"title":2001},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fcontainer-query-data-tables","Container Query Data Tables: Reflowing Tables to Cards",{"path":2003,"title":2004},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fcontainer-query-sidebar-layouts","Container Query Sidebar Layouts That Travel Between Contexts",{"path":2006,"title":2007},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns","Responsive Component Patterns: Architecture & Implementation",{"path":2009,"title":2010},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-forms-with-container-queries","Responsive Forms with Container Queries: Reflow Without Losing the Wiring",{"path":2012,"title":2013},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-hero-sections-with-container-queries","Responsive Hero Sections With Container Queries",{"path":2015,"title":2016},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-navigation-without-media-queries","Responsive Navigation Without Media Queries Using Container Queries",{"path":2018,"title":2019},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-pricing-tables","Responsive Pricing Tables: Aligned Features, a Clear Recommendation, Any Width",{"path":2021,"title":2022},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Ftabs-that-become-accordions","Tabs That Become an Accordion: One Component, Two Layouts",{"path":2024,"title":2025},"\u002Fmastering-container-queries-responsive-layouts\u002Fscroll-snap-and-overflow-layouts\u002Fcss-only-carousel-with-scroll-snap","A CSS-Only Carousel With Scroll Snap",{"path":2027,"title":2028},"\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":2030,"title":2031},"\u002Fmastering-container-queries-responsive-layouts\u002Fscroll-snap-and-overflow-layouts","Scroll Snap & Overflow Layouts: Designing Components That Scroll on Purpose",{"path":2033,"title":2034},"\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":2036,"title":2037},"\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":2039,"title":2040},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state\u002Fcombining-size-and-style-queries","Combining Size and Style Container Queries",{"path":2042,"title":2043},"\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":2045,"title":2046},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state","Style Queries and Container State: Token-Driven Component Variants",{"path":2048,"title":2049},"\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":2051,"title":2052},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state\u002Fstyle-query-component-variants","Component Variants With Style Queries: One Token, Many Looks",{"path":2054,"title":2055},"\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":2057,"title":2058},"\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":2060,"title":2061},"\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":2063,"title":2064},"\u002Fmastering-container-queries-responsive-layouts\u002Fviewport-units-and-mobile-layout","Viewport Units & Mobile Layout: Designing for the Screen You Actually Get",{"path":2066,"title":2067},"\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":2069,"title":2070},"\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":2072,"title":2073},"\u002Fmastering-container-queries-responsive-layouts\u002Fviewport-units-and-mobile-layout\u002Fvirtual-keyboard-and-interactive-widget","Layouts That Survive the Virtual Keyboard",1789717747986]