¿Cómo funciona la cuadrícula de 12 columnas de gpdf?
La cuadrícula de 12 columnas de gpdf usa r.Col(span, fn) con span de 1 a 12. El ancho de columna es (span/12) de la fila. Sin breakpoints ni canalones, diseñada para PDF.
La pregunta, dicha de otra forma
Ya conoces la API de gpdf — constructor de página, de fila, de columna — y el constructor de columna recibe un número: r.Col(4, fn), r.Col(8, fn). ¿Qué es ese número, qué pasa si los spans no suman 12, y en qué se parece a la cuadrícula que ya conoces de CSS?
Respuesta corta
r.Col(span, fn) recibe un entero de 1 a 12. Ese entero es la parte de la fila que ocupa la columna — span / 12 del ancho disponible. Valores por debajo de 1 se recortan a 1, por encima de 12 se recortan a 12, y la librería no obliga a que los spans sumen 12 por fila. La cuadrícula está fijada en 12 divisiones; lo demás es decisión tuya sobre cómo cortar cada fila.
Un ejemplo que funciona
package main
import (
"log"
"os"
"github.com/gpdf-dev/gpdf"
"github.com/gpdf-dev/gpdf/document"
"github.com/gpdf-dev/gpdf/template"
)
func main() {
doc := gpdf.NewDocument(
gpdf.WithPageSize(document.A4),
gpdf.WithMargins(document.UniformEdges(document.Mm(15))),
)
page := doc.AddPage()
// Ancho completo
page.AutoRow(func(r *template.RowBuilder) {
r.Col(12, func(c *template.ColBuilder) {
c.Text("Factura #2026-0416", template.FontSize(18), template.Bold())
})
})
// Cabecera a dos columnas (6 + 6)
page.AutoRow(func(r *template.RowBuilder) {
r.Col(6, func(c *template.ColBuilder) {
c.Text("Facturado a")
c.Text("Acme S.L.")
})
r.Col(6, func(c *template.ColBuilder) {
c.Text("Fecha de emisión")
c.Text("2026-04-16")
})
})
// Resumen a tres columnas (4 + 4 + 4)
page.AutoRow(func(r *template.RowBuilder) {
r.Col(4, func(c *template.ColBuilder) {
c.Text("Subtotal")
})
r.Col(4, func(c *template.ColBuilder) {
c.Text("IVA")
})
r.Col(4, func(c *template.ColBuilder) {
c.Text("Total")
})
})
// Asimétrica (8 + 4) — cuerpo + panel lateral
page.AutoRow(func(r *template.RowBuilder) {
r.Col(8, func(c *template.ColBuilder) {
c.Text("Las líneas aparecen aquí")
})
r.Col(4, func(c *template.ColBuilder) {
c.Text("Notas")
})
})
data, err := doc.Generate()
if err != nil {
log.Fatal(err)
}
if err := os.WriteFile("layout.pdf", data, 0o644); err != nil {
log.Fatal(err)
}
}
Ejecuta go run main.go. Obtienes una página con cuatro filas, cada una dividida de manera distinta.
Por qué 12
12 se divide limpiamente entre 2, 3, 4 y 6. Eso cubre casi cualquier maquetación real: mitades (6+6), tercios (4+4+4), cuartos (3+3+3+3), barra lateral + cuerpo (3+9 o 4+8), cuerpo + columna auxiliar (8+4). Con un número de menos factores pierdes una de esas combinaciones. Bootstrap se decantó por doce en 2011 por la misma razón, y hoy "cuadrícula de 12 columnas" es la lingua franca que cualquier diseñador o ingeniero de frontend ya habla. gpdf toma prestado ese modismo a propósito — una maquetación PDF no es un modelo mental distinto al de la web, aunque el destino de renderizado sea papel de ancho fijo.
La cuenta, escrita
Con A4 vertical y márgenes uniformes de 15 mm, el ancho útil es de 180 mm. Un Col(4) dentro de una fila ocupa 4/12 de eso — 60 mm. Col(8) ocupa 120 mm. Entre columnas no hay canalón (gutter) por defecto. Si quieres aire, añade un c.Spacer dentro de la columna más corta o deja vacío un Col(1).
El ancho se calcula como porcentaje en tiempo de construcción (la implementación está en gpdf/template/grid.go) y el motor de layout lo resuelve a puntos usando el ancho de página actual menos los márgenes. Es decir, el mismo r.Col(6, fn) tiene distinto ancho físico en A4 o Letter, pero la misma proporción de fila.
Cuando la suma no da 12
gpdf no valida que los spans sumen. Es intencionado.
- Suma < 12: el lado derecho queda en blanco. Útil cuando quieres anclar una columna al borde izquierdo y dejar el resto vacío a propósito.
- Suma > 12: la última columna se sale del margen derecho. Casi siempre un bug. El PDF sale torcido, pero no hay crash.
La mayoría de las maquetaciones acaban sumando exactamente 12 por fila, porque es lo que llena la página. Pero cuando quieres un bloque de ancho 6 en el centro de la línea, lo natural es escribir Col(3) vacía, Col(6) contenido, Col(3) vacía — la cuadrícula está pensada para ese tipo de taquigrafía.
AutoRow vs Row
page.AutoRow(fn) crece verticalmente hasta la columna más alta. La mayoría de filas deberían usarlo.
page.Row(height, fn) fija la altura. El contenido que sobresalga se recorta. Úsalo para cabeceras de factura que deben medir exactamente 30 mm para que cuadre el grapado posterior, y para cualquier situación en la que la consistencia visual pese más que la libertad del contenido.
page.Row(document.Mm(30), func(r *template.RowBuilder) {
r.Col(8, func(c *template.ColBuilder) {
c.Text("Logo")
})
r.Col(4, func(c *template.ColBuilder) {
c.Text("Nº de factura")
})
})
Lo que la cuadrícula no hace
Sin anidación. ColBuilder acepta elementos de contenido (Text / Image / Table / List / Spacer), pero no otra fila dentro. Las maquetaciones que parecen necesitar anidación suelen quedar mejor como dos filas hermanas al nivel de la página.
Sin columnas de offset. Bootstrap tiene .offset-2; gpdf no. Si quieres empujar contenido a la derecha, deja un Col(n) vacío a la izquierda.
Sin breakpoints. Las páginas PDF no cambian de tamaño. La cuadrícula produce la misma maquetación en cualquier dispositivo porque la salida es un ráster de coordenadas fijas, no un DOM que re-fluya.
Estas ausencias son el punto. Cada función que la cuadrícula no tiene es una clase de ambigüedad que la salida PDF no tiene que razonar.
Lecturas relacionadas
- ¿Cómo incrusto una fuente japonesa en gpdf? — CJK dentro de columnas de cuadrícula
- Comparativa de librerías Go PDF 2026 — cómo se compara la API Builder con gofpdf, gopdf y Maroto
- Guía de layout — referencia completa de filas, columnas y espaciado
Prueba gpdf
gpdf es una librería Go para generar PDFs. Licencia MIT, cero dependencias externas, soporte CJK nativo.
go get github.com/gpdf-dev/gpdf