hexa.ninja mascot

Welcome to my devlog. I will be sharing notes and tidbits from working on personal side projects.

You can subscribe to this page via RSS.

TIL about CSS scroll-margin

I am working on the bigbrowser documentation website, and the page has a sticky navigation bar at the top.

Everything was working well until I decided to add a basic table of content. Clicking on a section would scroll to the correct location, but the section title was hidden behind the sticky navbar.

It turns out there’s a CSS property designed to help with this use case: scroll-margin-top.

It’s mainly used for “scroll snapping” (which I’d never heard of before either). This helps implement carousel-style scrolling where content “snaps” into place (the MDN page shows an example). But since it also affects anchored links scroll positions, that’s exactly what I needed.

Here’s the fix, it can be applied to headings directly, and anchored links will magically have a 80px margin top:

#docs h2[id],
#docs h3[id] {
    scroll-margin-top: 80px;
}

I had no idea that “offsetting” the scroll was natively supported in CSS, it’s quite nice not having to resort to any hack!

The heading is now properly positioned below the sticky navbar

bigbrowser: content extraction weirdness

While reviewing the results of the content extractor (used to power the history search engine), I ended up with CSS rules as part of the extracted text.

.css-1x8m391 { fill: rgb(7, 79, 105); } extracted content

At first, I thought that the website somehow embedded CSS style outside of regular <style> tags.

It turns out that the indexed website is using XHTML (as in <html xmlns="http://www.w3.org/1999/xhtml" lang="en">) and uses some namespaced <style> tags: <a0:style>.

This is my first time stumbling upon namespaced tags while processing HTML documents.

bigbrowser uses html5ever for content extraction and the namespace is included as part of the tag local name.

This was kind of unexpected to me, but XHTML is XML and it makes sense for a “pure” HTML parser to parse the whole tag without parsing the namespace.

As a result, I ended up using tag_name_str.ends_with(":style") to detect style tags.