Scrolling inside nested flexboxes

I am working on a React app that has modal content with some tabs that sometimes require scrolling inside. However, the problem is that I cannot get the scrolling of the relevant content.

The modal is split into 3 main sections:

  • Heading
    • Should always be visible at the top of the modal
  • Content
    • Should fill the gap between the header and footer , but never force it to appear
  • Footer
    • Must always be visible under Content
    • This could mean at the bottom of the modal (if the Content is filling the remaining space) or below the Content (if the Content is t filling the space)

While it would be easy to implement (and I've already done it), the problem arises because the Content shouldn't scroll, but rather something inside it. The images below show two examples of intended behavior, one with long content that needs to scroll, and one without.

I am using a custom tab that does something inside a container. This container (white in the images below) is what needs to be scrolled if needed.

The farthest I have come can be found in the following CodePen code and example. Currently, I can scroll to an element containing the intended scrollable content, but I cannot actually scroll that content. If you check Pen, you can see that it (for some reason) passes by the containing element.

Modal examples

Sample code

CodePen example

Html

<div class="modal">
  <div class="background" />
  <div class="modal_content">
    <div class="header">Random header</div>
    <div class="tabbed_content">
      <div class="tabs">
        <div class="tab active">Tab 1</div>
        <div class="tab">Tab 2</div>
      </div>
      <div class="content">
        <div class="scrollable">
          Tabbed Content
          <br /><br /><br /><br /><br /><br />
          Another Couple Lines
          <br /><br /><br /><br /><br /><br />
          More Tabbed Content
          <br /><br /><br /><br /><br /><br />
          Even More Content!
          <br /><br /><br /><br /><br /><br />
          Why not more yet!
          <br /><br /><br /><br /><br /><br />
          Some Ending Content
          <br /><br /><br /><br /><br /><br />
          Final Content!
        </div>
      </div>
    </div>
    <div class='footer'>
      <button class='button'>
        Done
      </button>
    </div>
  </div>
</div>

      

CSS

body {
  font-family: 'Montserrat', sans-serif;
}

/* Modal wrapper */
.modal {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

/* Modal background styles */
.background {
  position: absolute;
  height: 100%;
  width: 100%;
  background-color: rgba(0, 0, 0, 0.5)
}

/* Modal content */
.modal_content {
  height: 100vh;
  display: flex;
  flex-direction: column;
  width: 85%;
  margin: 0 auto;
  background-color: white;
}

.header {
  margin-bottom: 1rem;
  padding: 1rem;
  font-size: 125%;
  text-align: center;
  font-weight: bold;
  background-color: #EEEEEE;
  border-bottom: 1px solid #CECECE;
}

/* Contains the tabs and content */
.tabbed_content {
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

/* IGNORE */
.tabs {
  display: flex;
  /* NOTE: Added to stop them from hiding */
  flex-shrink: 0;
}

/* IGNORE */
.tab {
  flex-grow: 1;
  margin-top: 8px;
  padding: 0.5rem;
  text-align: center;
  background-color: #CECECE;
}

/* IGNORE */
.tab.active {
  margin-top: 0;
  font-weight: bold;
  background-color: #EEEEEE;
}

/* Contains the current tab content */
/* NOTE: This shouldn't scroll */
.content {
  padding: 1rem;
  background-color: #EEEEEE;

  /* NOTE: Currently the closest I can come */
  /*overflow: auto;*/
}

/* IMPORTANT: This should scroll if necessary! */
.scrollable {
  padding: 0.5rem;
  background-color: white;
  /* NOTE: Can't get this to scroll */
  /*overflow: auto;*/
  border: 1px dashed #CECECE;
}

.footer {
  display: flex;
  flex-align: center;
  flex-shrink: 0;
  justify-content: center;
  margin-top: 1rem;
  padding: 1rem;
  border-top: 1px dashed #CECECE;
}

/* IGNORE */
.button {
  padding: 0.75rem 1rem;
  font-size: 90%;
  color: white;
  background-color: lightseagreen;
  border: none;
  border-radius: 2px;
  cursor: pointer;
}

      

I'm almost at it with this one (spent 2 hours showing). Thanks in advance for your help!

PS I also need to worry about stopping the background scrolling while the modal is open at some point ...

+3


source to share


3 answers


Generally speaking, in order overflow: auto

to create a vertical scrollbar, you need to define the height on the container.

For the effect to overflow

have an effect, a block-level container must have either a given height ( height

, or max-height

) or white-space

set to nowrap

.

source: https://developer.mozilla.org/en-US/docs/Web/CSS/overflow

However, this is not always a practical solution, especially in dynamic environments.

In your layout, a simple solution is to make container ( .content

) a flex container. This is enough to make the mock work in Chrome ( demo ).

However, in order for the layout to work in Firefox and Edge as well, you need to override the default minimum height of flex items, which is min-height: auto

. This prevents flex items from shrinking below the size of their content, which prevents them from occurring overflow

. ( full explanation )



Make these changes to your code:

.tabbed_content {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  min-height: 0;                  /* NEW, esp for FF & Edge (see link below) */
}

.content {
  padding: 1rem;
  background-color: #EEEEEE;
  overflow: auto;                /* KEEP THIS, for FF & Edge (see link below) */
  display: flex;                 /* NEW */
  flex-direction: column;        /* NEW */
}

.scrollable {
  padding: 0.5rem;
  background-color: white;
  overflow: auto;               /* RESTORE */
  border: 1px dashed #CECECE;
}

      

modified code

Read more: Why won't the element bend as the content is reduced?

+3


source


Layout, how difficult it is! I usually try to create simplified versions and work.

One way you could do this is by positioning absolute for the scrollable div.

https://codepen.io/sheriffderek/pen/zwQxLr/ - see this pen for long and short examples

<aside class="window">

    <header>header</header>

    <main>
        <div class="scroll-area">
            <ul>
                <li>short conent</li>
                <li>2</li>
                <li>3</li>
                <li>4</li>
                <li>5</li>
            </ul>
        </div>
    </main>

    <footer>footer</footer>

</aside>

      



CSS (this is the stylus - but this is just syntax - and the concept should be clear)

.window
    border: 10px solid $gray;
    max-width: 600px // arbitrary
    height: 80vh // arbitrary

    display: flex
    flex-direction: column

    header, main, footer
        padding: $pad

    header
        background: $color

    main
        flex-grow: 1
        background: $alternate
        position: relative

        .scroll-area
            position: absolute
            top: 0
            left: 0
            width: 100%
            height: 100%
            overflow: auto
            padding: $pad

    footer
        background: $highlight

      

For your additional question, you can add / remove a class from the body when you open the modal and stop scrolling.

Prevent body scrolling, but allow overlay scrolling

0


source


You have to set the height to .scrollable

as well overflow-y: auto;

, otherwise the overflow will be visible as there is no height to overflow.

0


source







All Articles