Search code examples
htmlcsstailwind-cssoverflowcss-grid

How to add overflow:auto to a grid item using CSS


enter image description here

I have created an interface as shown above. The blue part is my sidenav, and the red part is my page title. The orange part is my body, and in case it is longer than the container, I want to add scrollbars, that scrolls only that part. Here is the code:

    <div id="container" class="h-[var(--window-height)] grid grid-cols-[auto,1fr]">
        <div id="sidebar" class="bg-blue-500">
            <div class="w-[300px]"></div>
        </div>
        <div id="content" class="h-full grid grid-rows-[auto,1fr]">
            <div id="title">
                <div class="bg-red-600 h-[50px]"></div>
            </div>
            <div id="body" class="overflow-y-auto">
                <div class="h-[2000px] bg-orange-600"></div>
            </div>
        </div>
    </div>

The problem is instead of getting scrollbars on div#body, it simply stretches to fit the contents then the whole page scrolls. Interestingly if I remove div#sidebar (and remove .grid from div#container of course), it scrolls as expected.

Also if I change .h-[2000px] to .h-[2000%] on the div inside div#body as shown below, it scrolls as expected.

    <div id="container" class="h-[var(--window-height)] grid grid-cols-[auto,1fr]">
        <div id="sidebar" class="bg-blue-500">
            <div class="w-[300px]"></div>
        </div>
        <div id="content" class="h-full grid grid-rows-[auto,1fr]">
            <div id="title">
                <div class="bg-red-600 h-[50px]"></div>
            </div>
            <div id="body" class="overflow-y-auto">
                <div class="h-[2000%] bg-orange-600"></div>
            </div>
        </div>
    </div>

What could be causing this, and how do I change things to get the expected results?

Full code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Grid overflow</title>

    <script src="https://cdn.tailwindcss.com"></script>

</head>
<body>

    <div id="container" class="h-[var(--window-height)] grid grid-cols-[auto,1fr]">
        <div id="sidebar" class="bg-blue-500">
            <div class="w-[300px]"></div>
        </div>
        <div id="content" class="h-full grid grid-rows-[auto,1fr]">
            <div id="title">
                <div class="bg-red-600 h-[50px]"></div>
            </div>
            <div id="body" class="overflow-y-auto">
                <div class="h-[2000px] bg-orange-600"></div>
            </div>
        </div>
    </div>

    <script>

        function setCssVars() {
            document.documentElement.style.setProperty('--window-height', `${window.innerHeight}px`);
            document.documentElement.style.setProperty('--window-width', `${window.innerWidth}px`);
        }

        window.addEventListener('resize', setCssVars);
        setCssVars();

    </script>
    
</body>
</html>


Solution

  • The reason for this result is that div#content is actually overflowing. Although you specified h-full, it didn’t prevent the overflow. Its child elements will exceed the height limit, and the overflow-y-auto you set on the child element won’t work. To solve this issue, you just need to add overflow-hidden to div#content:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Grid overflow</title>
    
        <script src="https://cdn.tailwindcss.com"></script>
    
    </head>
    <body>
    
        <div id="container" class="h-[var(--window-height)] grid grid-cols-[auto,1fr]">
            <div id="sidebar" class="bg-blue-500">
                <div class="w-[300px]"></div>
            </div>
            <div id="content" class="h-full overflow-hidden grid grid-rows-[auto,1fr]">
                <div id="title">
                    <div class="bg-red-600 h-[50px]"></div>
                </div>
                <div id="body" class="overflow-y-auto">
                    <div class="h-[2000px] bg-orange-600"></div>
                </div>
            </div>
        </div>
    
        <script>
    
            function setCssVars() {
                document.documentElement.style.setProperty('--window-height', `${window.innerHeight}px`);
                document.documentElement.style.setProperty('--window-width', `${window.innerWidth}px`);
            }
    
            window.addEventListener('resize', setCssVars);
            setCssVars();
    
        </script>
        
    </body>
    </html>


    In your case, there's no need to use any JavaScript. Additionally, using flex will be more convenient than grid. Without changing the page structure, the simplest method I can think of is as follows:

    <script src="https://cdn.tailwindcss.com"></script>
    
    <article id="container" class="flex h-dvh">
      <nav id="sidebar" class="bg-blue-500">
        <div class="w-[300px]"></div>
      </nav>
      <div id="content" class="flex grow flex-col">
        <header id="title">
          <div class="h-[50px] bg-red-600"></div>
        </header>
        <section id="body" class="overflow-auto">
          <div class="h-[2000px] bg-orange-600"></div>
        </section>
      </div>
    </article>