3

I'm trying to create a responsive grid, where two rows of smaller items are in line with a bigger element.

What I'm trying to achieve:

Wide

Narrow

What I have:

#thumbs {
  background-color: lightcoral;
  width: 100%;
  margin-top: 90px;
  margin-left: auto;
  margin-right: auto;
  text-align: justify;
  -ms-text-justify: distribute-all-lines;
  text-justify: distribute-all-lines;
}

#thumbs div {
  vertical-align: top;
  display: inline-block;
  *display: inline;
  zoom: 1;
}

.stretch {
  width: 100%;
  display: inline-block;
  font-size: 0;
  line-height: 0
}
<div class=container>
  <div id="thumbs">
    <div>
      <a id="single_image1" href="#"><img src="http://dummyimage.com/300x200/444/fff" alt="" /></a>
    </div>
    <div>
      <a id="single_image3" href="#"><img src="http://dummyimage.com/100x100/444/fff" alt="" /></a>
    </div>
    <div>
      <a id="single_image3" href="#"><img src="http://dummyimage.com/100x100/444/fff" alt="" /></a>
    </div>
    <div>
      <a id="single_image3" href="#"><img src="http://dummyimage.com/100x100/444/fff" alt="" /></a>
    </div>
    <div>
      <a id="single_image3" href="#"><img src="http://dummyimage.com/100x100/444/fff" alt="" /></a>
    </div>
    <div>
      <a id="single_image3" href="#"><img src="http://dummyimage.com/100x100/444/fff" alt="" /></a>
    </div>
    <div>
      <a id="single_image3" href="#"><img src="http://dummyimage.com/100x100/444/fff" alt="" /></a>
    </div>
    <div>
      <a id="single_image3" href="#"><img src="http://dummyimage.com/100x100/444/fff" alt="" /></a>
    </div>
    <div>
      <a id="single_image3" href="#"><img src="http://dummyimage.com/100x100/444/fff" alt="" /></a>
    </div>
    <div>
      <a id="single_image3" href="#"><img src="http://dummyimage.com/100x100/444/fff" alt="" /></a>
    </div>
    <div>
      <a id="single_image3" href="#"><img src="http://dummyimage.com/100x100/444/fff" alt="" /></a>
    </div>
    <div>
      <a id="single_image3" href="#"><img src="http://dummyimage.com/100x100/444/fff" alt="" /></a>
    </div>
    <div>
      <a id="single_image3" href="#"><img src="http://dummyimage.com/100x100/444/fff" alt="" /></a>
    </div>
    <span class="stretch"></span>
  </div>
</div>

jsfiddle: http://jsfiddle.net/7985xjud/

I have also tried flexbox:

.flex-container {
  padding: 0;
  margin: 0;
  list-style: none;
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  -webkit-flex-flow: row wrap;
  justify-content: space-around;
}

.flex-item {
  background: tomato;
  padding: 5px;
  margin-top: 10px;
  line-height: 60px;
  color: white;
  font-weight: bold;
  font-size: 2em;
  text-align: center;
}

.big-item {
  width: 300px;
  height: 150px;
}

.small-item {
  width: 100px;
  height: 60px;
}
<ul class="flex-container">
  <li class="flex-item big-item">1</li>
  <li class="flex-item small-item">2</li>
  <li class="flex-item small-item">3</li>
  <li class="flex-item small-item">4</li>
  <li class="flex-item small-item">5</li>
  <li class="flex-item small-item">6</li>
  <li class="flex-item small-item">7</li>
</ul>

codepen: https://codepen.io/anon/pen/dRBKWr

How can I do that?

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Przemen
  • 105
  • 4

3 Answers3

2

The desired layout is not possible with flexbox, at least not in a clean and efficient way. The reasons are explained here: Is it possible for flex items to align tightly to the items above them?

On the other hand, the layout is relatively simple with CSS Grid Layout.

grid-container {
  display: grid;                                                 /* 1 */
  grid-auto-rows: 50px;                                          /* 2 */
  grid-gap: 10px;                                                /* 3 */
  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));  /* 4 */
}

grid-item:first-child {                                          
  grid-column: 1 / 4;                                            /* 5 */
  grid-row: 1 / 3;                                               /* 5 */
}

/* non-essential decorative styles */
grid-item {
  background-color: red;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-weight: bold;
}
<grid-container>
  <grid-item>01</grid-item>
  <grid-item>02</grid-item>
  <grid-item>03</grid-item>
  <grid-item>04</grid-item>
  <grid-item>05</grid-item>
  <grid-item>06</grid-item>
  <grid-item>07</grid-item>
  <grid-item>08</grid-item>
  <grid-item>09</grid-item>
  <grid-item>10</grid-item>
  <grid-item>11</grid-item>
  <grid-item>12</grid-item>
  <grid-item>13</grid-item>
</grid-container>

jsFiddle


How it works

  1. Establish a block-level grid container. (inline-grid would be the other option)
  2. The grid-auto-rows property sets the height of automatically generated rows. In this grid each row is 50px tall.
  3. The grid-gap property is a shorthand for grid-column-gap and grid-row-gap. This rule sets a 10px gap between grid items. (It doesn't apply to the area between items and the container.)
  4. The grid-template-columns property sets the width of explicitly defined columns.

    The repeat notation defines a pattern of repeating columns (or rows).

    The auto-fill function tells the grid to line up as many columns (or rows) as possible without overflowing the container. (This can create a similar behavior to flex layout's flex-wrap: wrap.)

    The minmax() function sets a minimum and maximum size range for each column (or row). In the code above, the width of each column will be a minimum of 100px of the container and maximum of whatever free space is available.

    The fr unit represents a fraction of the free space in the grid container. It's comparable to flexbox's flex-grow property.

  5. With grid-column and grid-row we're setting the grid area for this particular grid item by defining the grid lines.


Browser Support for CSS Grid

  • Chrome - full support as of March 8, 2017 (version 57)
  • Firefox - full support as of March 6, 2017 (version 52)
  • Safari - full support as of March 26, 2017 (version 10.1)
  • Edge - full support as of October 16, 2017 (version 16)
  • IE11 - no support for current spec; supports obsolete version

Here's the complete picture: http://caniuse.com/#search=grid


Cool grid overlay feature in Firefox

In Firefox dev tools, when you inspect the grid container, there is a tiny grid icon in the CSS declaration. On click it displays an outline of your grid on the page.

enter image description here

More details here: https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
0

Mostly using float: left

The float CSS property specifies that an element should be placed along the left or right side of its container, where text and inline elements will wrap around it. Then the element is taken from the normal flow of the web page, though still remaining a part of the flow, contrary to absolute positioning.

Although I used CSS Counters and Pseudo Elements for the <div> numbers, those rules don't have any effect on the layout.
The relative and absolute positioning are only used to control the numbers' layout.

I've added a <header> and <footer> (default display: block;) to show the interaction between them and the floating elements.
By adding clear: both; on the footer, we can stop it from being drawn into the floaters above it, and normal (non-floating) behaviour will continue below it.

body {
  counter-reset: num; 
}
div {
  position: relative;
  float: left;
  margin: .5em;
  padding: 3.25em 5em;
  background: tomato;
}
div:first-of-type {
  padding: 7em 10.5em;
}
div:before {
  counter-increment: num;
  content: counter( num );
  position: absolute;
  top: .4em;
  left: .5em;
  font: 3em sans-serif;
  color: white;
}
footer {
  clear: both; /* this breaks the floating behaviour */
}
<header>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</header>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<footer>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</footer>

Alternatively, we can separate our floating <div>s from the rest of the layout, by wrapping them in a <div> with display: inline-block;.
As long as its previous and next siblings do not display: inline*, the wrapper will behave as if it's display: block;.

body {
  counter-reset: num; 
}
.floaters {
  display: inline-block; /* will not display inline with sibling blocks */
}
.floaters div {
  position: relative;
  float: left;
  margin: .5em;
  padding: 3.25em 5em;
  background: tomato;
}
.floaters div:first-of-type {
  padding: 7em 10.5em;
}
.floaters div:before {
  counter-increment: num;
  content: counter( num );
  position: absolute;
  top: .4em;
  left: .5em;
  font: 3em sans-serif;
  color: white;
}
<header>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</header>
<div class="floaters">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>
<footer>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</footer>
Fred Gandt
  • 4,217
  • 2
  • 33
  • 41
  • Thanks for the answer. Is it possible to know the height of the body element? (It's 0px in this case) I would like to place additional elements BELOW all of the elements – Przemen Jul 20 '17 at 08:47
  • The `body { height: * }` can be set using various [CSS measurements](https://developer.mozilla.org/en/docs/Web/CSS/length) and can be got using JavaScript's [`getComputedStyle()`](https://developer.mozilla.org/en/docs/Web/API/Window/getComputedStyle). If the height of the body using this method is a problem, please explain why, and I will endeavour to provide a solution. – Fred Gandt Jul 20 '17 at 08:57
  • Sorry, I didn't see the edit to your comment until now (we must have just missed each other). I have to take my dog for a walk before doing actual code (the hours slip by otherwise); I'll update the answer in a couple of hours. – Fred Gandt Jul 20 '17 at 09:21
  • Thank you very much. To illustrate the problem: https://jsfiddle.net/ukeq31d0/ I couldn't find a way to place the black element below the last blue box using CSS. – Przemen Jul 20 '17 at 09:27
  • I'd add a clearfix here to make sure the content is shown afterwards – chrona Jul 20 '17 at 10:57
  • @Przemen - Sorry I took so long to get back to you; my dog is old and slow now - then we had lunch. I have updated the answer to show the addition of a `
    ` with a `clear: both;` rule. I also added another method in case you were interested.
    – Fred Gandt Jul 20 '17 at 14:47
  • @FredGandt Thank you and your dog! – Przemen Jul 20 '17 at 15:55
0

Since you tried flex-box I strongly recommend you to learn Grid layout. All the latest browsers support it. Defines it like a flex-box container by setting display: grid. You can find in Google many examples of grid using. Using this gives you an opportunity to make design as you want. And design you showed us can be easily implemented.

Sergey
  • 7,184
  • 13
  • 42
  • 85