How can I apply a linear gradient on only some content (the text) in headings?

Hello,

My heading is as follows`

#show heading.where(level: 1): set text(fill: gradient.linear(black, blue))

#let header_stroke = [#box(
  width: 1fr, 
  line(
    length: 100%,
    stroke: (
      paint: gradient.linear(black,blue,dir:ltr),
      thickness: 0.1em,cap: "butt"
    )
  )
)
]

= Sample Heading  #header_stroke

Problem is that the linear gradient is applied to both the objects together.

Question is, how do i get to apply the linear gradient on the elements individually.

Thanks

please see sample below on how it looks with and without the stroke.

= #lorem(1) #header_stroke

= #lorem(1)

The gradient is based on the size of the container that it’s in, which is the heading. Since the heading with stroke is wider, the gradient becomes wider as well.

The solution is to put a smaller container into the heading:

= #box(lorem(1)) #header_stroke

(this assumes that the header is less wide than the full page, otherwise you run into line break issues…)

To automate this, you could wrap all text (in headings) into boxes:

#show heading.where(level: 1): it => {
  show text: box
  it
}

But careful: if you have individually styled parts, e.g. in Lorem _ipsum_, this will break your text and restart the gradient.

If you want all headings to have the stroke, the better way would thus be to put the whole heading body in a box in a heading show rule. That could look something like this:

#show heading.where(level: 1): it => block(sticky: true, {
  if it.numbering != none {
    context counter(heading).display()
    [ ]
  }
  box(it.body)
  [ ]
  header_stroke
})