6

I have a layout consisting of a single ordered list containing a bunch of items.

All items have consistent width and height - except the first item - which is (3x) wider and (2x) taller. It looks like this:

enter image description here

ol {
  padding:0;
  margin:0;
  min-width: 488px;
}
li {
  list-style: none;
  width: 150px;
  padding-bottom: 16.66%;
  border: 5px solid tomato;
  display: inline-block;
}
li:first-child {
  float:left;
  width: 478px;
  border-color: green;
  padding-bottom: 34.25%;
  margin: 0 4px 4px 0;
}
<ol>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ol>

Codepen Demo (Resize viewport to see effect)

Currently, i'm using floats and inline-blocks to achieve the layout, but i'd like to use flexbox because of some extra features which flexbox offers.

I have made a couple of attempts, but with no success -

Attempt #1 - Codepen

ol {
  /* ... */
  display: flex;
  flex-wrap: wrap;
}

Attempt #2 - Codepen

Use a float before the list to secure space for the first large list item

Then set display absolute on the first list item.

In both attempts, the red boxes in the first line stretch to fill the height of the first item.

Is this possible?

(If not, then I would be interested in a CSS grid workaround)

Danield
  • 121,619
  • 37
  • 226
  • 255
  • 2
    This page might be a help if you are looking into flexbox - https://css-tricks.com/snippets/css/a-guide-to-flexbox/ – Andrew Jul 13 '16 at 12:39
  • Just to make it clear, I want the first red list items to wrap on 2 rows until they reach the height of the first item, and then proceed to wrap underneath the large item – Danield Jul 13 '16 at 12:43
  • @Andrew this is the best docuemtation / tutorial for this. – vaso123 Jul 13 '16 at 12:48
  • 2
    I don't think it's possible with a single flexbox container. That's why we'll be getting a native [css grid layout](https://www.w3.org/TR/css3-grid-layout/)! – fl0cke Jul 13 '16 at 13:00
  • 1
    No, this is not possible with a single container. using flexbox. – Paulie_D Jul 13 '16 at 13:26
  • I have been looking at this and created this fiddle for you I can see how to take up the row width of like 3 flex items but to take up 2 or 3 column items i don think this exists just now: https://jsfiddle.net/6vq1rvbt/ might be better adding it into your question – Andrew Jul 13 '16 at 13:27
  • 1
    Here's an explanation why this can't work with flexbox, and possible alternatives: http://stackoverflow.com/a/34481128/3597276 – Michael Benjamin Jul 13 '16 at 13:33
  • There's a somewhat similar question with an answer that tells you how to hack it, but it appears to only work for fixed layouts: http://stackoverflow.com/a/32173248/4326495 – Frank Tan Jul 13 '16 at 13:39
  • 1
    @Michael_B - thanks for the explanation. So it seems that float-based layouts aren't dead just yet. – Danield Jul 13 '16 at 20:09

1 Answers1

6

So it's pretty clear that flexbox can't produce a layout like this. So I'll answer this part of the question:

If not, then I would be interested in a CSS grid workaround

With the CSS Grid Layout Module this is surprisingly easy to produce:

Basically the relevant code boils down to this:

Codepen Demo (Resize to see the effect)

ul {
  display: grid; /* (1) */
  grid-template-columns: 120px 120px repeat(auto-fill, 120px); /* (2) */
  grid-template-rows: repeat(auto-fill, 150px); /* (3) */
  grid-gap: 1rem; /* (4) */
  justify-content: space-between; /* (5) */
}
li:first-child {
  grid-column: 1 / 4; /* (6) */
  grid-row:  1 / 3; /* (7) */
}

1) Make the container element a grid container

2) Set the grid with at least 3 columns of width 120px. (The auto-fill value is used for responsive layouts).

3) Set the grid with 150px high rows.

4) Set gaps/gutters for the grid rows and columns - here, since want a 'space-between' layout - the gap will actually be a minimum gap because it will grow as necessary.

5) Similar to flexbox.

6) occupy the first three columns

7) occupy the first two rows

body {
  margin: 0;
}
ul {
  display: grid;
  grid-template-columns: 120px 120px repeat(auto-fill, 120px);
  grid-template-rows: repeat(auto-fill, 150px);
  grid-gap: 1rem;
  justify-content: space-between;
  
  /* boring properties: */
  list-style: none;
  width: 90vw;
  height: 90vh;
  margin: 4vh auto;
  border: 5px solid green;
  padding: 0;
  overflow: auto;
}
li {
  background: tomato;
  min-height: 150px;
}
li:first-child {
  grid-column: 1 / 4;
  grid-row:  1 / 3; 
}
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
  <li>11</li>
  <li>12</li>
  <li>13</li>
  <li>14</li>
  <li>15</li>
  <li>16</li>
  <li>17</li>
  <li>18</li>
  <li>19</li>
  <li>20</li>
</ul>


Browser Support - Caniuse

Currently supported by Chrome (Blink) and Firefox, with partial support from IE and Edge (See this post by Rachel Andrew)

Danield
  • 121,619
  • 37
  • 226
  • 255