How to number page columns

I’m making a layout for a document that uses 2 columns. How can I add page/column numbers to the bottom of each column?

Trying this puts page numbers at the bottom of each page, but I want them at the bottom of each column, incremented on each column.

#set page(
  columns: 2,
  numbering: "1",
)

The page numbers at the bottom are just the default footer. You can use your own counter with your own footer for this:

#let column-count = 2
#set page(
  columns: column-count,
  numbering: "1",
  footer: grid(
    align: center,
    columns: (1fr,) * column-count,
    ..([
      #counter("column").step()
      #context counter("column").display()
    ],) * column-count
  )
)


// Demo
#set page(height: 20em)
#lorem(350)

Note that this solution will always print numbers for all columns, even if the last N columns are empty. Detecting the number of effectively used columns in a page is a much less trivial task.

2 Likes

I implemented the feature of not numbering blank columns based on the code from @PgBiel.

Basically, I achieved this by placing metadata at the end of the document and comparing the current position with the x-coordinate of the document’s end during numbering.

However, this might be unstable due to the presence of manually set margins on the page (in fact, the column number’s position can also shift, and although I tried to fix this, the default value of page.margin is set to auto, so I can’t retrieve the value). If this issue arises, you can try fixing it by modifying the total-w variable in the gutter-x function.

#let column-count = 3
#set page(
  columns: column-count,
  numbering: "1",
  footer: grid(
    align: center,
    columns: (1fr,) * column-count,
    ..(
      {
        let gutter-x(n) = {
          let total-w = page.width
          let col-w = total-w / column-count
          let res = col-w * (column-count - n - 1)
          return res
        }

        counter("column").step()
        context {
          let cnt = counter("column").final().first() - counter("column").get().first()
          if (cnt < column-count) {
            if (query(metadata.where(value: "eof")).first().location().position().x > gutter-x(cnt)) {
              counter("column").display()
            }
          } else {
            counter("column").display()
          }
        }
      },
    ) * column-count
  ),
)


// Demo
#set page(height: 20em)
#lorem(260)
#metadata("eof")

#context page.
Preview