Search code examples
cssflexboxz-indexsticky

CSS: 2-way sticky grid using flex-box (freeze panes)


I'm trying to understand if it's possible to do a 2-way sticky grid (freeze panes) using a flex-based grid. I want to have a certain number of sticky columns at the left, and a sticky header at the top.

Is it possible to make it so that the sticky cells disappear under the header? I tried playing with z-index but it doesn't seem to help.

I tried to do so using something similar to the following code (my actual example is much more complex but this is the basic idea), but as you can see at the codepen, it is not working - the sticky columns work ok, but then overwrite the header when scrolling up.

It's a little bit like this but needs to be in a div, not in the viewport.

HTML:

<div class="container">
  <div class="header-row">
    <div class="header header-sticky" style="left: 0">Sticky Header 1</div> 
    <div class="header header-sticky" style="left: 200px">Sticky Header 2</div>
    <div class="header header-sticky" style="left: 400px">Sticky Header 3</div>
    <div class="header header-scrollable">Scrollable Header 1</div> 
    <div class="header header-scrollable">Scrollable Header 2</div>
    <div class="header header-scrollable">Scrollable Header 3</div>
  </div>
  <div class="row">
      <div class="cell cell-sticky" style="left: 0">Sticky Cell 1</div>
      <div class="cell cell-sticky" style="left: 200px">Sticky Cell 2</div>
      <div class="cell cell-sticky" style="left: 400px">Sticky Cell 3</div>    
      <div class="cell cell-scrollable">Scrollable Cell 1</div>
      <div class="cell cell-scrollable">Scrollable Cell 2</div>
      <div class="cell cell-scrollable">Scrollable Cell 3</div>    
  </div>
    <div class="row">
      <div class="cell cell-sticky" style="left: 0">Sticky Cell 1</div>
      <div class="cell cell-sticky" style="left: 200px">Sticky Cell 2</div>
      <div class="cell cell-sticky" style="left: 400px">Sticky Cell 3</div>    
      <div class="cell cell-scrollable">Scrollable Cell 1</div>
      <div class="cell cell-scrollable">Scrollable Cell 2</div>
      <div class="cell cell-scrollable">Scrollable Cell 3</div>  
  </div>
</div>

CSS:

body {
  font-family: Calibri;
}

.container {
  width: 1000px;
  height: 180px;
  overflow: auto;
}


.row {
  display: flex;
  align-items: stretch;
}


.row:nth-child(2n) {
  background-color: white;
}


.row:nth-child(2n+1) {
  background-color: #dddddd;
}


.header-row {
  display: flex;
  align-items: stretch;
  position: sticky;
  top: 0;
}

.header {
  flex-grow: 1;
  min-width: 200px;
  min-height: 70px;
  padding: 5px;
  border: 1px solid #414141;
  font-weight: bold;
  background-color: white;
  margin: 0;
  text-align: center;
}

.header-sticky {
  position: sticky;
  z-index: 10;
}

.cell {
  margin: 0;
  min-width: 200px;
  min-height: 70px;
  padding: 5px;
  border: 1px solid #414141;
  text-align: center;  
}

.cell-sticky {
  position: sticky;
  z-index: 5;
}

https://codepen.io/ddddan/pen/PoygNMV


Solution

  • It turns out this was as simple as adding the z-index to the header row:

    .header-row {
      display: flex;
      align-items: stretch;
      position: sticky;
      top: 0;
      z-index: 50;
    }
    

    Hopefully this can help someone else!