[{"data":1,"prerenderedAt":1533},["ShallowReactive",2],{"blog-en-12-column-grid":3},{"id":4,"title":5,"author":6,"body":9,"date":614,"description":1499,"draft":1500,"extension":1501,"howTo":1502,"image":1523,"meta":1524,"navigation":79,"path":1525,"seo":1526,"stem":1527,"tags":1528,"updated":1523,"__hash__":1532},"blog/blog/005.12-column-grid.md","How does the 12-column grid work in gpdf?",{"name":7,"url":8},"gpdf team","https://gpdf.dev",{"type":10,"value":11,"toc":1487},"minimark",[12,17,30,34,48,52,1133,1140,1144,1147,1151,1166,1177,1181,1184,1200,1214,1218,1224,1230,1389,1393,1399,1410,1413,1416,1420,1446,1450,1453,1470,1483],[13,14,16],"h2",{"id":15},"the-question-in-other-words","The question, in other words",[18,19,20,21,25,26,29],"p",{},"You've seen the gpdf API — page builder, row builder, column builder — and the column constructor takes a number: ",[22,23,24],"code",{},"r.Col(4, fn)",", ",[22,27,28],{},"r.Col(8, fn)",". What's the number, what happens if the spans don't add up to 12, and how does this compare to the grid you already know from CSS?",[13,31,33],{"id":32},"the-short-version","The short version",[18,35,36,39,40,43,44],{},[22,37,38],{},"r.Col(span, fn)"," takes an integer from 1 to 12. That integer is the column's share of the row — ",[22,41,42],{},"span / 12"," of the available width. Spans under 1 are clamped to 1, spans over 12 are clamped to 12, and the library does not force spans to sum to 12 per row. ",[45,46,47],"strong",{},"The grid is fixed at 12 divisions. Everything else is you choosing how to carve up a row.",[13,49,51],{"id":50},"a-working-example","A working example",[53,54,59],"pre",{"className":55,"code":56,"language":57,"meta":58,"style":58},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","package main\n\nimport (\n    \"log\"\n    \"os\"\n\n    \"github.com/gpdf-dev/gpdf\"\n    \"github.com/gpdf-dev/gpdf/document\"\n    \"github.com/gpdf-dev/gpdf/template\"\n)\n\nfunc main() {\n    doc := gpdf.NewDocument(\n        gpdf.WithPageSize(document.A4),\n        gpdf.WithMargins(document.UniformEdges(document.Mm(15))),\n    )\n\n    page := doc.AddPage()\n\n    // Full width\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(12, func(c *template.ColBuilder) {\n            c.Text(\"Invoice #2026-0416\", template.FontSize(18), template.Bold())\n        })\n    })\n\n    // 2-column header (6 + 6)\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(6, func(c *template.ColBuilder) {\n            c.Text(\"Billed to\")\n            c.Text(\"Acme GmbH\")\n        })\n        r.Col(6, func(c *template.ColBuilder) {\n            c.Text(\"Issue date\")\n            c.Text(\"2026-04-16\")\n        })\n    })\n\n    // 3-column summary (4 + 4 + 4)\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(4, func(c *template.ColBuilder) {\n            c.Text(\"Subtotal\")\n        })\n        r.Col(4, func(c *template.ColBuilder) {\n            c.Text(\"Tax\")\n        })\n        r.Col(4, func(c *template.ColBuilder) {\n            c.Text(\"Total\")\n        })\n    })\n\n    // Asymmetric (8 + 4) — article area + side panel\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(8, func(c *template.ColBuilder) {\n            c.Text(\"Line items appear here.\")\n        })\n        r.Col(4, func(c *template.ColBuilder) {\n            c.Text(\"Notes\")\n        })\n    })\n\n    data, err := doc.Generate()\n    if err != nil {\n        log.Fatal(err)\n    }\n    if err := os.WriteFile(\"layout.pdf\", data, 0o644); err != nil {\n        log.Fatal(err)\n    }\n}\n","go","",[22,60,61,74,81,91,103,113,118,128,138,148,154,159,175,197,222,259,265,270,289,294,301,335,373,423,429,435,440,446,471,503,523,543,548,579,599,619,624,629,634,640,665,697,717,722,753,773,778,809,829,834,839,844,850,875,907,927,932,963,983,988,993,998,1020,1036,1054,1060,1107,1122,1127],{"__ignoreMap":58},[62,63,66,70],"span",{"class":64,"line":65},"line",1,[62,67,69],{"class":68},"sMK4o","package",[62,71,73],{"class":72},"sBMFI"," main\n",[62,75,77],{"class":64,"line":76},2,[62,78,80],{"emptyLinePlaceholder":79},true,"\n",[62,82,84,88],{"class":64,"line":83},3,[62,85,87],{"class":86},"s7zQu","import",[62,89,90],{"class":68}," (\n",[62,92,94,97,100],{"class":64,"line":93},4,[62,95,96],{"class":68},"    \"",[62,98,99],{"class":72},"log",[62,101,102],{"class":68},"\"\n",[62,104,106,108,111],{"class":64,"line":105},5,[62,107,96],{"class":68},[62,109,110],{"class":72},"os",[62,112,102],{"class":68},[62,114,116],{"class":64,"line":115},6,[62,117,80],{"emptyLinePlaceholder":79},[62,119,121,123,126],{"class":64,"line":120},7,[62,122,96],{"class":68},[62,124,125],{"class":72},"github.com/gpdf-dev/gpdf",[62,127,102],{"class":68},[62,129,131,133,136],{"class":64,"line":130},8,[62,132,96],{"class":68},[62,134,135],{"class":72},"github.com/gpdf-dev/gpdf/document",[62,137,102],{"class":68},[62,139,141,143,146],{"class":64,"line":140},9,[62,142,96],{"class":68},[62,144,145],{"class":72},"github.com/gpdf-dev/gpdf/template",[62,147,102],{"class":68},[62,149,151],{"class":64,"line":150},10,[62,152,153],{"class":68},")\n",[62,155,157],{"class":64,"line":156},11,[62,158,80],{"emptyLinePlaceholder":79},[62,160,162,165,169,172],{"class":64,"line":161},12,[62,163,164],{"class":68},"func",[62,166,168],{"class":167},"s2Zo4"," main",[62,170,171],{"class":68},"()",[62,173,174],{"class":68}," {\n",[62,176,178,182,185,188,191,194],{"class":64,"line":177},13,[62,179,181],{"class":180},"sTEyZ","    doc ",[62,183,184],{"class":68},":=",[62,186,187],{"class":180}," gpdf",[62,189,190],{"class":68},".",[62,192,193],{"class":167},"NewDocument",[62,195,196],{"class":68},"(\n",[62,198,200,203,205,208,211,214,216,219],{"class":64,"line":199},14,[62,201,202],{"class":180},"        gpdf",[62,204,190],{"class":68},[62,206,207],{"class":167},"WithPageSize",[62,209,210],{"class":68},"(",[62,212,213],{"class":180},"document",[62,215,190],{"class":68},[62,217,218],{"class":180},"A4",[62,220,221],{"class":68},"),\n",[62,223,225,227,229,232,234,236,238,241,243,245,247,250,252,256],{"class":64,"line":224},15,[62,226,202],{"class":180},[62,228,190],{"class":68},[62,230,231],{"class":167},"WithMargins",[62,233,210],{"class":68},[62,235,213],{"class":180},[62,237,190],{"class":68},[62,239,240],{"class":167},"UniformEdges",[62,242,210],{"class":68},[62,244,213],{"class":180},[62,246,190],{"class":68},[62,248,249],{"class":167},"Mm",[62,251,210],{"class":68},[62,253,255],{"class":254},"sbssI","15",[62,257,258],{"class":68},"))),\n",[62,260,262],{"class":64,"line":261},16,[62,263,264],{"class":68},"    )\n",[62,266,268],{"class":64,"line":267},17,[62,269,80],{"emptyLinePlaceholder":79},[62,271,273,276,278,281,283,286],{"class":64,"line":272},18,[62,274,275],{"class":180},"    page ",[62,277,184],{"class":68},[62,279,280],{"class":180}," doc",[62,282,190],{"class":68},[62,284,285],{"class":167},"AddPage",[62,287,288],{"class":68},"()\n",[62,290,292],{"class":64,"line":291},19,[62,293,80],{"emptyLinePlaceholder":79},[62,295,297],{"class":64,"line":296},20,[62,298,300],{"class":299},"sHwdD","    // Full width\n",[62,302,304,307,309,312,315,319,322,325,327,330,333],{"class":64,"line":303},21,[62,305,306],{"class":180},"    page",[62,308,190],{"class":68},[62,310,311],{"class":167},"AutoRow",[62,313,314],{"class":68},"(func(",[62,316,318],{"class":317},"sHdIc","r",[62,320,321],{"class":68}," *",[62,323,324],{"class":72},"template",[62,326,190],{"class":68},[62,328,329],{"class":72},"RowBuilder",[62,331,332],{"class":68},")",[62,334,174],{"class":68},[62,336,338,341,343,346,348,351,354,357,360,362,364,366,369,371],{"class":64,"line":337},22,[62,339,340],{"class":180},"        r",[62,342,190],{"class":68},[62,344,345],{"class":167},"Col",[62,347,210],{"class":68},[62,349,350],{"class":254},"12",[62,352,353],{"class":68},",",[62,355,356],{"class":68}," func(",[62,358,359],{"class":317},"c",[62,361,321],{"class":68},[62,363,324],{"class":72},[62,365,190],{"class":68},[62,367,368],{"class":72},"ColBuilder",[62,370,332],{"class":68},[62,372,174],{"class":68},[62,374,376,379,381,384,386,389,393,395,397,400,402,405,407,410,413,415,417,420],{"class":64,"line":375},23,[62,377,378],{"class":180},"            c",[62,380,190],{"class":68},[62,382,383],{"class":167},"Text",[62,385,210],{"class":68},[62,387,388],{"class":68},"\"",[62,390,392],{"class":391},"sfazB","Invoice #2026-0416",[62,394,388],{"class":68},[62,396,353],{"class":68},[62,398,399],{"class":180}," template",[62,401,190],{"class":68},[62,403,404],{"class":167},"FontSize",[62,406,210],{"class":68},[62,408,409],{"class":254},"18",[62,411,412],{"class":68},"),",[62,414,399],{"class":180},[62,416,190],{"class":68},[62,418,419],{"class":167},"Bold",[62,421,422],{"class":68},"())\n",[62,424,426],{"class":64,"line":425},24,[62,427,428],{"class":68},"        })\n",[62,430,432],{"class":64,"line":431},25,[62,433,434],{"class":68},"    })\n",[62,436,438],{"class":64,"line":437},26,[62,439,80],{"emptyLinePlaceholder":79},[62,441,443],{"class":64,"line":442},27,[62,444,445],{"class":299},"    // 2-column header (6 + 6)\n",[62,447,449,451,453,455,457,459,461,463,465,467,469],{"class":64,"line":448},28,[62,450,306],{"class":180},[62,452,190],{"class":68},[62,454,311],{"class":167},[62,456,314],{"class":68},[62,458,318],{"class":317},[62,460,321],{"class":68},[62,462,324],{"class":72},[62,464,190],{"class":68},[62,466,329],{"class":72},[62,468,332],{"class":68},[62,470,174],{"class":68},[62,472,474,476,478,480,482,485,487,489,491,493,495,497,499,501],{"class":64,"line":473},29,[62,475,340],{"class":180},[62,477,190],{"class":68},[62,479,345],{"class":167},[62,481,210],{"class":68},[62,483,484],{"class":254},"6",[62,486,353],{"class":68},[62,488,356],{"class":68},[62,490,359],{"class":317},[62,492,321],{"class":68},[62,494,324],{"class":72},[62,496,190],{"class":68},[62,498,368],{"class":72},[62,500,332],{"class":68},[62,502,174],{"class":68},[62,504,506,508,510,512,514,516,519,521],{"class":64,"line":505},30,[62,507,378],{"class":180},[62,509,190],{"class":68},[62,511,383],{"class":167},[62,513,210],{"class":68},[62,515,388],{"class":68},[62,517,518],{"class":391},"Billed to",[62,520,388],{"class":68},[62,522,153],{"class":68},[62,524,526,528,530,532,534,536,539,541],{"class":64,"line":525},31,[62,527,378],{"class":180},[62,529,190],{"class":68},[62,531,383],{"class":167},[62,533,210],{"class":68},[62,535,388],{"class":68},[62,537,538],{"class":391},"Acme GmbH",[62,540,388],{"class":68},[62,542,153],{"class":68},[62,544,546],{"class":64,"line":545},32,[62,547,428],{"class":68},[62,549,551,553,555,557,559,561,563,565,567,569,571,573,575,577],{"class":64,"line":550},33,[62,552,340],{"class":180},[62,554,190],{"class":68},[62,556,345],{"class":167},[62,558,210],{"class":68},[62,560,484],{"class":254},[62,562,353],{"class":68},[62,564,356],{"class":68},[62,566,359],{"class":317},[62,568,321],{"class":68},[62,570,324],{"class":72},[62,572,190],{"class":68},[62,574,368],{"class":72},[62,576,332],{"class":68},[62,578,174],{"class":68},[62,580,582,584,586,588,590,592,595,597],{"class":64,"line":581},34,[62,583,378],{"class":180},[62,585,190],{"class":68},[62,587,383],{"class":167},[62,589,210],{"class":68},[62,591,388],{"class":68},[62,593,594],{"class":391},"Issue date",[62,596,388],{"class":68},[62,598,153],{"class":68},[62,600,602,604,606,608,610,612,615,617],{"class":64,"line":601},35,[62,603,378],{"class":180},[62,605,190],{"class":68},[62,607,383],{"class":167},[62,609,210],{"class":68},[62,611,388],{"class":68},[62,613,614],{"class":391},"2026-04-16",[62,616,388],{"class":68},[62,618,153],{"class":68},[62,620,622],{"class":64,"line":621},36,[62,623,428],{"class":68},[62,625,627],{"class":64,"line":626},37,[62,628,434],{"class":68},[62,630,632],{"class":64,"line":631},38,[62,633,80],{"emptyLinePlaceholder":79},[62,635,637],{"class":64,"line":636},39,[62,638,639],{"class":299},"    // 3-column summary (4 + 4 + 4)\n",[62,641,643,645,647,649,651,653,655,657,659,661,663],{"class":64,"line":642},40,[62,644,306],{"class":180},[62,646,190],{"class":68},[62,648,311],{"class":167},[62,650,314],{"class":68},[62,652,318],{"class":317},[62,654,321],{"class":68},[62,656,324],{"class":72},[62,658,190],{"class":68},[62,660,329],{"class":72},[62,662,332],{"class":68},[62,664,174],{"class":68},[62,666,668,670,672,674,676,679,681,683,685,687,689,691,693,695],{"class":64,"line":667},41,[62,669,340],{"class":180},[62,671,190],{"class":68},[62,673,345],{"class":167},[62,675,210],{"class":68},[62,677,678],{"class":254},"4",[62,680,353],{"class":68},[62,682,356],{"class":68},[62,684,359],{"class":317},[62,686,321],{"class":68},[62,688,324],{"class":72},[62,690,190],{"class":68},[62,692,368],{"class":72},[62,694,332],{"class":68},[62,696,174],{"class":68},[62,698,700,702,704,706,708,710,713,715],{"class":64,"line":699},42,[62,701,378],{"class":180},[62,703,190],{"class":68},[62,705,383],{"class":167},[62,707,210],{"class":68},[62,709,388],{"class":68},[62,711,712],{"class":391},"Subtotal",[62,714,388],{"class":68},[62,716,153],{"class":68},[62,718,720],{"class":64,"line":719},43,[62,721,428],{"class":68},[62,723,725,727,729,731,733,735,737,739,741,743,745,747,749,751],{"class":64,"line":724},44,[62,726,340],{"class":180},[62,728,190],{"class":68},[62,730,345],{"class":167},[62,732,210],{"class":68},[62,734,678],{"class":254},[62,736,353],{"class":68},[62,738,356],{"class":68},[62,740,359],{"class":317},[62,742,321],{"class":68},[62,744,324],{"class":72},[62,746,190],{"class":68},[62,748,368],{"class":72},[62,750,332],{"class":68},[62,752,174],{"class":68},[62,754,756,758,760,762,764,766,769,771],{"class":64,"line":755},45,[62,757,378],{"class":180},[62,759,190],{"class":68},[62,761,383],{"class":167},[62,763,210],{"class":68},[62,765,388],{"class":68},[62,767,768],{"class":391},"Tax",[62,770,388],{"class":68},[62,772,153],{"class":68},[62,774,776],{"class":64,"line":775},46,[62,777,428],{"class":68},[62,779,781,783,785,787,789,791,793,795,797,799,801,803,805,807],{"class":64,"line":780},47,[62,782,340],{"class":180},[62,784,190],{"class":68},[62,786,345],{"class":167},[62,788,210],{"class":68},[62,790,678],{"class":254},[62,792,353],{"class":68},[62,794,356],{"class":68},[62,796,359],{"class":317},[62,798,321],{"class":68},[62,800,324],{"class":72},[62,802,190],{"class":68},[62,804,368],{"class":72},[62,806,332],{"class":68},[62,808,174],{"class":68},[62,810,812,814,816,818,820,822,825,827],{"class":64,"line":811},48,[62,813,378],{"class":180},[62,815,190],{"class":68},[62,817,383],{"class":167},[62,819,210],{"class":68},[62,821,388],{"class":68},[62,823,824],{"class":391},"Total",[62,826,388],{"class":68},[62,828,153],{"class":68},[62,830,832],{"class":64,"line":831},49,[62,833,428],{"class":68},[62,835,837],{"class":64,"line":836},50,[62,838,434],{"class":68},[62,840,842],{"class":64,"line":841},51,[62,843,80],{"emptyLinePlaceholder":79},[62,845,847],{"class":64,"line":846},52,[62,848,849],{"class":299},"    // Asymmetric (8 + 4) — article area + side panel\n",[62,851,853,855,857,859,861,863,865,867,869,871,873],{"class":64,"line":852},53,[62,854,306],{"class":180},[62,856,190],{"class":68},[62,858,311],{"class":167},[62,860,314],{"class":68},[62,862,318],{"class":317},[62,864,321],{"class":68},[62,866,324],{"class":72},[62,868,190],{"class":68},[62,870,329],{"class":72},[62,872,332],{"class":68},[62,874,174],{"class":68},[62,876,878,880,882,884,886,889,891,893,895,897,899,901,903,905],{"class":64,"line":877},54,[62,879,340],{"class":180},[62,881,190],{"class":68},[62,883,345],{"class":167},[62,885,210],{"class":68},[62,887,888],{"class":254},"8",[62,890,353],{"class":68},[62,892,356],{"class":68},[62,894,359],{"class":317},[62,896,321],{"class":68},[62,898,324],{"class":72},[62,900,190],{"class":68},[62,902,368],{"class":72},[62,904,332],{"class":68},[62,906,174],{"class":68},[62,908,910,912,914,916,918,920,923,925],{"class":64,"line":909},55,[62,911,378],{"class":180},[62,913,190],{"class":68},[62,915,383],{"class":167},[62,917,210],{"class":68},[62,919,388],{"class":68},[62,921,922],{"class":391},"Line items appear here.",[62,924,388],{"class":68},[62,926,153],{"class":68},[62,928,930],{"class":64,"line":929},56,[62,931,428],{"class":68},[62,933,935,937,939,941,943,945,947,949,951,953,955,957,959,961],{"class":64,"line":934},57,[62,936,340],{"class":180},[62,938,190],{"class":68},[62,940,345],{"class":167},[62,942,210],{"class":68},[62,944,678],{"class":254},[62,946,353],{"class":68},[62,948,356],{"class":68},[62,950,359],{"class":317},[62,952,321],{"class":68},[62,954,324],{"class":72},[62,956,190],{"class":68},[62,958,368],{"class":72},[62,960,332],{"class":68},[62,962,174],{"class":68},[62,964,966,968,970,972,974,976,979,981],{"class":64,"line":965},58,[62,967,378],{"class":180},[62,969,190],{"class":68},[62,971,383],{"class":167},[62,973,210],{"class":68},[62,975,388],{"class":68},[62,977,978],{"class":391},"Notes",[62,980,388],{"class":68},[62,982,153],{"class":68},[62,984,986],{"class":64,"line":985},59,[62,987,428],{"class":68},[62,989,991],{"class":64,"line":990},60,[62,992,434],{"class":68},[62,994,996],{"class":64,"line":995},61,[62,997,80],{"emptyLinePlaceholder":79},[62,999,1001,1004,1006,1009,1011,1013,1015,1018],{"class":64,"line":1000},62,[62,1002,1003],{"class":180},"    data",[62,1005,353],{"class":68},[62,1007,1008],{"class":180}," err ",[62,1010,184],{"class":68},[62,1012,280],{"class":180},[62,1014,190],{"class":68},[62,1016,1017],{"class":167},"Generate",[62,1019,288],{"class":68},[62,1021,1023,1026,1028,1031,1034],{"class":64,"line":1022},63,[62,1024,1025],{"class":86},"    if",[62,1027,1008],{"class":180},[62,1029,1030],{"class":68},"!=",[62,1032,1033],{"class":68}," nil",[62,1035,174],{"class":68},[62,1037,1039,1042,1044,1047,1049,1052],{"class":64,"line":1038},64,[62,1040,1041],{"class":180},"        log",[62,1043,190],{"class":68},[62,1045,1046],{"class":167},"Fatal",[62,1048,210],{"class":68},[62,1050,1051],{"class":180},"err",[62,1053,153],{"class":68},[62,1055,1057],{"class":64,"line":1056},65,[62,1058,1059],{"class":68},"    }\n",[62,1061,1063,1065,1067,1069,1072,1074,1077,1079,1081,1084,1086,1088,1091,1093,1096,1099,1101,1103,1105],{"class":64,"line":1062},66,[62,1064,1025],{"class":86},[62,1066,1008],{"class":180},[62,1068,184],{"class":68},[62,1070,1071],{"class":180}," os",[62,1073,190],{"class":68},[62,1075,1076],{"class":167},"WriteFile",[62,1078,210],{"class":68},[62,1080,388],{"class":68},[62,1082,1083],{"class":391},"layout.pdf",[62,1085,388],{"class":68},[62,1087,353],{"class":68},[62,1089,1090],{"class":180}," data",[62,1092,353],{"class":68},[62,1094,1095],{"class":254}," 0o644",[62,1097,1098],{"class":68},");",[62,1100,1008],{"class":180},[62,1102,1030],{"class":68},[62,1104,1033],{"class":68},[62,1106,174],{"class":68},[62,1108,1110,1112,1114,1116,1118,1120],{"class":64,"line":1109},67,[62,1111,1041],{"class":180},[62,1113,190],{"class":68},[62,1115,1046],{"class":167},[62,1117,210],{"class":68},[62,1119,1051],{"class":180},[62,1121,153],{"class":68},[62,1123,1125],{"class":64,"line":1124},68,[62,1126,1059],{"class":68},[62,1128,1130],{"class":64,"line":1129},69,[62,1131,1132],{"class":68},"}\n",[18,1134,1135,1136,1139],{},"Run ",[22,1137,1138],{},"go run main.go",". You get one page with four rows, each divided differently.",[13,1141,1143],{"id":1142},"why-12","Why 12",[18,1145,1146],{},"Twelve factors cleanly into 2, 3, 4, and 6. That covers almost every real layout: halves (6+6), thirds (4+4+4), quarters (3+3+3+3), a sidebar + body (3+9 or 4+8), and a body + rail (8+4). Pick a grid with a smaller factor count and you lose one of those cheaply. Bootstrap settled on twelve back in 2011, and by now \"12-column grid\" is the lingua franca that every designer and frontend engineer already speaks. gpdf borrows the idiom on purpose — a PDF layout isn't a different mental model than a web layout, even though the rendering target happens to be fixed-width paper.",[13,1148,1150],{"id":1149},"the-math-spelled-out","The math, spelled out",[18,1152,1153,1154,1157,1158,1161,1162,1165],{},"With A4 portrait and 15 mm uniform margins, the usable width is 180 mm. A ",[22,1155,1156],{},"Col(4)"," inside a row takes 4/12 of that — 60 mm. ",[22,1159,1160],{},"Col(8)"," takes 120 mm. There is no gutter between columns by default. If you want breathing room, either add a ",[22,1163,1164],{},"c.Spacer"," inside the shorter column or leave a one-unit span empty.",[18,1167,1168,1169,1172,1173,1176],{},"The width is computed as a percentage at build time (the relevant line is in ",[22,1170,1171],{},"gpdf/template/grid.go","), and the layout engine resolves it to points using the current page width minus margins. That means the same ",[22,1174,1175],{},"r.Col(6, fn)"," means different physical widths on A4 vs Letter, but the same proportion of the row.",[13,1178,1180],{"id":1179},"sums-that-dont-hit-12","Sums that don't hit 12",[18,1182,1183],{},"gpdf does not validate that your spans add up. This is deliberate.",[1185,1186,1187,1194],"ul",{},[1188,1189,1190,1193],"li",{},[45,1191,1192],{},"Sum \u003C 12",": the right side of the row is blank. Useful when you want a column anchored to the left edge and the rest of the line to stay empty.",[1188,1195,1196,1199],{},[45,1197,1198],{},"Sum > 12",": the last column overflows past the right margin. Usually a bug. The generated PDF looks wrong; nothing crashes.",[18,1201,1202,1203,1206,1207,1210,1211,1213],{},"Most layouts land on exactly 12 per row because that's what fills the page. But when you want a 6-width block centered on a line, the cheap move is ",[22,1204,1205],{},"Col(3)"," empty, ",[22,1208,1209],{},"Col(6)"," content, ",[22,1212,1205],{}," empty — the grid was designed for this kind of shorthand.",[13,1215,1217],{"id":1216},"autorow-vs-row","AutoRow vs Row",[18,1219,1220,1223],{},[22,1221,1222],{},"page.AutoRow(fn)"," grows vertically to fit the tallest column. Most rows should use this.",[18,1225,1226,1229],{},[22,1227,1228],{},"page.Row(height, fn)"," pins the height. Content past that height gets clipped. Use it for invoice headers that must stay exactly 30 mm tall so downstream stapling lines up, and for anything else where visual consistency beats content freedom.",[53,1231,1233],{"className":55,"code":1232,"language":57,"meta":58,"style":58},"page.Row(document.Mm(30), func(r *template.RowBuilder) {\n    r.Col(8, func(c *template.ColBuilder) {\n        c.Text(\"Logo\")\n    })\n    r.Col(4, func(c *template.ColBuilder) {\n        c.Text(\"Invoice #\")\n    })\n})\n",[22,1234,1235,1276,1307,1327,1331,1361,1380,1384],{"__ignoreMap":58},[62,1236,1237,1240,1242,1245,1247,1249,1251,1253,1255,1258,1260,1262,1264,1266,1268,1270,1272,1274],{"class":64,"line":65},[62,1238,1239],{"class":180},"page",[62,1241,190],{"class":68},[62,1243,1244],{"class":167},"Row",[62,1246,210],{"class":68},[62,1248,213],{"class":180},[62,1250,190],{"class":68},[62,1252,249],{"class":167},[62,1254,210],{"class":68},[62,1256,1257],{"class":254},"30",[62,1259,412],{"class":68},[62,1261,356],{"class":68},[62,1263,318],{"class":317},[62,1265,321],{"class":68},[62,1267,324],{"class":72},[62,1269,190],{"class":68},[62,1271,329],{"class":72},[62,1273,332],{"class":68},[62,1275,174],{"class":68},[62,1277,1278,1281,1283,1285,1287,1289,1291,1293,1295,1297,1299,1301,1303,1305],{"class":64,"line":76},[62,1279,1280],{"class":180},"    r",[62,1282,190],{"class":68},[62,1284,345],{"class":167},[62,1286,210],{"class":68},[62,1288,888],{"class":254},[62,1290,353],{"class":68},[62,1292,356],{"class":68},[62,1294,359],{"class":317},[62,1296,321],{"class":68},[62,1298,324],{"class":72},[62,1300,190],{"class":68},[62,1302,368],{"class":72},[62,1304,332],{"class":68},[62,1306,174],{"class":68},[62,1308,1309,1312,1314,1316,1318,1320,1323,1325],{"class":64,"line":83},[62,1310,1311],{"class":180},"        c",[62,1313,190],{"class":68},[62,1315,383],{"class":167},[62,1317,210],{"class":68},[62,1319,388],{"class":68},[62,1321,1322],{"class":391},"Logo",[62,1324,388],{"class":68},[62,1326,153],{"class":68},[62,1328,1329],{"class":64,"line":93},[62,1330,434],{"class":68},[62,1332,1333,1335,1337,1339,1341,1343,1345,1347,1349,1351,1353,1355,1357,1359],{"class":64,"line":105},[62,1334,1280],{"class":180},[62,1336,190],{"class":68},[62,1338,345],{"class":167},[62,1340,210],{"class":68},[62,1342,678],{"class":254},[62,1344,353],{"class":68},[62,1346,356],{"class":68},[62,1348,359],{"class":317},[62,1350,321],{"class":68},[62,1352,324],{"class":72},[62,1354,190],{"class":68},[62,1356,368],{"class":72},[62,1358,332],{"class":68},[62,1360,174],{"class":68},[62,1362,1363,1365,1367,1369,1371,1373,1376,1378],{"class":64,"line":115},[62,1364,1311],{"class":180},[62,1366,190],{"class":68},[62,1368,383],{"class":167},[62,1370,210],{"class":68},[62,1372,388],{"class":68},[62,1374,1375],{"class":391},"Invoice #",[62,1377,388],{"class":68},[62,1379,153],{"class":68},[62,1381,1382],{"class":64,"line":120},[62,1383,434],{"class":68},[62,1385,1386],{"class":64,"line":130},[62,1387,1388],{"class":68},"})\n",[13,1390,1392],{"id":1391},"what-the-grid-does-not-do","What the grid does not do",[18,1394,1395,1396,1398],{},"No nesting. You can't put a sub-row inside a column — ",[22,1397,368],{}," accepts content (Text, Image, Table, List, Spacer), not another row. Layouts that need that pattern are usually better expressed as two sibling rows at the page level.",[18,1400,1401,1402,1405,1406,1409],{},"No offset columns. Bootstrap has ",[22,1403,1404],{},".offset-2","; gpdf does not. Leave an empty ",[22,1407,1408],{},"Col(n)"," to push content right.",[18,1411,1412],{},"No breakpoints. PDF pages don't resize. The grid produces the same layout on every device because the output is a raster of fixed coordinates, not a DOM that re-flows.",[18,1414,1415],{},"These omissions are the point. Every feature the grid doesn't have is a class of ambiguity the PDF output doesn't have to reason about.",[13,1417,1419],{"id":1418},"related-reading","Related reading",[1185,1421,1422,1430,1437],{},[1188,1423,1424,1429],{},[1425,1426,1428],"a",{"href":1427},"/blog/embed-japanese-font","How do I embed a Japanese font in gpdf?"," — CJK inside grid columns, same API",[1188,1431,1432,1436],{},[1425,1433,1435],{"href":1434},"/blog/go-pdf-library-showdown-2026","Go PDF Library Showdown 2026"," — how the Builder API compares to gofpdf, gopdf, and Maroto",[1188,1438,1439,1445],{},[1425,1440,1444],{"href":1441,"rel":1442},"https://gpdf.dev/docs/guide/layout",[1443],"nofollow","Layout guide"," — full reference for rows, columns, and spacing",[13,1447,1449],{"id":1448},"try-gpdf","Try gpdf",[18,1451,1452],{},"gpdf is a Go library for generating PDFs. MIT licensed, zero external dependencies, native CJK support.",[53,1454,1458],{"className":1455,"code":1456,"language":1457,"meta":58,"style":58},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go get github.com/gpdf-dev/gpdf\n","bash",[22,1459,1460],{"__ignoreMap":58},[62,1461,1462,1464,1467],{"class":64,"line":65},[62,1463,57],{"class":72},[62,1465,1466],{"class":391}," get",[62,1468,1469],{"class":391}," github.com/gpdf-dev/gpdf\n",[18,1471,1472,1477,1478],{},[1425,1473,1476],{"href":1474,"rel":1475},"https://github.com/gpdf-dev/gpdf",[1443],"⭐ Star on GitHub"," · ",[1425,1479,1482],{"href":1480,"rel":1481},"https://gpdf.dev/docs/quickstart",[1443],"Read the docs",[1484,1485,1486],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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":58,"searchDepth":76,"depth":76,"links":1488},[1489,1490,1491,1492,1493,1494,1495,1496,1497,1498],{"id":15,"depth":76,"text":16},{"id":32,"depth":76,"text":33},{"id":50,"depth":76,"text":51},{"id":1142,"depth":76,"text":1143},{"id":1149,"depth":76,"text":1150},{"id":1179,"depth":76,"text":1180},{"id":1216,"depth":76,"text":1217},{"id":1391,"depth":76,"text":1392},{"id":1418,"depth":76,"text":1419},{"id":1448,"depth":76,"text":1449},"gpdf's 12-column grid uses r.Col(span, fn) where span is 1–12. Column width is (span/12) of the row. No breakpoints, no gutters, predictable by design.",false,"md",{"name":1503,"totalTime":1504,"tools":1505,"steps":1507},"Lay out a page with gpdf's 12-column grid","PT10M",[1506,125],"Go 1.22+",[1508,1511,1514,1517,1520],{"name":1509,"text":1510},"Open a row on the page","Call page.AutoRow(fn) for a row whose height grows to fit the tallest column, or page.Row(height, fn) when you want to pin the height.",{"name":1512,"text":1513},"Declare columns with r.Col(span, fn)","Inside the row, call r.Col(span, fn) once per column. span is an integer from 1 to 12 — the fraction of the row width this column takes.",{"name":1515,"text":1516},"Keep the spans per row summing to 12 or less","If the spans sum to less than 12 the remainder is left empty. If they sum to more than 12 the last column overflows the row — usually not what you want.",{"name":1518,"text":1519},"Fill the column with content","Inside the ColBuilder callback, call c.Text, c.Image, c.Table, or c.Spacer. Columns stack content vertically in the order you add it.",{"name":1521,"text":1522},"Start the next row","Call page.AutoRow again for the next visual row. Rows are independent — a 4+8 row can sit directly above a 3+3+3+3 row.",null,{},"/blog/12-column-grid",{"title":5,"description":1499},"blog/005.12-column-grid",[1529,1530,1531],"recipe","tutorial","templates","VkukJjF_h1mccyCuNBa-_3u6h22zpCgdRwRZ1XCbp2E",1776529258776]