Search code examples
htmlcssflexboxcss-grid

Newspaper style grid on pure css with different dynamic height of components


Let me start from a tiny example based on display:flex;.

#container {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  width: 150px;
}
.content {
  border: 1px solid black;
  display: inline-block;
  padding: 5px;
}
<div id="container">
  <div class="content">content</div>
  <div class="content">content <br/> big</div>
  <div class="content">content</div>
  <div class="content">content</div>
  <div class="content">content</div>
  <div class="content">content</div>
  <div class="content">content</div>
  <div class="content">content</div>
</div>

As you can see here, when there is a difference between component height in one row, empty space will appear near smaller component.
It will not happen when using flex-direction: column; but in this case height must be setted. I want to make a grid of unlimited height, with 2 columns, and items height can be extended when user clicks on it (to see additional info).
I also tried display: grid; (results was the same as with flex) and columns: 2 with presetted columns width.
With columns: 2 it almost worked, but sometimes when item height extends items from one column goes to another, which looks pretty bad.
So the question is there any way to do that kind of grid on pure css. Easiest way I see is in using display: flex; with flex-direction: column; but with javascript calculated height for container.But I want to avoid using javascript for styling as much as I can.

Thank you for any advise!


Solution

  • You were on the right track with the columns property. To solve the problem of an item in the column splitting across columns, you can wrap each column item in another element that has display: inline-block.

    Make sure to also either set the inline-block element to 100% width or wrap it in yet another element with a block-type display (block, flex, grid) in order to prevent two particularly small children from sitting side-by-side within a column. (Unless that's something you'd want.)

    #container {
      column-count: 2;
      column-gap: 20px;
      width: 160px;
    }
    .content-outer {
      width: 100%;
      display: inline-block;
    }
    .content {
      width: 100%; /* width as related to the column, not the whole container */
      border: 1px solid black;
      padding: 5px;
    }
    <div id="container">
      <div class="content-outer">
        <div class="content">content</div>
      </div>
      <div class="content-outer">
        <div class="content">content <br/> big</div>
      </div>
      <div class="content-outer">
        <div class="content">content</div>
      </div>
      <div class="content-outer">
        <div class="content">content</div>
      </div>
      <div class="content-outer">
        <div class="content">content</div>
      </div>
      <div class="content-outer">
        <div class="content">content</div>
      </div>
      <div class="content-outer">
        <div class="content">content</div>
      </div>
      <div class="content-outer">
        <div class="content">content</div>
      </div>
    </div>