3

I've got a set of divs displayed in 5 columns using display: inline-block.

I want them to stack like this:

1 5
2 6
3 7
4 8

Instead of:

1 2
3 4
5 6
7 8

What I have so far:

#parent {
  width: 1200px; 
}

.withchild {
  display: inline-block;
  width: 200px;
  margin-left: 5px;
  margin-top: 5px;
  vertical-align: top;
}
<div id="parent">
  <div class="withchild"> <a href="#">1</a > </div>
  <div class="withchild"> <a href="#">2 </a > </div>
  <div class="withchild"> <a href="#">3</a > </div>
  <div class="withchild"> <a href="#">4</a > </div>
  <div class="withchild"> <a href="#">5</a > </div>
  <div class="withchild"> <a href="#">6</a > </div>
  <div class="withchild"> <a href="#">7</a > </div>
  <div class="withchild"> <a href="#">8</a > </div>
  <div class="withchild"> <a href="#">9</a > </div>
  <div class="withchild"> <a href="#">10</a > </div>
  <div class="withchild"> <a href="#">11</a > </div>
  <div class="withchild"> <a href="#">12</a > </div>
  <div class="withchild"> <a href="#">13</a > </div>
  <div class="withchild"> <a href="#">14</a > </div>
  <div class="withchild"> <a href="#">15</a > </div>
  <div class="withchild"> <a href="#">16</a > </div>
  <div class="withchild"> <a href="#">17</a > </div>
  <div class="withchild"> <a href="#">18</a > </div>
  <div class="withchild"> <a href="#">19</a > </div>
  <div class="withchild"> <a href="#">20</a > </div>
  <div class="withchild"> <a href="#">21</a > </div>
  <div class="withchild"> <a href="#">22</a > </div>
  <div class="withchild"> <a href="#">23</a > </div>
  <div class="withchild"> <a href="#">24</a > </div>
  <div class="withchild"> <a href="#">25</a > </div>
  <div class="withchild"> <a href="#">26</a > </div>
  <div class="withchild"> <a href="#">27</a > </div>
  <div class="withchild"> <a href="#">28</a > </div>
  <div class="withchild"> <a href="#">29</a > </div>
  <div class="withchild"> <a href="#">30</a > </div>
</div>

How can I make them stack top to bottom instead of left to right?

Danziger
  • 19,628
  • 4
  • 53
  • 83
Joe
  • 199
  • 1
  • 1
  • 15

1 Answers1

5

You can do that using flexbox:

.parent {
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    height: 100vh;
}

Basically, you use flex-direction: column to stack the elements vertically and flex-wrap: wrap + height: 100vh to make them wrap when there's no more vertical space available.

You can then use align-items and justify-content to change the way they are aligned on both axis.

If you want to always have the same number of columns, in this case 5, but do not want to use column-count, you need to set width: 20% on the items and then, assuming they all have the same height, set the height of the parent using JavaScript to match that:

const parent = document.getElementById('parent');
const items = parent.children;
const rows = Math.ceil(items.length / 5);

parent.style.height = `${ items[0].offsetHeight * rows }px`;
body {
  margin: 0;
  font-family: monospace;
}

#parent {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  border-bottom: 2px solid black;
}

.withchild {
  width: 20%;
  padding: 4px 8px;
  box-sizing: border-box;
  
  /* Always keep the text in 1 line: */
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
}

.withchild:hover {
  background: yellow;
}
<div id="parent">
  <div class="withchild">1</div>
  <div class="withchild">2</div>
  <div class="withchild">3</div>
  <div class="withchild">4</div>
  <div class="withchild">5</div>
  <div class="withchild">6</div>
  <div class="withchild">7</div>
  <div class="withchild">8</div>
  <div class="withchild">9</div>
  <div class="withchild">10</div>
  <div class="withchild">11</div>
  <div class="withchild">12</div>
  <div class="withchild">13</div>
  <div class="withchild">14</div>
  <div class="withchild">15</div>
  <div class="withchild">16</div>
  <div class="withchild">17</div>
  <div class="withchild">18</div>
  <div class="withchild">19</div>
  <div class="withchild">20</div>
  <div class="withchild">21</div>
  <div class="withchild">22</div>
  <div class="withchild">23</div>
  <div class="withchild">24</div>
  <div class="withchild">25</div>
  <div class="withchild">26</div>
  <div class="withchild">27</div>
  <div class="withchild">28</div>
  <div class="withchild">29</div>
  <div class="withchild">30</div>
  <div class="withchild">31</div>
  <div class="withchild">32</div>
</div>

Here's the alternative without JavaScript using column-count, which you can see on MDN and on Can I use that I think has pretty good support in modern browsers (using vendor prefixes):

body {
  margin: 0;
  font-family: monospace;
}

#parent {
  border-bottom: 2px solid black;
  -moz-column-count: 5;
  -webkit-column-count: 5;
  column-count: 5;
  -moz-column-gap: 0;
  -webkit-column-gap: 0;
  column-gap: 0;
}

.withchild {
  width: 100%;
  padding: 0 8px;
  box-sizing: border-box;
  
  /* Always keep the text in 1 line: */
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
  line-height: 23px;
}

.withchild:hover {
  background: yellow;
}
<div id="parent">
  <div class="withchild">1</div>
  <div class="withchild">2</div>
  <div class="withchild">3</div>
  <div class="withchild">4</div>
  <div class="withchild">5</div>
  <div class="withchild">6</div>
  <div class="withchild">7</div>
  <div class="withchild">8</div>
  <div class="withchild">9</div>
  <div class="withchild">10</div>
  <div class="withchild">11</div>
  <div class="withchild">12</div>
  <div class="withchild">13</div>
  <div class="withchild">14</div>
  <div class="withchild">15</div>
  <div class="withchild">16</div>
  <div class="withchild">17</div>
  <div class="withchild">18</div>
  <div class="withchild">19</div>
  <div class="withchild">20</div>
  <div class="withchild">21</div>
  <div class="withchild">22</div>
  <div class="withchild">23</div>
  <div class="withchild">24</div>
  <div class="withchild">25</div>
  <div class="withchild">26</div>
  <div class="withchild">27</div>
  <div class="withchild">28</div>
  <div class="withchild">29</div>
  <div class="withchild">30</div>
  <div class="withchild">31</div>
  <div class="withchild">32</div>
</div>

Anyway, you can always use a mix of both solutions if you prefer to use column-count in browsers that support it and use Flexbox and a bit of JavaScript as a fallback.

Danziger
  • 19,628
  • 4
  • 53
  • 83
  • That wouldn't work, I need 5 columns across, and as this is for a dynamic navigation menu, the items will vary, I can't give a defined height: 100vh; – Joe Dec 01 '18 at 11:36
  • @Joe Take a look at the updated answer. To do that with Flexbox you need to use JavaScript to set the `height` of the parent. Alternatively, `column-count` has pretty good support in modern browsers using vendor prefixes, but it depends on which browsers and versions you need to support. – Danziger Dec 01 '18 at 17:47
  • This seems to be the best option so far... how would I do the Flexbox and JavaScript fallback? – Joe Dec 01 '18 at 21:49
  • You need separated classes for each version and apply one or the other depending on whether `column-count` is supported. Here's how to check if a CSS property is supported: https://stackoverflow.com/questions/36191797/how-to-check-if-css-value-is-supported-by-the-browser – Danziger Dec 02 '18 at 01:24