2

I'll start with a picture of what I'm working toward. This is a very common resonsive layout 'grid' of products - cards or whatever - not unlike instagram or dribble or any website that sells things.

The classic conundrum is that you most likely have to use some absolute heights to get something consistent - and absolute heights mean you have to have some logic in place to ensure nothing ever breaks out of that absolute world. Flexbox has many great options to help with things like 'stretching/growing' the main to keep the footer at the bottom / but each choice leans toward a certain markup that inevitably cuts out another option you wanted in the layout. I've generally used JS in the past.

I can hide and show the 'poster' type image markup to create an if else type query that ends up with a different markup - and it'll work to create the layout shown in the diagram. My question is - can this 'float' like thing (shown with arrows) be done with flex-box alone? If I wrap those 2 elements in a parent / I'm no longer able to use the flexbox stuff that makes the other parts of this elegant.

(I'll place my code at the bottom)

enter image description here

Example with only flexbox - that I'm trying to fill in https://codepen.io/sheriffderek/pen/VWgGgv?editors=0100

Example of a different markup - but that won't allow me to use grow and keep the button visually resting at the bottom (I guess I could use absolute positioning here) https://codepen.io/sheriffderek/pen/c12df0754ea9cdd40bb9425a120088d7

Here is an implemetion of @MichaelCoker's suggestion to wrap the main and footer in a parent: https://codepen.io/sheriffderek/pen/weNNMp?editors=0100

But the answer to this question is likely: "No - there is no way to do that without changing the markup and approach." I'm not saying there is a silver bullet- and that all scenarios can be covered, but a parent limits the ability to do things like change the order of the 3 things in the same scope.

Markup:

<ul class='thing-list'>
    
    <li class='thing'>
        <header>
            HEADER
            <figure>
                <img src="http://placehold.it/1600x900" alt="">
            </figure>
        </header>
        
        <main>
            MAIN: 
            <h2>Something...</h2>
        </main>
        
        <footer>
            FOOTER<br>
            <button>Call to action</button>
        </footer>
    </li>
    <!-- ... -->

Styles:
.thing-list
    display: flex
    flex-direction: column
    .thing
        display: flex
        flex-direction: column
        margin-bottom: 2rem
    
        
@media (min-width: 450px)
    .thing-list
        // ?
        .thing
            // ?
            border: 3px solid red

@media (min-width: 700px)
    .thing-list
        flex-direction: row
        flex-wrap: wrap
        justify-content: space-between
        .thing
            flex-basis: 48%
            border: 0
            main
                flex-grow: 1
                
@media (min-width: 900px)
    .thing-list
        //
        .thing
            flex-basis: 32%
sheriffderek
  • 8,848
  • 6
  • 43
  • 70

1 Answers1

1

You can wrap your main and footer sections in another element, and in the medium @media query, set .thing to a flex row so the row columns consist of header and the new element wrapping main and footer.

.thing-list {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
      -ms-flex-direction: column;
          flex-direction: column;
}
.thing-list .thing {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
      -ms-flex-direction: column;
          flex-direction: column;
  margin-bottom: 2rem;
}
@media (min-width: 450px) {
  .thing-list .thing {
    border: 3px solid #f00;
  }
}
@media (min-width: 700px) {
  .thing-list {
    -webkit-box-orient: horizontal;
    -webkit-box-direction: normal;
        -ms-flex-direction: row;
            flex-direction: row;
    -ms-flex-wrap: wrap;
        flex-wrap: wrap;
    -webkit-box-pack: justify;
        -ms-flex-pack: justify;
            justify-content: space-between;
  }
  .thing-list .thing {
    -ms-flex-preferred-size: 48%;
        flex-basis: 48%;
    border: 0;
  }
  .thing-list .thing main {
    -webkit-box-flex: 1;
        -ms-flex-positive: 1;
            flex-grow: 1;
  }
 .thing-list .thing {
  -webkit-box-orient: horizontal;
  -webkit-box-direction: normal;
      -ms-flex-direction: row;
          flex-direction: row;
 }
 .thing-list .thing header, .thing-list .thing .mainFoot {
  -webkit-box-flex: 1;
      -ms-flex: 1 0 0;
          flex: 1 0 0;
 }
 .thing-list .thing .mainFoot {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
      -ms-flex-direction: column;
          flex-direction: column;
 }
}
@media (min-width: 900px) {
  .thing-list .thing {
    -ms-flex-preferred-size: 32%;
        flex-basis: 32%;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
      -ms-flex-direction: column;
          flex-direction: column;
  }
 .thing-list .thing .mainFoot {
  -webkit-box-flex: 1;
      -ms-flex: auto;
          flex: auto;
 }
}
body {
  padding: 1rem;
}
.thing header,
.thing main,
.thing footer {
  padding: 1rem;
}
.thing header {
  background: #add8e6;
}
.thing main {
  background: #f5deb3;
}
.thing footer {
  background: #ffc0cb;
}
figure {
  margin: 0;
}
figure img {
  display: block;
  width: 100%;
  height: auto;
}
<ul class='thing-list'>
 
 <li class='thing'>
  <header>
   HEADER
   <figure>
    <img src="http://placehold.it/1600x900" alt="">
   </figure>
  </header>
  <div class="mainFoot">
  <main>
   MAIN: 
   <h2>Something...</h2>
   <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Eum dolorum similique dolores ipsum, cumque aspernatur.</p>
  </main>
  
  <footer>
   FOOTER<br>
   <button>Call to action</button>
  </footer>
  </div>
 </li>
 

 <li class='thing'>
  <header>
   HEADER
   <figure>
    <img src="http://placehold.it/1600x900" alt="">
   </figure>
  </header>
  <div class="mainFoot">
  <main>
   MAIN: 
   <h2>Something...</h2>
   <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Eum dolorum similique dolores ipsum, cumque aspernatur. Lorem ipsum dolor sit amet consectetur adipisicing elit. Eum dolorum similique dolores ipsum, cumque aspernatur.</p>
  </main>
  
  <footer>
   FOOTER<br>
   <button>Call to action</button>
  </footer>
  </div>
 </li>
 
 <li class='thing'>
  <header>
   HEADER
   <figure>
    <img src="http://placehold.it/1600x900" alt="">
   </figure>
  </header>
  <div class="mainFoot">
  <main>
   MAIN: 
   <h2>Something...</h2>
   <p>Lorem ipsum dolor sit amet consectetur.</p>
  </main>
  
  <footer>
   FOOTER<br>
   <button>Call to action</button>
  </footer>
  </div>
 </li>
 
 <li class='thing'>
  <header>
   HEADER
   <figure>
    <img src="http://placehold.it/1600x900" alt="">
   </figure>
  </header>
  <div class="mainFoot">
  <main>
   MAIN: 
   <h2>Something...</h2>
   <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Eum dolorum similique dolores ipsum, cumque aspernatur.</p>
  </main>
  
  <footer>
   FOOTER<br>
   <button>Call to action</button>
  </footer>
  </div>
 </li>
 
 <li class='thing'>
  <header>
   HEADER
   <figure>
    <img src="http://placehold.it/1600x900" alt="">
   </figure>
  </header>
  <div class="mainFoot">
  <main>
   MAIN: 
   <h2>Something...</h2>
   <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Eum dolorum similique dolores ipsum, cumque aspernatur.</p>
  </main>
  
  <footer>
   FOOTER<br>
   <button>Call to action</button>
  </footer>
  </div>
 </li>
</ul>
Michael Coker
  • 52,626
  • 5
  • 64
  • 64
  • I'll have to take a look in a bit - and ensure that adding the parent div doesn't cause another issue. : ) Thanks – sheriffderek Jul 13 '17 at 18:01
  • Your suggestion gets the job done, but the answer is likely "No, you cannot currently do that with flexbox alone - but here's a work around." – sheriffderek Jul 13 '17 at 19:31
  • @sheriffderek well, it's still all flexbox. I think the answer is more like "yes, if you add another element" - the new element is still using flex, both itself (it's a flex column) and it is a flex child in a horizontal row of the parent. So it's still all a flexbox solution, just requires adding an additional element for the media query to create a row with the right side element as a flex column. – Michael Coker Jul 14 '17 at 02:40
  • Side-note / I guess that StackSnippets iframe is too small - or doesn't respond to these media queries... That's not great. In this case, it seems like a lot of extra work : / – sheriffderek Jul 14 '17 at 03:18
  • @sheriffderek use the "full page" view and resize your browser - http://imgur.com/a/rRCcU I don't think it's an excessive amount of work. Flexbox won't automagically do your layout. Something like [masonry](https://masonry.desandro.com/) might and you might be able to use [css masonry](http://w3bits.com/css-masonry/) but I think either of those would be more work than this. Personally I don't think this is too much work - you have to switch those layouts at different breakpoints with any solution. It's just adding a couple of properties in each of breakpoints. – Michael Coker Jul 14 '17 at 13:42
  • Ah, full page. OK. I'll try that out. I didn't mean the work to write the code. I just mean - for you, to make this stackSnippet and add in all the vendor prefixes that won't be relevant in a year or so etc. - for a preview that doesn't immediately let you see the story-line. Autoprefixer built in would be a huge plus. I am not the type to worry about a layout divider or having to write _too much_ code. Certainly, a pleasure to write this CSS. – sheriffderek Jul 14 '17 at 17:17
  • 1
    @sheriffderek ah gotcha. Yeah I use the autoprefixer built in to codepen :) Definitely don't want to write all that out, it is a lot of work. – Michael Coker Jul 14 '17 at 18:27