Positioning heading numbers in markdown documents through CSS

Hello DT3 users,

I’d like to number the headings in my markdown documents through CSS, and I’d like those numbers to be in the margin of the page. I was able to do that with a CSS that includes the following:

body {
counter-reset: h1;
}

h1 {
display: list-item;
}

h1::marker {
counter-increment: h1;
content: counter(h1) " ";
list-style-position: outside;
}

However, that only works in Firefox. The h1::marker pseudo-element doesn’t seem to be well supported in Chrome, Safari, or DT3. I tried using an h1::before pseudo-element instead — for example, like this:

body {
counter-reset: h1;
}

h1::before {
counter-increment: h1;
content: counter(h1) " ";
}

But I can’t seem to figure out how to position the h1::before pseudo-element in the margin. I’m therefore wondering whether anyone could be so kind as to point me in the right direction. Thank you for your consideration.

Sincerely,
Enrico

A visual of what you hope to see would be helpful.
Like this… ?

… or this …?

… or maybe even… ?

Thank you for your prompt reply. My apologies. Here’s a screenshot of what I’m trying to accomplish:

Thank you.
Enrico

Enrico, this might work for your purpose, but the real CSS expert here are @chrillek and @BLUEFROG

body {
  counter-reset: section;  /* Initialize the h1 counter */
}

h1 {
  counter-reset: subsection;  /* Initialize the h2 counter */
}

h1::before {
  counter-increment: section;  /* Increment the h1 counter */
  content: counter(section) ". ";  /* Display the h1 counter */
}

h2 {
  counter-reset: subsubsection;  /* Initialize the h3 counter */
}

h2::before {
  counter-increment: subsection;  /* Increment the h2 counter */
  content: counter(section) "." counter(subsection) ". ";  /* Display the h1 and h2 counters */
}

h3::before {
  counter-increment: subsubsection;  /* Increment the h3 counter */
  content: counter(section) "." counter(subsection) "." counter(subsubsection) ". ";  /* Display the h1, h2 and h3 counters */
}

/* INDENTATION OF SUBHEADING PARAPGRAPHS */
h1, h1 + p {
  margin-left: 1rem;
}

h2, h2 + p {
  margin-left: 2rem;
}

h3, h3 + p {
  margin-left: 3rem;
}

h4, h4 + p {
  margin-left: 4rem;
}

I don’t see your logic in 1.2.1 since you’re only level deep with the h2. It seems it should be 1.1.1 unless you had a second h2.

Indeed there’s no logic, only a mistake: “1.2.1” should read “1.1.1”. Other than that, is it clear what I’m trying to achieve?

2 Likes

Thank you very much! I’ll try that first thing tomorrow morning as soon as I’m at my computer and report back. Thank you again.

(Not via the code from @vinschger)

Now updated and a bit more delicate to look at (and based on our DEVONtech color palette :slight_smile: )

Note: I zoomed out to show the numbering working properly.

That is beautifully implemented. Could you please also publish the corresponding CSS stylesheet code?

I want to look at something else in my styling, so later today I likely will. It’s 02:15 now and I’m crashing :face_with_spiral_eyes::sleeping:

That’s exactly what I was trying to achieve, @BLUEFROG! Thank you very much! Like @vinschger, I too would be really grateful if you could share the corresponding CSS — whenever most convenient to you of course. Again, thank you very much.

1 Like

Here is the document, not a stylesheet.
The styling is not complicated, but there are some CSS options I added for flexibility and to make it smarter.

As I advocate very often, do the styling inside the document while learning or developing it. This is faster and simpler as you see the changes immediately upon saving, no styling is ever cached, and there is only one document to deal with. Once the styling is working as desired, you can copy the styling to an external stylesheet (whether stored in DT or not) and link to it as needed.

Secondly, setting a default stylesheet isn’t the answer to all things Markdown unless you are only and always making documents with that particular styling. In this example, I flexed the headers in a specific way that would be undesirable in other documents, especially as prevalent as section headers are. A default stylesheet should contain only truly global styles. Again, if you’re only creating the same Markdown documents over and over again, the default stylesheet could be more complete. But if you’re using Markdown for many different purposes, it will be much smaller. Perhaps this forum post will clear some of this up:

And the document:
numbered-headers-final.md.zip (1.6 KB)

PS: This is not the only solution, but it works well.

1 Like

Cool.
I like that you’re using rem for units, a variable for the color and :has() for selectors!

@enricoscarpella: the ::marker pseudo-element is currently only defined for lists.

1 Like

wow - thank you!

The concept of integrating styling directly within a Markdown document for testing purposes is indeed helpful. I appreciate your guidance on this. Additionally, the ability to include multiple files with stylesheet codes for various purposes through transclusion is extremely beneficial. For example, using {{numberedheadings.md}} and {{largerheadings.md}} allows for easy adjustment of the current document’s style with pre-formatted styles as needed. This approach enables the use of a customized stylesheet while incorporating special formatting when necessary.

3 Likes

And this is something I have been exploring as a best practice. It’s like how UNIX has many small processes that do one thing incredibly well, I think smaller chunks of styling can often be very useful.

@BLUEFROG: Thank you very much for doing all that work for me. I went through the styling component of your file and learned that the only reason why my CSS wasn’t styling headings the way I wanted is that I hadn’t set negative margins for them. So, for example, for heading 1 I had:

body {
color: black;
background-color: white;
margin: 6em;
max-width: 66em;
text-align: left;
font-family: "Georgia", serif;
font-size: 100%;
counter-reset: h1;
}

p {
margin-top: 1.5em;
margin-bottom: 1.5em;
font-size: 1em;
line-height: 1.5em;
}

h1::before {
counter-increment: h1;
content: counter(h1) " ";
}

h1 {
margin-top: 0.63em;
margin-bottom: 0.63em;
font-weight: normal;
font-size: 2.18em;
line-height: 1.17em;
counter-reset: h2;
}

But if I add margin-left: -0.75em to h1, everything works the way I want:

I also like that you used rem, instead of em, units, so I will start working with those units from now on.

Finally, thank you for directing me to that post of yours. I agree with @vinschger: including styling directly into the file is very helpful, especially during the testing phase.

Again, thank you very much for all your help.

@chrillek: Thank you very much for your feedback. The ::marker pseudo-element seems to work with headings as long as I include in h1, for example, display: list-item, as I mentioned I had done in my opening post. So, again for example, if I use:

h1 {
display: list-item;
}

h1::marker {
content: "🙂 ";
list-style-position: outside;
}

I get the following in MDN Playground (but only if I use Firefox; If I use the playground in Safari, the bullet is not replaced by the emoji):

Would you then know by any chance why the content of the ::marker pseudo-element cannot be a counter? Thank you very much, also for your series of posts on CSS: I learned a lot from them.

I never thought of transclusion in this context, nice idea. Another way to fix the precedence problem, ie “how do I override only some pre-defined styles” might be the @layer rule.

For example, the main stylesheet could put all its definitions in a
@layer main
part. Any MD file could then define is own rules, thus selectively overriding what it wants. The “cool” thing here is that specificity does not matter: a more specific rule in the main lawyer can be overridden by a less specific one in the MD file.

Is it possible to create a numbered table of contents {{TOC}} with the same numbers as in the markdown document?

Make sure to understand the difference. rem is mostly fine, but em might be more appropriate in some cases, Jamey when you’re referring to the font size of an element. Eg, specifying the bottom margin for a h1 might be more natural in em

I overlooked that. And using display that way makes me cringe, but I can’t explain why. ::marker for list items is fully supported in all major browsers (except Safari, which isn’t “major” – consequently it might not work as it should in DT.)
I’d go for ::before and adding whatever you want to its content property.

According to the spec, it can be. Or rather content can be, and as a counter can be used by content
But then there’s Safari: "::marker" | Can I use... Support tables for HTML5, CSS3, etc
Another thing that they don’t do properly :cry:

I’d therefore style the ::before pseudo-element and use a negative margin as demonstrated by @BLUEFROG.

1 Like