Search code examples
cssflexboxgridcss-grid

Recreating a CSS Grid layout with Flexbox


This is a simple layout I've created using CSS Grid for a website that displays events in a list format. The info area contains the date, and there are two more areas for content and a featured image. Using grid-row and order this can be done in relatively few lines.

I'm trying to improve my skills with Flexbox and tried to recreate the same layout (with similar adjustments to the layout depending on breakpoint) and failed. If someone could point me in the right direction or provide a similar example, I would truly appreciate it!

Code is here: https://codepen.io/mwaterous/pen/OrPmLL


Solution

  • I'm glad that you have figured out one of the ways to achieve this (with restructured HTML). If, for any reason, you are stuck with HTML which you cannot change, this could be one of the solutions.

    Disclaimer: The main challenge (and the question really) was how to achieve 2-dimensional layout (easily achieved with CSS grid) if we have 3 sibling divs within one parent and we are to use flexbox.

    The biggest advantage of css grid over flexbox is that it allows you to manipulate content in 2 dimensions. My solution to achieve that using flexbox needed a "help" of absolute positioning, but it does the trick. I've intentionally left some parts of the code commented out to show you alternatives, and I've tried to include some useful comments. Unfortunately, code snippet doesn't allow scss code, so I'll include it in the body along with this: https://codepen.io/nemanjaglumac/pen/OrVgLR

    // HTML CODE
    <section class="container">
      <div class="cell info">.info</div>
      <div class="cell main">.main</div>
      <div class="cell image">.image</div>
    </section>
    

    One option for css.

    // SCSS CODE
    // GLOBAL VARIABLES
    $main-color: #fff;
    
    *,
    *:before,
    *:after {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    html {
      background: linear-gradient(-20deg, #00b09b, #96c93d);
      min-height: 100vh;
      font-family: Ubuntu, sans-serif;
      font-size: 18px;
      text-shadow: 1px 1px 0 #000;
      color: $main-color;
      text-align: center;
    }
    
    .cell {
      background-color: rgba($main-color, 0.15);
      border: 1px solid $main-color;
      border-radius: 2px;
      padding: 20px;
      margin: 10px;
      text-align: center;
    
      &:hover {
        background-color: rgba($main-color, 0.25);
      }
    }
    
    @media screen and (min-width: 768px) {
      .container {
        display: flex;
        flex-flow: wrap-reverse; // this has saved us 3 lines of code (flex-direction: row [1], flex-wrap: wrap [2], and then later we would have to set order to -1 on .image [3])
        // flex-direction: row; // [1]
        // flex-wrap: wrap; // [2]
        position: relative;
        height: 300px;
      }
    
      .info {
        width: 180px;
        position: absolute;
        top: 0;
        bottom: 0;
        // left: 0; 
      }
    
      .main, 
      .image {
        width: calc(100% - 180px - 4*10px); // we need to count all four margins (2elements x left+right)
        margin-left: auto; // this moves elements all the way to the right. Alternative would be to set justify-content of the .container to flex-end, but then we would need to explicitly set .info's left position to 0 to "keep it in place"
      }
    
      // .image {
      //   order: -1; [3]
      // }
    }
    
    @media screen and (min-width: 1021px) {
      .info {
        position: initial;
      }
    
      .main,
      .image {
        margin: 10px;
      }
    
      .main {
        flex: 2;
      }
    
      .image {
        flex: 1;
        // order: 0; [3]
      }
    }
    

    Additional reading: