CSS Snippet: Keep divider line from being folded into headers

If you’re like me and use divider lines to visually separate note sections - this snippet is for you!

One of my pain points using Obsidian is that I like to use divider lines (aka divider bar or <hr> / horizontal rule) to make the different sections of my notes visually distinct. I use headers for section titles, but at a glance I like the visual of a divider line between sections as well.

The problem? Folding (aka collapsing) a header section (which I often do in certain notes) hides the divider line. While this is correct as per the Markdown spec, I wanted a workaround.

So, here’s my fix (originally shared in a feature request post):

The below CSS snippet makes it easy to turn a divider into a header (protecting it from folding), doesn’t introduce any additional characters or html into the note, and leaves everything working normally except when # is added to the line immediately above your ---:

/* 
Hide and resize H1 style when it has a hr divider line immediately after.
*/

.HyperMD-header-1:has(+ .hr) {
    opacity: 0;
    font-size: 1px;
}

.cm-active.HyperMD-header-1:has(+ .hr) {
    opacity: 100;
    font-size: var(--h1-size);
}

The snippet is pretty simple! Here’s how to use it after installing:

  1. Add # to the line before your divider line (---)
  2. That’s it!

What the snippet is doing: It’s basically restyling your H1 (#) when it’s immediately followed by a --- on the next line (which Obsidian automatically adds a hr class to). Thanks to the CSS has:() modifier it’ll only restyle your H1 if it sees an hr class after.

The H1 line will then become 1px (so the spacing around the divider looks good) and the visible markdown will disappear without needing to do anything else to it. To keep things user friendly, the H1 line will display normally when it’s the active line so it’s easy to adjust or delete the markdown whenever needed.

If you want the same thing to happen with H2-6, here’s the CSS for that (I personally always use H2 for my divider lines as H1 is reserved for my note title):

/* 
Hide and resize header styles when there's a hr divider line immediately after.
*/

.HyperMD-header-1:has(+ .hr) {
    opacity: 0;
    font-size: 1px;
}

.cm-active.HyperMD-header-1:has(+ .hr) {
    opacity: 100;
    font-size: var(--h1-size);
}

.HyperMD-header-2:has(+ .hr) {
    opacity: 0;
    font-size: 1px;
}

.cm-active.HyperMD-header-2:has(+ .hr) {
    opacity: 100;
    font-size: var(--h2-size);
}

.HyperMD-header-3:has(+ .hr) {
    opacity: 0;
    font-size: 1px;
}

.cm-active.HyperMD-header-3:has(+ .hr) {
    opacity: 100;
    font-size: var(--h3-size);
}

.HyperMD-header-4:has(+ .hr) {
    opacity: 0;
    font-size: 1px;
}

.cm-active.HyperMD-header-4:has(+ .hr) {
    opacity: 100;
    font-size: var(--h4-size);
}

.HyperMD-header-5:has(+ .hr) {
    opacity: 0;
    font-size: 1px;
}

.cm-active.HyperMD-header-5:has(+ .hr) {
    opacity: 100;
    font-size: var(--h5-size);
}

.HyperMD-header-6:has(+ .hr) {
    opacity: 0;
    font-size: 1px;
}

.cm-active.HyperMD-header-6:has(+ .hr) {
    opacity: 100;
    font-size: var(--h6-size);
}

Hope others find this helpful! I love Obsidian snippets.

9 Likes

It’s not work :smiling_face_with_tear:

1 Like

Yep, seems to have stopped working recently. Was a game-changer

1 Like

Glad folks like it! And bummer it’s not working. It still seems to be working for me as expected on Obsidian Version 1.4.16 running on Windows / Mac / iOS / Android.

Could folks post their setups where it stopped working? And any screenshots of what not working looks like (ie does it now just not hide the markdown?). I can try to troubleshoot.

If others are wanting to fiddle with things: if it broke it’s likely due to how Obsidian is treating the hr or active class (ie if they are no longer appending .hr to ---). The rest of the CSS is pretty straightforward and is unlikely to break since it’s just changing opacity and font size. The inspector is the best way to check this out (on mac you can open it by pressing: cmd + option + i).

1 Like

Thank u, I found it’s working when I don’t fold the headers with line :+1:
ezgif.com-video-to-gif

1 Like

For anybody following along, I’ve made an improvement to this snippet for my use case. I’ve made it so the header markdown is much smaller when visible. This makes it less obtrusive when navigating through line breaks. The CSS is also simplified as a result.

Now anytime there’s a line break after header markdown, the header markdown font size will be 1em and will otherwise disappear when not the active line like you would expect w/ markdown in preview mode.

The duplication is to avoid some CSS pop-in that happens when navigating the text in weird ways (like clicking and holding on a new line). This should keep the header markdown a solid 1em regardless of how you click/navigate.

.HyperMD-header:has(+ .hr) {
    opacity: 0;
    font-size: 1px;
}

.cm-active.HyperMD-header:has(+ .hr) {
    opacity: 100;
    font-size: 1em;
}

.HyperMD-header:has(+ .HyperMD-hr) {
    font-size: 1em;
}

.cm-active.HyperMD-header:has(+ .HyperMD-hr) {
    font-size: 1em;
}

.cm-line:has(+ .cm-active.HyperMD-hr) {
    font-size: 1em;
}
2 Likes

Thanks for the snippet @mattmaiorana!

I took a moment to simplify it quite a bit. This version targets all heading levels and accomplishes everything form your original snippet within a single declaration:

/* 
Hide non-active headers that are followed by hr divider line.
*/
.HyperMD-header:not(.cm-active):has(+ .hr) {
    opacity: 0;
    font-size: 1px;
}

Then I expanded it so any headings with text will still be visible. In this version, only non-active and empty headings followed by an hr divider are hidden:

/* 
Hide non-active and empty headers that are followed by hr divider line.
*/
.HyperMD-header:not(.cm-active):not(:has(.cm-header:not(.cm-formatting))):has(+ .hr) {
    opacity: 0;
    font-size: 1px;
}
4 Likes

Yo this snippet was awesome!
Just for future onlookers. You can modify this code to not only fit with --- dividers but also custom dividers.

How to create custom dividers
image

This code modifies any html embed I create that contains the class divider.

/*Hide non-active headers that are followed by .cm-html-embed with .divider inside.*/
.HyperMD-header:not(.cm-active):has(.cm-header:not(.cm-formatting)):has(+ .cm-html-embed .divider),
.HyperMD-header:not(.cm-active):has(.cm-header:not(.cm-formatting)):has(+ .cm-html-embed .divider) {
    opacity: 0 !important;
    font-size: 1px !important;
}

Note: This code is modified so that it doesn’t show headers even if not empty. You can use the original code of :not(:has(.cm-header:not(.cm-formatting))) if you don’t want this behaviour. I just like that I can give my dividers titles as well.

Here’s an example of how I used them:
image
image

Heres the css snippet code you can use to try this out.

/*Hide non-active headers that are followed by .cm-html-embed with .divider inside.*/
.HyperMD-header:not(.cm-active):has(.cm-header:not(.cm-formatting)):has(+ .cm-html-embed .divider),
.HyperMD-header:not(.cm-active):has(.cm-header:not(.cm-formatting)):has(+ .cm-html-embed .divider) {
    opacity: 0 !important;
    font-size: 1px !important;
}

/*Add Custom Divider*/
.divider {
    display: flex;
    align-items: center;
    text-align: center;
    color: grey;
}

.divider::after,
.divider::before {
    content: "";
    border-bottom: 1px solid grey;
    flex: 1;
}

.divider:not(:empty)::before {
    margin-right: .25em;
}

.divider:not(:empty)::after {
    margin-left: .25em;
}

Here is the html code you can embed in your obsidian notes.

<div class="divider">TEXT</div>
1 Like

Love the additions and improvements! Thanks for chiming in @rzen and @IanTeves.

1 Like

You don’t know how happy this topic and its replies makes me. Thank you!

Seriously, Rzen, that’s some harry potter-level industrial light and magic @$#$ happening with that tiny amount of code. HOW. HOW YOU DO?