How can I make a grid more flexible?

Hello, I am quite new to Typst and this is my first attempt at creating a layout. I’m recreating some templates from a labeling software, so I’m trying to get the measurements in the layout as close as possible to the original.

I started with grids and here is what I came up with (code below):

If you notice, the main difference is the placement of the lime square. Of course, this would make the other squares squish/expand depending on the placement. Is starting with a grid a bad idea? I feel like if I structured this differently, I could get closer to being able to using an if statement somewhere that determines where to place the lime square, rather than in the several places I’d be forced to, given the above layout (including changing column/row sizes).

Hope that makes sense and thanks for any pointers in the right direction.

#set page(
  width: 90mm,
  height: 25mm, 
  margin: (y: 2mm, left: 3mm, right: 2mm)
)

#set text(size: 8pt, font: "Public Sans")

#grid(
  columns: (3mm, 1fr),
  column-gutter: (1mm),
  // stroke: .5pt,
  rows: 21mm,
  align: horizon,
  rect(fill: gray, width: 100%, height: 9mm),
  stack(
    grid(
      columns: (73mm, 1fr),
      rows: (5mm),
      rect(fill: lime, width: 100%),
      none
    ),
    v(1mm, weak: true),
    grid(
      columns: (73mm, 1fr),
      rows: (9mm),
      align: bottom,
      rect(fill: blue, width: 100%, height: 100%),
      rect(fill: olive, width: 100%, height: 100%)
    ),
    grid(
      columns: (38mm, 1fr),
      rows: (3mm),
      none,
      rect(fill: purple, width: 100%)
    ),
    grid(
      columns: (38mm, 1fr),
      rows: (3mm),
      rect(fill: orange, width: 100%),
      rect(fill: maroon, width: 100%)
    )
  )
)

#grid(
  columns: (3mm, 11mm, 1fr),
  column-gutter: (1mm),
  // stroke: .5pt,
  rows: 21mm,
  align: horizon,
  rect(fill: gray, width: 100%, height: 9mm),
  rect(fill: lime, width: 100%),
  stack(
    v(1mm, weak: true),
    grid(
      columns: (61mm, 1fr),
      rows: (14mm),
      align: bottom,
      rect(fill: blue, width: 100%, height: 100%),
      rect(fill: olive, width: 100%, height: 100%)
    ),
    grid(
      columns: (38mm, 1fr),
      rows: (3mm),
      none,
      rect(fill: purple, width: 100%)
    ),
    grid(
      columns: (38mm, 1fr),
      rows: (3mm),
      rect(fill: orange, width: 100%),
      rect(fill: maroon, width: 100%)
    )
  )
)

I think the main observation here is that you can simplify the “main” part of the layout, the one that’s squished/stretched, to a single grid. The olive square is always 8mm wide, so don’t use 1fr for that one. You end up with a grid like this:

grid(
  columns: (38mm, 1fr, 8mm),
  rows: (1fr, 3mm, 3mm),
  align: bottom,
  
  grid.cell(colspan: 2, rect(fill: blue, width: 100%, height: 100%)),
  rect(fill: olive, width: 100%, height: 100%),

  none,
  grid.cell(colspan: 2, rect(fill: purple, width: 100%)),

  rect(fill: orange, width: 100%),
  grid.cell(colspan: 2, rect(fill: maroon, width: 100%)),
)

The topmost row now also has a size of 1fr instead of 9mm or 14mm, respectively. Unfortunately, a fractional height in a vertical stack doesn’t play nicely, but we can replace it with a grid. That gives us

#let main = grid(...)

#grid(
  columns: (3mm, 1fr),
  column-gutter: 1mm,
  // stroke: .5pt,
  rows: 21mm,
  align: horizon,
  rect(fill: gray, width: 100%, height: 9mm),
  grid(
    columns: 1fr,
    rows: (5mm, 1fr),
    pad(right: 8mm, rect(fill: lime, width: 100%)),
    pad(top: 1mm, main),
  )
)

#grid(
  columns: (3mm, 11mm, 1fr),
  column-gutter: 1mm,
  // stroke: .5pt,
  rows: 21mm,
  align: horizon,
  rect(fill: gray, width: 100%, height: 9mm),
  rect(fill: lime, width: 100%),
  pad(top: 1mm, main),
)

I think that’s most of the way to simplifying this. Next steps could be

  • instead of using grids with different numbers of columns for the two situations, you could nest more grids:
    • top (same as now): the main grid within a grid that adds the lime block on top, within a grid that adds the gray block on the left
    • bottom: the main grid within a grid that adds the lime block on the left, within a grid that adds the gray block on the left
  • make the creation of the middle grid (the one adding the lime block) the conditional part

Awesome, that helps a ton. Thanks!