Search code examples
htmlcssscrollflexboxfocus

Keep scrolling focused - style CSS flexbox multiple columns with different number of rows


I am building a layout that has a variable number of columns, each having an independent number of rows.

It is not strictly a grid (each column should have equal number of rows), I will call it "board" layout.

Goals :

  • user must be able to scroll horizontally only the board, and scroll vertically only the columns: I want to scroll the currently focused column and to prevent scrolling in diagonal direction of the whole board.

  • Vertical scrolling on column must end when user reaches the end of the column, not of the parent board (the board's height could be longer if there are other columns higher than the focused column).

I wonder if I could achieve this behavior only with CSS - eventually also refactoring the html.

Could you illustrate a possible solution for point 1, 2, using CSS only ?

This is what I tried making use of flex css solution.


desired layout

Columns contains different number of rows and their background is rendered accordingly.

enter image description here

attempts

The following code rendered the desired layout, but if I have many columns, the view port will adjust them below the others: instead I want to keep the horizontal order and horizontal scrolling.

<div class="board">
    <div class="column>
        <item>..</item>
    </div>
</div>


.board {
}

.column {
  margin: 10px;
  padding: 10px;
  border: 1px solid #cfcfcf;
  background-color: #ddd;
  display: flex;
  flex-flow: column wrap;
  flex: 1 1 30%;
  
  width: 20%;
  float:left;
}

I tried with this other solution:

.grid {
  display:flex;
}

and remove width: 20%; float:left; in the column class.

Now the problems are:

  • The user can move the board object in diagonal (see the scrolling-bars on the image): user can only scrolling horizontally the board , and vertically the focused column.

  • The shorter columns' height is 'stretched' to meet the max height of the board, resulting in fully colored columns also if there is only element in it.

enter image description here


Solution

  • I believe this snippet begins to address all of your desired points. It fixes the board to the size of the viewport and enables horizontal scrolling for horizontal overflow while hiding vertical overflow. Column scrolling is implemented using nested columns set to scroll vertical overflow

    (The reason your columns were being pushed into a second row is that you had specified wrap.)

    body {
      margin: 0;
    }
    .board {  
      background-color: green;
      width: 100vw;
      height: 100vh;
      display: flex;
      flex-direction: row;
      flex-wrap: nowrap;
      overflow-x: scroll;
      overflow-y: hidden;
      align-items: flex-start;
    }
    .column{
      margin: 10px;
      padding: 10px;
      flex-basis: 20%;
      min-width: 200px;
      overflow-y: scroll;
      height: 100%;
    }
    .column-inner {
      border: 1px solid #cfcfcf;
      background-color: #ddd;
      display: flex;
      flex-direction: column;
    }
    div.item {
      margin: 10px;
      padding: 10px;
      height: 100px;
      background-color: red;
    }
    <div class="board">
      <div class="column">
        <div class="column-inner">
          <div class="item">..</div>
          <div class="item">..</div>
        </div>
      </div>
      <div class="column">
        <div class="column-inner">
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
    
        </div>
      </div>
      <div class="column">
        <div class="column-inner">
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
          <div class="item">..</div>
        </div>
      </div>
      <div class="column">
        <div class="column-inner">
          <div class="item">..</div>
          <div class="item">..</div>
        </div>
      </div>
      <div class="column">
        <div class="column-inner">
          <div class="item">..</div>
          <div class="item">..</div>
        </div>
      </div>
      <div class="column">
        <div class="column-inner">
          <div class="item">..</div>
          <div class="item">..</div>
        </div>
      </div>
      <div class="column">
        <div class="column-inner">
          <div class="item">..</div>
          <div class="item">..</div>
        </div>
      </div>
      <div class="column">
        <div class="column-inner">
          <div class="item">..</div>
          <div class="item">..</div>
        </div>
      </div>
    </div>