Luuk Skeur
Luuk Skeur

Reputation: 1940

Flexbox: variable/dynamic height items with column wrap

I'm struggling with creating a dynamic layout which is different for mobile and desktop. The items should be different sorted based on the screen width and the layout should change.

Below is the main objective, where the left layout is for mobile and the right one is desktop:

enter image description here

The content of the blue, purple and yellow div can vary so the height is adjustable. The purple and yellow block must always be on the side of the gray + blue block on desktop.

Right now I have it working for only 3 columns but the 'dynamic' height is duplicated on all columns: Bootstrap 4: sidebar between columns on mobile. Columns under each other layout

To give you a clear idea of the possibilities here are some desktop variations: enter image description here

I've managed to get it working with floats but the columns align on each other. Also have fixed it with a static max-height for the parent and use column wrap but I don't want to use a static max-height since the content should have a dynamic height..

I don't want to use some glitchy javascript or unsupported grid-css.

Looking forward to ideas/suggestions! Cheers.

Upvotes: 0

Views: 2496

Answers (2)

Carol Skelly
Carol Skelly

Reputation: 362410

You should be able to get this layout to work with a combination of CSS columns (not CSS grid) on "desktop", and flexbox on "mobile".

<div class="container">
    <div class="d-flex d-md-columns flex-column min-vh-100">
        <div class="d-md-inline-block light order-0">
            light
        </div>
        <div class="d-md-inline-block blue order-2">
            blue
        </div>
        <div class="d-md-inline-block purple order-1">
            purple
        </div>
        <div class="d-md-inline-block yellow order-3">
            yellow
        </div>
    </div>
</div>

The only extra CSS you'll need is a media query for the columns on larger (md) desktop widths. The the flexbox ordering will kick-in on mobile..

@media (min-width: 768px) {
    .d-md-columns {
        display: inline-block !important;
        column-count: 2;
        -webkit-column-gap: 0
        -moz-column-gap: 0;
        column-gap: 0;
    }
}

https://codeply.com/go/QWIlredUTk

This works specifically for this 4 column layout. However, generally speaking flexbox columns do NOT fit together vertically like a "masonry" layout: Is it possible for flex items to align tightly to the items above them?

Upvotes: 1

ReSedano
ReSedano

Reputation: 5060

I think there is no pure CSS solution for this (at least without using CSS-grid or display:contents). Every CSS way I thought had bugs: float & column flexbox simple don't work in this particular case.

Column flexbox cannot wrap correctly an item if we work with a content without fix height and float can't create a "masonry" layout. Also Bootstrap card-columns are not a solution because your main objective is to align left and right column in height.

I know, you don't want glitchy javascript, but I think it is necessary to create your layout. So, I post you my solution (a jquery solution) without use any d-none class to prevent duplicate HTML & SEO problems.

Moreover, you are using Bootstrap and this framework makes extensive use of jQuery so, I think, it not a problem to ask jQuery for a little help. This help:

  function move(){
    if($(".main .col-lg-8").css('display')=='block'){
      $('.purple').insertAfter('.gray');
    } else {
      $('.purple').insertBefore('.yellow'); 
    }
  }

  $(window).resize(function(){move()})
  $(document).ready(function(){move()})

To move our purple div in second position when .col-lg-8 have display:block

This is all code in action:

function move(){
  if($(".main .col-lg-8").css('display')=='block'){
    $('.purple').insertAfter('.gray');
  } else {
    $('.purple').insertBefore('.yellow'); 
  }
}

$(window).resize(function(){move()})
$(document).ready(function(){move()})
.gray{
  background-color: gray;
}

.blue{
  background-color: blue;
}

.purple{
  background-color: purple;
}

.yellow{
  background-color: yellow;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>

<div class="container mt-5">
  <div class="row main">
      <div class="col-lg-4 d-lg-flex flex-lg-column">
        <div class="gray mb-4">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sodales finibus faucibus. Morbi blandit neque a diam laoreet pellentesque. Vivamus in orci sed turpis posuere iaculis quis sed augue. Curabitur lorem magna, bibendum vitae vestibulum nec faucibus. Morbi blandit neque a diam laoreet pellentesque. Vivamus in orci sed turpis posuere iaculis quis sed augue. Curabitur lorem magna, bibendum vitae vestibulum nec, feugiat eget justo. Ut aliquam quis velit non euismod. Ut vehicula, sem quis cursus pretium, purus libero tincidunt eros, vitae hendrerit nisi mi vitae erat. Curabitur augue purus, sagittis tempor volutpat quis, congue sed mi. Sed gravida odio sed orci iaculis tincidunt. Etiam ac mauris sit amet turpis consequat fermentum ut vitae sem. Aliquam tincidunt convallis sem.</div> 
        <div class="blue flex-fill mb-4 mb-lg-0">
        Lorem ipsum dolor sit amet, consectetur.Quisque sodales finibus </div>
      </div>
      <div class="col-lg-8 d-lg-flex flex-lg-column">
        <div class="purple mb-4">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. faucibus. Morbi blandit neque a diam laoreet pellentesque. Vivamus in orci sed turpis posuere iaculis quis sed augue. Curabitur lorem magna, bibendum vitae vestibulum nec, feugiat eget justo. Ut aliquam quis velit non euismod. Ut vehicula, sem quis cursus pretium, purus libero tincidunt eros, vitae hendrerit nisi mi vitae erat. Curabitur augue purus, sagittis tempor volutpat quis, congue sed mi. Sed gravida odio sed orci iaculis tincidunt. Etiam ac mauris sit amet turpis consequat fermentum ut vitae sem. Aliquam tincidunt convallis sem. </div>
        <div class="yellow flex-fill">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
      </div>
  </div>
</div>

Waiting a pure CSS solution, this could be a way.

Upvotes: 1

Related Questions