Before I get to the topic of this post, I want to mention a few things:
- This post is a test post. I wrote it to try a few things regarding this website, not because its content is really interesting.
- This post only applies to this website in its current state (see release and update dates above). It may be entirely obsolete when you read this.
With that out of the way, let's get going!
If you have used this website both on a mobile and a desktop device, you may have noticed that it changes its look to fit the devices size. This is called responsive (web) design, and while important, not particularly impressive in the modern web.
One part that is majorly affected by this is the navigation. On a big screen, you will find that all the links are directly in the header. On a small screen they are hidden behind a hamburger menu. The same also applies to the desktops side bar, which is hidden behind the arrow button in the mobile versions header.
When you open either of these on a small screen, they will take up the entire screen. As you would expect, you can no longer interact with the content behind the menu. And you would be forgiven if you thought the browser does this automatically.
Sadly, in reality, the website author needs to remember to implement this. So in this post I want to explain how I did it.
How the menus work
However, first we need to talk about how the menus work.
Basically, we have a checkbox, a label for it and a
<div> with our menu content. We make the
checkbox and the menu invisible. If the checkbox is checked (the user clicked on the label), we
make the menu visible again.
Here is a small code example:
1 2 Toggle Button 3 Some Content
With our knowledge of the menus functionality from above, we can now set out to solve the problem at hand.
Basically, we just need to test if either of the checkboxes is checked and, if so, disable scrolling
The following code resembles the functionality of my first implementation. However, I made it a bit more organized, so I can easily highlight the changes later on.
At first glance, this seems to work quite well. However, there is a catch.
The header of this website stays fixed to the top of your screen on almost all devices. However, on a vertically small device (like a smartphone in landscape mode) it remains at the top of the page instead. This causes a problem.
With the code above, if a user open a menu in portrait mode and then changes their phone to landscape, they will be left without a way to close it. Here a screenshot of how it looks like on my Google Pixel 5:
On my site, I use
for this, which also requires me to set
In the following snippet, the changes compared to earlier are highlighted.
Perfect! Now the users will always have a way to close the menu.
However, there still is a problem. If somebody opens the website in a small window on a computer, opens a menu and then makes the screen big enough for the desktop navigation, they will no longer be able to close it (since the close button disappeared) and won't be able to scroll either. We need to fix this!
This is the most complicated part. We need to check wether we are in mobile or desktop mode. There
are a few techniques we could use to determine this, like checking
However, I didn't want to specify breakpoints in more than one file, so I decided to rely on a
styled element. This element is
#aside-toggle-closer and it is set to
display: none; when in
To check if this is the case, we first need to use
to get the actual values.
element.style only contains the styling rules specific to an element.
With that, we can check if we are on mobile before locking and unlocking scrolling:
All we now have left to do is to call the function we just wrote. We need to call it on three different occasions:
- when the page is opened,
- when the window is resized and
- when one of the menus is opened or closed.
We can write a function to do this:
Now we just need to call this function when the page is loaded:
1 if document.readyState != "loading"
While this scroll locking functionality is quite easy to implement, as you have seen, I still dislike it.
this website I couldn't implement without it, which annoys me considerably. It also means that I
have to include
script-src: 'self' in my
Content Security Policy.
So I tried to find a CSS based alternative. And happy me I found one:
:has(). This should make it possible to
write CSS like this:
Now you might be confused. If there is a CSS solution, why did I write this post at all? Well, if
you read the linked page to the end, you'll find that currently no browser supports
honestly seemed like a bad joke when I noticed that.
With that said, have a nice day!