Resolving Auto-Scroll issues for overflow container in a Nuxt app

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 Table of Contents The Initial Design The Issue The Solution Summary 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: 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

Jan 15, 2025 - 09:58
Resolving Auto-Scroll issues for overflow container in a Nuxt app

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

  • Table of Contents
  • The Initial Design
  • The Issue
  • The Solution
  • Summary

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:

 class="h-full flex flex-col bg-mayash-main-light dark-mode">
   />
   class="flex-1 overflow-y-auto overflow-x-hidden">
     />
  
   />

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