Quantcast
Channel: Active questions tagged flexbox - Stack Overflow
Viewing all articles
Browse latest Browse all 1675

How to make a child fill 100% height for a "full-screen" scroll effect, inside a dynamic flexbox container?

$
0
0

I am trying to build a page layout with a standard structure: a Header, a Footer, and a main content area that fills the available vertical space.

The Goal

Inside the main content area, I want to create "full-screen" scrollable sections. The desired behavior is:

  1. The first section (.screen-1) should take up exactly 100% of the visible height of its scrolling container (.main-content-wrapper).
  2. Any subsequent content (.screen-2, etc.) should be positioned directly below the first section.
  3. The user must scroll within the main content area to see the subsequent content.

Essentially, I'm aiming for a "full-page" slide effect inside a specific part of the layout, not the whole browser window.

My Layout Structure

My page is built with Flexbox.

  • A top-level .layout-container uses display: flex and flex-direction: column to arrange the Header, Main Content, and Footer.
  • The .main-content-wrapper has flex: 1 so it grows to fill the space between the header and footer. This is the element that should have its own scrollbar when content overflows.
  • Inside it, .page-main-content holds the actual sections.

What I've Tried and The Problem

The core issue is that I cannot get .screen-1 to be 100% of its parent's height. It seems the height of the flex: 1 container isn't "defined" in a way that allows its children to use percentage-based heights effectively.

Here are my attempts:

  1. Using flex: 1 on the child: My first thought was to apply flex: 1 to .screen-1. I expected this would make it greedily take up all available space, pushing .screen-2 out of view.

    • Actual Result: Instead of filling the container, .screen-1 only takes up the remaining space after .screen-2 has taken up space for its own content. Both sections remain visible simultaneously.
  2. Using height: 100%: I also tried setting height: 100% or min-height: 100% on .screen-1.

    • Actual Result: This had no effect. The element collapsed to the height of its inner content, likely because its flex parent (.page-main-content) doesn't have a specific height for the percentage to be based on.

Here is a Minimal Reproducible Example (MRE) that demonstrates my setup and the issue.

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Flexbox Height Problem MRE</title><style>    /* Basic Reset & Body Setup */    * {      box-sizing: border-box;      margin: 0;    }    html, body {      height: 100%;      font-family: sans-serif;    }    /*       This is the main layout container, similar to my `layouts/default.vue`.      It arranges Header, Main Content, and Footer vertically.    */    .layout-container {      display: flex;      flex-direction: column;      min-height: 100vh;      background-color: #f0f2f5;    }    .app-header {      padding: 1rem;      background-color: #e3f2fd;      border-bottom: 1px solid #bbdefb;      text-align: center;    }    .app-footer {      padding: 1rem;      background-color: #e8f5e9;      border-top: 1px solid #c8e6c9;      text-align: center;    }    /*       This is the main content area that should fill the remaining space.      It has `flex: 1`. This is the container I want to have its own scrollbar.    */    .main-content-wrapper {      flex: 1;      display: flex; /* This is crucial, it allows its child to grow */      flex-direction: column;      /* For demonstration: show the boundary and enable scrolling if content overflows */      overflow-y: auto;       border: 2px dashed red;    }    /*       This represents my "page" component, like `pages/index.vue`.      It's inside the main content wrapper.    */    .page-main-content {      /* My initial attempt uses flex: 1 here */      flex: 1;      display: flex;      flex-direction: column;    }    /* --- THE PROBLEM IS HERE --- */    .screen {      display: grid;      place-items: center;      padding: 2rem;      font-size: 1.5rem;      font-weight: bold;      color: white;    }    /* This is "Screen 1" */    .screen-1 {      /* This is what I tried. It doesn't make the screen full-height. */      /* It just takes up the *remaining* space. */      flex: 1;      background-color: #3f51b5;    }    /* This is "Screen 2" */    .screen-2 {      /* This screen just takes space for its content, but it's still visible. */      background-color: #43a047;      min-height: 150px; /* Give it some height for the demo */    }</style></head><body><div class="layout-container"><header class="app-header"><h1>Header</h1></header><div class="main-content-wrapper"><main class="page-main-content"><div class="screen screen-1"><p>Screen 1</p><p style="font-size: 1rem; font-weight: normal;">I want this section to be 100% the height of the red dashed container.</p></div><div class="screen screen-2"><p>Screen 2</p><p style="font-size: 1rem; font-weight: normal;">I should only be visible after scrolling down inside the red dashed container.</p></div></main></div><footer class="app-footer"><p>Footer</p></footer></div></body></html>

My question is: What is the correct CSS approach to make .screen-1 occupy 100% of the height of its scrollable container (.main-content-wrapper), thereby forcing .screen-2 to be pushed down and become visible only after scrolling?

If possible, please try to provide a solution that doesn't change the nested HTML structure in the MRE. This is a key constraint for me, as changing it would break my existing layout. 🫠
That said, I'm not entirely sure if my HTML structure is the correct approach to begin with. For full context, I've also attached my original Vue code below for reference.

Thank you in advance for any help


<template><div class="layout relative isolate"><div ref="bgLayerAEl" class="fixed inset-0 -z-10 h-[100dvh] bg-cover bg-fixed bg-center opacity-100" /><div ref="bgLayerBEl" class="fixed inset-0 -z-10 h-[100dvh] bg-cover bg-fixed bg-center opacity-0" /><div class="flex min-h-screen flex-col pb-12"><AppHeader        ref="headerCmp"        class="sticky top-0 pb-0!" :class="[{'mb-2 p-2 md:mb-3 md:p-3 lg:mb-4 lg:p-4': spacing === 'small','mb-4 p-4 md:mb-6 md:p-6 lg:mb-8 lg:p-8': spacing === 'medium','mb-8 p-8 md:mb-12 md:p-12 lg:mb-16 lg:p-16': spacing === 'large',        }]"      /><div        class="flex flex-1 flex-col overflow-y-auto" :class="{'px-2 md:px-3 lg:px-4': spacing === 'small','px-4 md:px-6 lg:px-8': spacing === 'medium','px-8 md:px-12 lg:p-16': spacing === 'large',        }"><slot /></div></div><AppFooter /></div></template>
<template><!-- will be into <slot /> --><main><div class="text-2xl">      Screen 1</div><div class="text-2xl">      Screen 2</div></main></template>

Viewing all articles
Browse latest Browse all 1675

Trending Articles