0

I've tried many different approaches to make a table body scrolling, while having a fixed table header - none of them worked really satisfying, so finally I ended up using a table for the header, and a second table for the body, that is placed within a scrolling container. This works, as long as I give the scrollable container that contains the table body a fixed height.

Now I want a flexible height, so I'm trying with flex:

/* SOME BASE CSS SETTINGS */

* {
  box-sizing: border-box;
}

body,
html {
  color: white;
  width: 100%;
  height: 100%;
  padding: 0px;
  margin: 0px;
}


/* A FLEX COLUMN CONTAINER */

.flexContainer {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}


/* FLEX ELEMENT THAT SHOULD GROW TO FIT THE AVAILABLE SPACE */

.flexGrow {
  flex-grow: 1;
}


/* SECTION ONE IS HIDDEN, BUT EXISTS IN REAL LIFE */

#S1 {
  display: none;
  visibility: hidden;
}

#S1>header {
  background-color: red;
  min-height: 450px;
}

#S1>main {
  background-color: green;
  overflow: auto;
  min-height: calc(100% - 550px);
  max-height: calc(100% - 550px);
}

#S1>footer {
  background-color: blue;
  min-height: 100px;
}


/* SECTION 2 IS VISIBLE */

#S2>header {
  background-color: red;
  min-height: 150px;
}

#S2>main {
  background-color: green;
  /* If I remove this, MAIN won't be displayed beside NAV */
  display: inline-block;
  /* If I remove this, the document body will scroll :( */
  min-height: calc(100% - 250px);
  max-height: calc(100% - 250px);
}

#S2>main>div {
  flex-direction: row;
}

#S2>main>div>nav {
  background-color: black;
  min-width: 450px;
}

#S2>main>div>section {
  background-color: teal;
  width: 100%;
  height: 100%;
  /* If I remove this, the body will scroll the big table of sub section 1! */
  overflow: auto;
}

#S2>footer {
  background-color: blue;
  min-height: 100px;
}


/* SUB SECTION 1 IS VISIBLE */

#SS1 {
  border: 5px solid green;
}

#SS1>div {
  background-color: turquoise;
  border: 5px solid turquoise;
}

#SS1>div>.table {
  /* Why does this overflow!? It should only fill the available space. */
  background-color: violet;
  border: 5px solid violet;
  width: 100%;
}

#SS1>div>.table>.container {
  background-color: wheat;
  border: 5px solid wheat;
}

#SS1>div>.table>.container>.header {
  background-color: silver;
  border: 5px solid silver;
  width: 100%;
  height: 40px;
}

#SS1>div>.table>.container>.data {
  background-color: yellowgreen;
  border: 5px solid yellowgreen;
  width: 100%;
}

#SS1>div>.table>.container>.data>.container {
  background-color: cadetblue;
  border: 5px solid cadetblue;
  width: 100%;
  height: 100%;
  /* This scrolling should be applied to have a fixed header and a scrolling body - but instead the sub section is scrolling :S */
  overflow-y: auto;
}

#SS1>div>.table>.container>.data>.container>.body {
  background-color: brown;
  border: 5px solid brown;
  width: 100%;
}

#SS1>div>.table>.container>.data>.container>.body tr {
  height: 200px;
  /* Ensure the table data will overflow */
}

#SS1>div>.table td {
  width: 150px;
}

#SS1>div>.table td:nth-child(2) {
  width: auto;
}


/* SUB SECTION 2 IS HIDDEN, BUT EXISTS IN REAL LIFE */

#SS2 {
  display: none;
  visibility: hidden;
}
<!DOCTYPE html>

<body>
  <section id="S1" class="flexContainer">
    <header>S1 HEADER</header>
    <main class="flexGrow">S1 MAIN</main>
    <footer>S1 FOOTER</footer>
  </section>
  <section id="S2" class="flexContainer">
    <header>S2 HEADER</header>
    <main class="flexGrow">
      <div class="flexContainer">
        <nav>S2 NAV</nav>
        <section id="SS1" class="flexGrow">
          <div class="flexContainer">
            <h1>S2 SECTION 2</h1>
            <div class="table flexGrow">
              <div class="container flexContainer">
                <table class="header">
                  <thead>
                    <tr>
                      <td>Column 1</td>
                      <td>Column 2</td>
                      <td>Column 3</td>
                      <td>Column 4</td>
                      <td>Column 5</td>
                    </tr>
                  </thead>
                </table>
                <div class="data flexGrow">
                  <div class="container">
                    <table class="body">
                      <tbody>
                        <tr>
                          <td>Cell 1</td>
                          <td>Cell 2</td>
                          <td>Cell 3</td>
                          <td>Cell 4</td>
                          <td>Cell 5</td>
                        </tr>
                        <tr>
                          <td>Cell 1</td>
                          <td>Cell 2</td>
                          <td>Cell 3</td>
                          <td>Cell 4</td>
                          <td>Cell 5</td>
                        </tr>
                        <tr>
                          <td>Cell 1</td>
                          <td>Cell 2</td>
                          <td>Cell 3</td>
                          <td>Cell 4</td>
                          <td>Cell 5</td>
                        </tr>
                        <tr>
                          <td>Cell 1</td>
                          <td>Cell 2</td>
                          <td>Cell 3</td>
                          <td>Cell 4</td>
                          <td>Cell 5</td>
                        </tr>
                        <tr>
                          <td>Cell 1</td>
                          <td>Cell 2</td>
                          <td>Cell 3</td>
                          <td>Cell 4</td>
                          <td>Cell 5</td>
                        </tr>
                        <tr>
                          <td>Cell 1</td>
                          <td>Cell 2</td>
                          <td>Cell 3</td>
                          <td>Cell 4</td>
                          <td>Cell 5</td>
                        </tr>
                      </tbody>
                    </table>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </section>
        <section id="SS2">S2 SECTION 2</section>
      </div>
    </main>
    <footer>S2 FOOTER</footer>
  </section>
</body>

But there are several problems with the result:

  1. The violet container should only fit the available space, but not overflow!
  2. The same with the yellow green container
  3. The cadet blue container contains the table and should scroll, because the table does overflow - but it doesn't scroll

And there are some more things, that I don't really like/understand:

  • Why has #S2>main to be inline-block to be displayed beside #S2>nav?
  • Why do I have to give #S2>main a height? I assumed the height will fit to the available height, but if I don't give a height, the document will scroll

Finally the most important thing for me is: How can I avoid the scrolling of the turquoise container and force the cadet blue container to scroll the overflowing content?

Edit: Thanks to "David says reinstate Monica" for reformatting HTML & CSS :) Thanks to G-Cyrillus I was able to get what I want just by adding min-height:0px; to the flexGrow CSS class. And of course I'll overwork my fixed table header solution to become sticky...

nd_
  • 93
  • 1
  • 9

1 Answers1

3

You could maybe use less imbrication and start from a template and a few reusable class (easier to add /remove for testing minimal rules) , then fill the template.

body {margin:0}
.vh-100 {height:100vh}
.flex {display:flex;}
.flex-grow-1 {flex-grow:1;}
.column {flex-flow:column;}
.min-height-0 {min-height:0}
.overflow-A{overflow:auto; }
#test:hover {height:100vh;}

section {background:tomato}
header {background:gold}
aside {background:lightblue;}
footer {background:orange}
#test {background:lightgreen}
section section, header,aside,footer ,#test{padding:0.25em;}
<section class="vh-100 flex column">
  <header>Section HEADER</header>
  <main class="flex-grow-1 flex min-height-0">
    <aside>
      <nav>Section NAV</nav>
    </aside>
    <section class="flex column flex-grow-1">
      <h1 >main header</h1>
      <div class="overflow-A flex-grow-1"> content to scroll if  needed
      <div id="test">test div to hover</div>
      </div>
    </section>
  </main>
  <footer>Section FOOTER</footer>
</section>

Once you have an efficient layout and scrolling element, you can fill it up and maybe think about a min-height safe value.

Also, Instead breaking the table into 2 tables breaking the table-layout holding together thead and tbody, you may give a try to position:sticky; for thead

example

body {margin:0}
.vh-100 {height:100vh}
.w-100 {width:100%;}
.minH-300 {min-height:300px;}/* make sure content don't get over squizzed */
.flex {display:flex;}
.flex-grow-1 {flex-grow:1;}
.column {flex-flow:column;}
.min-height-0 {min-height:0}
.overflow-A{overflow:auto; }
#test:hover {height:100vh;}

section {background:tomato}
header {background:gold}
aside {background:lightblue;}
footer {background:orange}
table,td {border:solid;}

.sticky-top {position:sticky;top:0;background:white}


section section, header,aside,footer{padding:0.25em;}
<section class="vh-100 flex column minH-300">
  <header>Section HEADER</header>
  <main class="flex-grow-1 flex min-height-0">
    <aside>
      <nav>Section NAV</nav>
    </aside>
    <section class="flex column flex-grow-1">
      <h1 >main header</h1>
      <div class="overflow-A flex-grow-1">
      
      <table class="header w-100">
        <thead class="sticky-top w-100">
          <tr>
            <td>Column 1</td>
            <td>Column 2</td>
            <td>Column 3</td>
            <td>Column 4</td>
            <td>Column 5</td>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
          <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
            <td>Cell 4</td>
            <td>Cell 5</td>
          </tr>
        </tbody>
      </table>
      </div>
      <p>a paraph standing below scrolling div</p>
    </section>
  </main>
  <footer>Section FOOTER</footer>
</section>
G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129
  • First: Thanks a lot! Good news: It took some time, but finally I see what does the trick for me: `height:100vh` and `min-height:0`. Bad news: I still don't understand why :( The `min-height:0` makes no sense for me. To me it's like a hack to make the annoying result become to the satisfying result - but I have the feeling it's not as it should be. What's the technical reason for the `min-height:0` - is there any reference available that explains that? – nd_ Mar 07 '20 at 16:07
  • 1
    @nd_ min-height or overflow:hidden, makes the browser calculate the height of the flex parent, else it doesn't to spare a few bits of memory :( Let me search for a duplicate – G-Cyrillus Mar 07 '20 at 16:09
  • @nd_ here is some explanation https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size – G-Cyrillus Mar 07 '20 at 16:11
  • Thanks again! Now I've got the point :) Btw. the sticky header works for the `th`, but not for the `thead` - but for this it works like charme! So I can use a single table that has a fixed header. The problem with the solutions I've tried so far was that when I make the tbody scrollable, the cell widths won't match the header column widths anymore as soon as a scrollbar is displayed within the tbody. But when I "stick" to the sticky solution, the scrollbar will appear on the table container, not on the table body - so it won't destroy the layout. – nd_ Mar 07 '20 at 16:50