In this article, I share how I resolved the auto-scroll issue caused by an overflow container within a non-scrollable body
in a Nuxt app, and improved the user experience when scrolling my website
Table of Contents
The Initial Design
When I built my website using Nuxt.js, my initial design was to have only the main
content container scrollable, while the header
and footer
remained fixed—without using CSS fixed
or absolute
positioning.
To achieve this, I used a combination of CSS flex
and overflow
properties, starting with the body
tag:
body {
overflow: hidden;
height: 100%;
}
In the default.vue
layout:
<div class="h-full flex flex-col bg-mayash-main-light dark-mode">
<nav-header />
<main class="flex-1 overflow-y-auto overflow-x-hidden">
<slot />
</main>
<nav-footer />
</div>
In the above code, I ensured the body was not scrollable using overflow-hidden
while keeping the height statically set to 100%
. The main
container was set to flex-1
to expand and fill the remaining space after the header and footer. I used overflow-y-auto
to make the container scrollable vertically only. This setup allowed the page to work as intended based on the initial design.
However, problems arose when I added the table of contents to the article page. The table of contents is a list of links to section headings within an article, and clicking on a link should scroll to the corresponding section. Unfortunately, it didn’t.
Additionally, when refreshing the article page with an HTML anchor (#
) in the URL, the browser didn’t scroll to the desired section. Navigating back to the article page from another page also failed to auto-scroll to the top of the page. For example, navigating to the Speaking page from the Article page left the user at the bottom instead of at the top.
Furthermore, I received complaints about the footer being fixed at the bottom of the page, which some users found distracting when reading the article.
Clearly, I needed to change my design and fix these issues. But is it that simple? Let's find out.
The Issue
Nuxt.js 3 uses Vue Router to handle application routing, which includes auto-scrolling when navigating between pages, with a smooth transition effect. So, it should work, right?
Unfortunately, it didn’t.
I tried different workarounds, including using Vue Router custom scroll behavior, using scrollBehaviorType
, and even window.scrollTo
. None of these approaches worked.
So, is there a way to fix this issue?
The Solution
After some research, I discovered that the issue was caused by the combination of the overflow
and height
CSS properties. When height
is set to a fixed value (like 100%
) and overflow
on the body
tag is set to hidden
, the scrollbar displayed on the right side of the page isn’t for the body
tag but for the main
container instead.
When navigating between routes or sections, the browser, by default, tries to scroll the body
tag. Since the body
is not scrollable, the browser doesn’t know which container to scroll, leading to the issue.
There are several ways to work around this problem, such as querying the main
container's DOM reference and using the scrollTo
method to manually scroll the container to the desired section whenever the route changes. However, this approach is not ideal — it’s complex to implement and not a good practice.
A more straightforward solution is to remove the height: 100%
and overflow: hidden
properties from the body
tag and use position: sticky
for the header
to keep it fixed at the top instead:
body {
/* overflow: hidden; */
/* height: 100%; */
}
header {
position: sticky;
top: 0;
z-index: 100;
}
We also need to set top: 0
and z-index
to ensure the header remains at the top of the page and appears above other elements.
And that’s it! The page now has the header fixed at the top, and the content automatically scrolls based on route changes or HTML anchor links, utilizing the browser’s default smooth transition effect.
Summary
In this article, I shared how I resolved the auto-scroll issue caused by an overflow container within a non-scrollable body
in a Nuxt app. The issue stemmed from the combination of overflow
and a fixed height
CSS property and can affect any web project, not just those using Nuxt or Vue Router. Depending on your goals, the solution may involve simply removing this CSS combination or implementing a more complex workaround, such as manually triggering scrollTo on the target scrollable container. So, the next time you encounter this issue, you’ll know how to fix it 😉!
👉 Learn about Vue 3 and TypeScript with my new book Learning Vue!
👉 If you'd like to catch up with me sometimes, follow me on X | LinkedIn.
Like this post or find it helpful? Share it 👇🏼 😉
Top comments (0)