Solution 1 :

You can try to set both scroll bars on table, and set .container position as absolute and tableHeader as sticky with top: 0;. For cells background, set background-color on tableCell and add class for header cell with another background-color :

#container {
  width: 400px;
  height: 200px;
  display: flex;
  flex-direction: column;
  position: absolute;
}

#header, #footer {
  background-color: #666;
}

#table {
  overflow-x: scroll;
  overflow-y: scroll;
  display: grid;
}

#tableHeader {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  position: sticky;
  top: 0;
}
.head {
  background-color: #AAA !important;
}
#tableBody {
  display: flex;
  flex-direction: column;
}

.tableRow {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  background-color: #DDD;
}
.tableRow:nth-child(odd) {
  background-color: #40E0D0;
}
.tableRow:nth-child(even) {
  background-color: violet;
}

.tableCell {
  padding: 4px;
  width: 300px;
  flex-shrink: 0;
  border: solid 1px black;
 /* background-color: #DDD;*/
}

.fixedSize {
  width: 40px;
  height: 40px;
  background-color: blue;
}
<div id="container">
  <div id="header">Header</div>
  <div id="table">
    <div id="tableHeader">
      <div class="tableCell head">Column1</div>
      <div class="tableCell head">Column2</div>
      <div class="tableCell head">Column3</div>
      <div class="tableCell head">Column4</div>
    </div>
    <div id="tableBody">
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
    </div>
  </div>
  <div id="footer">Footer</div>
</div>

Solution 2 :

First You need to define which container will provide scrolls – since that is table give it overflow: scroll to allow scroll its contents in both axis.

If You need to stick table header in place – use ‘sticky’ positioning (commented in code example) or absolute with top/left/right 0 to tableHeader, and for tableBody relative positioning in couple with padding equal to tableHeader height value

Then all BIG DATA placed in appropriate container should be protected from shrinking with overflow:visible to be drawn correctly.

#container {
  width: 400px;
  height: 200px;
  display: flex;
  flex-direction: column;
}

#header, #footer {
  background-color: #666;
}

#table {
  overflow: scroll;
}

#tableHeader {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  background-color: #AAA;
  /* uncomment it if header sticky position needed
  position:sticky;
  top:0;
  */
}

#tableBody {
  display: flex;
  flex-direction: column;
  overflow: visible;
}

.tableRow {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  
}

.tableCell {
  padding: 4px;
  width: 300px;
  flex-shrink: 0;
  border: solid 1px black;
  background-color: #DDD;
}

.fixedSize {
  width: 40px;
  height: 40px;
  background-color: blue;
}
<div id="container">
  <div id="header">Header</div>
  <div id="table">
    <div id="tableHeader">
      <div class="tableCell">Column1</div>
      <div class="tableCell">Column2</div>
      <div class="tableCell">Column3</div>
      <div class="tableCell">Column4</div>
    </div>
    <div id="tableBody">
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
    </div>
  </div>
  <div id="footer">Footer</div>
</div>

Solution 3 :

See if this meets the requirements. No positioning like fixed or absolute needed:

* {
  padding: 0;
  margin: 0;
}

#container {
  width: 400px;
  height: 200px;
  display: flex;
  flex-direction: column;
}

#header,
#footer {
  background-color: #666;
}

#table {
  overflow: auto;
}

#tableHeader {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  background-color: #AAA;
}

#tableBody {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}

.tableRow {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  background-color: #DDD;
}

.tableCell {
  padding: 4px;
  width: 300px;
  flex-shrink: 0;
  border: solid 1px black;
}

.fixedSize {
  width: 40px;
  height: 40px;
  background-color: blue;
}
<div id="container">
  <div id="header">Header</div>
  <div id="table">
    <div id="tableHeader">
      <div class="tableRow">
        <div class="tableCell">Column1</div>
        <div class="tableCell">Column2</div>
        <div class="tableCell">Column3</div>
        <div class="tableCell">Column4</div>
      </div>
      <div id="tableBody">
        <div class="tableRow">
          <div class="tableCell">
            <div class="fixedSize"></div>
          </div>
          <div class="tableCell"></div>
          <div class="tableCell"></div>
          <div class="tableCell"></div>
        </div>
        <div class="tableRow">
          <div class="tableCell">
            <div class="fixedSize"></div>
          </div>
          <div class="tableCell"></div>
          <div class="tableCell"></div>
          <div class="tableCell"></div>
        </div>
        <div class="tableRow">
          <div class="tableCell">
            <div class="fixedSize"></div>
          </div>
          <div class="tableCell"></div>
          <div class="tableCell"></div>
          <div class="tableCell"></div>
        </div>
        <div class="tableRow">
          <div class="tableCell">
            <div class="fixedSize"></div>
          </div>
          <div class="tableCell"></div>
          <div class="tableCell"></div>
          <div class="tableCell"></div>
        </div>
        <div class="tableRow">
          <div class="tableCell">
            <div class="fixedSize"></div>
          </div>
          <div class="tableCell"></div>
          <div class="tableCell"></div>
          <div class="tableCell"></div>
        </div>
      </div>
    </div>
  </div>
  <div id="footer">Footer</div>
</div>

Problem :

I am struggling to get my flexbox layout to scroll as I need. My requirements are:

  1. Fixed size container
  2. Fixed header and footer
  3. Table to scroll horizontally
  4. Table body to scroll vertically

I am hoping to do the above with only defining the sizes of:

  1. The container width/height
  2. The cell width
  3. Cell content height (the blue squares in the below fiddle).

Is this possible or do I need to define more widths/heights? In the fiddle I also notice that when the table scrolls horizontally, the background colours are lost. How can this be conserved? Link to the fiddle:

https://jsfiddle.net/talbot82/83wrktvb/6/

HTML:

<div id="container">
  <div id="header">Header</div>
  <div id="table">
    <div id="tableHeader">
      <div class="tableCell">Column1</div>
      <div class="tableCell">Column2</div>
      <div class="tableCell">Column3</div>
      <div class="tableCell">Column4</div>
    </div>
    <div id="tableBody">
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
      <div class="tableRow">
        <div class="tableCell">
          <div class="fixedSize"></div>
        </div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
        <div class="tableCell"></div>
      </div>
    </div>
  </div>
  <div id="footer">Footer</div>
</div>

CSS:

#container {
  width: 400px;
  height: 200px;
  display: flex;
  flex-direction: column;
}

#header, #footer {
  background-color: #666;
}

#table {
  overflow-x: scroll;
  overflow-y: hidden;
}

#tableHeader {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  background-color: #AAA;
}

#tableBody {
  display: flex;
  flex-direction: column;
  overflow-y: scroll;
}

.tableRow {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  background-color: #DDD;
}

.tableCell {
  padding: 4px;
  width: 300px;
  flex-shrink: 0;
  border: solid 1px black;
}

.fixedSize {
  width: 40px;
  height: 40px;
  background-color: blue;
}

Comments

Comment posted by David Talbot

This is great, but I need to be able to set the row colour rather than cell, as in my real project I have alternating row colours. Sorry this info wasn’t included in the question.

Comment posted by David Talbot

I think

Comment posted by Nikola Pavicevic

hey mate, i think he wants only table body to be scrollable, not table Header, or i miss understood completely , cheers 🙂

Comment posted by Rob Moll

@NikolaPavicevic – Ya, I’m not sure. I like your fixed table header. If he doesn’t use it, I will!

Comment posted by David Talbot

Yes, that’s right, I want the table header to only scroll horizontally header. I appreciate the suggestion though!

By