[{"data":1,"prerenderedAt":8009},["ShallowReactive",2],{"home-articles":3,"category-count-vue":97,"category-count-frontend":155,"category-count-css":165,"category-count-javascript":111,"category-count-music":111,"category-count-fullstack":8008,"category-count-notes":8008},{"count":4,"latest":5},14,[6,1452,2398,5526,6361,7622],{"id":7,"title":8,"body":9,"category":177,"date":1439,"description":1440,"draft":1441,"extension":1442,"meta":1443,"navigation":243,"path":1444,"seo":1445,"stem":1446,"tags":1447,"__hash__":1451},"blog\u002Fblog\u002Fcss-containing-block.md","你不知道的 CSS 之包含块",{"type":10,"value":11,"toc":1429},"minimark",[12,16,38,45,60,66,79,84,173,298,316,322,328,331,343,363,367,439,444,530,756,773,779,783,793,835,844,881,889,895,904,910,913,1118,1121,1176,1195,1198,1248,1262,1286,1292,1342,1366,1374,1380,1383,1425],[13,14,8],"h1",{"id":15},"你不知道的-css-之包含块",[17,18,19,20,24,25,29,30,33,34,37],"p",{},"盒模型、",[21,22,23],"code",{},"border-box"," 很多人熟，但 ",[26,27,28],"strong",{},"包含块（containing block）"," 一听就懵——它平时「看不见」，却决定 ",[21,31,32],{},"width: 50%","、",[21,35,36],{},"left: 10px"," 相对谁算。",[17,39,40],{},[41,42],"img",{"alt":43,"src":44},"包含块决定元素的尺寸与百分比参照区域","\u002Fdemos\u002Fcontaining-block\u002Fconcept.svg",[17,46,47,48,51,52,59],{},"简单说：",[26,49,50],{},"元素的尺寸与位置（以及百分比值的计算）受包含块影响。"," 规范见 ",[53,54,58],"a",{"href":55,"rel":56},"https:\u002F\u002Fdrafts.csswg.org\u002Fcss2\u002F#containing-block-details",[57],"nofollow","CSS2 containing block","。",[17,61,62],{},[41,63],{"alt":64,"src":65},"不同定位方式下的包含块规则","\u002Fdemos\u002Fcontaining-block\u002Frules-overview.svg",[17,67,68,69,73,74,78],{},"在 ",[53,70,72],{"href":71},"\u002Fblog\u002Fbrowser-rendering-pipeline","浏览器布局阶段","，几何信息就是结合 DOM、Computed Style 与包含块算出来的；",[53,75,77],{"href":76},"\u002Fblog\u002Fcss-property-calculation","样式计算"," 里算不定的百分比宽高，到这一步才定稿。",[80,81,83],"h2",{"id":82},"最简例子50-相对谁","最简例子：50% 相对谁？",[85,86,91],"pre",{"className":87,"code":88,"language":89,"meta":90,"style":90},"language-html shiki shiki-themes github-light github-dark","\u003Cbody>\n  \u003Cdiv class=\"container\">\n    \u003Cdiv class=\"item\">\u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Fbody>\n","html","",[21,92,93,109,131,153,163],{"__ignoreMap":90},[94,95,98,102,106],"span",{"class":96,"line":97},"line",1,[94,99,101],{"class":100},"sVt8B","\u003C",[94,103,105],{"class":104},"s9eBZ","body",[94,107,108],{"class":100},">\n",[94,110,112,115,118,122,125,129],{"class":96,"line":111},2,[94,113,114],{"class":100},"  \u003C",[94,116,117],{"class":104},"div",[94,119,121],{"class":120},"sScJk"," class",[94,123,124],{"class":100},"=",[94,126,128],{"class":127},"sZZnC","\"container\"",[94,130,108],{"class":100},[94,132,134,137,139,141,143,146,149,151],{"class":96,"line":133},3,[94,135,136],{"class":100},"    \u003C",[94,138,117],{"class":104},[94,140,121],{"class":120},[94,142,124],{"class":100},[94,144,145],{"class":127},"\"item\"",[94,147,148],{"class":100},">\u003C\u002F",[94,150,117],{"class":104},[94,152,108],{"class":100},[94,154,156,159,161],{"class":96,"line":155},4,[94,157,158],{"class":100},"  \u003C\u002F",[94,160,117],{"class":104},[94,162,108],{"class":100},[94,164,166,169,171],{"class":96,"line":165},5,[94,167,168],{"class":100},"\u003C\u002F",[94,170,105],{"class":104},[94,172,108],{"class":100},[85,174,178],{"className":175,"code":176,"language":177,"meta":90,"style":90},"language-css shiki shiki-themes github-light github-dark",".container {\n  width: 500px;\n  height: 300px;\n  background-color: skyblue;\n}\n\n.item {\n  width: 50%;\n  height: 50%;\n  background-color: red;\n}\n","css",[21,179,180,188,207,221,233,238,245,253,268,281,293],{"__ignoreMap":90},[94,181,182,185],{"class":96,"line":97},[94,183,184],{"class":120},".container",[94,186,187],{"class":100}," {\n",[94,189,190,194,197,200,204],{"class":96,"line":111},[94,191,193],{"class":192},"sj4cs","  width",[94,195,196],{"class":100},": ",[94,198,199],{"class":192},"500",[94,201,203],{"class":202},"szBVR","px",[94,205,206],{"class":100},";\n",[94,208,209,212,214,217,219],{"class":96,"line":133},[94,210,211],{"class":192},"  height",[94,213,196],{"class":100},[94,215,216],{"class":192},"300",[94,218,203],{"class":202},[94,220,206],{"class":100},[94,222,223,226,228,231],{"class":96,"line":155},[94,224,225],{"class":192},"  background-color",[94,227,196],{"class":100},[94,229,230],{"class":192},"skyblue",[94,232,206],{"class":100},[94,234,235],{"class":96,"line":165},[94,236,237],{"class":100},"}\n",[94,239,241],{"class":96,"line":240},6,[94,242,244],{"emptyLinePlaceholder":243},true,"\n",[94,246,248,251],{"class":96,"line":247},7,[94,249,250],{"class":120},".item",[94,252,187],{"class":100},[94,254,256,258,260,263,266],{"class":96,"line":255},8,[94,257,193],{"class":192},[94,259,196],{"class":100},[94,261,262],{"class":192},"50",[94,264,265],{"class":202},"%",[94,267,206],{"class":100},[94,269,271,273,275,277,279],{"class":96,"line":270},9,[94,272,211],{"class":192},[94,274,196],{"class":100},[94,276,262],{"class":192},[94,278,265],{"class":202},[94,280,206],{"class":100},[94,282,284,286,288,291],{"class":96,"line":283},10,[94,285,225],{"class":192},[94,287,196],{"class":100},[94,289,290],{"class":192},"red",[94,292,206],{"class":100},[94,294,296],{"class":96,"line":295},11,[94,297,237],{"class":100},[17,299,300,303,304,307,308,311,312,315],{},[21,301,302],{},"item"," 是 250×150？对。但更准确的说法是：",[26,305,306],{},"百分比相对包含块","。这里包含块是最近祖先块容器的 ",[26,309,310],{},"内容区（content box）","——即 ",[21,313,314],{},"container"," 的内容区 500×300，50% 才是 250×150。",[17,317,318],{},[41,319],{"alt":320,"src":321},"50% 相对 container 内容区，结果为 250×150","\u002Fdemos\u002Fcontaining-block\u002Fpercent-demo.svg",[17,323,324,325,59],{},"平时说「相对父元素宽高」多半没错，但严谨表述是 ",[26,326,327],{},"相对包含块",[80,329,330],{"id":330},"初始包含块",[17,332,333,338,339,342],{},[26,334,335,336],{},"根元素 ",[21,337,89],{}," 的包含块叫 ",[26,340,341],{},"初始包含块（initial containing block）","：",[344,345,346,353,356],"ul",{},[347,348,349,350],"li",{},"大小通常等于 ",[26,351,352],{},"视口（viewport）",[347,354,355],{},"原点在视口左上角",[347,357,358,359,362],{},"是 ",[26,360,361],{},"绝对定位、固定定位"," 的重要参照",[80,364,366],{"id":365},"非根元素怎么找包含块","非根元素：怎么找包含块？",[368,369,370,385],"table",{},[371,372,373],"thead",{},[374,375,376,382],"tr",{},[377,378,379],"th",{},[21,380,381],{},"position",[377,383,384],{},"包含块由谁建立",[386,387,388,411,421],"tbody",{},[374,389,390,400],{},[391,392,393,396,397],"td",{},[21,394,395],{},"static"," \u002F ",[21,398,399],{},"relative",[391,401,402,403,406,407,410],{},"最近 ",[26,404,405],{},"块容器"," 的 ",[26,408,409],{},"内容区"," 边缘",[374,412,413,418],{},[391,414,415],{},[21,416,417],{},"fixed",[391,419,420],{},"视口（初始包含块）",[374,422,423,428],{},[391,424,425],{},[21,426,427],{},"absolute",[391,429,402,430,432,433,435,436,410],{},[21,431,381],{}," 不为 ",[21,434,395],{}," 的祖先的 ",[26,437,438],{},"padding 区",[440,441,443],"h3",{"id":442},"absolute-不看父元素看定位祖先","absolute 不看「父元素」，看「定位祖先」",[85,445,447],{"className":87,"code":446,"language":89,"meta":90,"style":90},"\u003Cbody>\n  \u003Cdiv class=\"container\">\n    \u003Cdiv class=\"item\">\n      \u003Cdiv class=\"item2\">\u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Fbody>\n",[21,448,449,457,471,485,505,514,522],{"__ignoreMap":90},[94,450,451,453,455],{"class":96,"line":97},[94,452,101],{"class":100},[94,454,105],{"class":104},[94,456,108],{"class":100},[94,458,459,461,463,465,467,469],{"class":96,"line":111},[94,460,114],{"class":100},[94,462,117],{"class":104},[94,464,121],{"class":120},[94,466,124],{"class":100},[94,468,128],{"class":127},[94,470,108],{"class":100},[94,472,473,475,477,479,481,483],{"class":96,"line":133},[94,474,136],{"class":100},[94,476,117],{"class":104},[94,478,121],{"class":120},[94,480,124],{"class":100},[94,482,145],{"class":127},[94,484,108],{"class":100},[94,486,487,490,492,494,496,499,501,503],{"class":96,"line":155},[94,488,489],{"class":100},"      \u003C",[94,491,117],{"class":104},[94,493,121],{"class":120},[94,495,124],{"class":100},[94,497,498],{"class":127},"\"item2\"",[94,500,148],{"class":100},[94,502,117],{"class":104},[94,504,108],{"class":100},[94,506,507,510,512],{"class":96,"line":165},[94,508,509],{"class":100},"    \u003C\u002F",[94,511,117],{"class":104},[94,513,108],{"class":100},[94,515,516,518,520],{"class":96,"line":240},[94,517,158],{"class":100},[94,519,117],{"class":104},[94,521,108],{"class":100},[94,523,524,526,528],{"class":96,"line":247},[94,525,168],{"class":100},[94,527,105],{"class":104},[94,529,108],{"class":100},[85,531,533],{"className":175,"code":532,"language":177,"meta":90,"style":90},".container {\n  width: 500px;\n  height: 300px;\n  background-color: skyblue;\n  position: relative;\n}\n\n.item {\n  width: 300px;\n  height: 150px;\n  border: 5px solid;\n  margin-left: 100px;\n}\n\n.item2 {\n  width: 100px;\n  height: 100px;\n  background-color: red;\n  position: absolute;\n  left: 10px;\n  top: 10px;\n}\n",[21,534,535,541,553,565,575,586,590,594,600,612,625,642,657,662,666,674,687,700,711,722,737,751],{"__ignoreMap":90},[94,536,537,539],{"class":96,"line":97},[94,538,184],{"class":120},[94,540,187],{"class":100},[94,542,543,545,547,549,551],{"class":96,"line":111},[94,544,193],{"class":192},[94,546,196],{"class":100},[94,548,199],{"class":192},[94,550,203],{"class":202},[94,552,206],{"class":100},[94,554,555,557,559,561,563],{"class":96,"line":133},[94,556,211],{"class":192},[94,558,196],{"class":100},[94,560,216],{"class":192},[94,562,203],{"class":202},[94,564,206],{"class":100},[94,566,567,569,571,573],{"class":96,"line":155},[94,568,225],{"class":192},[94,570,196],{"class":100},[94,572,230],{"class":192},[94,574,206],{"class":100},[94,576,577,580,582,584],{"class":96,"line":165},[94,578,579],{"class":192},"  position",[94,581,196],{"class":100},[94,583,399],{"class":192},[94,585,206],{"class":100},[94,587,588],{"class":96,"line":240},[94,589,237],{"class":100},[94,591,592],{"class":96,"line":247},[94,593,244],{"emptyLinePlaceholder":243},[94,595,596,598],{"class":96,"line":255},[94,597,250],{"class":120},[94,599,187],{"class":100},[94,601,602,604,606,608,610],{"class":96,"line":270},[94,603,193],{"class":192},[94,605,196],{"class":100},[94,607,216],{"class":192},[94,609,203],{"class":202},[94,611,206],{"class":100},[94,613,614,616,618,621,623],{"class":96,"line":283},[94,615,211],{"class":192},[94,617,196],{"class":100},[94,619,620],{"class":192},"150",[94,622,203],{"class":202},[94,624,206],{"class":100},[94,626,627,630,632,635,637,640],{"class":96,"line":295},[94,628,629],{"class":192},"  border",[94,631,196],{"class":100},[94,633,634],{"class":192},"5",[94,636,203],{"class":202},[94,638,639],{"class":192}," solid",[94,641,206],{"class":100},[94,643,645,648,650,653,655],{"class":96,"line":644},12,[94,646,647],{"class":192},"  margin-left",[94,649,196],{"class":100},[94,651,652],{"class":192},"100",[94,654,203],{"class":202},[94,656,206],{"class":100},[94,658,660],{"class":96,"line":659},13,[94,661,237],{"class":100},[94,663,664],{"class":96,"line":4},[94,665,244],{"emptyLinePlaceholder":243},[94,667,669,672],{"class":96,"line":668},15,[94,670,671],{"class":120},".item2",[94,673,187],{"class":100},[94,675,677,679,681,683,685],{"class":96,"line":676},16,[94,678,193],{"class":192},[94,680,196],{"class":100},[94,682,652],{"class":192},[94,684,203],{"class":202},[94,686,206],{"class":100},[94,688,690,692,694,696,698],{"class":96,"line":689},17,[94,691,211],{"class":192},[94,693,196],{"class":100},[94,695,652],{"class":192},[94,697,203],{"class":202},[94,699,206],{"class":100},[94,701,703,705,707,709],{"class":96,"line":702},18,[94,704,225],{"class":192},[94,706,196],{"class":100},[94,708,290],{"class":192},[94,710,206],{"class":100},[94,712,714,716,718,720],{"class":96,"line":713},19,[94,715,579],{"class":192},[94,717,196],{"class":100},[94,719,427],{"class":192},[94,721,206],{"class":100},[94,723,725,728,730,733,735],{"class":96,"line":724},20,[94,726,727],{"class":192},"  left",[94,729,196],{"class":100},[94,731,732],{"class":192},"10",[94,734,203],{"class":202},[94,736,206],{"class":100},[94,738,740,743,745,747,749],{"class":96,"line":739},21,[94,741,742],{"class":192},"  top",[94,744,196],{"class":100},[94,746,732],{"class":192},[94,748,203],{"class":202},[94,750,206],{"class":100},[94,752,754],{"class":96,"line":753},22,[94,755,237],{"class":100},[17,757,758,761,762,766,767,770,771,342],{},[21,759,760],{},"item2"," 的包含块是 ",[26,763,764],{},[21,765,314],{},"（有 ",[21,768,769],{},"position: relative","），不是中间的 ",[21,772,302],{},[17,774,775],{},[41,776],{"alt":777,"src":778},"item2 的包含块是 container，而非中间的 item","\u002Fdemos\u002Fcontaining-block\u002Fabsolute-demo.svg",[440,780,782],{"id":781},"transform-也会建立包含块","transform 也会建立包含块",[17,784,785,396,787,789,790,342],{},[21,786,427],{},[21,788,417],{}," 的包含块还可能是满足下列条件的 ",[26,791,792],{},"最近祖先的 padding 区",[344,794,795,807,818,830],{},[347,796,797,396,800,803,804],{},[21,798,799],{},"transform",[21,801,802],{},"perspective"," 不是 ",[21,805,806],{},"none",[347,808,809,812,813,815,816],{},[21,810,811],{},"will-change"," 为 ",[21,814,799],{}," 或 ",[21,817,802],{},[347,819,820,803,823,825,826,829],{},[21,821,822],{},"filter",[21,824,806],{},"（或 Firefox 下 ",[21,827,828],{},"will-change: filter","）",[347,831,832],{},[21,833,834],{},"contain: paint",[17,836,837,838,840,841,342],{},"给 ",[21,839,302],{}," 加上 ",[21,842,843],{},"transform: rotate(0deg)",[85,845,847],{"className":175,"code":846,"language":177,"meta":90,"style":90},".item {\n  transform: rotate(0deg);\n}\n",[21,848,849,855,877],{"__ignoreMap":90},[94,850,851,853],{"class":96,"line":97},[94,852,250],{"class":120},[94,854,187],{"class":100},[94,856,857,860,862,865,868,871,874],{"class":96,"line":111},[94,858,859],{"class":192},"  transform",[94,861,196],{"class":100},[94,863,864],{"class":192},"rotate",[94,866,867],{"class":100},"(",[94,869,870],{"class":192},"0",[94,872,873],{"class":202},"deg",[94,875,876],{"class":100},");\n",[94,878,879],{"class":96,"line":133},[94,880,237],{"class":100},[17,882,883,884,888],{},"包含块变为 ",[26,885,886],{},[21,887,302],{}," 自身：",[17,890,891],{},[41,892],{"alt":893,"src":894},"transform 在 item 上建立新的包含块","\u002Fdemos\u002Fcontaining-block\u002Ftransform-demo.svg",[17,896,897,898,900,901,59],{},"这也是 ",[21,899,799],{}," 常和层叠、合成一起讨论的原因——不仅影响包含块，还影响 ",[53,902,903],{"href":71},"分层与绘制",[17,905,906],{},[41,907],{"alt":908,"src":909},"包含块知识要点一览","\u002Fdemos\u002Fcontaining-block\u002Fsummary-map.svg",[80,911,912],{"id":912},"规范例题",[85,914,916],{"className":87,"code":915,"language":89,"meta":90,"style":90},"\u003Chtml>\n  \u003Chead>\n    \u003Ctitle>Illustration of containing blocks\u003C\u002Ftitle>\n  \u003C\u002Fhead>\n  \u003Cbody id=\"body\">\n    \u003Cdiv id=\"div1\">\n      \u003Cp id=\"p1\">This is text in the first paragraph...\u003C\u002Fp>\n      \u003Cp id=\"p2\">\n        This is text\n        \u003Cem id=\"em1\">\n          in the\n          \u003Cstrong id=\"strong1\">second\u003C\u002Fstrong>\n          paragraph.\n        \u003C\u002Fem>\n      \u003C\u002Fp>\n    \u003C\u002Fdiv>\n  \u003C\u002Fbody>\n\u003C\u002Fhtml>\n",[21,917,918,926,935,949,957,973,988,1008,1023,1028,1045,1050,1071,1076,1085,1094,1102,1110],{"__ignoreMap":90},[94,919,920,922,924],{"class":96,"line":97},[94,921,101],{"class":100},[94,923,89],{"class":104},[94,925,108],{"class":100},[94,927,928,930,933],{"class":96,"line":111},[94,929,114],{"class":100},[94,931,932],{"class":104},"head",[94,934,108],{"class":100},[94,936,937,939,942,945,947],{"class":96,"line":133},[94,938,136],{"class":100},[94,940,941],{"class":104},"title",[94,943,944],{"class":100},">Illustration of containing blocks\u003C\u002F",[94,946,941],{"class":104},[94,948,108],{"class":100},[94,950,951,953,955],{"class":96,"line":155},[94,952,158],{"class":100},[94,954,932],{"class":104},[94,956,108],{"class":100},[94,958,959,961,963,966,968,971],{"class":96,"line":165},[94,960,114],{"class":100},[94,962,105],{"class":104},[94,964,965],{"class":120}," id",[94,967,124],{"class":100},[94,969,970],{"class":127},"\"body\"",[94,972,108],{"class":100},[94,974,975,977,979,981,983,986],{"class":96,"line":240},[94,976,136],{"class":100},[94,978,117],{"class":104},[94,980,965],{"class":120},[94,982,124],{"class":100},[94,984,985],{"class":127},"\"div1\"",[94,987,108],{"class":100},[94,989,990,992,994,996,998,1001,1004,1006],{"class":96,"line":247},[94,991,489],{"class":100},[94,993,17],{"class":104},[94,995,965],{"class":120},[94,997,124],{"class":100},[94,999,1000],{"class":127},"\"p1\"",[94,1002,1003],{"class":100},">This is text in the first paragraph...\u003C\u002F",[94,1005,17],{"class":104},[94,1007,108],{"class":100},[94,1009,1010,1012,1014,1016,1018,1021],{"class":96,"line":255},[94,1011,489],{"class":100},[94,1013,17],{"class":104},[94,1015,965],{"class":120},[94,1017,124],{"class":100},[94,1019,1020],{"class":127},"\"p2\"",[94,1022,108],{"class":100},[94,1024,1025],{"class":96,"line":270},[94,1026,1027],{"class":100},"        This is text\n",[94,1029,1030,1033,1036,1038,1040,1043],{"class":96,"line":283},[94,1031,1032],{"class":100},"        \u003C",[94,1034,1035],{"class":104},"em",[94,1037,965],{"class":120},[94,1039,124],{"class":100},[94,1041,1042],{"class":127},"\"em1\"",[94,1044,108],{"class":100},[94,1046,1047],{"class":96,"line":295},[94,1048,1049],{"class":100},"          in the\n",[94,1051,1052,1055,1057,1059,1061,1064,1067,1069],{"class":96,"line":644},[94,1053,1054],{"class":100},"          \u003C",[94,1056,26],{"class":104},[94,1058,965],{"class":120},[94,1060,124],{"class":100},[94,1062,1063],{"class":127},"\"strong1\"",[94,1065,1066],{"class":100},">second\u003C\u002F",[94,1068,26],{"class":104},[94,1070,108],{"class":100},[94,1072,1073],{"class":96,"line":659},[94,1074,1075],{"class":100},"          paragraph.\n",[94,1077,1078,1081,1083],{"class":96,"line":4},[94,1079,1080],{"class":100},"        \u003C\u002F",[94,1082,1035],{"class":104},[94,1084,108],{"class":100},[94,1086,1087,1090,1092],{"class":96,"line":668},[94,1088,1089],{"class":100},"      \u003C\u002F",[94,1091,17],{"class":104},[94,1093,108],{"class":100},[94,1095,1096,1098,1100],{"class":96,"line":676},[94,1097,509],{"class":100},[94,1099,117],{"class":104},[94,1101,108],{"class":100},[94,1103,1104,1106,1108],{"class":96,"line":689},[94,1105,158],{"class":100},[94,1107,105],{"class":104},[94,1109,108],{"class":100},[94,1111,1112,1114,1116],{"class":96,"line":702},[94,1113,168],{"class":100},[94,1115,89],{"class":104},[94,1117,108],{"class":100},[17,1119,1120],{},"无额外 CSS 时：",[368,1122,1123,1133],{},[371,1124,1125],{},[374,1126,1127,1130],{},[377,1128,1129],{},"元素",[377,1131,1132],{},"包含块",[386,1134,1135,1141,1147,1154,1161,1169],{},[374,1136,1137,1139],{},[391,1138,89],{},[391,1140,330],{},[374,1142,1143,1145],{},[391,1144,105],{},[391,1146,89],{},[374,1148,1149,1152],{},[391,1150,1151],{},"div1",[391,1153,105],{},[374,1155,1156,1159],{},[391,1157,1158],{},"p1、p2",[391,1160,1151],{},[374,1162,1163,1166],{},[391,1164,1165],{},"em1",[391,1167,1168],{},"p2",[374,1170,1171,1174],{},[391,1172,1173],{},"strong1",[391,1175,1168],{},[17,1177,1178,761,1180,1182,1183,1185,1186,803,1188,1190,1191,1194],{},[21,1179,1173],{},[21,1181,1168],{}," 而非 ",[21,1184,1165],{},"，因为 ",[21,1187,1165],{},[26,1189,405],{},"；规则要求 ",[26,1192,1193],{},"最近的块容器"," 的内容区。",[17,1196,1197],{},"加上：",[85,1199,1201],{"className":175,"code":1200,"language":177,"meta":90,"style":90},"#div1 {\n  position: absolute;\n  left: 50px;\n  top: 50px;\n}\n",[21,1202,1203,1210,1220,1232,1244],{"__ignoreMap":90},[94,1204,1205,1208],{"class":96,"line":97},[94,1206,1207],{"class":120},"#div1",[94,1209,187],{"class":100},[94,1211,1212,1214,1216,1218],{"class":96,"line":111},[94,1213,579],{"class":192},[94,1215,196],{"class":100},[94,1217,427],{"class":192},[94,1219,206],{"class":100},[94,1221,1222,1224,1226,1228,1230],{"class":96,"line":133},[94,1223,727],{"class":192},[94,1225,196],{"class":100},[94,1227,262],{"class":192},[94,1229,203],{"class":202},[94,1231,206],{"class":100},[94,1233,1234,1236,1238,1240,1242],{"class":96,"line":155},[94,1235,742],{"class":192},[94,1237,196],{"class":100},[94,1239,262],{"class":192},[94,1241,203],{"class":202},[94,1243,206],{"class":100},[94,1245,1246],{"class":96,"line":165},[94,1247,237],{"class":100},[17,1249,1250,1252,1253,1255,1256,1258,1259,1261],{},[21,1251,1151],{}," 的包含块变为 ",[26,1254,330],{},"（",[21,1257,105],{}," 仍是 ",[21,1260,395],{},"，向上找不到定位祖先）：",[368,1263,1264,1272],{},[371,1265,1266],{},[374,1267,1268,1270],{},[377,1269,1129],{},[377,1271,1132],{},[386,1273,1274,1280],{},[374,1275,1276,1278],{},[391,1277,1151],{},[391,1279,330],{},[374,1281,1282,1284],{},[391,1283,1158],{},[391,1285,1151],{},[17,1287,1288,1289,1291],{},"再给 ",[21,1290,1165],{}," 定位：",[85,1293,1295],{"className":175,"code":1294,"language":177,"meta":90,"style":90},"#em1 {\n  position: absolute;\n  left: 100px;\n  top: 100px;\n}\n",[21,1296,1297,1304,1314,1326,1338],{"__ignoreMap":90},[94,1298,1299,1302],{"class":96,"line":97},[94,1300,1301],{"class":120},"#em1",[94,1303,187],{"class":100},[94,1305,1306,1308,1310,1312],{"class":96,"line":111},[94,1307,579],{"class":192},[94,1309,196],{"class":100},[94,1311,427],{"class":192},[94,1313,206],{"class":100},[94,1315,1316,1318,1320,1322,1324],{"class":96,"line":133},[94,1317,727],{"class":192},[94,1319,196],{"class":100},[94,1321,652],{"class":192},[94,1323,203],{"class":202},[94,1325,206],{"class":100},[94,1327,1328,1330,1332,1334,1336],{"class":96,"line":155},[94,1329,742],{"class":192},[94,1331,196],{"class":100},[94,1333,652],{"class":192},[94,1335,203],{"class":202},[94,1337,206],{"class":100},[94,1339,1340],{"class":96,"line":165},[94,1341,237],{"class":100},[368,1343,1344,1352],{},[371,1345,1346],{},[374,1347,1348,1350],{},[377,1349,1129],{},[377,1351,1132],{},[386,1353,1354,1360],{},[374,1355,1356,1358],{},[391,1357,1165],{},[391,1359,1151],{},[374,1361,1362,1364],{},[391,1363,1173],{},[391,1365,1165],{},[17,1367,1368,1369],{},"更多示例见 MDN：",[53,1370,1373],{"href":1371,"rel":1372},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-CN\u002Fdocs\u002FWeb\u002FCSS\u002FContaining_block",[57],"Containing block",[17,1375,1376],{},[41,1377],{"alt":1378,"src":1379},"规范例题中的 DOM 树与包含块关系","\u002Fdemos\u002Fcontaining-block\u002Fdom-tree.svg",[80,1381,1382],{"id":1382},"小结",[344,1384,1385,1390,1409,1418],{},[347,1386,1387,1389],{},[26,1388,1132],{}," 决定百分比与定位偏移的参照区域，不是笼统的「父元素」。",[347,1391,1392,1394,1395,1397,1398,1400,1401,1403,1404,1400,1406,1408],{},[21,1393,395],{},"\u002F",[21,1396,399],{}," 看最近块容器的 ",[26,1399,409],{},"；",[21,1402,427],{}," 看定位祖先的 ",[26,1405,438],{},[21,1407,417],{}," 看视口。",[347,1410,1411,1413,1414,1417],{},[21,1412,799],{}," 等属性会 ",[26,1415,1416],{},"新建包含块","，布局结果可能「突然变了」。",[347,1419,1420,1421,59],{},"布局阶段算几何信息时离不开包含块；改样式触发的 reflow 见 ",[53,1422,1424],{"href":1423},"\u002Fblog\u002Freflow-repaint-transform","reflow 与 repaint",[1426,1427,1428],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":90,"searchDepth":133,"depth":133,"links":1430},[1431,1432,1433,1437,1438],{"id":82,"depth":111,"text":83},{"id":330,"depth":111,"text":330},{"id":365,"depth":111,"text":366,"children":1434},[1435,1436],{"id":442,"depth":133,"text":443},{"id":781,"depth":133,"text":782},{"id":912,"depth":111,"text":912},{"id":1382,"depth":111,"text":1382},"2026-06-28","百分比宽高与绝对定位偏移到底相对谁算？搞懂 containing block 与初始包含块，布局阶段的几何信息才说得清。",false,"md",{},"\u002Fblog\u002Fcss-containing-block",{"title":8,"description":1440},"blog\u002Fcss-containing-block",[1448,1449,1450],"layout","containing-block","interview","7-rbTxShL5j-yWfKcjpRnC_JvYeoy2-lO_1z13rrAsk",{"id":1453,"title":1454,"body":1455,"category":177,"date":2389,"description":2390,"draft":1441,"extension":1442,"meta":2391,"navigation":243,"path":76,"seo":2392,"stem":2393,"tags":2394,"__hash__":2397},"blog\u002Fblog\u002Fcss-property-calculation.md","CSS 属性计算过程：从声明到最终值",{"type":10,"value":1456,"toc":2376},[1457,1460,1463,1489,1500,1506,1519,1522,1556,1569,1575,1581,1584,1590,1605,1611,1615,1621,1643,1649,1652,1656,1663,1682,1685,1688,1706,1712,1718,1755,1761,1769,1772,1778,1819,1878,1884,1890,1893,1896,1902,1955,1958,1964,1968,1979,2013,2038,2048,2054,2060,2115,2165,2177,2183,2189,2195,2199,2205,2211,2214,2220,2224,2277,2301,2307,2345,2347,2373],[13,1458,1454],{"id":1459},"css-属性计算过程从声明到最终值",[17,1461,1462],{},"写 CSS 时往往只写几行：",[85,1464,1466],{"className":175,"code":1465,"language":177,"meta":90,"style":90},"p {\n  color: red;\n}\n",[21,1467,1468,1474,1485],{"__ignoreMap":90},[94,1469,1470,1472],{"class":96,"line":97},[94,1471,17],{"class":104},[94,1473,187],{"class":100},[94,1475,1476,1479,1481,1483],{"class":96,"line":111},[94,1477,1478],{"class":192},"  color",[94,1480,196],{"class":100},[94,1482,290],{"class":192},[94,1484,206],{"class":100},[94,1486,1487],{"class":96,"line":133},[94,1488,237],{"class":100},[17,1490,1491,1492,1495,1496,1499],{},"但打开开发者工具 → 元素 → ",[26,1493,1494],{},"计算样式"," → 勾选「全部显示」，会发现每个元素都有 ",[26,1497,1498],{},"成百个属性","。它们从哪来？为什么有的没写却有值，有的写了却不是你以为的结果？",[17,1501,1502],{},[41,1503],{"alt":1504,"src":1505},"CSS 属性计算流程概览","\u002Fdemos\u002Fcss-property-calc\u002Fflow-overview.svg",[17,1507,1508,1509,1512,1513,1515,1516,1518],{},"属性值的计算大致分 ",[26,1510,1511],{},"四步","：确定声明值 → 层叠冲突 → 使用继承 → 使用默认值。算完后的结果会进入渲染流水线的 ",[53,1514,77],{"href":71}," 阶段，再与 ",[53,1517,1132],{"href":1444}," 一起在布局里定稿几何尺寸。",[80,1520,1521],{"id":1521},"每个元素都有一套完整样式",[85,1523,1525],{"className":87,"code":1524,"language":89,"meta":90,"style":90},"\u003Cbody>\n  \u003Ch1>这是一个 h1 标题\u003C\u002Fh1>\n\u003C\u002Fbody>\n",[21,1526,1527,1535,1548],{"__ignoreMap":90},[94,1528,1529,1531,1533],{"class":96,"line":97},[94,1530,101],{"class":100},[94,1532,105],{"class":104},[94,1534,108],{"class":100},[94,1536,1537,1539,1541,1544,1546],{"class":96,"line":111},[94,1538,114],{"class":100},[94,1540,13],{"class":104},[94,1542,1543],{"class":100},">这是一个 h1 标题\u003C\u002F",[94,1545,13],{"class":104},[94,1547,108],{"class":100},[94,1549,1550,1552,1554],{"class":96,"line":133},[94,1551,168],{"class":100},[94,1553,105],{"class":104},[94,1555,108],{"class":100},[17,1557,1558,1559,1561,1562,1565,1566,59],{},"没给 ",[21,1560,13],{}," 写任何样式，它仍有默认字号、颜色等——因为 ",[26,1563,1564],{},"任意 HTML 元素都对应一整套 CSS 属性","；没写的，多数走继承或 ",[26,1567,1568],{},"用户代理样式表（浏览器默认样式）",[17,1570,1571],{},[41,1572],{"alt":1573,"src":1574},"未写样式时的 h1 外观","\u002Fdemos\u002Fcss-property-calc\u002Fh1-default.svg",[17,1576,1577],{},[41,1578],{"alt":1579,"src":1580},"元素上实际存在的全部属性","\u002Fdemos\u002Fcss-property-calc\u002Fall-props.svg",[17,1582,1583],{},"在计算样式里勾选全部显示即可验证：",[17,1585,1586],{},[41,1587],{"alt":1588,"src":1589},"计算样式面板","\u002Fdemos\u002Fcss-property-calc\u002Fcomputed-panel.svg",[17,1591,1592,1593,1596,1597,1600,1601,1604],{},"注意：没写 ",[26,1594,1595],{},"不等于"," 一定用默认值——中间还有 ",[26,1598,1599],{},"继承"," 和 ",[26,1602,1603],{},"层叠","，所以必须理解计算流程。",[17,1606,1607],{},[41,1608],{"alt":1609,"src":1610},"并非总是默认值","\u002Fdemos\u002Fcss-property-calc\u002Fnot-only-default.svg",[80,1612,1614],{"id":1613},"第一步确定声明值","第一步：确定声明值",[17,1616,1617,1620],{},[26,1618,1619],{},"声明值"," 就是样式表里写明的规则，包括：",[344,1622,1623,1629],{},[347,1624,1625,1628],{},[26,1626,1627],{},"作者样式表","（你写的 CSS）",[347,1630,1631,1634,1635,406,1637,33,1640,829],{},[26,1632,1633],{},"用户代理样式表","（浏览器内置，如 ",[21,1636,13],{},[21,1638,1639],{},"display",[21,1641,1642],{},"margin",[17,1644,1645],{},[41,1646],{"alt":1647,"src":1648},"作者样式与用户代理样式","\u002Fdemos\u002Fcss-property-calc\u002Fauthor-ua.svg",[17,1650,1651],{},"若声明之间无冲突，直接采用对应声明。",[80,1653,1655],{"id":1654},"第二步层叠冲突","第二步：层叠冲突",[17,1657,1658,1659,1662],{},"多条规则声明同一属性时，进入 ",[26,1660,1661],{},"层叠（Cascade）"," 解决，细分为：",[1664,1665,1666,1672,1677],"ol",{},[347,1667,1668,1669],{},"比较 ",[26,1670,1671],{},"源的重要性",[347,1673,1668,1674],{},[26,1675,1676],{},"优先级（特异性）",[347,1678,1668,1679],{},[26,1680,1681],{},"次序",[440,1683,1684],{"id":1684},"比较源的重要性",[17,1686,1687],{},"样式来源（重要性从高到低）：",[344,1689,1690,1695,1701],{},[347,1691,1692],{},[26,1693,1694],{},"页面作者样式",[347,1696,1697,1700],{},[26,1698,1699],{},"用户样式","（用户自定义）",[347,1702,1703],{},[26,1704,1705],{},"用户代理样式",[17,1707,1708],{},[41,1709],{"alt":1710,"src":1711},"样式源重要性","\u002Fdemos\u002Fcss-property-calc\u002Fsource-priority.svg",[17,1713,1714,1715,1717],{},"作者与用户代理同时声明 ",[21,1716,1639],{}," 时，作者胜出：",[85,1719,1721],{"className":175,"code":1720,"language":177,"meta":90,"style":90},"p {\n  color: red;\n  display: inline-block;\n}\n",[21,1722,1723,1729,1739,1751],{"__ignoreMap":90},[94,1724,1725,1727],{"class":96,"line":97},[94,1726,17],{"class":104},[94,1728,187],{"class":100},[94,1730,1731,1733,1735,1737],{"class":96,"line":111},[94,1732,1478],{"class":192},[94,1734,196],{"class":100},[94,1736,290],{"class":192},[94,1738,206],{"class":100},[94,1740,1741,1744,1746,1749],{"class":96,"line":133},[94,1742,1743],{"class":192},"  display",[94,1745,196],{"class":100},[94,1747,1748],{"class":192},"inline-block",[94,1750,206],{"class":100},[94,1752,1753],{"class":96,"line":155},[94,1754,237],{"class":100},[17,1756,1757],{},[41,1758],{"alt":1759,"src":1760},"display 由作者样式决定","\u002Fdemos\u002Fcss-property-calc\u002Fcascade-display.svg",[17,1762,1763,1764],{},"详见 MDN：",[53,1765,1768],{"href":1766,"rel":1767},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-CN\u002Fdocs\u002FWeb\u002FCSS\u002FCascade",[57],"Cascade",[440,1770,1771],{"id":1771},"比较优先级",[17,1773,1774,1775,342],{},"同一源内冲突，比 ",[26,1776,1777],{},"选择器权重",[85,1779,1781],{"className":87,"code":1780,"language":89,"meta":90,"style":90},"\u003Cdiv class=\"test\">\n  \u003Ch1>test\u003C\u002Fh1>\n\u003C\u002Fdiv>\n",[21,1782,1783,1798,1811],{"__ignoreMap":90},[94,1784,1785,1787,1789,1791,1793,1796],{"class":96,"line":97},[94,1786,101],{"class":100},[94,1788,117],{"class":104},[94,1790,121],{"class":120},[94,1792,124],{"class":100},[94,1794,1795],{"class":127},"\"test\"",[94,1797,108],{"class":100},[94,1799,1800,1802,1804,1807,1809],{"class":96,"line":111},[94,1801,114],{"class":100},[94,1803,13],{"class":104},[94,1805,1806],{"class":100},">test\u003C\u002F",[94,1808,13],{"class":104},[94,1810,108],{"class":100},[94,1812,1813,1815,1817],{"class":96,"line":133},[94,1814,168],{"class":100},[94,1816,117],{"class":104},[94,1818,108],{"class":100},[85,1820,1822],{"className":175,"code":1821,"language":177,"meta":90,"style":90},".test h1 {\n  font-size: 50px;\n}\n\nh1 {\n  font-size: 20px;\n}\n",[21,1823,1824,1834,1847,1851,1855,1861,1874],{"__ignoreMap":90},[94,1825,1826,1829,1832],{"class":96,"line":97},[94,1827,1828],{"class":120},".test",[94,1830,1831],{"class":104}," h1",[94,1833,187],{"class":100},[94,1835,1836,1839,1841,1843,1845],{"class":96,"line":111},[94,1837,1838],{"class":192},"  font-size",[94,1840,196],{"class":100},[94,1842,262],{"class":192},[94,1844,203],{"class":202},[94,1846,206],{"class":100},[94,1848,1849],{"class":96,"line":133},[94,1850,237],{"class":100},[94,1852,1853],{"class":96,"line":155},[94,1854,244],{"emptyLinePlaceholder":243},[94,1856,1857,1859],{"class":96,"line":165},[94,1858,13],{"class":104},[94,1860,187],{"class":100},[94,1862,1863,1865,1867,1870,1872],{"class":96,"line":240},[94,1864,1838],{"class":192},[94,1866,196],{"class":100},[94,1868,1869],{"class":192},"20",[94,1871,203],{"class":202},[94,1873,206],{"class":100},[94,1875,1876],{"class":96,"line":247},[94,1877,237],{"class":100},[17,1879,1880,1883],{},[21,1881,1882],{},".test h1"," 权重更高 → 50px：",[17,1885,1886],{},[41,1887],{"alt":1888,"src":1889},"权重较高规则生效","\u002Fdemos\u002Fcss-property-calc\u002Fspecificity.svg",[17,1891,1892],{},"落败规则在 Styles 面板中会被划掉。",[440,1894,1895],{"id":1895},"比较次序",[17,1897,1898,1899,342],{},"同源、同权重时，",[26,1900,1901],{},"后面的规则覆盖前面的",[85,1903,1905],{"className":175,"code":1904,"language":177,"meta":90,"style":90},"h1 {\n  font-size: 50px;\n}\n\nh1 {\n  font-size: 20px;\n}\n",[21,1906,1907,1913,1925,1929,1933,1939,1951],{"__ignoreMap":90},[94,1908,1909,1911],{"class":96,"line":97},[94,1910,13],{"class":104},[94,1912,187],{"class":100},[94,1914,1915,1917,1919,1921,1923],{"class":96,"line":111},[94,1916,1838],{"class":192},[94,1918,196],{"class":100},[94,1920,262],{"class":192},[94,1922,203],{"class":202},[94,1924,206],{"class":100},[94,1926,1927],{"class":96,"line":133},[94,1928,237],{"class":100},[94,1930,1931],{"class":96,"line":155},[94,1932,244],{"emptyLinePlaceholder":243},[94,1934,1935,1937],{"class":96,"line":165},[94,1936,13],{"class":104},[94,1938,187],{"class":100},[94,1940,1941,1943,1945,1947,1949],{"class":96,"line":240},[94,1942,1838],{"class":192},[94,1944,196],{"class":100},[94,1946,1869],{"class":192},[94,1948,203],{"class":202},[94,1950,206],{"class":100},[94,1952,1953],{"class":96,"line":247},[94,1954,237],{"class":100},[17,1956,1957],{},"最终 20px：",[17,1959,1960],{},[41,1961],{"alt":1962,"src":1963},"同权重时后者胜出","\u002Fdemos\u002Fcss-property-calc\u002Fsource-order.svg",[80,1965,1967],{"id":1966},"第三步使用继承","第三步：使用继承",[17,1969,1970,1971,1974,1975,1978],{},"没有声明的属性，若该属性 ",[26,1972,1973],{},"可继承","，则从 ",[26,1976,1977],{},"最近的祖先"," 取值：",[85,1980,1982],{"className":87,"code":1981,"language":89,"meta":90,"style":90},"\u003Cdiv>\n  \u003Cp>Lorem ipsum dolor sit amet.\u003C\u002Fp>\n\u003C\u002Fdiv>\n",[21,1983,1984,1992,2005],{"__ignoreMap":90},[94,1985,1986,1988,1990],{"class":96,"line":97},[94,1987,101],{"class":100},[94,1989,117],{"class":104},[94,1991,108],{"class":100},[94,1993,1994,1996,1998,2001,2003],{"class":96,"line":111},[94,1995,114],{"class":100},[94,1997,17],{"class":104},[94,1999,2000],{"class":100},">Lorem ipsum dolor sit amet.\u003C\u002F",[94,2002,17],{"class":104},[94,2004,108],{"class":100},[94,2006,2007,2009,2011],{"class":96,"line":133},[94,2008,168],{"class":100},[94,2010,117],{"class":104},[94,2012,108],{"class":100},[85,2014,2016],{"className":175,"code":2015,"language":177,"meta":90,"style":90},"div {\n  color: red;\n}\n",[21,2017,2018,2024,2034],{"__ignoreMap":90},[94,2019,2020,2022],{"class":96,"line":97},[94,2021,117],{"class":104},[94,2023,187],{"class":100},[94,2025,2026,2028,2030,2032],{"class":96,"line":111},[94,2027,1478],{"class":192},[94,2029,196],{"class":100},[94,2031,290],{"class":192},[94,2033,206],{"class":100},[94,2035,2036],{"class":96,"line":133},[94,2037,237],{"class":100},[17,2039,2040,406,2042,2045,2046,342],{},[21,2041,17],{},[21,2043,2044],{},"color"," 来自 ",[21,2047,117],{},[17,2049,2050],{},[41,2051],{"alt":2052,"src":2053},"color 继承","\u002Fdemos\u002Fcss-property-calc\u002Finherit-basic.svg",[17,2055,2056,2057,342],{},"强调 ",[26,2058,2059],{},"最近祖先",[85,2061,2063],{"className":87,"code":2062,"language":89,"meta":90,"style":90},"\u003Cdiv class=\"test\">\n  \u003Cdiv>\n    \u003Cp>Lorem ipsum dolor sit amet.\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n",[21,2064,2065,2079,2087,2099,2107],{"__ignoreMap":90},[94,2066,2067,2069,2071,2073,2075,2077],{"class":96,"line":97},[94,2068,101],{"class":100},[94,2070,117],{"class":104},[94,2072,121],{"class":120},[94,2074,124],{"class":100},[94,2076,1795],{"class":127},[94,2078,108],{"class":100},[94,2080,2081,2083,2085],{"class":96,"line":111},[94,2082,114],{"class":100},[94,2084,117],{"class":104},[94,2086,108],{"class":100},[94,2088,2089,2091,2093,2095,2097],{"class":96,"line":133},[94,2090,136],{"class":100},[94,2092,17],{"class":104},[94,2094,2000],{"class":100},[94,2096,17],{"class":104},[94,2098,108],{"class":100},[94,2100,2101,2103,2105],{"class":96,"line":155},[94,2102,158],{"class":100},[94,2104,117],{"class":104},[94,2106,108],{"class":100},[94,2108,2109,2111,2113],{"class":96,"line":165},[94,2110,168],{"class":100},[94,2112,117],{"class":104},[94,2114,108],{"class":100},[85,2116,2118],{"className":175,"code":2117,"language":177,"meta":90,"style":90},"div {\n  color: red;\n}\n\n.test {\n  color: blue;\n}\n",[21,2119,2120,2126,2136,2140,2144,2150,2161],{"__ignoreMap":90},[94,2121,2122,2124],{"class":96,"line":97},[94,2123,117],{"class":104},[94,2125,187],{"class":100},[94,2127,2128,2130,2132,2134],{"class":96,"line":111},[94,2129,1478],{"class":192},[94,2131,196],{"class":100},[94,2133,290],{"class":192},[94,2135,206],{"class":100},[94,2137,2138],{"class":96,"line":133},[94,2139,237],{"class":100},[94,2141,2142],{"class":96,"line":155},[94,2143,244],{"emptyLinePlaceholder":243},[94,2145,2146,2148],{"class":96,"line":165},[94,2147,1828],{"class":120},[94,2149,187],{"class":100},[94,2151,2152,2154,2156,2159],{"class":96,"line":240},[94,2153,1478],{"class":192},[94,2155,196],{"class":100},[94,2157,2158],{"class":192},"blue",[94,2160,206],{"class":100},[94,2162,2163],{"class":96,"line":247},[94,2164,237],{"class":100},[17,2166,2167,2168,2170,2171,2173,2174,2176],{},"内层 ",[21,2169,117],{}," 更近 → ",[21,2172,17],{}," 继承蓝色（这里不比权重，因为根本没选中 ",[21,2175,17],{},"）：",[17,2178,2179],{},[41,2180],{"alt":2181,"src":2182},"继承听最近的祖先","\u002Fdemos\u002Fcss-property-calc\u002Finherit-nearest.svg",[17,2184,2185,2186,342],{},"哪些属性可继承？查 MDN 各属性页，例如 ",[21,2187,2188],{},"text-align",[17,2190,2191],{},[41,2192],{"alt":2193,"src":2194},"MDN 上的 inherits 说明","\u002Fdemos\u002Fcss-property-calc\u002Finherits-hint.svg",[80,2196,2198],{"id":2197},"第四步使用默认值","第四步：使用默认值",[17,2200,2201,2202,342],{},"仍无法确定的，用 ",[26,2203,2204],{},"initial \u002F 用户代理默认值",[17,2206,2207],{},[41,2208],{"alt":2209,"src":2210},"最终落到默认值","\u002Fdemos\u002Fcss-property-calc\u002Finitial-default.svg",[17,2212,2213],{},"元素要在浏览器里渲染，必须具备完整属性集；大量属性既未声明、也无法继承，就靠这一步补齐。",[17,2215,2216],{},[41,2217],{"alt":2218,"src":2219},"四步流程回顾","\u002Fdemos\u002Fcss-property-calc\u002Fsteps-summary.svg",[80,2221,2223],{"id":2222},"面试题a-和-p-各是什么颜色","面试题：a 和 p 各是什么颜色？",[85,2225,2227],{"className":87,"code":2226,"language":89,"meta":90,"style":90},"\u003Cdiv>\n  \u003Ca href=\"\">test\u003C\u002Fa>\n  \u003Cp>test\u003C\u002Fp>\n\u003C\u002Fdiv>\n",[21,2228,2229,2237,2257,2269],{"__ignoreMap":90},[94,2230,2231,2233,2235],{"class":96,"line":97},[94,2232,101],{"class":100},[94,2234,117],{"class":104},[94,2236,108],{"class":100},[94,2238,2239,2241,2243,2246,2248,2251,2253,2255],{"class":96,"line":111},[94,2240,114],{"class":100},[94,2242,53],{"class":104},[94,2244,2245],{"class":120}," href",[94,2247,124],{"class":100},[94,2249,2250],{"class":127},"\"\"",[94,2252,1806],{"class":100},[94,2254,53],{"class":104},[94,2256,108],{"class":100},[94,2258,2259,2261,2263,2265,2267],{"class":96,"line":133},[94,2260,114],{"class":100},[94,2262,17],{"class":104},[94,2264,1806],{"class":100},[94,2266,17],{"class":104},[94,2268,108],{"class":100},[94,2270,2271,2273,2275],{"class":96,"line":155},[94,2272,168],{"class":100},[94,2274,117],{"class":104},[94,2276,108],{"class":100},[85,2278,2279],{"className":175,"code":2015,"language":177,"meta":90,"style":90},[21,2280,2281,2287,2297],{"__ignoreMap":90},[94,2282,2283,2285],{"class":96,"line":97},[94,2284,117],{"class":104},[94,2286,187],{"class":100},[94,2288,2289,2291,2293,2295],{"class":96,"line":111},[94,2290,1478],{"class":192},[94,2292,196],{"class":100},[94,2294,290],{"class":192},[94,2296,206],{"class":100},[94,2298,2299],{"class":96,"line":133},[94,2300,237],{"class":100},[17,2302,2303],{},[41,2304],{"alt":2305,"src":2306},"面试题解答","\u002Fdemos\u002Fcss-property-calc\u002Finterview-a-p.svg",[344,2308,2309,2326],{},[347,2310,2311,2315,2316,2318,2319,2322,2323,2325],{},[26,2312,2313],{},[21,2314,53],{},"：用户代理样式表里已为链接声明了 ",[21,2317,2044],{},"，有声明值，",[26,2320,2321],{},"不继承"," ",[21,2324,117],{}," 的红色。",[347,2327,2328,2332,2333,2335,2336,2338,2339,2341,2342,2344],{},[26,2329,2330],{},[21,2331,17],{},"：作者与 UA 都未给 ",[21,2334,17],{}," 声明 ",[21,2337,2044],{},"，而 ",[21,2340,2044],{}," 可继承 → 从 ",[21,2343,117],{}," 继承红色。",[80,2346,1382],{"id":1382},[344,2348,2349,2355,2361,2367],{},[347,2350,2351,2352,59],{},"计算样式四步：",[26,2353,2354],{},"声明 → 层叠 → 继承 → 默认",[347,2356,2357,2358,59],{},"层叠内部：",[26,2359,2360],{},"源 > 权重 > 次序",[347,2362,2363,2364,2366],{},"继承看 ",[26,2365,2059],{},"，与选择器权重无关。",[347,2368,2369,2370,59],{},"算出的 Computed Style 是渲染流水线「样式计算」的输入；百分比尺寸还要等 ",[53,2371,2372],{"href":1444},"布局与包含块",[1426,2374,2375],{},"html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-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 .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 .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":90,"searchDepth":133,"depth":133,"links":2377},[2378,2379,2380,2385,2386,2387,2388],{"id":1521,"depth":111,"text":1521},{"id":1613,"depth":111,"text":1614},{"id":1654,"depth":111,"text":1655,"children":2381},[2382,2383,2384],{"id":1684,"depth":133,"text":1684},{"id":1771,"depth":133,"text":1771},{"id":1895,"depth":133,"text":1895},{"id":1966,"depth":111,"text":1967},{"id":2197,"depth":111,"text":2198},{"id":2222,"depth":111,"text":2223},{"id":1382,"depth":111,"text":1382},"2026-06-27","确定声明值、层叠冲突、继承与默认值——搞懂 Computed 面板里那一长串属性是怎么来的。",{},{"title":1454,"description":2390},"blog\u002Fcss-property-calculation",[2395,2396,1450],"cascade","computed-style","VHFx82BlHxxsO9OMlz7Mo-xU23maWSskailB9o960y8",{"id":2399,"title":2400,"body":2401,"category":5515,"date":5516,"description":5517,"draft":1441,"extension":1442,"meta":5518,"navigation":243,"path":1423,"seo":5519,"stem":5520,"tags":5521,"__hash__":5525},"blog\u002Fblog\u002Freflow-repaint-transform.md","reflow、repaint 与 transform 为何高效",{"type":10,"value":2402,"toc":5506},[2403,2406,2424,2428,2433,2440,2443,2450,2456,2460,2477,2483,2555,2559,2564,2584,2591,2599,2646,2650,2666,2668,2686,2699,2715,5474,5476,5503],[13,2404,2400],{"id":2405},"reflowrepaint-与-transform-为何高效",[17,2407,2408,2409,2412,2413,2416,2417,33,2420,2423],{},"上一篇 ",[53,2410,2411],{"href":71},"浏览器渲染流水线"," 讲的是「从零画一页」。页面跑起来之后，改 DOM 或样式会触发 ",[26,2414,2415],{},"局部重算","。面试里常说的 ",[26,2418,2419],{},"回流（reflow）",[26,2421,2422],{},"重绘（repaint）","，指的就是流水线里哪些阶段要重跑。",[80,2425,2427],{"id":2426},"什么是-reflow回流","什么是 reflow（回流）？",[17,2429,2430],{},[26,2431,2432],{},"Reflow 的本质是重新计算布局树（Layout）。",[17,2434,2435,2436,2439],{},"凡是会影响布局树的操作——改宽高、边距、显示方式、插入删除节点等——都需要重新做 ",[26,2437,2438],{},"Layout"," 及之后的阶段（分层、绘制、分块、光栅化、合成）。",[440,2441,2442],{"id":2442},"浏览器会合并多次改动",[17,2444,2445,2446,2449],{},"连续多次改布局相关属性时，浏览器往往 ",[26,2447,2448],{},"先合并","，等当前 JS 执行块结束后再统一算布局，避免同一帧里反复 reflow。",[17,2451,2452,2453],{},"因此：",[26,2454,2455],{},"改属性触发的 reflow 常常是异步批量的。",[440,2457,2459],{"id":2458},"读布局属性会强制同步-reflow","读布局属性会强制同步 reflow",[17,2461,2462,2463,2322,2466,33,2469,2472,2473,2476],{},"如果 JS 在改完布局后又 ",[26,2464,2465],{},"读取",[21,2467,2468],{},"offsetWidth",[21,2470,2471],{},"getBoundingClientRect()"," 等依赖最新几何信息的属性，浏览器必须 ",[26,2474,2475],{},"立刻算出最新布局","，否则会返回过期数据。",[17,2478,2479,2480],{},"所以常见性能建议：",[26,2481,2482],{},"先读后写，或批量改样式，避免读写交错。",[2484,2485,2488],"code-block",{"lang":2486,"title":2487},"javascript","读写交错可能触发强制同步布局",[85,2489,2492],{"className":2490,"code":2491,"language":2486,"meta":90,"style":90},"language-javascript shiki shiki-themes github-light github-dark","const el = document.querySelector('.box')\nel.style.width = '200px'\n\u002F\u002F 读宽度会迫使浏览器立即 reflow\nconsole.log(el.offsetWidth)\nel.style.width = '300px'\n",[21,2493,2494,2519,2529,2535,2546],{"__ignoreMap":90},[94,2495,2496,2499,2502,2505,2508,2511,2513,2516],{"class":96,"line":97},[94,2497,2498],{"class":202},"const",[94,2500,2501],{"class":192}," el",[94,2503,2504],{"class":202}," =",[94,2506,2507],{"class":100}," document.",[94,2509,2510],{"class":120},"querySelector",[94,2512,867],{"class":100},[94,2514,2515],{"class":127},"'.box'",[94,2517,2518],{"class":100},")\n",[94,2520,2521,2524,2526],{"class":96,"line":111},[94,2522,2523],{"class":100},"el.style.width ",[94,2525,124],{"class":202},[94,2527,2528],{"class":127}," '200px'\n",[94,2530,2531],{"class":96,"line":133},[94,2532,2534],{"class":2533},"sJ8bj","\u002F\u002F 读宽度会迫使浏览器立即 reflow\n",[94,2536,2537,2540,2543],{"class":96,"line":155},[94,2538,2539],{"class":100},"console.",[94,2541,2542],{"class":120},"log",[94,2544,2545],{"class":100},"(el.offsetWidth)\n",[94,2547,2548,2550,2552],{"class":96,"line":165},[94,2549,2523],{"class":100},[94,2551,124],{"class":202},[94,2553,2554],{"class":127}," '300px'\n",[80,2556,2558],{"id":2557},"什么是-repaint重绘","什么是 repaint（重绘）？",[17,2560,2561],{},[26,2562,2563],{},"Repaint 的本质是重新生成绘制指令（Paint）及之后步骤。",[17,2565,2566,2567,2570,2571,33,2573,33,2576,2579,2580,2583],{},"改的是 ",[26,2568,2569],{},"可见样式但不改布局"," 时——例如 ",[21,2572,2044],{},[21,2574,2575],{},"background",[21,2577,2578],{},"visibility","（在仍占位的情况下）——可能只需 ",[26,2581,2582],{},"Repaint","，不必完整 reflow。",[17,2585,2586,2587,2590],{},"但 ",[26,2588,2589],{},"布局信息本身也是可见结果的一部分","，所以：",[2592,2593,2594],"blockquote",{},[17,2595,2596],{},[26,2597,2598],{},"Reflow 一定会引起 Repaint。",[368,2600,2601,2614],{},[371,2602,2603],{},[374,2604,2605,2608,2611],{},[377,2606,2607],{},"操作类型",[377,2609,2610],{},"典型属性",[377,2612,2613],{},"至少触发的阶段",[386,2615,2616,2633],{},[374,2617,2618,2621,2630],{},[391,2619,2620],{},"Reflow",[391,2622,2623,33,2626,33,2628],{},[21,2624,2625],{},"width",[21,2627,1642],{},[21,2629,1639],{},[391,2631,2632],{},"Layout → … → Draw",[374,2634,2635,2637,2643],{},[391,2636,2582],{},[391,2638,2639,33,2641],{},[21,2640,2044],{},[21,2642,2575],{},[391,2644,2645],{},"Paint → … → Draw",[80,2647,2649],{"id":2648},"为什么-transform-效率高","为什么 transform 效率高？",[17,2651,2652,2322,2654,2657,2658,2661,2662,2665],{},[21,2653,799],{},[26,2655,2656],{},"不改变布局树","，也 ",[26,2659,2660],{},"不改变绘制指令的生成方式","（不触发典型意义上的 layout \u002F paint 重算）。它主要影响流水线最后的 ",[26,2663,2664],{},"Draw（合成）"," 阶段：在合成线程里对已有位图做位移、旋转、缩放。",[17,2667,2452],{},[344,2669,2670,2679],{},[347,2671,2672,2674,2675,2678],{},[21,2673,799],{}," 变化时，",[26,2676,2677],{},"渲染主线程"," 往往仍很空闲",[347,2680,2681,2682,2685],{},"主线程再忙，",[26,2683,2684],{},"也不应挡住"," 合成线程上的 transform 动画",[17,2687,2688,2689,396,2692,2695,2696,2698],{},"对比：用 ",[21,2690,2691],{},"top",[21,2693,2694],{},"left"," 做位移动画会改布局，通常走 ",[26,2697,2620],{}," 路径，代价大得多。",[17,2700,2701,2704,2705,2708,2709,2711,2712,2714],{},[26,2702,2703],{},"注意："," 对比的前提是 ",[26,2706,2707],{},"画面一样、实现不同","。下面 demo 两个小球同步左右移动，左边用 ",[21,2710,799],{},"，右边用 ",[21,2713,2694],{},"；视觉上应一致，差别在每一帧走合成还是 Layout。",[2716,2717,2719],"code-playground",{"title":2718},"transform vs left：同动画、不同实现",[85,2720,2724],{"className":2721,"code":2722,"language":2723,"meta":90,"style":90},"language-vue shiki shiki-themes github-light github-dark","\u003Ctemplate>\n  \u003Cdiv class=\"wrap\">\n    \u003Cp class=\"tip\">\n      点「开始动画」：两球同步往复移动。左边 \u003Ccode>transform: translateX\u003C\u002Fcode>，右边\n      \u003Ccode>left\u003C\u002Fcode>。画面应一致；右轨每帧触发布局，主线程更忙时可能更卡。\n    \u003C\u002Fp>\n\n    \u003Cdiv class=\"compare\">\n      \u003Cdiv class=\"col\">\n        \u003Cdiv class=\"col-head\">\n          \u003Cspan class=\"tag good\">transform\u003C\u002Fspan>\n          \u003Cspan class=\"metric\">本帧 ≈ {{ transformMs }}ms\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"track\">\n          \u003Cdiv class=\"ball\" :style=\"{ transform: `translateX(${x}px)` }\" \u002F>\n        \u003C\u002Fdiv>\n        \u003Cp class=\"note\">合成阶段位移，不改布局树\u003C\u002Fp>\n      \u003C\u002Fdiv>\n\n      \u003Cdiv class=\"col\">\n        \u003Cdiv class=\"col-head\">\n          \u003Cspan class=\"tag warn\">left\u003C\u002Fspan>\n          \u003Cspan class=\"metric warn-m\">{{ layoutMs }}ms\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"track\">\n          \u003Cdiv ref=\"leftBall\" class=\"ball\" :style=\"{ left: `${x}px` }\" \u002F>\n        \u003C\u002Fdiv>\n        \u003Cp class=\"note\">每帧改几何位置 → Layout\u003C\u002Fp>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"actions\">\n      \u003Cbutton class=\"btn\" :class=\"{ active: running }\" @click=\"toggle\">\n        {{ running ? '停止动画' : '开始动画' }}\n      \u003C\u002Fbutton>\n      \u003Cbutton class=\"btn ghost\" @click=\"reset\">复位\u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { nextTick, onUnmounted, ref } from 'vue'\n\nconst running = ref(false)\nconst x = ref(0)\nconst transformMs = ref(0)\nconst layoutMs = ref(0)\nconst leftBall = ref(null)\n\nlet rafId = 0\nlet start = 0\nlet tSamples = []\nlet lSamples = []\n\nfunction tick(now) {\n  if (!start) start = now\n  const phase = (now - start) \u002F 420\n  const value = Math.sin(phase) * 100 + 100\n\n  const t0 = performance.now()\n  x.value = value\n  const tCost = performance.now() - t0\n  tSamples.push(tCost)\n  if (tSamples.length > 20) tSamples.shift()\n  transformMs.value = Math.round((tSamples.reduce((a, b) => a + b, 0) \u002F tSamples.length) * 100) \u002F 100\n\n  nextTick(() => {\n    const l0 = performance.now()\n    const el = leftBall.value\n    if (el) {\n      void el.offsetLeft\n      void el.offsetWidth\n      void el.getBoundingClientRect()\n    }\n    const lCost = performance.now() - l0\n    lSamples.push(lCost)\n    if (lSamples.length > 20) lSamples.shift()\n    layoutMs.value = Math.round((lSamples.reduce((a, b) => a + b, 0) \u002F lSamples.length) * 10) \u002F 10\n\n    if (running.value) {\n      rafId = requestAnimationFrame(tick)\n    }\n  })\n}\n\nfunction resetAnim() {\n  start = 0\n  x.value = 0\n  tSamples = []\n  lSamples = []\n  transformMs.value = 0\n  layoutMs.value = 0\n}\n\nfunction toggle() {\n  running.value = !running.value\n  if (running.value) {\n    resetAnim()\n    rafId = requestAnimationFrame(tick)\n  } else {\n    cancelAnimationFrame(rafId)\n  }\n}\n\nfunction reset() {\n  running.value = false\n  cancelAnimationFrame(rafId)\n  resetAnim()\n}\n\nonUnmounted(() => cancelAnimationFrame(rafId))\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n.wrap {\n  padding: 20px;\n  font-family: system-ui, sans-serif;\n}\n\n.tip {\n  margin: 0 0 14px;\n  color: #64748b;\n  font-size: 0.85rem;\n  line-height: 1.55;\n}\n\n.tip code {\n  font-size: 0.8em;\n  padding: 1px 4px;\n  border-radius: 4px;\n  background: #e2e8f0;\n}\n\n.compare {\n  display: grid;\n  gap: 12px;\n}\n\n@media (min-width: 520px) {\n  .compare {\n    grid-template-columns: 1fr 1fr;\n  }\n}\n\n.col {\n  padding: 10px;\n  border-radius: 10px;\n  background: #f8fafc;\n  border: 1px solid #e2e8f0;\n}\n\n.col-head {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  margin-bottom: 8px;\n  gap: 6px;\n}\n\n.tag {\n  font-size: 11px;\n  font-weight: 600;\n  padding: 2px 8px;\n  border-radius: 999px;\n}\n\n.tag.good {\n  background: #dcfce7;\n  color: #166534;\n}\n\n.tag.warn {\n  background: #fef3c7;\n  color: #92400e;\n}\n\n.metric {\n  font-size: 11px;\n  font-weight: 600;\n  font-variant-numeric: tabular-nums;\n  color: #166534;\n}\n\n.metric.warn-m {\n  color: #b45309;\n}\n\n.track {\n  position: relative;\n  height: 44px;\n  border-radius: 8px;\n  background: #e2e8f0;\n  overflow: hidden;\n}\n\n.ball {\n  position: absolute;\n  top: 10px;\n  left: 0;\n  width: 24px;\n  height: 24px;\n  border-radius: 50%;\n  background: #6366f1;\n  will-change: transform, left;\n}\n\n.note {\n  margin: 8px 0 0;\n  font-size: 11px;\n  color: #94a3b8;\n}\n\n.actions {\n  display: flex;\n  gap: 8px;\n  margin-top: 14px;\n}\n\n.btn {\n  padding: 8px 16px;\n  border: none;\n  border-radius: 8px;\n  background: #6366f1;\n  color: white;\n  font-weight: 600;\n  cursor: pointer;\n  font-size: 13px;\n}\n\n.btn.active {\n  background: #4f46e5;\n}\n\n.btn.ghost {\n  background: #e2e8f0;\n  color: #334155;\n}\n\u003C\u002Fstyle>\n","vue",[21,2725,2726,2735,2750,2765,2780,2794,2802,2806,2821,2836,2851,2871,2891,2899,2914,2941,2949,2969,2977,2981,2995,3009,3028,3049,3058,3073,3105,3114,3134,3143,3152,3157,3173,3206,3212,3221,3249,3258,3267,3276,3281,3294,3309,3314,3333,3351,3369,3387,3406,3411,3425,3437,3450,3462,3467,3485,3505,3530,3561,3566,3584,3595,3617,3629,3654,3722,3727,3740,3757,3769,3778,3787,3795,3808,3814,3835,3846,3867,3927,3932,3940,3954,3959,3965,3970,3975,3986,3996,4005,4015,4025,4034,4044,4049,4054,4064,4078,4085,4093,4105,4116,4125,4131,4136,4141,4151,4161,4169,4177,4182,4187,4203,4212,4217,4229,4237,4251,4269,4274,4279,4287,4307,4319,4334,4347,4352,4357,4367,4381,4400,4415,4428,4433,4438,4446,4458,4473,4478,4483,4503,4511,4531,4536,4541,4546,4554,4567,4580,4592,4610,4615,4620,4628,4640,4653,4666,4681,4695,4700,4705,4713,4727,4740,4759,4773,4778,4783,4791,4803,4815,4820,4825,4833,4845,4857,4862,4867,4875,4888,4899,4912,4923,4928,4933,4941,4953,4958,4963,4971,4982,4996,5009,5020,5033,5038,5043,5051,5062,5075,5086,5100,5113,5126,5138,5151,5156,5161,5169,5186,5199,5211,5216,5221,5229,5240,5253,5268,5273,5278,5286,5304,5315,5328,5339,5351,5362,5375,5389,5394,5399,5407,5419,5424,5429,5437,5448,5460,5465],{"__ignoreMap":90},[94,2727,2728,2730,2733],{"class":96,"line":97},[94,2729,101],{"class":100},[94,2731,2732],{"class":104},"template",[94,2734,108],{"class":100},[94,2736,2737,2739,2741,2743,2745,2748],{"class":96,"line":111},[94,2738,114],{"class":100},[94,2740,117],{"class":104},[94,2742,121],{"class":120},[94,2744,124],{"class":100},[94,2746,2747],{"class":127},"\"wrap\"",[94,2749,108],{"class":100},[94,2751,2752,2754,2756,2758,2760,2763],{"class":96,"line":133},[94,2753,136],{"class":100},[94,2755,17],{"class":104},[94,2757,121],{"class":120},[94,2759,124],{"class":100},[94,2761,2762],{"class":127},"\"tip\"",[94,2764,108],{"class":100},[94,2766,2767,2770,2772,2775,2777],{"class":96,"line":155},[94,2768,2769],{"class":100},"      点「开始动画」：两球同步往复移动。左边 \u003C",[94,2771,21],{"class":104},[94,2773,2774],{"class":100},">transform: translateX\u003C\u002F",[94,2776,21],{"class":104},[94,2778,2779],{"class":100},">，右边\n",[94,2781,2782,2784,2786,2789,2791],{"class":96,"line":165},[94,2783,489],{"class":100},[94,2785,21],{"class":104},[94,2787,2788],{"class":100},">left\u003C\u002F",[94,2790,21],{"class":104},[94,2792,2793],{"class":100},">。画面应一致；右轨每帧触发布局，主线程更忙时可能更卡。\n",[94,2795,2796,2798,2800],{"class":96,"line":240},[94,2797,509],{"class":100},[94,2799,17],{"class":104},[94,2801,108],{"class":100},[94,2803,2804],{"class":96,"line":247},[94,2805,244],{"emptyLinePlaceholder":243},[94,2807,2808,2810,2812,2814,2816,2819],{"class":96,"line":255},[94,2809,136],{"class":100},[94,2811,117],{"class":104},[94,2813,121],{"class":120},[94,2815,124],{"class":100},[94,2817,2818],{"class":127},"\"compare\"",[94,2820,108],{"class":100},[94,2822,2823,2825,2827,2829,2831,2834],{"class":96,"line":270},[94,2824,489],{"class":100},[94,2826,117],{"class":104},[94,2828,121],{"class":120},[94,2830,124],{"class":100},[94,2832,2833],{"class":127},"\"col\"",[94,2835,108],{"class":100},[94,2837,2838,2840,2842,2844,2846,2849],{"class":96,"line":283},[94,2839,1032],{"class":100},[94,2841,117],{"class":104},[94,2843,121],{"class":120},[94,2845,124],{"class":100},[94,2847,2848],{"class":127},"\"col-head\"",[94,2850,108],{"class":100},[94,2852,2853,2855,2857,2859,2861,2864,2867,2869],{"class":96,"line":295},[94,2854,1054],{"class":100},[94,2856,94],{"class":104},[94,2858,121],{"class":120},[94,2860,124],{"class":100},[94,2862,2863],{"class":127},"\"tag good\"",[94,2865,2866],{"class":100},">transform\u003C\u002F",[94,2868,94],{"class":104},[94,2870,108],{"class":100},[94,2872,2873,2875,2877,2879,2881,2884,2887,2889],{"class":96,"line":644},[94,2874,1054],{"class":100},[94,2876,94],{"class":104},[94,2878,121],{"class":120},[94,2880,124],{"class":100},[94,2882,2883],{"class":127},"\"metric\"",[94,2885,2886],{"class":100},">本帧 ≈ {{ transformMs }}ms\u003C\u002F",[94,2888,94],{"class":104},[94,2890,108],{"class":100},[94,2892,2893,2895,2897],{"class":96,"line":659},[94,2894,1080],{"class":100},[94,2896,117],{"class":104},[94,2898,108],{"class":100},[94,2900,2901,2903,2905,2907,2909,2912],{"class":96,"line":4},[94,2902,1032],{"class":100},[94,2904,117],{"class":104},[94,2906,121],{"class":120},[94,2908,124],{"class":100},[94,2910,2911],{"class":127},"\"track\"",[94,2913,108],{"class":100},[94,2915,2916,2918,2920,2922,2924,2927,2930,2932,2935,2939],{"class":96,"line":668},[94,2917,1054],{"class":100},[94,2919,117],{"class":104},[94,2921,121],{"class":120},[94,2923,124],{"class":100},[94,2925,2926],{"class":127},"\"ball\"",[94,2928,2929],{"class":120}," :style",[94,2931,124],{"class":100},[94,2933,2934],{"class":127},"\"{ transform: `translateX(${x}px)` }\"",[94,2936,2938],{"class":2937},"s7hpK"," \u002F",[94,2940,108],{"class":100},[94,2942,2943,2945,2947],{"class":96,"line":676},[94,2944,1080],{"class":100},[94,2946,117],{"class":104},[94,2948,108],{"class":100},[94,2950,2951,2953,2955,2957,2959,2962,2965,2967],{"class":96,"line":689},[94,2952,1032],{"class":100},[94,2954,17],{"class":104},[94,2956,121],{"class":120},[94,2958,124],{"class":100},[94,2960,2961],{"class":127},"\"note\"",[94,2963,2964],{"class":100},">合成阶段位移，不改布局树\u003C\u002F",[94,2966,17],{"class":104},[94,2968,108],{"class":100},[94,2970,2971,2973,2975],{"class":96,"line":702},[94,2972,1089],{"class":100},[94,2974,117],{"class":104},[94,2976,108],{"class":100},[94,2978,2979],{"class":96,"line":713},[94,2980,244],{"emptyLinePlaceholder":243},[94,2982,2983,2985,2987,2989,2991,2993],{"class":96,"line":724},[94,2984,489],{"class":100},[94,2986,117],{"class":104},[94,2988,121],{"class":120},[94,2990,124],{"class":100},[94,2992,2833],{"class":127},[94,2994,108],{"class":100},[94,2996,2997,2999,3001,3003,3005,3007],{"class":96,"line":739},[94,2998,1032],{"class":100},[94,3000,117],{"class":104},[94,3002,121],{"class":120},[94,3004,124],{"class":100},[94,3006,2848],{"class":127},[94,3008,108],{"class":100},[94,3010,3011,3013,3015,3017,3019,3022,3024,3026],{"class":96,"line":753},[94,3012,1054],{"class":100},[94,3014,94],{"class":104},[94,3016,121],{"class":120},[94,3018,124],{"class":100},[94,3020,3021],{"class":127},"\"tag warn\"",[94,3023,2788],{"class":100},[94,3025,94],{"class":104},[94,3027,108],{"class":100},[94,3029,3031,3033,3035,3037,3039,3042,3045,3047],{"class":96,"line":3030},23,[94,3032,1054],{"class":100},[94,3034,94],{"class":104},[94,3036,121],{"class":120},[94,3038,124],{"class":100},[94,3040,3041],{"class":127},"\"metric warn-m\"",[94,3043,3044],{"class":100},">{{ layoutMs }}ms\u003C\u002F",[94,3046,94],{"class":104},[94,3048,108],{"class":100},[94,3050,3052,3054,3056],{"class":96,"line":3051},24,[94,3053,1080],{"class":100},[94,3055,117],{"class":104},[94,3057,108],{"class":100},[94,3059,3061,3063,3065,3067,3069,3071],{"class":96,"line":3060},25,[94,3062,1032],{"class":100},[94,3064,117],{"class":104},[94,3066,121],{"class":120},[94,3068,124],{"class":100},[94,3070,2911],{"class":127},[94,3072,108],{"class":100},[94,3074,3076,3078,3080,3083,3085,3088,3090,3092,3094,3096,3098,3101,3103],{"class":96,"line":3075},26,[94,3077,1054],{"class":100},[94,3079,117],{"class":104},[94,3081,3082],{"class":120}," ref",[94,3084,124],{"class":100},[94,3086,3087],{"class":127},"\"leftBall\"",[94,3089,121],{"class":120},[94,3091,124],{"class":100},[94,3093,2926],{"class":127},[94,3095,2929],{"class":120},[94,3097,124],{"class":100},[94,3099,3100],{"class":127},"\"{ left: `${x}px` }\"",[94,3102,2938],{"class":2937},[94,3104,108],{"class":100},[94,3106,3108,3110,3112],{"class":96,"line":3107},27,[94,3109,1080],{"class":100},[94,3111,117],{"class":104},[94,3113,108],{"class":100},[94,3115,3117,3119,3121,3123,3125,3127,3130,3132],{"class":96,"line":3116},28,[94,3118,1032],{"class":100},[94,3120,17],{"class":104},[94,3122,121],{"class":120},[94,3124,124],{"class":100},[94,3126,2961],{"class":127},[94,3128,3129],{"class":100},">每帧改几何位置 → Layout\u003C\u002F",[94,3131,17],{"class":104},[94,3133,108],{"class":100},[94,3135,3137,3139,3141],{"class":96,"line":3136},29,[94,3138,1089],{"class":100},[94,3140,117],{"class":104},[94,3142,108],{"class":100},[94,3144,3146,3148,3150],{"class":96,"line":3145},30,[94,3147,509],{"class":100},[94,3149,117],{"class":104},[94,3151,108],{"class":100},[94,3153,3155],{"class":96,"line":3154},31,[94,3156,244],{"emptyLinePlaceholder":243},[94,3158,3160,3162,3164,3166,3168,3171],{"class":96,"line":3159},32,[94,3161,136],{"class":100},[94,3163,117],{"class":104},[94,3165,121],{"class":120},[94,3167,124],{"class":100},[94,3169,3170],{"class":127},"\"actions\"",[94,3172,108],{"class":100},[94,3174,3176,3178,3181,3183,3185,3188,3191,3193,3196,3199,3201,3204],{"class":96,"line":3175},33,[94,3177,489],{"class":100},[94,3179,3180],{"class":104},"button",[94,3182,121],{"class":120},[94,3184,124],{"class":100},[94,3186,3187],{"class":127},"\"btn\"",[94,3189,3190],{"class":120}," :class",[94,3192,124],{"class":100},[94,3194,3195],{"class":127},"\"{ active: running }\"",[94,3197,3198],{"class":120}," @click",[94,3200,124],{"class":100},[94,3202,3203],{"class":127},"\"toggle\"",[94,3205,108],{"class":100},[94,3207,3209],{"class":96,"line":3208},34,[94,3210,3211],{"class":100},"        {{ running ? '停止动画' : '开始动画' }}\n",[94,3213,3215,3217,3219],{"class":96,"line":3214},35,[94,3216,1089],{"class":100},[94,3218,3180],{"class":104},[94,3220,108],{"class":100},[94,3222,3224,3226,3228,3230,3232,3235,3237,3239,3242,3245,3247],{"class":96,"line":3223},36,[94,3225,489],{"class":100},[94,3227,3180],{"class":104},[94,3229,121],{"class":120},[94,3231,124],{"class":100},[94,3233,3234],{"class":127},"\"btn ghost\"",[94,3236,3198],{"class":120},[94,3238,124],{"class":100},[94,3240,3241],{"class":127},"\"reset\"",[94,3243,3244],{"class":100},">复位\u003C\u002F",[94,3246,3180],{"class":104},[94,3248,108],{"class":100},[94,3250,3252,3254,3256],{"class":96,"line":3251},37,[94,3253,509],{"class":100},[94,3255,117],{"class":104},[94,3257,108],{"class":100},[94,3259,3261,3263,3265],{"class":96,"line":3260},38,[94,3262,158],{"class":100},[94,3264,117],{"class":104},[94,3266,108],{"class":100},[94,3268,3270,3272,3274],{"class":96,"line":3269},39,[94,3271,168],{"class":100},[94,3273,2732],{"class":104},[94,3275,108],{"class":100},[94,3277,3279],{"class":96,"line":3278},40,[94,3280,244],{"emptyLinePlaceholder":243},[94,3282,3284,3286,3289,3292],{"class":96,"line":3283},41,[94,3285,101],{"class":100},[94,3287,3288],{"class":104},"script",[94,3290,3291],{"class":120}," setup",[94,3293,108],{"class":100},[94,3295,3297,3300,3303,3306],{"class":96,"line":3296},42,[94,3298,3299],{"class":202},"import",[94,3301,3302],{"class":100}," { nextTick, onUnmounted, ref } ",[94,3304,3305],{"class":202},"from",[94,3307,3308],{"class":127}," 'vue'\n",[94,3310,3312],{"class":96,"line":3311},43,[94,3313,244],{"emptyLinePlaceholder":243},[94,3315,3317,3319,3322,3324,3326,3328,3331],{"class":96,"line":3316},44,[94,3318,2498],{"class":202},[94,3320,3321],{"class":192}," running",[94,3323,2504],{"class":202},[94,3325,3082],{"class":120},[94,3327,867],{"class":100},[94,3329,3330],{"class":192},"false",[94,3332,2518],{"class":100},[94,3334,3336,3338,3341,3343,3345,3347,3349],{"class":96,"line":3335},45,[94,3337,2498],{"class":202},[94,3339,3340],{"class":192}," x",[94,3342,2504],{"class":202},[94,3344,3082],{"class":120},[94,3346,867],{"class":100},[94,3348,870],{"class":192},[94,3350,2518],{"class":100},[94,3352,3354,3356,3359,3361,3363,3365,3367],{"class":96,"line":3353},46,[94,3355,2498],{"class":202},[94,3357,3358],{"class":192}," transformMs",[94,3360,2504],{"class":202},[94,3362,3082],{"class":120},[94,3364,867],{"class":100},[94,3366,870],{"class":192},[94,3368,2518],{"class":100},[94,3370,3372,3374,3377,3379,3381,3383,3385],{"class":96,"line":3371},47,[94,3373,2498],{"class":202},[94,3375,3376],{"class":192}," layoutMs",[94,3378,2504],{"class":202},[94,3380,3082],{"class":120},[94,3382,867],{"class":100},[94,3384,870],{"class":192},[94,3386,2518],{"class":100},[94,3388,3390,3392,3395,3397,3399,3401,3404],{"class":96,"line":3389},48,[94,3391,2498],{"class":202},[94,3393,3394],{"class":192}," leftBall",[94,3396,2504],{"class":202},[94,3398,3082],{"class":120},[94,3400,867],{"class":100},[94,3402,3403],{"class":192},"null",[94,3405,2518],{"class":100},[94,3407,3409],{"class":96,"line":3408},49,[94,3410,244],{"emptyLinePlaceholder":243},[94,3412,3414,3417,3420,3422],{"class":96,"line":3413},50,[94,3415,3416],{"class":202},"let",[94,3418,3419],{"class":100}," rafId ",[94,3421,124],{"class":202},[94,3423,3424],{"class":192}," 0\n",[94,3426,3428,3430,3433,3435],{"class":96,"line":3427},51,[94,3429,3416],{"class":202},[94,3431,3432],{"class":100}," start ",[94,3434,124],{"class":202},[94,3436,3424],{"class":192},[94,3438,3440,3442,3445,3447],{"class":96,"line":3439},52,[94,3441,3416],{"class":202},[94,3443,3444],{"class":100}," tSamples ",[94,3446,124],{"class":202},[94,3448,3449],{"class":100}," []\n",[94,3451,3453,3455,3458,3460],{"class":96,"line":3452},53,[94,3454,3416],{"class":202},[94,3456,3457],{"class":100}," lSamples ",[94,3459,124],{"class":202},[94,3461,3449],{"class":100},[94,3463,3465],{"class":96,"line":3464},54,[94,3466,244],{"emptyLinePlaceholder":243},[94,3468,3470,3473,3476,3478,3482],{"class":96,"line":3469},55,[94,3471,3472],{"class":202},"function",[94,3474,3475],{"class":120}," tick",[94,3477,867],{"class":100},[94,3479,3481],{"class":3480},"s4XuR","now",[94,3483,3484],{"class":100},") {\n",[94,3486,3488,3491,3494,3497,3500,3502],{"class":96,"line":3487},56,[94,3489,3490],{"class":202},"  if",[94,3492,3493],{"class":100}," (",[94,3495,3496],{"class":202},"!",[94,3498,3499],{"class":100},"start) start ",[94,3501,124],{"class":202},[94,3503,3504],{"class":100}," now\n",[94,3506,3508,3511,3514,3516,3519,3522,3525,3527],{"class":96,"line":3507},57,[94,3509,3510],{"class":202},"  const",[94,3512,3513],{"class":192}," phase",[94,3515,2504],{"class":202},[94,3517,3518],{"class":100}," (now ",[94,3520,3521],{"class":202},"-",[94,3523,3524],{"class":100}," start) ",[94,3526,1394],{"class":202},[94,3528,3529],{"class":192}," 420\n",[94,3531,3533,3535,3538,3540,3543,3546,3549,3552,3555,3558],{"class":96,"line":3532},58,[94,3534,3510],{"class":202},[94,3536,3537],{"class":192}," value",[94,3539,2504],{"class":202},[94,3541,3542],{"class":100}," Math.",[94,3544,3545],{"class":120},"sin",[94,3547,3548],{"class":100},"(phase) ",[94,3550,3551],{"class":202},"*",[94,3553,3554],{"class":192}," 100",[94,3556,3557],{"class":202}," +",[94,3559,3560],{"class":192}," 100\n",[94,3562,3564],{"class":96,"line":3563},59,[94,3565,244],{"emptyLinePlaceholder":243},[94,3567,3569,3571,3574,3576,3579,3581],{"class":96,"line":3568},60,[94,3570,3510],{"class":202},[94,3572,3573],{"class":192}," t0",[94,3575,2504],{"class":202},[94,3577,3578],{"class":100}," performance.",[94,3580,3481],{"class":120},[94,3582,3583],{"class":100},"()\n",[94,3585,3587,3590,3592],{"class":96,"line":3586},61,[94,3588,3589],{"class":100},"  x.value ",[94,3591,124],{"class":202},[94,3593,3594],{"class":100}," value\n",[94,3596,3598,3600,3603,3605,3607,3609,3612,3614],{"class":96,"line":3597},62,[94,3599,3510],{"class":202},[94,3601,3602],{"class":192}," tCost",[94,3604,2504],{"class":202},[94,3606,3578],{"class":100},[94,3608,3481],{"class":120},[94,3610,3611],{"class":100},"() ",[94,3613,3521],{"class":202},[94,3615,3616],{"class":100}," t0\n",[94,3618,3620,3623,3626],{"class":96,"line":3619},63,[94,3621,3622],{"class":100},"  tSamples.",[94,3624,3625],{"class":120},"push",[94,3627,3628],{"class":100},"(tCost)\n",[94,3630,3632,3634,3637,3640,3643,3646,3649,3652],{"class":96,"line":3631},64,[94,3633,3490],{"class":202},[94,3635,3636],{"class":100}," (tSamples.",[94,3638,3639],{"class":192},"length",[94,3641,3642],{"class":202}," >",[94,3644,3645],{"class":192}," 20",[94,3647,3648],{"class":100},") tSamples.",[94,3650,3651],{"class":120},"shift",[94,3653,3583],{"class":100},[94,3655,3657,3660,3662,3664,3667,3670,3673,3676,3678,3681,3684,3687,3690,3693,3696,3699,3701,3703,3705,3708,3710,3712,3714,3716,3718,3720],{"class":96,"line":3656},65,[94,3658,3659],{"class":100},"  transformMs.value ",[94,3661,124],{"class":202},[94,3663,3542],{"class":100},[94,3665,3666],{"class":120},"round",[94,3668,3669],{"class":100},"((tSamples.",[94,3671,3672],{"class":120},"reduce",[94,3674,3675],{"class":100},"((",[94,3677,53],{"class":3480},[94,3679,3680],{"class":100},", ",[94,3682,3683],{"class":3480},"b",[94,3685,3686],{"class":100},") ",[94,3688,3689],{"class":202},"=>",[94,3691,3692],{"class":100}," a ",[94,3694,3695],{"class":202},"+",[94,3697,3698],{"class":100}," b, ",[94,3700,870],{"class":192},[94,3702,3686],{"class":100},[94,3704,1394],{"class":202},[94,3706,3707],{"class":100}," tSamples.",[94,3709,3639],{"class":192},[94,3711,3686],{"class":100},[94,3713,3551],{"class":202},[94,3715,3554],{"class":192},[94,3717,3686],{"class":100},[94,3719,1394],{"class":202},[94,3721,3560],{"class":192},[94,3723,3725],{"class":96,"line":3724},66,[94,3726,244],{"emptyLinePlaceholder":243},[94,3728,3730,3733,3736,3738],{"class":96,"line":3729},67,[94,3731,3732],{"class":120},"  nextTick",[94,3734,3735],{"class":100},"(() ",[94,3737,3689],{"class":202},[94,3739,187],{"class":100},[94,3741,3743,3746,3749,3751,3753,3755],{"class":96,"line":3742},68,[94,3744,3745],{"class":202},"    const",[94,3747,3748],{"class":192}," l0",[94,3750,2504],{"class":202},[94,3752,3578],{"class":100},[94,3754,3481],{"class":120},[94,3756,3583],{"class":100},[94,3758,3760,3762,3764,3766],{"class":96,"line":3759},69,[94,3761,3745],{"class":202},[94,3763,2501],{"class":192},[94,3765,2504],{"class":202},[94,3767,3768],{"class":100}," leftBall.value\n",[94,3770,3772,3775],{"class":96,"line":3771},70,[94,3773,3774],{"class":202},"    if",[94,3776,3777],{"class":100}," (el) {\n",[94,3779,3781,3784],{"class":96,"line":3780},71,[94,3782,3783],{"class":202},"      void",[94,3785,3786],{"class":100}," el.offsetLeft\n",[94,3788,3790,3792],{"class":96,"line":3789},72,[94,3791,3783],{"class":202},[94,3793,3794],{"class":100}," el.offsetWidth\n",[94,3796,3798,3800,3803,3806],{"class":96,"line":3797},73,[94,3799,3783],{"class":202},[94,3801,3802],{"class":100}," el.",[94,3804,3805],{"class":120},"getBoundingClientRect",[94,3807,3583],{"class":100},[94,3809,3811],{"class":96,"line":3810},74,[94,3812,3813],{"class":100},"    }\n",[94,3815,3817,3819,3822,3824,3826,3828,3830,3832],{"class":96,"line":3816},75,[94,3818,3745],{"class":202},[94,3820,3821],{"class":192}," lCost",[94,3823,2504],{"class":202},[94,3825,3578],{"class":100},[94,3827,3481],{"class":120},[94,3829,3611],{"class":100},[94,3831,3521],{"class":202},[94,3833,3834],{"class":100}," l0\n",[94,3836,3838,3841,3843],{"class":96,"line":3837},76,[94,3839,3840],{"class":100},"    lSamples.",[94,3842,3625],{"class":120},[94,3844,3845],{"class":100},"(lCost)\n",[94,3847,3849,3851,3854,3856,3858,3860,3863,3865],{"class":96,"line":3848},77,[94,3850,3774],{"class":202},[94,3852,3853],{"class":100}," (lSamples.",[94,3855,3639],{"class":192},[94,3857,3642],{"class":202},[94,3859,3645],{"class":192},[94,3861,3862],{"class":100},") lSamples.",[94,3864,3651],{"class":120},[94,3866,3583],{"class":100},[94,3868,3870,3873,3875,3877,3879,3882,3884,3886,3888,3890,3892,3894,3896,3898,3900,3902,3904,3906,3908,3911,3913,3915,3917,3920,3922,3924],{"class":96,"line":3869},78,[94,3871,3872],{"class":100},"    layoutMs.value ",[94,3874,124],{"class":202},[94,3876,3542],{"class":100},[94,3878,3666],{"class":120},[94,3880,3881],{"class":100},"((lSamples.",[94,3883,3672],{"class":120},[94,3885,3675],{"class":100},[94,3887,53],{"class":3480},[94,3889,3680],{"class":100},[94,3891,3683],{"class":3480},[94,3893,3686],{"class":100},[94,3895,3689],{"class":202},[94,3897,3692],{"class":100},[94,3899,3695],{"class":202},[94,3901,3698],{"class":100},[94,3903,870],{"class":192},[94,3905,3686],{"class":100},[94,3907,1394],{"class":202},[94,3909,3910],{"class":100}," lSamples.",[94,3912,3639],{"class":192},[94,3914,3686],{"class":100},[94,3916,3551],{"class":202},[94,3918,3919],{"class":192}," 10",[94,3921,3686],{"class":100},[94,3923,1394],{"class":202},[94,3925,3926],{"class":192}," 10\n",[94,3928,3930],{"class":96,"line":3929},79,[94,3931,244],{"emptyLinePlaceholder":243},[94,3933,3935,3937],{"class":96,"line":3934},80,[94,3936,3774],{"class":202},[94,3938,3939],{"class":100}," (running.value) {\n",[94,3941,3943,3946,3948,3951],{"class":96,"line":3942},81,[94,3944,3945],{"class":100},"      rafId ",[94,3947,124],{"class":202},[94,3949,3950],{"class":120}," requestAnimationFrame",[94,3952,3953],{"class":100},"(tick)\n",[94,3955,3957],{"class":96,"line":3956},82,[94,3958,3813],{"class":100},[94,3960,3962],{"class":96,"line":3961},83,[94,3963,3964],{"class":100},"  })\n",[94,3966,3968],{"class":96,"line":3967},84,[94,3969,237],{"class":100},[94,3971,3973],{"class":96,"line":3972},85,[94,3974,244],{"emptyLinePlaceholder":243},[94,3976,3978,3980,3983],{"class":96,"line":3977},86,[94,3979,3472],{"class":202},[94,3981,3982],{"class":120}," resetAnim",[94,3984,3985],{"class":100},"() {\n",[94,3987,3989,3992,3994],{"class":96,"line":3988},87,[94,3990,3991],{"class":100},"  start ",[94,3993,124],{"class":202},[94,3995,3424],{"class":192},[94,3997,3999,4001,4003],{"class":96,"line":3998},88,[94,4000,3589],{"class":100},[94,4002,124],{"class":202},[94,4004,3424],{"class":192},[94,4006,4008,4011,4013],{"class":96,"line":4007},89,[94,4009,4010],{"class":100},"  tSamples ",[94,4012,124],{"class":202},[94,4014,3449],{"class":100},[94,4016,4018,4021,4023],{"class":96,"line":4017},90,[94,4019,4020],{"class":100},"  lSamples ",[94,4022,124],{"class":202},[94,4024,3449],{"class":100},[94,4026,4028,4030,4032],{"class":96,"line":4027},91,[94,4029,3659],{"class":100},[94,4031,124],{"class":202},[94,4033,3424],{"class":192},[94,4035,4037,4040,4042],{"class":96,"line":4036},92,[94,4038,4039],{"class":100},"  layoutMs.value ",[94,4041,124],{"class":202},[94,4043,3424],{"class":192},[94,4045,4047],{"class":96,"line":4046},93,[94,4048,237],{"class":100},[94,4050,4052],{"class":96,"line":4051},94,[94,4053,244],{"emptyLinePlaceholder":243},[94,4055,4057,4059,4062],{"class":96,"line":4056},95,[94,4058,3472],{"class":202},[94,4060,4061],{"class":120}," toggle",[94,4063,3985],{"class":100},[94,4065,4067,4070,4072,4075],{"class":96,"line":4066},96,[94,4068,4069],{"class":100},"  running.value ",[94,4071,124],{"class":202},[94,4073,4074],{"class":202}," !",[94,4076,4077],{"class":100},"running.value\n",[94,4079,4081,4083],{"class":96,"line":4080},97,[94,4082,3490],{"class":202},[94,4084,3939],{"class":100},[94,4086,4088,4091],{"class":96,"line":4087},98,[94,4089,4090],{"class":120},"    resetAnim",[94,4092,3583],{"class":100},[94,4094,4096,4099,4101,4103],{"class":96,"line":4095},99,[94,4097,4098],{"class":100},"    rafId ",[94,4100,124],{"class":202},[94,4102,3950],{"class":120},[94,4104,3953],{"class":100},[94,4106,4108,4111,4114],{"class":96,"line":4107},100,[94,4109,4110],{"class":100},"  } ",[94,4112,4113],{"class":202},"else",[94,4115,187],{"class":100},[94,4117,4119,4122],{"class":96,"line":4118},101,[94,4120,4121],{"class":120},"    cancelAnimationFrame",[94,4123,4124],{"class":100},"(rafId)\n",[94,4126,4128],{"class":96,"line":4127},102,[94,4129,4130],{"class":100},"  }\n",[94,4132,4134],{"class":96,"line":4133},103,[94,4135,237],{"class":100},[94,4137,4139],{"class":96,"line":4138},104,[94,4140,244],{"emptyLinePlaceholder":243},[94,4142,4144,4146,4149],{"class":96,"line":4143},105,[94,4145,3472],{"class":202},[94,4147,4148],{"class":120}," reset",[94,4150,3985],{"class":100},[94,4152,4154,4156,4158],{"class":96,"line":4153},106,[94,4155,4069],{"class":100},[94,4157,124],{"class":202},[94,4159,4160],{"class":192}," false\n",[94,4162,4164,4167],{"class":96,"line":4163},107,[94,4165,4166],{"class":120},"  cancelAnimationFrame",[94,4168,4124],{"class":100},[94,4170,4172,4175],{"class":96,"line":4171},108,[94,4173,4174],{"class":120},"  resetAnim",[94,4176,3583],{"class":100},[94,4178,4180],{"class":96,"line":4179},109,[94,4181,237],{"class":100},[94,4183,4185],{"class":96,"line":4184},110,[94,4186,244],{"emptyLinePlaceholder":243},[94,4188,4190,4193,4195,4197,4200],{"class":96,"line":4189},111,[94,4191,4192],{"class":120},"onUnmounted",[94,4194,3735],{"class":100},[94,4196,3689],{"class":202},[94,4198,4199],{"class":120}," cancelAnimationFrame",[94,4201,4202],{"class":100},"(rafId))\n",[94,4204,4206,4208,4210],{"class":96,"line":4205},112,[94,4207,168],{"class":100},[94,4209,3288],{"class":104},[94,4211,108],{"class":100},[94,4213,4215],{"class":96,"line":4214},113,[94,4216,244],{"emptyLinePlaceholder":243},[94,4218,4220,4222,4224,4227],{"class":96,"line":4219},114,[94,4221,101],{"class":100},[94,4223,1426],{"class":104},[94,4225,4226],{"class":120}," scoped",[94,4228,108],{"class":100},[94,4230,4232,4235],{"class":96,"line":4231},115,[94,4233,4234],{"class":120},".wrap",[94,4236,187],{"class":100},[94,4238,4240,4243,4245,4247,4249],{"class":96,"line":4239},116,[94,4241,4242],{"class":192},"  padding",[94,4244,196],{"class":100},[94,4246,1869],{"class":192},[94,4248,203],{"class":202},[94,4250,206],{"class":100},[94,4252,4254,4257,4259,4262,4264,4267],{"class":96,"line":4253},117,[94,4255,4256],{"class":192},"  font-family",[94,4258,196],{"class":100},[94,4260,4261],{"class":192},"system-ui",[94,4263,3680],{"class":100},[94,4265,4266],{"class":192},"sans-serif",[94,4268,206],{"class":100},[94,4270,4272],{"class":96,"line":4271},118,[94,4273,237],{"class":100},[94,4275,4277],{"class":96,"line":4276},119,[94,4278,244],{"emptyLinePlaceholder":243},[94,4280,4282,4285],{"class":96,"line":4281},120,[94,4283,4284],{"class":120},".tip",[94,4286,187],{"class":100},[94,4288,4290,4293,4295,4297,4300,4303,4305],{"class":96,"line":4289},121,[94,4291,4292],{"class":192},"  margin",[94,4294,196],{"class":100},[94,4296,870],{"class":192},[94,4298,4299],{"class":192}," 0",[94,4301,4302],{"class":192}," 14",[94,4304,203],{"class":202},[94,4306,206],{"class":100},[94,4308,4310,4312,4314,4317],{"class":96,"line":4309},122,[94,4311,1478],{"class":192},[94,4313,196],{"class":100},[94,4315,4316],{"class":192},"#64748b",[94,4318,206],{"class":100},[94,4320,4322,4324,4326,4329,4332],{"class":96,"line":4321},123,[94,4323,1838],{"class":192},[94,4325,196],{"class":100},[94,4327,4328],{"class":192},"0.85",[94,4330,4331],{"class":202},"rem",[94,4333,206],{"class":100},[94,4335,4337,4340,4342,4345],{"class":96,"line":4336},124,[94,4338,4339],{"class":192},"  line-height",[94,4341,196],{"class":100},[94,4343,4344],{"class":192},"1.55",[94,4346,206],{"class":100},[94,4348,4350],{"class":96,"line":4349},125,[94,4351,237],{"class":100},[94,4353,4355],{"class":96,"line":4354},126,[94,4356,244],{"emptyLinePlaceholder":243},[94,4358,4360,4362,4365],{"class":96,"line":4359},127,[94,4361,4284],{"class":120},[94,4363,4364],{"class":104}," code",[94,4366,187],{"class":100},[94,4368,4370,4372,4374,4377,4379],{"class":96,"line":4369},128,[94,4371,1838],{"class":192},[94,4373,196],{"class":100},[94,4375,4376],{"class":192},"0.8",[94,4378,1035],{"class":202},[94,4380,206],{"class":100},[94,4382,4384,4386,4388,4391,4393,4396,4398],{"class":96,"line":4383},129,[94,4385,4242],{"class":192},[94,4387,196],{"class":100},[94,4389,4390],{"class":192},"1",[94,4392,203],{"class":202},[94,4394,4395],{"class":192}," 4",[94,4397,203],{"class":202},[94,4399,206],{"class":100},[94,4401,4403,4406,4408,4411,4413],{"class":96,"line":4402},130,[94,4404,4405],{"class":192},"  border-radius",[94,4407,196],{"class":100},[94,4409,4410],{"class":192},"4",[94,4412,203],{"class":202},[94,4414,206],{"class":100},[94,4416,4418,4421,4423,4426],{"class":96,"line":4417},131,[94,4419,4420],{"class":192},"  background",[94,4422,196],{"class":100},[94,4424,4425],{"class":192},"#e2e8f0",[94,4427,206],{"class":100},[94,4429,4431],{"class":96,"line":4430},132,[94,4432,237],{"class":100},[94,4434,4436],{"class":96,"line":4435},133,[94,4437,244],{"emptyLinePlaceholder":243},[94,4439,4441,4444],{"class":96,"line":4440},134,[94,4442,4443],{"class":120},".compare",[94,4445,187],{"class":100},[94,4447,4449,4451,4453,4456],{"class":96,"line":4448},135,[94,4450,1743],{"class":192},[94,4452,196],{"class":100},[94,4454,4455],{"class":192},"grid",[94,4457,206],{"class":100},[94,4459,4461,4464,4466,4469,4471],{"class":96,"line":4460},136,[94,4462,4463],{"class":192},"  gap",[94,4465,196],{"class":100},[94,4467,4468],{"class":192},"12",[94,4470,203],{"class":202},[94,4472,206],{"class":100},[94,4474,4476],{"class":96,"line":4475},137,[94,4477,237],{"class":100},[94,4479,4481],{"class":96,"line":4480},138,[94,4482,244],{"emptyLinePlaceholder":243},[94,4484,4486,4489,4491,4494,4496,4499,4501],{"class":96,"line":4485},139,[94,4487,4488],{"class":202},"@media",[94,4490,3493],{"class":100},[94,4492,4493],{"class":192},"min-width",[94,4495,196],{"class":100},[94,4497,4498],{"class":192},"520",[94,4500,203],{"class":202},[94,4502,3484],{"class":100},[94,4504,4506,4509],{"class":96,"line":4505},140,[94,4507,4508],{"class":120},"  .compare",[94,4510,187],{"class":100},[94,4512,4514,4517,4519,4521,4524,4527,4529],{"class":96,"line":4513},141,[94,4515,4516],{"class":192},"    grid-template-columns",[94,4518,196],{"class":100},[94,4520,4390],{"class":192},[94,4522,4523],{"class":202},"fr",[94,4525,4526],{"class":192}," 1",[94,4528,4523],{"class":202},[94,4530,206],{"class":100},[94,4532,4534],{"class":96,"line":4533},142,[94,4535,4130],{"class":100},[94,4537,4539],{"class":96,"line":4538},143,[94,4540,237],{"class":100},[94,4542,4544],{"class":96,"line":4543},144,[94,4545,244],{"emptyLinePlaceholder":243},[94,4547,4549,4552],{"class":96,"line":4548},145,[94,4550,4551],{"class":120},".col",[94,4553,187],{"class":100},[94,4555,4557,4559,4561,4563,4565],{"class":96,"line":4556},146,[94,4558,4242],{"class":192},[94,4560,196],{"class":100},[94,4562,732],{"class":192},[94,4564,203],{"class":202},[94,4566,206],{"class":100},[94,4568,4570,4572,4574,4576,4578],{"class":96,"line":4569},147,[94,4571,4405],{"class":192},[94,4573,196],{"class":100},[94,4575,732],{"class":192},[94,4577,203],{"class":202},[94,4579,206],{"class":100},[94,4581,4583,4585,4587,4590],{"class":96,"line":4582},148,[94,4584,4420],{"class":192},[94,4586,196],{"class":100},[94,4588,4589],{"class":192},"#f8fafc",[94,4591,206],{"class":100},[94,4593,4595,4597,4599,4601,4603,4605,4608],{"class":96,"line":4594},149,[94,4596,629],{"class":192},[94,4598,196],{"class":100},[94,4600,4390],{"class":192},[94,4602,203],{"class":202},[94,4604,639],{"class":192},[94,4606,4607],{"class":192}," #e2e8f0",[94,4609,206],{"class":100},[94,4611,4613],{"class":96,"line":4612},150,[94,4614,237],{"class":100},[94,4616,4618],{"class":96,"line":4617},151,[94,4619,244],{"emptyLinePlaceholder":243},[94,4621,4623,4626],{"class":96,"line":4622},152,[94,4624,4625],{"class":120},".col-head",[94,4627,187],{"class":100},[94,4629,4631,4633,4635,4638],{"class":96,"line":4630},153,[94,4632,1743],{"class":192},[94,4634,196],{"class":100},[94,4636,4637],{"class":192},"flex",[94,4639,206],{"class":100},[94,4641,4643,4646,4648,4651],{"class":96,"line":4642},154,[94,4644,4645],{"class":192},"  align-items",[94,4647,196],{"class":100},[94,4649,4650],{"class":192},"center",[94,4652,206],{"class":100},[94,4654,4656,4659,4661,4664],{"class":96,"line":4655},155,[94,4657,4658],{"class":192},"  justify-content",[94,4660,196],{"class":100},[94,4662,4663],{"class":192},"space-between",[94,4665,206],{"class":100},[94,4667,4669,4672,4674,4677,4679],{"class":96,"line":4668},156,[94,4670,4671],{"class":192},"  margin-bottom",[94,4673,196],{"class":100},[94,4675,4676],{"class":192},"8",[94,4678,203],{"class":202},[94,4680,206],{"class":100},[94,4682,4684,4686,4688,4691,4693],{"class":96,"line":4683},157,[94,4685,4463],{"class":192},[94,4687,196],{"class":100},[94,4689,4690],{"class":192},"6",[94,4692,203],{"class":202},[94,4694,206],{"class":100},[94,4696,4698],{"class":96,"line":4697},158,[94,4699,237],{"class":100},[94,4701,4703],{"class":96,"line":4702},159,[94,4704,244],{"emptyLinePlaceholder":243},[94,4706,4708,4711],{"class":96,"line":4707},160,[94,4709,4710],{"class":120},".tag",[94,4712,187],{"class":100},[94,4714,4716,4718,4720,4723,4725],{"class":96,"line":4715},161,[94,4717,1838],{"class":192},[94,4719,196],{"class":100},[94,4721,4722],{"class":192},"11",[94,4724,203],{"class":202},[94,4726,206],{"class":100},[94,4728,4730,4733,4735,4738],{"class":96,"line":4729},162,[94,4731,4732],{"class":192},"  font-weight",[94,4734,196],{"class":100},[94,4736,4737],{"class":192},"600",[94,4739,206],{"class":100},[94,4741,4743,4745,4747,4750,4752,4755,4757],{"class":96,"line":4742},163,[94,4744,4242],{"class":192},[94,4746,196],{"class":100},[94,4748,4749],{"class":192},"2",[94,4751,203],{"class":202},[94,4753,4754],{"class":192}," 8",[94,4756,203],{"class":202},[94,4758,206],{"class":100},[94,4760,4762,4764,4766,4769,4771],{"class":96,"line":4761},164,[94,4763,4405],{"class":192},[94,4765,196],{"class":100},[94,4767,4768],{"class":192},"999",[94,4770,203],{"class":202},[94,4772,206],{"class":100},[94,4774,4776],{"class":96,"line":4775},165,[94,4777,237],{"class":100},[94,4779,4781],{"class":96,"line":4780},166,[94,4782,244],{"emptyLinePlaceholder":243},[94,4784,4786,4789],{"class":96,"line":4785},167,[94,4787,4788],{"class":120},".tag.good",[94,4790,187],{"class":100},[94,4792,4794,4796,4798,4801],{"class":96,"line":4793},168,[94,4795,4420],{"class":192},[94,4797,196],{"class":100},[94,4799,4800],{"class":192},"#dcfce7",[94,4802,206],{"class":100},[94,4804,4806,4808,4810,4813],{"class":96,"line":4805},169,[94,4807,1478],{"class":192},[94,4809,196],{"class":100},[94,4811,4812],{"class":192},"#166534",[94,4814,206],{"class":100},[94,4816,4818],{"class":96,"line":4817},170,[94,4819,237],{"class":100},[94,4821,4823],{"class":96,"line":4822},171,[94,4824,244],{"emptyLinePlaceholder":243},[94,4826,4828,4831],{"class":96,"line":4827},172,[94,4829,4830],{"class":120},".tag.warn",[94,4832,187],{"class":100},[94,4834,4836,4838,4840,4843],{"class":96,"line":4835},173,[94,4837,4420],{"class":192},[94,4839,196],{"class":100},[94,4841,4842],{"class":192},"#fef3c7",[94,4844,206],{"class":100},[94,4846,4848,4850,4852,4855],{"class":96,"line":4847},174,[94,4849,1478],{"class":192},[94,4851,196],{"class":100},[94,4853,4854],{"class":192},"#92400e",[94,4856,206],{"class":100},[94,4858,4860],{"class":96,"line":4859},175,[94,4861,237],{"class":100},[94,4863,4865],{"class":96,"line":4864},176,[94,4866,244],{"emptyLinePlaceholder":243},[94,4868,4870,4873],{"class":96,"line":4869},177,[94,4871,4872],{"class":120},".metric",[94,4874,187],{"class":100},[94,4876,4878,4880,4882,4884,4886],{"class":96,"line":4877},178,[94,4879,1838],{"class":192},[94,4881,196],{"class":100},[94,4883,4722],{"class":192},[94,4885,203],{"class":202},[94,4887,206],{"class":100},[94,4889,4891,4893,4895,4897],{"class":96,"line":4890},179,[94,4892,4732],{"class":192},[94,4894,196],{"class":100},[94,4896,4737],{"class":192},[94,4898,206],{"class":100},[94,4900,4902,4905,4907,4910],{"class":96,"line":4901},180,[94,4903,4904],{"class":192},"  font-variant-numeric",[94,4906,196],{"class":100},[94,4908,4909],{"class":192},"tabular-nums",[94,4911,206],{"class":100},[94,4913,4915,4917,4919,4921],{"class":96,"line":4914},181,[94,4916,1478],{"class":192},[94,4918,196],{"class":100},[94,4920,4812],{"class":192},[94,4922,206],{"class":100},[94,4924,4926],{"class":96,"line":4925},182,[94,4927,237],{"class":100},[94,4929,4931],{"class":96,"line":4930},183,[94,4932,244],{"emptyLinePlaceholder":243},[94,4934,4936,4939],{"class":96,"line":4935},184,[94,4937,4938],{"class":120},".metric.warn-m",[94,4940,187],{"class":100},[94,4942,4944,4946,4948,4951],{"class":96,"line":4943},185,[94,4945,1478],{"class":192},[94,4947,196],{"class":100},[94,4949,4950],{"class":192},"#b45309",[94,4952,206],{"class":100},[94,4954,4956],{"class":96,"line":4955},186,[94,4957,237],{"class":100},[94,4959,4961],{"class":96,"line":4960},187,[94,4962,244],{"emptyLinePlaceholder":243},[94,4964,4966,4969],{"class":96,"line":4965},188,[94,4967,4968],{"class":120},".track",[94,4970,187],{"class":100},[94,4972,4974,4976,4978,4980],{"class":96,"line":4973},189,[94,4975,579],{"class":192},[94,4977,196],{"class":100},[94,4979,399],{"class":192},[94,4981,206],{"class":100},[94,4983,4985,4987,4989,4992,4994],{"class":96,"line":4984},190,[94,4986,211],{"class":192},[94,4988,196],{"class":100},[94,4990,4991],{"class":192},"44",[94,4993,203],{"class":202},[94,4995,206],{"class":100},[94,4997,4999,5001,5003,5005,5007],{"class":96,"line":4998},191,[94,5000,4405],{"class":192},[94,5002,196],{"class":100},[94,5004,4676],{"class":192},[94,5006,203],{"class":202},[94,5008,206],{"class":100},[94,5010,5012,5014,5016,5018],{"class":96,"line":5011},192,[94,5013,4420],{"class":192},[94,5015,196],{"class":100},[94,5017,4425],{"class":192},[94,5019,206],{"class":100},[94,5021,5023,5026,5028,5031],{"class":96,"line":5022},193,[94,5024,5025],{"class":192},"  overflow",[94,5027,196],{"class":100},[94,5029,5030],{"class":192},"hidden",[94,5032,206],{"class":100},[94,5034,5036],{"class":96,"line":5035},194,[94,5037,237],{"class":100},[94,5039,5041],{"class":96,"line":5040},195,[94,5042,244],{"emptyLinePlaceholder":243},[94,5044,5046,5049],{"class":96,"line":5045},196,[94,5047,5048],{"class":120},".ball",[94,5050,187],{"class":100},[94,5052,5054,5056,5058,5060],{"class":96,"line":5053},197,[94,5055,579],{"class":192},[94,5057,196],{"class":100},[94,5059,427],{"class":192},[94,5061,206],{"class":100},[94,5063,5065,5067,5069,5071,5073],{"class":96,"line":5064},198,[94,5066,742],{"class":192},[94,5068,196],{"class":100},[94,5070,732],{"class":192},[94,5072,203],{"class":202},[94,5074,206],{"class":100},[94,5076,5078,5080,5082,5084],{"class":96,"line":5077},199,[94,5079,727],{"class":192},[94,5081,196],{"class":100},[94,5083,870],{"class":192},[94,5085,206],{"class":100},[94,5087,5089,5091,5093,5096,5098],{"class":96,"line":5088},200,[94,5090,193],{"class":192},[94,5092,196],{"class":100},[94,5094,5095],{"class":192},"24",[94,5097,203],{"class":202},[94,5099,206],{"class":100},[94,5101,5103,5105,5107,5109,5111],{"class":96,"line":5102},201,[94,5104,211],{"class":192},[94,5106,196],{"class":100},[94,5108,5095],{"class":192},[94,5110,203],{"class":202},[94,5112,206],{"class":100},[94,5114,5116,5118,5120,5122,5124],{"class":96,"line":5115},202,[94,5117,4405],{"class":192},[94,5119,196],{"class":100},[94,5121,262],{"class":192},[94,5123,265],{"class":202},[94,5125,206],{"class":100},[94,5127,5129,5131,5133,5136],{"class":96,"line":5128},203,[94,5130,4420],{"class":192},[94,5132,196],{"class":100},[94,5134,5135],{"class":192},"#6366f1",[94,5137,206],{"class":100},[94,5139,5141,5144,5147,5149],{"class":96,"line":5140},204,[94,5142,5143],{"class":192},"  will-change",[94,5145,5146],{"class":100},": transform, ",[94,5148,2694],{"class":192},[94,5150,206],{"class":100},[94,5152,5154],{"class":96,"line":5153},205,[94,5155,237],{"class":100},[94,5157,5159],{"class":96,"line":5158},206,[94,5160,244],{"emptyLinePlaceholder":243},[94,5162,5164,5167],{"class":96,"line":5163},207,[94,5165,5166],{"class":120},".note",[94,5168,187],{"class":100},[94,5170,5172,5174,5176,5178,5180,5182,5184],{"class":96,"line":5171},208,[94,5173,4292],{"class":192},[94,5175,196],{"class":100},[94,5177,4676],{"class":192},[94,5179,203],{"class":202},[94,5181,4299],{"class":192},[94,5183,4299],{"class":192},[94,5185,206],{"class":100},[94,5187,5189,5191,5193,5195,5197],{"class":96,"line":5188},209,[94,5190,1838],{"class":192},[94,5192,196],{"class":100},[94,5194,4722],{"class":192},[94,5196,203],{"class":202},[94,5198,206],{"class":100},[94,5200,5202,5204,5206,5209],{"class":96,"line":5201},210,[94,5203,1478],{"class":192},[94,5205,196],{"class":100},[94,5207,5208],{"class":192},"#94a3b8",[94,5210,206],{"class":100},[94,5212,5214],{"class":96,"line":5213},211,[94,5215,237],{"class":100},[94,5217,5219],{"class":96,"line":5218},212,[94,5220,244],{"emptyLinePlaceholder":243},[94,5222,5224,5227],{"class":96,"line":5223},213,[94,5225,5226],{"class":120},".actions",[94,5228,187],{"class":100},[94,5230,5232,5234,5236,5238],{"class":96,"line":5231},214,[94,5233,1743],{"class":192},[94,5235,196],{"class":100},[94,5237,4637],{"class":192},[94,5239,206],{"class":100},[94,5241,5243,5245,5247,5249,5251],{"class":96,"line":5242},215,[94,5244,4463],{"class":192},[94,5246,196],{"class":100},[94,5248,4676],{"class":192},[94,5250,203],{"class":202},[94,5252,206],{"class":100},[94,5254,5256,5259,5261,5264,5266],{"class":96,"line":5255},216,[94,5257,5258],{"class":192},"  margin-top",[94,5260,196],{"class":100},[94,5262,5263],{"class":192},"14",[94,5265,203],{"class":202},[94,5267,206],{"class":100},[94,5269,5271],{"class":96,"line":5270},217,[94,5272,237],{"class":100},[94,5274,5276],{"class":96,"line":5275},218,[94,5277,244],{"emptyLinePlaceholder":243},[94,5279,5281,5284],{"class":96,"line":5280},219,[94,5282,5283],{"class":120},".btn",[94,5285,187],{"class":100},[94,5287,5289,5291,5293,5295,5297,5300,5302],{"class":96,"line":5288},220,[94,5290,4242],{"class":192},[94,5292,196],{"class":100},[94,5294,4676],{"class":192},[94,5296,203],{"class":202},[94,5298,5299],{"class":192}," 16",[94,5301,203],{"class":202},[94,5303,206],{"class":100},[94,5305,5307,5309,5311,5313],{"class":96,"line":5306},221,[94,5308,629],{"class":192},[94,5310,196],{"class":100},[94,5312,806],{"class":192},[94,5314,206],{"class":100},[94,5316,5318,5320,5322,5324,5326],{"class":96,"line":5317},222,[94,5319,4405],{"class":192},[94,5321,196],{"class":100},[94,5323,4676],{"class":192},[94,5325,203],{"class":202},[94,5327,206],{"class":100},[94,5329,5331,5333,5335,5337],{"class":96,"line":5330},223,[94,5332,4420],{"class":192},[94,5334,196],{"class":100},[94,5336,5135],{"class":192},[94,5338,206],{"class":100},[94,5340,5342,5344,5346,5349],{"class":96,"line":5341},224,[94,5343,1478],{"class":192},[94,5345,196],{"class":100},[94,5347,5348],{"class":192},"white",[94,5350,206],{"class":100},[94,5352,5354,5356,5358,5360],{"class":96,"line":5353},225,[94,5355,4732],{"class":192},[94,5357,196],{"class":100},[94,5359,4737],{"class":192},[94,5361,206],{"class":100},[94,5363,5365,5368,5370,5373],{"class":96,"line":5364},226,[94,5366,5367],{"class":192},"  cursor",[94,5369,196],{"class":100},[94,5371,5372],{"class":192},"pointer",[94,5374,206],{"class":100},[94,5376,5378,5380,5382,5385,5387],{"class":96,"line":5377},227,[94,5379,1838],{"class":192},[94,5381,196],{"class":100},[94,5383,5384],{"class":192},"13",[94,5386,203],{"class":202},[94,5388,206],{"class":100},[94,5390,5392],{"class":96,"line":5391},228,[94,5393,237],{"class":100},[94,5395,5397],{"class":96,"line":5396},229,[94,5398,244],{"emptyLinePlaceholder":243},[94,5400,5402,5405],{"class":96,"line":5401},230,[94,5403,5404],{"class":120},".btn.active",[94,5406,187],{"class":100},[94,5408,5410,5412,5414,5417],{"class":96,"line":5409},231,[94,5411,4420],{"class":192},[94,5413,196],{"class":100},[94,5415,5416],{"class":192},"#4f46e5",[94,5418,206],{"class":100},[94,5420,5422],{"class":96,"line":5421},232,[94,5423,237],{"class":100},[94,5425,5427],{"class":96,"line":5426},233,[94,5428,244],{"emptyLinePlaceholder":243},[94,5430,5432,5435],{"class":96,"line":5431},234,[94,5433,5434],{"class":120},".btn.ghost",[94,5436,187],{"class":100},[94,5438,5440,5442,5444,5446],{"class":96,"line":5439},235,[94,5441,4420],{"class":192},[94,5443,196],{"class":100},[94,5445,4425],{"class":192},[94,5447,206],{"class":100},[94,5449,5451,5453,5455,5458],{"class":96,"line":5450},236,[94,5452,1478],{"class":192},[94,5454,196],{"class":100},[94,5456,5457],{"class":192},"#334155",[94,5459,206],{"class":100},[94,5461,5463],{"class":96,"line":5462},237,[94,5464,237],{"class":100},[94,5466,5468,5470,5472],{"class":96,"line":5467},238,[94,5469,168],{"class":100},[94,5471,1426],{"class":104},[94,5473,108],{"class":100},[80,5475,1382],{"id":1382},[344,5477,5478,5486,5491],{},[347,5479,5480,5482,5483,59],{},[26,5481,2620],{}," = 重算布局树，代价高；浏览器会批量，但 ",[26,5484,5485],{},"读布局属性会强制同步",[347,5487,5488,5490],{},[26,5489,2582],{}," = 重算绘制及之后；reflow 必然连带 repaint。",[347,5492,5493,5495,5496,5498,5499,396,5501,59],{},[26,5494,799],{}," 主要在合成阶段完成，适合做位移、旋转、缩放动画；位移动画优先 ",[21,5497,799],{},"，慎用 ",[21,5500,2691],{},[21,5502,2694],{},[1426,5504,5505],{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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 .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .s7hpK, html code.shiki .s7hpK{--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":90,"searchDepth":133,"depth":133,"links":5507},[5508,5512,5513,5514],{"id":2426,"depth":111,"text":2427,"children":5509},[5510,5511],{"id":2442,"depth":133,"text":2442},{"id":2458,"depth":133,"text":2459},{"id":2557,"depth":111,"text":2558},{"id":2648,"depth":111,"text":2649},{"id":1382,"depth":111,"text":1382},"frontend","2026-06-26","回流与重绘分别对应布局树与绘制指令的重新计算，以及为何 transform 动画大多不拖累渲染主线程。",{},{"title":2400,"description":5517},"blog\u002Freflow-repaint-transform",[5522,5523,5524],"browser","rendering","performance","9qGt4nC5IYw-1z--ZpE9qqITwfWBE18SKN7ZWLP5isc",{"id":5527,"title":5528,"body":5529,"category":5515,"date":6354,"description":6355,"draft":1441,"extension":1442,"meta":6356,"navigation":243,"path":71,"seo":6357,"stem":6358,"tags":6359,"__hash__":6360},"blog\u002Fblog\u002Fbrowser-rendering-pipeline.md","浏览器是如何渲染页面的？",{"type":10,"value":5530,"toc":6334},[5531,5534,5549,5555,5562,5568,5572,5698,5701,5714,5724,5728,5738,5752,5758,5761,5785,5789,5803,5807,5823,5846,5852,5941,5945,5952,5955,5979,5992,5996,6006,6010,6016,6077,6083,6095,6099,6105,6112,6115,6139,6145,6149,6166,6172,6181,6193,6197,6200,6204,6215,6219,6236,6240,6254,6260,6267,6271,6280,6282,6331],[13,5532,5528],{"id":5533},"浏览器是如何渲染页面的",[17,5535,5536,5537,5539,5540,5543,5544,5548],{},"当网络进程把 HTML 文档下载完成后，渲染进程会收到字节流，并往 ",[26,5538,2677],{}," 的消息队列里塞入一个 ",[26,5541,5542],{},"渲染任务","。主线程在 ",[53,5545,5547],{"href":5546},"\u002Fblog\u002Fjs-event-loop","事件循环"," 里取出该任务后，才开始「把文档变成屏幕上的像素」。",[17,5550,5551],{},[41,5552],{"alt":5553,"src":5554},"HTML 下载完成后渲染任务进入消息队列","\u002Fdemos\u002Fbrowser-rendering\u002Ftask-entry.svg",[17,5556,5557,5558,5561],{},"这不是一次性的函数调用，而是一条 ",[26,5559,5560],{},"流水线","：每个阶段有明确的输入和输出，上一阶段的产出是下一阶段的输入。可以把它想象成工厂里的装配线——材料从一端进去，成品从另一端出来。",[17,5563,5564],{},[41,5565],{"alt":5566,"src":5567},"渲染流水线总览：主线程五段 + 合成三段","\u002Fdemos\u002Fbrowser-rendering\u002Fpipeline-overview.svg",[80,5569,5571],{"id":5570},"总览八个阶段","总览：八个阶段",[368,5573,5574,5590],{},[371,5575,5576],{},[374,5577,5578,5581,5584,5587],{},[377,5579,5580],{},"阶段",[377,5582,5583],{},"执行者",[377,5585,5586],{},"输入",[377,5588,5589],{},"输出",[386,5591,5592,5605,5617,5630,5643,5656,5670,5684],{},[374,5593,5594,5597,5599,5602],{},[391,5595,5596],{},"HTML 解析",[391,5598,2677],{},[391,5600,5601],{},"HTML 字节流",[391,5603,5604],{},"DOM 树 + CSSOM 树",[374,5606,5607,5609,5611,5614],{},[391,5608,77],{},[391,5610,2677],{},[391,5612,5613],{},"DOM + CSSOM",[391,5615,5616],{},"带 Computed Style 的节点",[374,5618,5619,5622,5624,5627],{},[391,5620,5621],{},"布局 Layout",[391,5623,2677],{},[391,5625,5626],{},"样式树",[391,5628,5629],{},"布局树（几何信息）",[374,5631,5632,5635,5637,5640],{},[391,5633,5634],{},"分层 Layer",[391,5636,2677],{},[391,5638,5639],{},"布局树",[391,5641,5642],{},"图层树",[374,5644,5645,5648,5650,5653],{},[391,5646,5647],{},"绘制 Paint",[391,5649,2677],{},[391,5651,5652],{},"图层",[391,5654,5655],{},"绘制指令集（display list）",[374,5657,5658,5661,5664,5667],{},[391,5659,5660],{},"分块 Tiling",[391,5662,5663],{},"合成线程",[391,5665,5666],{},"绘制指令",[391,5668,5669],{},"图层小块",[374,5671,5672,5675,5678,5681],{},[391,5673,5674],{},"光栅化 Raster",[391,5676,5677],{},"GPU 进程",[391,5679,5680],{},"块信息",[391,5682,5683],{},"位图（bitmap）",[374,5685,5686,5689,5692,5695],{},[391,5687,5688],{},"画 Draw",[391,5690,5691],{},"合成线程 + GPU",[391,5693,5694],{},"位图",[391,5696,5697],{},"屏幕像素",[17,5699,5700],{},"记忆口诀：",[344,5702,5703,5709],{},[347,5704,5705,5708],{},[26,5706,5707],{},"主线程","：Parse → Style → Layout → Layer → Paint",[347,5710,5711,5713],{},[26,5712,5691],{},"：Tiling → Raster → Draw",[17,5715,5716,5717,5719,5720,5723],{},"主线程极其繁忙——",[53,5718,5547],{"href":5546}," 里还要执行 JS、处理事件、跑计时器。渲染只是它众多职责之一；一旦某段 JS 长时间占用主线程，整条渲染流水线都会暂停（见 ",[53,5721,5722],{"href":1423},"reflow、repaint 与 transform","）。",[80,5725,5727],{"id":5726},"第一步html-解析","第一步：HTML 解析",[17,5729,5730,5731,5734,5735,59],{},"解析 HTML 时，遇到 ",[26,5732,5733],{},"CSS 就解析 CSS","，遇到 ",[26,5736,5737],{},"JS 就执行 JS",[17,5739,5740,5741,5744,5745,33,5748,5751],{},"为提高效率，浏览器在正式解析前还会启动 ",[26,5742,5743],{},"预解析（preload scanner）","，提前下载 HTML 里 ",[21,5746,5747],{},"\u003Clink>",[21,5749,5750],{},"\u003Cscript>"," 引用的外部资源，减少主线程空等。",[17,5753,5754],{},[41,5755],{"alt":5756,"src":5757},"解析 HTML 得到 DOM 树与 CSSOM 树","\u002Fdemos\u002Fbrowser-rendering\u002Fparse-dom-cssom.svg",[17,5759,5760],{},"解析完成后得到两棵树：",[344,5762,5763,5769],{},[347,5764,5765,5768],{},[26,5766,5767],{},"DOM 树","：文档结构，对应 HTML 标签的嵌套关系",[347,5770,5771,5774,5775,33,5778,5781,5782,5784],{},[26,5772,5773],{},"CSSOM 树","：汇总 ",[26,5776,5777],{},"用户代理默认样式",[21,5779,5780],{},"\u003Cstyle>","、外链 CSS、行内 ",[21,5783,1426],{}," 等全部 CSS 规则",[440,5786,5788],{"id":5787},"css-为什么不阻塞-html-解析","CSS 为什么不阻塞 HTML 解析？",[17,5790,5791,5792,5795,5796,5799,5800,59],{},"主线程扫到 ",[21,5793,5794],{},"\u003Clink rel=\"stylesheet\">"," 时，即使 CSS 文件还没下载完，",[26,5797,5798],{},"也不会停下来等","，会继续解析后面的 HTML。CSS 的下载与解析由预解析等机制并行处理，因此 ",[26,5801,5802],{},"CSS 默认不阻塞 DOM 树的构建",[440,5804,5806],{"id":5805},"js-为什么会阻塞-html-解析","JS 为什么会阻塞 HTML 解析？",[17,5808,5791,5809,2322,5812,5814,5815,5818,5819,5822],{},[26,5810,5811],{},"同步",[21,5813,5750],{}," 时，会 ",[26,5816,5817],{},"暂停 HTML 解析","，先等 JS 下载并执行完。因为 JS 可能通过 ",[21,5820,5821],{},"document.write"," 等方式修改 DOM，必须保证 DOM 生成顺序与脚本执行顺序一致。",[17,5824,5825,33,5828,33,5831,5834,5835,5838,5839,5841,5842,5845],{},[21,5826,5827],{},"defer",[21,5829,5830],{},"async",[21,5832,5833],{},"type=\"module\""," 等会改变具体行为，但 ",[26,5836,5837],{},"「同步脚本阻塞解析」"," 是默认规则，也是 ",[21,5840,5750],{}," 放 ",[21,5843,5844],{},"\u003C\u002Fbody>"," 前、或把脚本移到底部的原因。",[17,5847,5848],{},[41,5849],{"alt":5850,"src":5851},"link 不阻塞解析，同步 script 会阻塞","\u002Fdemos\u002Fbrowser-rendering\u002Fcss-js-parse.svg",[2484,5853,5855],{"lang":89,"title":5854},"同步脚本阻塞 DOM 构建",[85,5856,5858],{"className":87,"code":5857,"language":89,"meta":90,"style":90},"\u003Cp id=\"before\">before\u003C\u002Fp>\n\u003Cscript>\n  document.querySelector('#before').textContent = 'changed'\n\u003C\u002Fscript>\n\u003Cp id=\"after\">after\u003C\u002Fp>\n\u003C!-- 解析器在遇到 script 时必须先执行完再继续 -->\n",[21,5859,5860,5880,5888,5908,5916,5936],{"__ignoreMap":90},[94,5861,5862,5864,5866,5868,5870,5873,5876,5878],{"class":96,"line":97},[94,5863,101],{"class":100},[94,5865,17],{"class":104},[94,5867,965],{"class":120},[94,5869,124],{"class":100},[94,5871,5872],{"class":127},"\"before\"",[94,5874,5875],{"class":100},">before\u003C\u002F",[94,5877,17],{"class":104},[94,5879,108],{"class":100},[94,5881,5882,5884,5886],{"class":96,"line":111},[94,5883,101],{"class":100},[94,5885,3288],{"class":104},[94,5887,108],{"class":100},[94,5889,5890,5893,5895,5897,5900,5903,5905],{"class":96,"line":133},[94,5891,5892],{"class":100},"  document.",[94,5894,2510],{"class":120},[94,5896,867],{"class":100},[94,5898,5899],{"class":127},"'#before'",[94,5901,5902],{"class":100},").textContent ",[94,5904,124],{"class":202},[94,5906,5907],{"class":127}," 'changed'\n",[94,5909,5910,5912,5914],{"class":96,"line":155},[94,5911,168],{"class":100},[94,5913,3288],{"class":104},[94,5915,108],{"class":100},[94,5917,5918,5920,5922,5924,5926,5929,5932,5934],{"class":96,"line":165},[94,5919,101],{"class":100},[94,5921,17],{"class":104},[94,5923,965],{"class":120},[94,5925,124],{"class":100},[94,5927,5928],{"class":127},"\"after\"",[94,5930,5931],{"class":100},">after\u003C\u002F",[94,5933,17],{"class":104},[94,5935,108],{"class":100},[94,5937,5938],{"class":96,"line":240},[94,5939,5940],{"class":2533},"\u003C!-- 解析器在遇到 script 时必须先执行完再继续 -->\n",[80,5942,5944],{"id":5943},"第二步样式计算","第二步：样式计算",[17,5946,5947,5948,5951],{},"主线程遍历 DOM，结合 CSSOM，为每个节点算出最终用于渲染的样式，即 ",[26,5949,5950],{},"Computed Style","（计算样式）。",[17,5953,5954],{},"此阶段会把许多值「算实」：",[344,5956,5957,5965,5972],{},[347,5958,5959,5961,5962],{},[21,5960,290],{}," → ",[21,5963,5964],{},"rgb(255, 0, 0)",[347,5966,5967,5961,5969,5971],{},[21,5968,1035],{},[21,5970,203],{},"（在父级字号已知时）",[347,5973,5974,5975,5978],{},"经过 ",[53,5976,5977],{"href":76},"层叠、继承、默认值"," 得到每个属性的最终声明",[17,5980,2586,5981,5984,5985,5987,5988,5991],{},[26,5982,5983],{},"百分比宽高"," 等仍可能待定——它们依赖 ",[53,5986,1132],{"href":1444},"，要在 ",[26,5989,5990],{},"布局"," 阶段结合几何上下文才能定稿。",[80,5993,5995],{"id":5994},"第三步布局layout","第三步：布局（Layout）",[17,5997,5998,5999,6002,6003,59],{},"布局阶段遍历带样式的节点，计算 ",[26,6000,6001],{},"几何信息","：宽高、位置（相对包含块）、行盒高度等，产出 ",[26,6004,6005],{},"布局树（Layout Tree）",[440,6007,6009],{"id":6008},"布局树-dom-树","布局树 ≠ DOM 树",[17,6011,6012,6013,342],{},"两棵树 ",[26,6014,6015],{},"常常不是一一对应",[368,6017,6018,6029],{},[371,6019,6020],{},[374,6021,6022,6025,6027],{},[377,6023,6024],{},"情况",[377,6026,5767],{},[377,6028,5639],{},[386,6030,6031,6047,6066],{},[374,6032,6033,6038,6041],{},[391,6034,6035],{},[21,6036,6037],{},"display: none",[391,6039,6040],{},"有节点",[391,6042,6043,6044,5639],{},"无几何信息，",[26,6045,6046],{},"不进",[374,6048,6049,6057,6060],{},[391,6050,6051,396,6054],{},[21,6052,6053],{},"::before",[21,6055,6056],{},"::after",[391,6058,6059],{},"无对应节点",[391,6061,6062,6063,5639],{},"有几何信息，",[26,6064,6065],{},"会进",[374,6067,6068,6071,6074],{},[391,6069,6070],{},"匿名行盒 \u002F 块盒",[391,6072,6073],{},"无独立节点",[391,6075,6076],{},"布局算法自动生成",[17,6078,6079],{},[41,6080],{"alt":6081,"src":6082},"DOM 树与布局树并不总是一一对应","\u002Fdemos\u002Fbrowser-rendering\u002Fdom-vs-layout.svg",[17,6084,6085,6086,6088,6089,6092,6093,59],{},"布局完成后，每个可见元素在屏幕上「占哪块地方」就确定了。改宽高、边距、",[21,6087,1639],{}," 等会触发 ",[26,6090,6091],{},"reflow（回流）","，需要重新跑 Layout 及之后阶段——详见 ",[53,6094,1424],{"href":1423},[80,6096,6098],{"id":6097},"第四步分层layer","第四步：分层（Layer）",[17,6100,6101,6102,59],{},"主线程按策略把布局树 ",[26,6103,6104],{},"分成多个图层（Layer）",[17,6106,6107,6108,6111],{},"分层是性能优化：将来只改某一层的样式或内容时，可以 ",[26,6109,6110],{},"只更新该层"," 的后续步骤，而不必重算整页。",[17,6113,6114],{},"常见影响因素：",[344,6116,6117,6120,6127,6134],{},[347,6118,6119],{},"滚动容器、滚动条",[347,6121,6122,6123,6126],{},"堆叠上下文（",[21,6124,6125],{},"z-index"," 等）",[347,6128,6129,33,6131],{},[21,6130,799],{},[21,6132,6133],{},"opacity",[347,6135,6136,6138],{},[21,6137,811],{}," 提示浏览器提前分层",[17,6140,6141,6142,59],{},"分层策略因浏览器而异，属于实现细节；开发上只需知道：",[26,6143,6144],{},"分层是为了增量更新更快",[80,6146,6148],{"id":6147},"第五步绘制paint","第五步：绘制（Paint）",[17,6150,6151,6152,6155,6156,6158,6159,33,6162,6165],{},"主线程为 ",[26,6153,6154],{},"每一层"," 单独生成 ",[26,6157,5655],{},"，描述这一层该怎么画——类似 Canvas 的 ",[21,6160,6161],{},"fillRect",[21,6163,6164],{},"drawText"," 等调用序列。",[17,6167,6168],{},[41,6169],{"alt":6170,"src":6171},"图层与绘制指令","\u002Fdemos\u002Fbrowser-rendering\u002Flayers-paint.svg",[17,6173,6174,6177,6178,59],{},[26,6175,6176],{},"渲染主线程的工作到这里为止。"," 之后把各层的绘制信息交给 ",[26,6179,6180],{},"合成线程（Compositor Thread）",[17,6182,6183,6184,33,6186,6188,6189,6192],{},"改 ",[21,6185,2044],{},[21,6187,2575],{}," 等可见但不改布局的样式，可能只需 ",[26,6190,6191],{},"repaint","（重算绘制及之后），不必完整 reflow。",[80,6194,6196],{"id":6195},"第六八步分块光栅化上屏","第六～八步：分块、光栅化、上屏",[17,6198,6199],{},"合成线程接手后：",[440,6201,6203],{"id":6202},"_1-分块tiling","1. 分块（Tiling）",[17,6205,6206,6207,6210,6211,6214],{},"把每一层划成更小的 ",[26,6208,6209],{},"图块（tile）","，交给 ",[26,6212,6213],{},"线程池"," 并行处理，避免单次任务过大。",[440,6216,6218],{"id":6217},"_2-光栅化raster","2. 光栅化（Raster）",[17,6220,6221,6222,6224,6225,6227,6228,6231,6232,6235],{},"把块信息交给 ",[26,6223,5677],{},"，由 GPU 以极高速度转成 ",[26,6226,5683],{},"——每个块是一小块像素矩阵。靠近 ",[26,6229,6230],{},"视口"," 的块会 ",[26,6233,6234],{},"优先"," 光栅化，所以你滚动时远处内容可能稍晚才清晰。",[440,6237,6239],{"id":6238},"_3-画draw","3. 画（Draw）",[17,6241,6242,6243,6246,6247,6249,6250,6253],{},"合成线程为每块位图生成 ",[26,6244,6245],{},"指引（quad）","：在屏幕上的位置、旋转、缩放等。",[21,6248,799],{}," 的变形主要发生在此阶段，",[26,6251,6252],{},"不经过主线程的 Layout\u002FPaint","，因此动画往往更顺滑。",[17,6255,6256],{},[41,6257],{"alt":6258,"src":6259},"分块、光栅化、quad、GPU 上屏","\u002Fdemos\u002Fbrowser-rendering\u002Fcompositor-gpu.svg",[17,6261,6262,6263,6266],{},"最后 GPU 进程通过系统调用把结果交给显卡。",[26,6264,6265],{},"渲染进程跑在沙盒里","，不能直接碰硬件，崩溃也不会拖垮整个系统。",[80,6268,6270],{"id":6269},"常见面试答法精简版","常见面试答法（精简版）",[2592,6272,6273],{},[17,6274,6275,6276,6279],{},"网络进程收到 HTML 后，产生渲染任务进入渲染主线程的消息队列；事件循环取出任务，开启流水线：",[26,6277,6278],{},"解析 → 样式 → 布局 → 分层 → 绘制 → 分块 → 光栅化 → 画","。主线程负责前五步，合成线程和 GPU 负责后三步。CSS 不阻塞 DOM 构建，同步 JS 会阻塞解析。改动样式可能触发 reflow\u002Frepaint，是流水线运行中的局部重跑。",[80,6281,1382],{"id":1382},[344,6283,6284,6291,6296,6304,6319],{},[347,6285,6286,6287,6290],{},"渲染由 ",[26,6288,6289],{},"事件循环调度","，是主线程与合成线程协作的流水线。",[347,6292,6293,59],{},[26,6294,6295],{},"DOM + CSSOM → 样式 → 布局 → 图层 → 绘制指令 → 位图 → 屏幕",[347,6297,6298,1400,6301,59],{},[26,6299,6300],{},"同步 JS 阻塞解析",[26,6302,6303],{},"CSS 默认不阻塞 DOM",[347,6305,6306,6309,6310,6309,6313,1400,6316,6318],{},[26,6307,6308],{},"Layout 定几何","，",[26,6311,6312],{},"Paint 出指令",[26,6314,6315],{},"Compositor + GPU 上屏",[21,6317,799],{}," 多在合成阶段完成。",[347,6320,6321,6322,33,6325,33,6327,6330],{},"与 ",[53,6323,6324],{"href":76},"CSS 属性计算",[53,6326,1132],{"href":1444},[53,6328,6329],{"href":1423},"reflow\u002Frepaint"," 串联起来，就是前端性能优化的完整地图。",[1426,6332,6333],{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":90,"searchDepth":133,"depth":133,"links":6335},[6336,6337,6341,6342,6345,6346,6347,6352,6353],{"id":5570,"depth":111,"text":5571},{"id":5726,"depth":111,"text":5727,"children":6338},[6339,6340],{"id":5787,"depth":133,"text":5788},{"id":5805,"depth":133,"text":5806},{"id":5943,"depth":111,"text":5944},{"id":5994,"depth":111,"text":5995,"children":6343},[6344],{"id":6008,"depth":133,"text":6009},{"id":6097,"depth":111,"text":6098},{"id":6147,"depth":111,"text":6148},{"id":6195,"depth":111,"text":6196,"children":6348},[6349,6350,6351],{"id":6202,"depth":133,"text":6203},{"id":6217,"depth":133,"text":6218},{"id":6238,"depth":133,"text":6239},{"id":6269,"depth":111,"text":6270},{"id":1382,"depth":111,"text":1382},"2026-06-25","从 HTML 解析到 GPU 上屏，详解渲染主线程与合成线程分工，以及 DOM 树、布局树、图层与位图如何串联成流水线。",{},{"title":5528,"description":6355},"blog\u002Fbrowser-rendering-pipeline",[5522,5523,1450],"4ob-xZgG6ctKPWs2Yp8VJvQBEfU9jF8aTlNCAjPdHBg",{"id":6362,"title":6363,"body":6364,"category":2486,"date":7614,"description":7615,"draft":1441,"extension":1442,"meta":7616,"navigation":243,"path":5546,"seo":7617,"stem":7618,"tags":7619,"__hash__":7621},"blog\u002Fblog\u002Fjs-event-loop.md","浏览器事件循环：从进程模型到任务队列",{"type":10,"value":6365,"toc":7596},[6366,6369,6379,6382,6385,6389,6396,6402,6406,6416,6422,6426,6432,6438,6454,6458,6461,6478,6481,6487,6493,6516,6524,6533,6537,6544,6570,6573,6579,6589,6595,6601,6605,6620,6624,6631,6826,6841,6844,7354,7358,7368,7376,7395,7404,7407,7467,7470,7520,7523,7527,7538,7542,7548,7562,7564,7593],[13,6367,6363],{"id":6368},"浏览器事件循环从进程模型到任务队列",[17,6370,6371,6372,6374,6375,6378],{},"JavaScript 常被说成「单线程」，但真正决定页面是否流畅的，是浏览器里那条繁忙的 ",[26,6373,2677],{},"。它既要解析 HTML\u002FCSS、布局绘制，又要执行 JS 与事件回调——这些任务如何排队、谁先谁后，就是 ",[26,6376,6377],{},"事件循环（消息循环）"," 要回答的问题。",[17,6380,6381],{},"下文从浏览器进程模型讲起，再到异步模型、阻塞渲染的实测，以及 W3C 与 Chrome 对任务队列的最新理解。",[80,6383,6384],{"id":6384},"浏览器的进程与线程",[440,6386,6388],{"id":6387},"进程是什么","进程是什么？",[17,6390,6391,6392,6395],{},"程序运行需要专属的内存空间，这块空间可以理解为 ",[26,6393,6394],{},"进程","。每个应用至少有一个进程；进程之间相互独立，若要通信也需要双方同意。",[17,6397,6398],{},[41,6399],{"alt":6400,"src":6401},"进程与内存空间示意图","\u002Fdemos\u002Fevent-loop\u002Fprocess.png",[440,6403,6405],{"id":6404},"线程是什么","线程是什么？",[17,6407,6408,6409,6412,6413,6415],{},"有了进程，才能在其中运行代码。执行代码的单元叫 ",[26,6410,6411],{},"线程","。进程启动后会自动创建一个线程运行代码，称为 ",[26,6414,5707],{},"；若需并行执行多段代码，进程内还可再开更多线程。",[17,6417,6418],{},[41,6419],{"alt":6420,"src":6421},"进程内的主线程与额外线程","\u002Fdemos\u002Fevent-loop\u002Fthread.png",[440,6423,6425],{"id":6424},"浏览器有哪些进程","浏览器有哪些进程？",[17,6427,6428,6431],{},[26,6429,6430],{},"浏览器是多进程、多线程应用。"," 启动后会拉起多个进程，以降低相互影响和连环崩溃的风险。可在浏览器任务管理器中查看当前进程列表。",[17,6433,6434],{},[41,6435],{"alt":6436,"src":6437},"浏览器主要进程示意","\u002Fdemos\u002Fevent-loop\u002Fbrowser.png",[17,6439,6440,6441,6444,6445,6447,6448,6453],{},"与前端开发最相关的是 ",[26,6442,6443],{},"渲染进程","：启动后会开启 ",[26,6446,2677],{},"，负责执行 HTML、CSS、JavaScript。默认情况下，每个标签页对应一个渲染进程，标签页之间互不影响。（Chrome 的进程模型仍在演进，详见 ",[53,6449,6452],{"href":6450,"rel":6451},"https:\u002F\u002Fchromium.googlesource.com\u002Fchromium\u002Fsrc\u002F+\u002Fmain\u002Fdocs\u002Fprocess_model_and_site_isolation.md#Modes-and-Availability",[57],"Chrome 官方说明","。）",[80,6455,6457],{"id":6456},"渲染主线程如何工作","渲染主线程如何工作？",[17,6459,6460],{},"渲染主线程是浏览器中最繁忙的线程，典型工作包括：",[344,6462,6463,6466,6469,6472,6475],{},[347,6464,6465],{},"解析 HTML、CSS",[347,6467,6468],{},"计算样式、布局、处理图层",[347,6470,6471],{},"以约 60fps 重绘页面",[347,6473,6474],{},"执行全局 JS、事件处理函数、计时器回调",[347,6476,6477],{},"……",[17,6479,6480],{},"这么多任务如何调度？例如：JS 执行到一半时用户点了按钮，要立即处理点击吗？计时器到时了，要立即跑回调吗？点击与计时器同时到来，先处理谁？",[17,6482,6483,6484,59],{},"主线程的做法是：",[26,6485,6486],{},"排队",[17,6488,6489],{},[41,6490],{"alt":6491,"src":6492},"事件循环与消息队列","\u002Fdemos\u002Fevent-loop\u002Fqueue.png",[1664,6494,6495,6502,6509],{},[347,6496,6497,6498,6501],{},"渲染主线程进入一个 ",[26,6499,6500],{},"不会结束的循环","（事件循环）。",[347,6503,6504,6505,6508],{},"每次循环检查 ",[26,6506,6507],{},"消息队列","：有任务则取出第一个执行，执行完再进入下一轮；没有任务则休眠。",[347,6510,6511,6512,6515],{},"其他线程（含其他进程的线程）可随时把任务加到队列 ",[26,6513,6514],{},"末尾","；若主线程在休眠，会被唤醒继续取任务。",[17,6517,6518,6519,815,6521,59],{},"整条链路也叫 ",[26,6520,5547],{},[26,6522,6523],{},"消息循环",[2592,6525,6526],{},[17,6527,6528,6529,6532],{},"思考题：为什么渲染进程不用多个线程并行做解析、布局、绘制？",[6530,6531],"br",{},"\n简答：DOM 与样式状态需要一致的可预测顺序；多线程并行改同一棵 DOM 树会带来同步与竞态难题，单主线程 + 队列调度是更稳妥的工程取舍（GPU 合成等仍可由其他线程辅助）。",[80,6534,6536],{"id":6535},"异步主线程不能阻塞","异步：主线程不能阻塞",[17,6538,6539,6540,6543],{},"有些任务 ",[26,6541,6542],{},"无法立刻完成","，例如：",[344,6545,6546,6555,6564],{},[347,6547,6548,6549,33,6552],{},"计时器：",[21,6550,6551],{},"setTimeout",[21,6553,6554],{},"setInterval",[347,6556,6557,6558,33,6561],{},"网络：",[21,6559,6560],{},"XHR",[21,6562,6563],{},"Fetch",[347,6565,6566,6567],{},"用户操作：",[21,6568,6569],{},"addEventListener",[17,6571,6572],{},"若主线程一直等到「时间到了」「请求返回」「用户点击」，就会长期阻塞，页面卡死：",[17,6574,6575],{},[41,6576],{"alt":6577,"src":6578},"同步等待导致主线程阻塞","\u002Fdemos\u002Fevent-loop\u002Fsync.png",[17,6580,6581,6582,6585,6586,342],{},"渲染主线程承担页面更新与交互，",[26,6583,6584],{},"绝不能被长时间阻塞","。浏览器因此采用 ",[26,6587,6588],{},"异步",[17,6590,6591],{},[41,6592],{"alt":6593,"src":6594},"异步模型：其他线程处理，回调入队","\u002Fdemos\u002Fevent-loop\u002Fasync.png",[17,6596,6597,6598],{},"主线程把计时、网络、监听等交给其他线程，自己继续执行后续代码；待时机成熟，将回调包装成任务加入消息队列末尾，由主线程在空闲时调度。",[26,6599,6600],{},"异步模式下，主线程不会因等待 I\u002FO 而空转阻塞。",[440,6602,6604],{"id":6603},"如何理解-js-的异步面试要点","如何理解 JS 的异步？（面试要点）",[344,6606,6607,6614,6617],{},[347,6608,6609,6610,6613],{},"JS 运行在渲染主线程中，",[26,6611,6612],{},"同一时刻只有一条执行栈","，故常被称为单线程语言。",[347,6615,6616],{},"主线程还要负责渲染；若大量任务同步等待，队列里其他任务无法执行，页面无法及时更新。",[347,6618,6619],{},"异步做法：计时、网络、事件等交由其他线程；完成后把回调入队，主线程按序执行。",[80,6621,6623],{"id":6622},"js-为何会阻碍渲染","JS 为何会阻碍渲染？",[17,6625,6626,6627,6630],{},"改 DOM 与真正画到屏幕上并非同一瞬间完成。若主线程正在执行一段 ",[26,6628,6629],{},"长时间占用的 JS","，渲染任务只能等在队列后面。",[2484,6632,6634],{"lang":89,"title":6633},"主线程阻塞导致画面延迟更新",[85,6635,6637],{"className":87,"code":6636,"language":89,"meta":90,"style":90},"\u003Ch1>Hello, Event Loop!\u003C\u002Fh1>\n\u003Cbutton>change\u003C\u002Fbutton>\n\u003Cscript>\n  const h1 = document.querySelector('h1')\n  const btn = document.querySelector('button')\n\n  function delay(duration) {\n    const start = Date.now()\n    while (Date.now() - start \u003C duration) {}\n  }\n\n  btn.onclick = function () {\n    h1.textContent = '页面已更新！'\n    delay(3000)\n  }\n\u003C\u002Fscript>\n",[21,6638,6639,6652,6665,6673,6692,6712,6716,6731,6747,6768,6772,6776,6792,6802,6814,6818],{"__ignoreMap":90},[94,6640,6641,6643,6645,6648,6650],{"class":96,"line":97},[94,6642,101],{"class":100},[94,6644,13],{"class":104},[94,6646,6647],{"class":100},">Hello, Event Loop!\u003C\u002F",[94,6649,13],{"class":104},[94,6651,108],{"class":100},[94,6653,6654,6656,6658,6661,6663],{"class":96,"line":111},[94,6655,101],{"class":100},[94,6657,3180],{"class":104},[94,6659,6660],{"class":100},">change\u003C\u002F",[94,6662,3180],{"class":104},[94,6664,108],{"class":100},[94,6666,6667,6669,6671],{"class":96,"line":133},[94,6668,101],{"class":100},[94,6670,3288],{"class":104},[94,6672,108],{"class":100},[94,6674,6675,6677,6679,6681,6683,6685,6687,6690],{"class":96,"line":155},[94,6676,3510],{"class":202},[94,6678,1831],{"class":192},[94,6680,2504],{"class":202},[94,6682,2507],{"class":100},[94,6684,2510],{"class":120},[94,6686,867],{"class":100},[94,6688,6689],{"class":127},"'h1'",[94,6691,2518],{"class":100},[94,6693,6694,6696,6699,6701,6703,6705,6707,6710],{"class":96,"line":165},[94,6695,3510],{"class":202},[94,6697,6698],{"class":192}," btn",[94,6700,2504],{"class":202},[94,6702,2507],{"class":100},[94,6704,2510],{"class":120},[94,6706,867],{"class":100},[94,6708,6709],{"class":127},"'button'",[94,6711,2518],{"class":100},[94,6713,6714],{"class":96,"line":240},[94,6715,244],{"emptyLinePlaceholder":243},[94,6717,6718,6721,6724,6726,6729],{"class":96,"line":247},[94,6719,6720],{"class":202},"  function",[94,6722,6723],{"class":120}," delay",[94,6725,867],{"class":100},[94,6727,6728],{"class":3480},"duration",[94,6730,3484],{"class":100},[94,6732,6733,6735,6738,6740,6743,6745],{"class":96,"line":255},[94,6734,3745],{"class":202},[94,6736,6737],{"class":192}," start",[94,6739,2504],{"class":202},[94,6741,6742],{"class":100}," Date.",[94,6744,3481],{"class":120},[94,6746,3583],{"class":100},[94,6748,6749,6752,6755,6757,6759,6761,6763,6765],{"class":96,"line":270},[94,6750,6751],{"class":202},"    while",[94,6753,6754],{"class":100}," (Date.",[94,6756,3481],{"class":120},[94,6758,3611],{"class":100},[94,6760,3521],{"class":202},[94,6762,3432],{"class":100},[94,6764,101],{"class":202},[94,6766,6767],{"class":100}," duration) {}\n",[94,6769,6770],{"class":96,"line":283},[94,6771,4130],{"class":100},[94,6773,6774],{"class":96,"line":295},[94,6775,244],{"emptyLinePlaceholder":243},[94,6777,6778,6781,6784,6786,6789],{"class":96,"line":644},[94,6779,6780],{"class":100},"  btn.",[94,6782,6783],{"class":120},"onclick",[94,6785,2504],{"class":202},[94,6787,6788],{"class":202}," function",[94,6790,6791],{"class":100}," () {\n",[94,6793,6794,6797,6799],{"class":96,"line":659},[94,6795,6796],{"class":100},"    h1.textContent ",[94,6798,124],{"class":202},[94,6800,6801],{"class":127}," '页面已更新！'\n",[94,6803,6804,6807,6809,6812],{"class":96,"line":4},[94,6805,6806],{"class":120},"    delay",[94,6808,867],{"class":100},[94,6810,6811],{"class":192},"3000",[94,6813,2518],{"class":100},[94,6815,6816],{"class":96,"line":668},[94,6817,4130],{"class":100},[94,6819,6820,6822,6824],{"class":96,"line":676},[94,6821,168],{"class":100},[94,6823,3288],{"class":104},[94,6825,108],{"class":100},[17,6827,6828,6829,6832,6833,6840],{},"点击按钮后：",[21,6830,6831],{},"textContent"," 虽已修改，但 ",[26,6834,6835,6836,6839],{},"画面要等 ",[21,6837,6838],{},"delay(3000)"," 跑完"," 才会更新——因为渲染步骤也要主线程空闲才能执行。",[17,6842,6843],{},"下方可亲自点击体验（约 3 秒内标题不会变，之后才刷新）：",[2716,6845,6847],{"title":6846},"JS 阻塞渲染",[85,6848,6850],{"className":2721,"code":6849,"language":2723,"meta":90,"style":90},"\u003Ctemplate>\n  \u003Cdiv class=\"demo\">\n    \u003Ch1>{{ title }}\u003C\u002Fh1>\n    \u003Cp class=\"hint\">点击按钮后，标题会延迟约 3 秒才变化。\u003C\u002Fp>\n    \u003Cbutton class=\"btn\" @click=\"onChange\">change\u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { ref } from 'vue'\n\nconst title = ref('Hello, Event Loop!')\n\nfunction delay(duration) {\n  const start = Date.now()\n  while (Date.now() - start \u003C duration) {}\n}\n\nfunction onChange() {\n  title.value = '页面已更新！'\n  delay(3000)\n}\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n.demo {\n  padding: 24px;\n  font-family: system-ui, sans-serif;\n  text-align: center;\n}\n\nh1 {\n  margin: 0 0 12px;\n  font-size: 1.5rem;\n}\n\n.hint {\n  margin: 0 0 16px;\n  color: #64748b;\n  font-size: 0.9rem;\n}\n\n.btn {\n  padding: 10px 20px;\n  border: none;\n  border-radius: 8px;\n  background: #6366f1;\n  color: white;\n  font-weight: 600;\n  cursor: pointer;\n}\n\u003C\u002Fstyle>\n",[21,6851,6852,6860,6875,6888,6908,6933,6941,6949,6953,6963,6974,6978,6996,7000,7012,7026,7045,7049,7053,7062,7071,7082,7086,7094,7098,7108,7115,7127,7141,7152,7156,7160,7166,7183,7196,7200,7204,7211,7227,7237,7250,7254,7258,7264,7280,7290,7302,7312,7322,7332,7342,7346],{"__ignoreMap":90},[94,6853,6854,6856,6858],{"class":96,"line":97},[94,6855,101],{"class":100},[94,6857,2732],{"class":104},[94,6859,108],{"class":100},[94,6861,6862,6864,6866,6868,6870,6873],{"class":96,"line":111},[94,6863,114],{"class":100},[94,6865,117],{"class":104},[94,6867,121],{"class":120},[94,6869,124],{"class":100},[94,6871,6872],{"class":127},"\"demo\"",[94,6874,108],{"class":100},[94,6876,6877,6879,6881,6884,6886],{"class":96,"line":133},[94,6878,136],{"class":100},[94,6880,13],{"class":104},[94,6882,6883],{"class":100},">{{ title }}\u003C\u002F",[94,6885,13],{"class":104},[94,6887,108],{"class":100},[94,6889,6890,6892,6894,6896,6898,6901,6904,6906],{"class":96,"line":155},[94,6891,136],{"class":100},[94,6893,17],{"class":104},[94,6895,121],{"class":120},[94,6897,124],{"class":100},[94,6899,6900],{"class":127},"\"hint\"",[94,6902,6903],{"class":100},">点击按钮后，标题会延迟约 3 秒才变化。\u003C\u002F",[94,6905,17],{"class":104},[94,6907,108],{"class":100},[94,6909,6910,6912,6914,6916,6918,6920,6922,6924,6927,6929,6931],{"class":96,"line":165},[94,6911,136],{"class":100},[94,6913,3180],{"class":104},[94,6915,121],{"class":120},[94,6917,124],{"class":100},[94,6919,3187],{"class":127},[94,6921,3198],{"class":120},[94,6923,124],{"class":100},[94,6925,6926],{"class":127},"\"onChange\"",[94,6928,6660],{"class":100},[94,6930,3180],{"class":104},[94,6932,108],{"class":100},[94,6934,6935,6937,6939],{"class":96,"line":240},[94,6936,158],{"class":100},[94,6938,117],{"class":104},[94,6940,108],{"class":100},[94,6942,6943,6945,6947],{"class":96,"line":247},[94,6944,168],{"class":100},[94,6946,2732],{"class":104},[94,6948,108],{"class":100},[94,6950,6951],{"class":96,"line":255},[94,6952,244],{"emptyLinePlaceholder":243},[94,6954,6955,6957,6959,6961],{"class":96,"line":270},[94,6956,101],{"class":100},[94,6958,3288],{"class":104},[94,6960,3291],{"class":120},[94,6962,108],{"class":100},[94,6964,6965,6967,6970,6972],{"class":96,"line":283},[94,6966,3299],{"class":202},[94,6968,6969],{"class":100}," { ref } ",[94,6971,3305],{"class":202},[94,6973,3308],{"class":127},[94,6975,6976],{"class":96,"line":295},[94,6977,244],{"emptyLinePlaceholder":243},[94,6979,6980,6982,6985,6987,6989,6991,6994],{"class":96,"line":644},[94,6981,2498],{"class":202},[94,6983,6984],{"class":192}," title",[94,6986,2504],{"class":202},[94,6988,3082],{"class":120},[94,6990,867],{"class":100},[94,6992,6993],{"class":127},"'Hello, Event Loop!'",[94,6995,2518],{"class":100},[94,6997,6998],{"class":96,"line":659},[94,6999,244],{"emptyLinePlaceholder":243},[94,7001,7002,7004,7006,7008,7010],{"class":96,"line":4},[94,7003,3472],{"class":202},[94,7005,6723],{"class":120},[94,7007,867],{"class":100},[94,7009,6728],{"class":3480},[94,7011,3484],{"class":100},[94,7013,7014,7016,7018,7020,7022,7024],{"class":96,"line":668},[94,7015,3510],{"class":202},[94,7017,6737],{"class":192},[94,7019,2504],{"class":202},[94,7021,6742],{"class":100},[94,7023,3481],{"class":120},[94,7025,3583],{"class":100},[94,7027,7028,7031,7033,7035,7037,7039,7041,7043],{"class":96,"line":676},[94,7029,7030],{"class":202},"  while",[94,7032,6754],{"class":100},[94,7034,3481],{"class":120},[94,7036,3611],{"class":100},[94,7038,3521],{"class":202},[94,7040,3432],{"class":100},[94,7042,101],{"class":202},[94,7044,6767],{"class":100},[94,7046,7047],{"class":96,"line":689},[94,7048,237],{"class":100},[94,7050,7051],{"class":96,"line":702},[94,7052,244],{"emptyLinePlaceholder":243},[94,7054,7055,7057,7060],{"class":96,"line":713},[94,7056,3472],{"class":202},[94,7058,7059],{"class":120}," onChange",[94,7061,3985],{"class":100},[94,7063,7064,7067,7069],{"class":96,"line":724},[94,7065,7066],{"class":100},"  title.value ",[94,7068,124],{"class":202},[94,7070,6801],{"class":127},[94,7072,7073,7076,7078,7080],{"class":96,"line":739},[94,7074,7075],{"class":120},"  delay",[94,7077,867],{"class":100},[94,7079,6811],{"class":192},[94,7081,2518],{"class":100},[94,7083,7084],{"class":96,"line":753},[94,7085,237],{"class":100},[94,7087,7088,7090,7092],{"class":96,"line":3030},[94,7089,168],{"class":100},[94,7091,3288],{"class":104},[94,7093,108],{"class":100},[94,7095,7096],{"class":96,"line":3051},[94,7097,244],{"emptyLinePlaceholder":243},[94,7099,7100,7102,7104,7106],{"class":96,"line":3060},[94,7101,101],{"class":100},[94,7103,1426],{"class":104},[94,7105,4226],{"class":120},[94,7107,108],{"class":100},[94,7109,7110,7113],{"class":96,"line":3075},[94,7111,7112],{"class":120},".demo",[94,7114,187],{"class":100},[94,7116,7117,7119,7121,7123,7125],{"class":96,"line":3107},[94,7118,4242],{"class":192},[94,7120,196],{"class":100},[94,7122,5095],{"class":192},[94,7124,203],{"class":202},[94,7126,206],{"class":100},[94,7128,7129,7131,7133,7135,7137,7139],{"class":96,"line":3116},[94,7130,4256],{"class":192},[94,7132,196],{"class":100},[94,7134,4261],{"class":192},[94,7136,3680],{"class":100},[94,7138,4266],{"class":192},[94,7140,206],{"class":100},[94,7142,7143,7146,7148,7150],{"class":96,"line":3136},[94,7144,7145],{"class":192},"  text-align",[94,7147,196],{"class":100},[94,7149,4650],{"class":192},[94,7151,206],{"class":100},[94,7153,7154],{"class":96,"line":3145},[94,7155,237],{"class":100},[94,7157,7158],{"class":96,"line":3154},[94,7159,244],{"emptyLinePlaceholder":243},[94,7161,7162,7164],{"class":96,"line":3159},[94,7163,13],{"class":104},[94,7165,187],{"class":100},[94,7167,7168,7170,7172,7174,7176,7179,7181],{"class":96,"line":3175},[94,7169,4292],{"class":192},[94,7171,196],{"class":100},[94,7173,870],{"class":192},[94,7175,4299],{"class":192},[94,7177,7178],{"class":192}," 12",[94,7180,203],{"class":202},[94,7182,206],{"class":100},[94,7184,7185,7187,7189,7192,7194],{"class":96,"line":3208},[94,7186,1838],{"class":192},[94,7188,196],{"class":100},[94,7190,7191],{"class":192},"1.5",[94,7193,4331],{"class":202},[94,7195,206],{"class":100},[94,7197,7198],{"class":96,"line":3214},[94,7199,237],{"class":100},[94,7201,7202],{"class":96,"line":3223},[94,7203,244],{"emptyLinePlaceholder":243},[94,7205,7206,7209],{"class":96,"line":3251},[94,7207,7208],{"class":120},".hint",[94,7210,187],{"class":100},[94,7212,7213,7215,7217,7219,7221,7223,7225],{"class":96,"line":3260},[94,7214,4292],{"class":192},[94,7216,196],{"class":100},[94,7218,870],{"class":192},[94,7220,4299],{"class":192},[94,7222,5299],{"class":192},[94,7224,203],{"class":202},[94,7226,206],{"class":100},[94,7228,7229,7231,7233,7235],{"class":96,"line":3269},[94,7230,1478],{"class":192},[94,7232,196],{"class":100},[94,7234,4316],{"class":192},[94,7236,206],{"class":100},[94,7238,7239,7241,7243,7246,7248],{"class":96,"line":3278},[94,7240,1838],{"class":192},[94,7242,196],{"class":100},[94,7244,7245],{"class":192},"0.9",[94,7247,4331],{"class":202},[94,7249,206],{"class":100},[94,7251,7252],{"class":96,"line":3283},[94,7253,237],{"class":100},[94,7255,7256],{"class":96,"line":3296},[94,7257,244],{"emptyLinePlaceholder":243},[94,7259,7260,7262],{"class":96,"line":3311},[94,7261,5283],{"class":120},[94,7263,187],{"class":100},[94,7265,7266,7268,7270,7272,7274,7276,7278],{"class":96,"line":3316},[94,7267,4242],{"class":192},[94,7269,196],{"class":100},[94,7271,732],{"class":192},[94,7273,203],{"class":202},[94,7275,3645],{"class":192},[94,7277,203],{"class":202},[94,7279,206],{"class":100},[94,7281,7282,7284,7286,7288],{"class":96,"line":3335},[94,7283,629],{"class":192},[94,7285,196],{"class":100},[94,7287,806],{"class":192},[94,7289,206],{"class":100},[94,7291,7292,7294,7296,7298,7300],{"class":96,"line":3353},[94,7293,4405],{"class":192},[94,7295,196],{"class":100},[94,7297,4676],{"class":192},[94,7299,203],{"class":202},[94,7301,206],{"class":100},[94,7303,7304,7306,7308,7310],{"class":96,"line":3371},[94,7305,4420],{"class":192},[94,7307,196],{"class":100},[94,7309,5135],{"class":192},[94,7311,206],{"class":100},[94,7313,7314,7316,7318,7320],{"class":96,"line":3389},[94,7315,1478],{"class":192},[94,7317,196],{"class":100},[94,7319,5348],{"class":192},[94,7321,206],{"class":100},[94,7323,7324,7326,7328,7330],{"class":96,"line":3408},[94,7325,4732],{"class":192},[94,7327,196],{"class":100},[94,7329,4737],{"class":192},[94,7331,206],{"class":100},[94,7333,7334,7336,7338,7340],{"class":96,"line":3413},[94,7335,5367],{"class":192},[94,7337,196],{"class":100},[94,7339,5372],{"class":192},[94,7341,206],{"class":100},[94,7343,7344],{"class":96,"line":3427},[94,7345,237],{"class":100},[94,7347,7348,7350,7352],{"class":96,"line":3439},[94,7349,168],{"class":100},[94,7351,1426],{"class":104},[94,7353,108],{"class":100},[80,7355,7357],{"id":7356},"任务有优先级吗","任务有优先级吗？",[17,7359,7360,7363,7364,7367],{},[26,7361,7362],{},"单个任务","在所属队列里通常是先进先出，没有「插队」；但 ",[26,7365,7366],{},"队列之间"," 有优先级差异。",[17,7369,7370,7371,2176],{},"W3C 现行表述要点（",[53,7372,7375],{"href":7373,"rel":7374},"https:\u002F\u002Fhtml.spec.whatwg.org\u002Fmultipage\u002Fwebappapis.html#perform-a-microtask-checkpoint",[57],"Perform a microtask checkpoint",[344,7377,7378,7385,7388],{},[347,7379,7380,7381,7384],{},"每个任务有 ",[26,7382,7383],{},"任务类型","；同类型任务在同一队列，不同类型可分到不同队列。",[347,7386,7387],{},"一次事件循环中，浏览器可按情况从不同队列取任务。",[347,7389,7390,7391,7394],{},"浏览器必须维护 ",[26,7392,7393],{},"微队列（microtask queue）","，其中任务优先于其他队列执行。",[2592,7396,7397],{},[17,7398,7399,7400,7403],{},"随着浏览器复杂度提升，简单区分「宏队列 \u002F 微队列」已不足以描述全部行为，但 ",[26,7401,7402],{},"微任务优先清空"," 仍是硬性要求。",[17,7405,7406],{},"在 Chrome 实现中，至少包括：",[368,7408,7409,7422],{},[371,7410,7411],{},[374,7412,7413,7416,7419],{},[377,7414,7415],{},"队列",[377,7417,7418],{},"典型内容",[377,7420,7421],{},"优先级（相对）",[386,7423,7424,7441,7452],{},[374,7425,7426,7429,7438],{},[391,7427,7428],{},"微队列",[391,7430,7431,33,7434,7437],{},[21,7432,7433],{},"Promise.then",[21,7435,7436],{},"MutationObserver"," 等",[391,7439,7440],{},"最高",[374,7442,7443,7446,7449],{},[391,7444,7445],{},"交互队列",[391,7447,7448],{},"用户操作产生的事件处理",[391,7450,7451],{},"高",[374,7453,7454,7457,7464],{},[391,7455,7456],{},"延时队列",[391,7458,7459,396,7461,7463],{},[21,7460,6551],{},[21,7462,6554],{}," 到期回调",[391,7465,7466],{},"中",[17,7468,7469],{},"立即把函数放进微队列的常见写法：",[2484,7471,7473],{"lang":2486,"title":7472},"Promise 入微队列",[85,7474,7476],{"className":2490,"code":7475,"language":2486,"meta":90,"style":90},"Promise.resolve().then(() => {\n  console.log('microtask')\n})\n",[21,7477,7478,7501,7515],{"__ignoreMap":90},[94,7479,7480,7483,7486,7489,7492,7495,7497,7499],{"class":96,"line":97},[94,7481,7482],{"class":192},"Promise",[94,7484,7485],{"class":100},".",[94,7487,7488],{"class":120},"resolve",[94,7490,7491],{"class":100},"().",[94,7493,7494],{"class":120},"then",[94,7496,3735],{"class":100},[94,7498,3689],{"class":202},[94,7500,187],{"class":100},[94,7502,7503,7506,7508,7510,7513],{"class":96,"line":111},[94,7504,7505],{"class":100},"  console.",[94,7507,2542],{"class":120},[94,7509,867],{"class":100},[94,7511,7512],{"class":127},"'microtask'",[94,7514,2518],{"class":100},[94,7516,7517],{"class":96,"line":133},[94,7518,7519],{"class":100},"})\n",[80,7521,7522],{"id":7522},"常见面试题",[440,7524,7526],{"id":7525},"阐述-js-的事件循环","阐述 JS 的事件循环",[17,7528,7529,7530,7533,7534,7537],{},"事件循环是渲染主线程的工作方式：开启不会结束的循环，每次从队列取一个任务执行；其他线程在合适时机把任务加到队列末尾。任务按类型分队列，浏览器在一次循环中决定取哪个队列；",[26,7531,7532],{},"微队列任务必须优先调度执行","。Chrome 源码层面可理解为 ",[21,7535,7536],{},"for"," 循环 + 队列取任务，而非过去教科书里单一的「宏队列」模型。",[440,7539,7541],{"id":7540},"计时器能精确计时吗","计时器能精确计时吗？",[17,7543,7544,7547],{},[26,7545,7546],{},"不能做到严格精确","，原因包括：",[1664,7549,7550,7553,7556],{},[347,7551,7552],{},"硬件与 OS 计时本身存在误差，JS 计时器最终依赖系统调用。",[347,7554,7555],{},"W3C 规定：嵌套超过 5 层的计时器，最小间隔为 4ms，短于 4ms 的设定会被抬高。",[347,7557,7558,7559,59],{},"回调只在主线程空闲时执行，前面若有长任务，到期时间到了也会 ",[26,7560,7561],{},"晚跑",[80,7563,1382],{"id":1382},[344,7565,7566,7572,7577,7586],{},[347,7567,7568,7569,7571],{},"浏览器多进程隔离标签页；",[26,7570,2677],{}," 是页面与 JS 的核心调度点。",[347,7573,7574,7576],{},[26,7575,5547],{}," 用消息队列 + 无限循环保证任务有序执行。",[347,7578,7579,7581,7582,7585],{},[26,7580,6588],{}," 避免主线程等待 I\u002FO；",[26,7583,7584],{},"长同步 JS"," 仍会阻塞渲染与交互。",[347,7587,7588,7589,7592],{},"理解 ",[26,7590,7591],{},"微队列优先"," 与多队列模型，比死记「宏\u002F微」更符合当前规范与 Chrome 行为。",[1426,7594,7595],{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":90,"searchDepth":133,"depth":133,"links":7597},[7598,7603,7604,7607,7608,7609,7613],{"id":6384,"depth":111,"text":6384,"children":7599},[7600,7601,7602],{"id":6387,"depth":133,"text":6388},{"id":6404,"depth":133,"text":6405},{"id":6424,"depth":133,"text":6425},{"id":6456,"depth":111,"text":6457},{"id":6535,"depth":111,"text":6536,"children":7605},[7606],{"id":6603,"depth":133,"text":6604},{"id":6622,"depth":111,"text":6623},{"id":7356,"depth":111,"text":7357},{"id":7522,"depth":111,"text":7522,"children":7610},[7611,7612],{"id":7525,"depth":133,"text":7526},{"id":7540,"depth":133,"text":7541},{"id":1382,"depth":111,"text":1382},"2026-06-24","梳理渲染主线程如何调度任务、异步为何必要、JS 为何会阻塞渲染，以及 Chrome 中延时\u002F交互\u002F微队列的优先级。",{},{"title":6363,"description":7615},"blog\u002Fjs-event-loop",[5522,7620,1450],"event-loop","zpAwwSlMoh5xOkPrZCWcA8rP62VybczZfOtCHemEflo",{"id":7623,"title":7624,"body":7625,"category":7996,"date":7997,"description":7998,"draft":1441,"extension":1442,"meta":7999,"navigation":243,"path":8000,"seo":8001,"stem":8002,"tags":8003,"__hash__":8007},"blog\u002Fblog\u002Fweb-piano.md","网页钢琴与 Web Audio 合成",{"type":10,"value":7626,"toc":7986},[7627,7630,7650,7653,7657,7667,7834,7838,7848,7856,7875,7879,7890,7894,7950,7957,7960,7971,7974,7976,7983],[13,7628,7624],{"id":7629},"网页钢琴与-web-audio-合成",[17,7631,7632,7633,7636,7637,7641,7642,7645,7646,7649],{},"Web Audio 不只能分析已有音频——用 ",[26,7634,7635],{},"振荡器（Oscillator）"," 也能从零合成声音。下面 demo 实现了一个 3 个八度的网页钢琴：按住琴键持续发声，松手渐弱；空格键控制延音踏板；还可点击内置乐谱自动演奏。若你读过 ",[53,7638,7640],{"href":7639},"\u002Fblog\u002Faudio-visualizer","Web Audio 音乐可视化","，那篇讲的是 ",[26,7643,7644],{},"AnalyserNode 分析播放","，本篇则走 ",[26,7647,7648],{},"合成发声"," 路线。",[80,7651,7652],{"id":7652},"核心链路",[440,7654,7656],{"id":7655},"_1-音高音符名-频率","1. 音高：音符名 → 频率",[17,7658,7659,7660,33,7663,7666],{},"每个琴键对应如 ",[21,7661,7662],{},"C4",[21,7664,7665],{},"F#5"," 的音符名。通过 MIDI 公式换算频率（A4 = 440Hz）：",[85,7668,7670],{"className":2490,"code":7669,"language":2486,"meta":90,"style":90},"function noteToFreq(note) {\n  const match = note.match(\u002F^([A-G]#?)(\\d)$\u002F)\n  const [, name, octaveStr] = match\n  const midi = (Number(octaveStr) + 1) * 12 + NOTE_INDEX[name]\n  return 440 * Math.pow(2, (midi - 69) \u002F 12)\n}\n",[21,7671,7672,7686,7736,7759,7794,7830],{"__ignoreMap":90},[94,7673,7674,7676,7679,7681,7684],{"class":96,"line":97},[94,7675,3472],{"class":202},[94,7677,7678],{"class":120}," noteToFreq",[94,7680,867],{"class":100},[94,7682,7683],{"class":3480},"note",[94,7685,3484],{"class":100},[94,7687,7688,7690,7693,7695,7698,7701,7703,7705,7708,7711,7714,7717,7720,7723,7726,7729,7732,7734],{"class":96,"line":111},[94,7689,3510],{"class":202},[94,7691,7692],{"class":192}," match",[94,7694,2504],{"class":202},[94,7696,7697],{"class":100}," note.",[94,7699,7700],{"class":120},"match",[94,7702,867],{"class":100},[94,7704,1394],{"class":127},[94,7706,7707],{"class":202},"^",[94,7709,867],{"class":7710},"sA_wV",[94,7712,7713],{"class":192},"[A-G]",[94,7715,7716],{"class":7710},"#",[94,7718,7719],{"class":202},"?",[94,7721,7722],{"class":7710},")(",[94,7724,7725],{"class":192},"\\d",[94,7727,7728],{"class":7710},")",[94,7730,7731],{"class":202},"$",[94,7733,1394],{"class":127},[94,7735,2518],{"class":100},[94,7737,7738,7740,7743,7746,7748,7751,7754,7756],{"class":96,"line":133},[94,7739,3510],{"class":202},[94,7741,7742],{"class":100}," [, ",[94,7744,7745],{"class":192},"name",[94,7747,3680],{"class":100},[94,7749,7750],{"class":192},"octaveStr",[94,7752,7753],{"class":100},"] ",[94,7755,124],{"class":202},[94,7757,7758],{"class":100}," match\n",[94,7760,7761,7763,7766,7768,7770,7773,7776,7778,7780,7782,7784,7786,7788,7791],{"class":96,"line":155},[94,7762,3510],{"class":202},[94,7764,7765],{"class":192}," midi",[94,7767,2504],{"class":202},[94,7769,3493],{"class":100},[94,7771,7772],{"class":120},"Number",[94,7774,7775],{"class":100},"(octaveStr) ",[94,7777,3695],{"class":202},[94,7779,4526],{"class":192},[94,7781,3686],{"class":100},[94,7783,3551],{"class":202},[94,7785,7178],{"class":192},[94,7787,3557],{"class":202},[94,7789,7790],{"class":192}," NOTE_INDEX",[94,7792,7793],{"class":100},"[name]\n",[94,7795,7796,7799,7802,7805,7807,7810,7812,7814,7817,7819,7822,7824,7826,7828],{"class":96,"line":165},[94,7797,7798],{"class":202},"  return",[94,7800,7801],{"class":192}," 440",[94,7803,7804],{"class":202}," *",[94,7806,3542],{"class":100},[94,7808,7809],{"class":120},"pow",[94,7811,867],{"class":100},[94,7813,4749],{"class":192},[94,7815,7816],{"class":100},", (midi ",[94,7818,3521],{"class":202},[94,7820,7821],{"class":192}," 69",[94,7823,3686],{"class":100},[94,7825,1394],{"class":202},[94,7827,7178],{"class":192},[94,7829,2518],{"class":100},[94,7831,7832],{"class":96,"line":240},[94,7833,237],{"class":100},[440,7835,7837],{"id":7836},"_2-发声振荡器-adsr-包络","2. 发声：振荡器 + ADSR 包络",[17,7839,7840,7841,7844,7845,342],{},"每次按键创建一个 ",[21,7842,7843],{},"OscillatorNode","（三角波）和 ",[21,7846,7847],{},"GainNode",[85,7849,7854],{"className":7850,"code":7852,"language":7853},[7851],"language-text","Oscillator → GainNode → destination\n","text",[21,7855,7852],{"__ignoreMap":90},[17,7857,7858,7859,7862,7863,7866,7867,7870,7871,7874],{},"按下时 ",[21,7860,7861],{},"gain"," 从极小值指数爬升到 ",[21,7864,7865],{},"PEAK_GAIN","（attack ≈ 20ms）；松手时指数衰减到 0 再 ",[21,7868,7869],{},"stop"," 振荡器。多音同奏用 ",[21,7872,7873],{},"Map\u003Cnote, voice>"," 管理，每个音符独立一条链路。",[440,7876,7878],{"id":7877},"_3-延音踏板","3. 延音踏板",[17,7880,7881,7882,7885,7886,7889],{},"踩下踏板（空格或点击踏板按钮）时，松开的键不会立刻 ",[21,7883,7884],{},"releaseVoice","，声音会保持到抬踏板。抬踏板后，所有 ",[21,7887,7888],{},"keyHeld === false"," 的 voice 才进入释放包络。",[440,7891,7893],{"id":7892},"_4-三路输入","4. 三路输入",[368,7895,7896,7905],{},[371,7897,7898],{},[374,7899,7900,7902],{},[377,7901,5586],{},[377,7903,7904],{},"处理方式",[386,7906,7907,7927,7938],{},[374,7908,7909,7912],{},[391,7910,7911],{},"鼠标 \u002F 触摸",[391,7913,7914,7917,7918,1400,7921,5961,7924],{},[21,7915,7916],{},"pointerdown"," 捕获 → ",[21,7919,7920],{},"pressNote",[21,7922,7923],{},"pointerup",[21,7925,7926],{},"releaseNote",[374,7928,7929,7932],{},[391,7930,7931],{},"物理键盘",[391,7933,7934,7937],{},[21,7935,7936],{},"KEY_MAP"," 映射 QWERTY 键到音符",[374,7939,7940,7943],{},[391,7941,7942],{},"内置乐谱",[391,7944,7945,7946,7949],{},"按 BPM 计算节拍时长，",[21,7947,7948],{},"playNoteTimed"," 定时发声",[17,7951,7952,7953,7956],{},"乐谱播放用 ",[21,7954,7955],{},"playToken"," 取消机制：切换曲目或点停止时递增 token，异步循环检测到 token 变化即退出。",[80,7958,7959],{"id":7959},"在线体验",[17,7961,7962,7963,7966,7967,59],{},"点击或键盘演奏（需用户手势后 ",[21,7964,7965],{},"AudioContext"," 才会 resume）。也可 ",[53,7968,7970],{"href":7969},"\u002Fdemos\u002Fweb-piano","全屏预览",[7972,7973],"web-piano-demo",{},[80,7975,1382],{"id":1382},[17,7977,7978,7979,7982],{},"网页钢琴的核心是 ",[26,7980,7981],{},"振荡器合成 + 包络塑形 + 多 voice 管理","。和音乐可视化的 AnalyserNode 不同，这里完全在「生成」声音。真实钢琴音色需要更复杂的采样或物理建模，但三角波 + 简单 ADSR 已足够演示 Web Audio 的合成路径。想继续深入，可以试试换波形、加滤波器，或接入 SoundFont 采样。",[1426,7984,7985],{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sA_wV, html code.shiki .sA_wV{--shiki-default:#032F62;--shiki-dark:#DBEDFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":90,"searchDepth":133,"depth":133,"links":7987},[7988,7994,7995],{"id":7652,"depth":111,"text":7652,"children":7989},[7990,7991,7992,7993],{"id":7655,"depth":133,"text":7656},{"id":7836,"depth":133,"text":7837},{"id":7877,"depth":133,"text":7878},{"id":7892,"depth":133,"text":7893},{"id":7959,"depth":111,"text":7959},{"id":1382,"depth":111,"text":1382},"music","2026-06-20","用振荡器与 GainNode 包络合成钢琴音，支持键盘演奏、延音踏板与内置乐谱自动播放。",{},"\u002Fblog\u002Fweb-piano",{"title":7624,"description":7998},"blog\u002Fweb-piano",[8004,8005,8006],"web-audio","piano","synthesis","X7pBoWNSCuyPLsw20K-xCjEh7X0xvqwlB3lQ2I-Xk4o",0,1782309644511]