Logical off-screen positioning for “skip navigation” links
My home page has a skip navigation link as the very first child of the body
element. This allows folks who use assistive technologies to go directly to the main content of the page, bypassing the boring site-wide header text.
To make this skipnav link available to AT users but hidden otherwise, I used some simple CSS to position it off-screen by default and reveal it when focused:
#skipnav {
position: absolute;
top: -2em;
}
#skipnav:focus {
position: static;
top: auto;
}
These days, though, I’ve got multiple language variants of my landing page. The Japanese variant uses 縦書き (tategaki, vertical writing). (Cross-browser support for CSS writing modes is pretty good these days—not perfect, mind, but more than adequate for a simple personal website like mine.)
This is what English text looks like by default when set in writing-mode: vertical-rl
. And here’s some Japanese text set vertically:
娘はエーリンです。彼女のもう一人の母親はエーリンです。私の恋人はエーリンです。これは紛らわしいかもしれません。私の娘とパートナーと私はサンフランシスコに住んでいます。私の出身はボストンです。
writing-mode: vertical-rl
.You probably see where I’m going with this. On a page using vertical, right-to-left writing, using top: -2em
to push the skipnav link off-screen doesn’t work.
This is what English text looks like by default when set in writing-mode: vertical-rl
. And here’s some Japanese text set vertically:
娘はエーリンです。彼女のもう一人の母親はエーリンです。私の恋人はエーリンです。これは紛らわしいかもしれません。私の娘とパートナーと私はサンフランシスコに住んでいます。私の出身はボストンです。
top: -2em
does in vertical-rl
.At first, I worked around this by adding some additional styles on just my Japanese home page:
#skipnav {
top: auto;
right: -2em;
}
#skipnav:focus {
right: auto;
}
This isn’t great, though. I’d like to write a single bit of CSS that I can apply to all of my pages, regardless of their writing mode.
No problem! It’s 2024, and logical properties have been a thing for a while now. Just use inset-block-start
instead of top
—it’s supported in all three major browser engines.
#skipnav {
position: absolute;
inset-block-start: -2em;
}
#skipnav:focus {
position: static;
inset-block-start: auto;
}