Different order items and layout with css3 by resolution with the same html

Viewed 179

I don´t manage to get a responsive result keeping the same HTML layout.

I need :

  1. two different block orders if the screen width is before or after 1024px,
  2. => 1024px, I have to display items organized in two columns and make sure blocks 1, 2, 3 are inside the left column and blocks 4, 5 are inside the right column (the height of the wrapper has to fit of the content ),
  3. < 1024px, all blocks are inside unique column but the order is different.

Like this...

1024px and more

enter image description here

1023px and less

enter image description here

Current CSS

@media screen and (max-width: 1023px) {
    .production-container{
        display: grid;
        grid-template-columns: repeat(1, 1fr);
        padding: 0 var(--standard-margin) 0 var(--standard-margin);
        justify-content: stretch;
        min-height: 200px;
    }

    aside.production-block{
        max-width: 100vw;
        width: 100%;
        display: flex;
        flex: 1;
        flex-direction: column;
        margin: 24px 0;
        display: grid;
        grid-template-rows: 1fr auto;
        break-inside: avoid;
    }

    .production-container > .production-block-4 {
        order: 1;
    }

    .production-container > .production-block-1 {
        order: 2;
    }

    .production-container > .production-block-2 {
        order: 3;
    }

    .production-container > .production-block-5 {
        order: 4;
    }

    .production-container > .production-block-3 {
        order: 5;
    }

}

@media screen and (min-width: 1024px) {

   .production-container{
        column-count: 2;
        column-gap: 50px;
        max-width: 1024px;
        background: linear-gradient( var(--text-light-color), var(--text-light-color) ) no-repeat center/1px 100%; /* vertical line in the center */
   }
   .production-block {
        margin: 0 0 10px 0;
        break-inside: avoid;
        max-width: 520px;
    }

}

The most important problem is, in the biggest resolution, I don´t manage to force each block to be on the first or second column, they place thereself naturally based on height content. Maybe, I should change of css strategy compatible with the smallest resolution but when I used "grid", each row got a height that made big blank spaces.

Someone has got an idea ?

6 Answers

You can switch from a grid layout to a column CSS layout (untill masonry CSS grid layout is widely avalaible https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout , here is an example https://codepen.io/gc-nomade/pen/ExXNXdd For FF at this time if activated)

Demo from your HTML code in the snippet lower below withouth blank space

How does it work ?

  • 1 - < 1024px grid for the single column to use order (grid creates a single column if no template is set)

  • 2 - > 1023px column-count and display:block for a 2 column layout . break-after:always & break-before: column will be avalaible for browsers using the chrome engine (see CSS Fragmentation ).

  • 3 - For firefox & >1023px a hudge margin-bottom on the third element, so there can be only 3 on the first column. This margin won't be applied inside the container, npr will be overflowing it, it will only push the fourth on the next column. Firefox can be filtered via (untill it understands break-after:always with Column CSS) to apply the margin trick only for Firefox browsers use :

@-moz-document url-prefix() {
  .grid > div:nth-child(3) {
   margin-bottom:100%;
   }
}

Live Example where the main container takes only the height needed to wrap the 2 columns, no matter the height of the children, you will notice that on the second example, where col 2 is taller, Chrome(s) seem follows the breaking rules, the first column do not need to be the tallest one.

.grid {
  display: grid;
  gap: 1em;
  border:solid;
  background:gray;
    
}

.grid > div:nth-child(1) {
  order: 1;
}
.grid > div:nth-child(2) {
  order: 2;
}
.grid > div:nth-child(3) {
  order: 4;
}
.grid > div:nth-child(4) {
  order: 0;
}
.grid > div:nth-child(5) {
  order: 3;

}

@media (min-width: 1024px) {
  .grid {
    display: block;
    column-count: 2;
  }
  .grid > div {
    margin-bottom: 1em;
  }
  .grid > div:nth-child(3) {
    break-after:always;
  }
  .grid> div:nth-child(4) {
      break-before: column;
      }
  @-moz-document url-prefix() {
    .grid > div:nth-child(3) {
    margin-bottom:100%;/* trick for FF that won't show that margin if the last inside a column but not in the last column */
  }
}
}

/* demo */
.grid {
  counter-reset: divs;
}
.grid > div {
  display: grid;
}
.grid > div::before {
  counter-increment: divs;
  content: counter(divs);
  color: white;
  margin: auto;
  font-size: clamp(10px, 5vmin, 30px);
}
.grid > div:nth-child(1) {
  background: #fa9917;
  height: 100px;
}
.grid > div:nth-child(2) {
  background: #33e0fe;
  height: 160px;
}
.grid > div:nth-child(3) {
  background: #ff3366;
  height: 80px;
}
.grid > div:nth-child(4) {
  background: #2bc940;
  height: 80px;
}
.grid > div:nth-child(5) {
  background: #3399fe;
  height: 160px;
}
<div class=grid>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>
Hello the world
<hr>
Make second column taller to see where the fourth stands before you test or ask ;)
<div class=grid>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div style="height:600px"></div>
</div>

Finally, i would advise to use a tiny bit of javascript, or the well known and solid masonry library to avoid that FF CSS tricks. Tricks can become obsolete anytime ;)

  • No idea about Safari behavior about CSS Fragmentation.

https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fragmentation

CSS Fragmentation is a module of CSS that defines how content is displayed when it is broken (fragmented) across multiple pages, regions, or columns.

Fragmentation occurs when an inline box wraps onto multiple lines. It also occurs when a block spans more than one column inside a column layout container, or spans a page break when printed. Each piece of the rendering for the element is called a fragment.

about the native CSS grid masonry, you can see & read : https://www.smashingmagazine.com/native-css-masonry-layout-css-grid/

Actually it works, you're almost done. Just add the orders to:

@media screen and (min-width: 1024px) {

   .production-container{
        column-count: 2;
        column-gap: 50px;
        max-width: 1024px;
        background: linear-gradient( var(--text-light-color), var(--text-light-color) ) no-repeat center/1px 100%; /* vertical line in the center */
   }
   
   .production-block {
        margin: 0 0 10px 0;
        break-inside: avoid;
        max-width: 520px;
        border: 1px solid red;
    }
    
    .production-container > .production-block-4 {
        order: 1;
    }

    .production-container > .production-block-1 {
        order: 2;
    }

    .production-container > .production-block-2 {
        order: 3;
    }

    .production-container > .production-block-5 {
        order: 4;
    }

    .production-container > .production-block-3 {
        order: 5;
    }
}

I found a solution with grid-template-areas.

@media screen and (min-width: 1024px) {

   .production-container{
        height: 100%;
        display: grid;
        grid-template-areas: "zone-row1-column1 zone-row1-column2" "zone-row2-column1 zone-row2-column2" "zone-row3-column1 zone-row3-column2";
        grid-template-rows: minmax(290px, auto) 1fr;
        grid-template-columns: 1fr 1fr;
        grid-gap: 50px;
        max-width: 1024px;
        background: linear-gradient( var(--text-light-color), var(--text-light-color) ) no-repeat center/1px 100%; /* vertical line in the center */
   }
    
    .production-container > .production-block-4 {
        grid-area: zone-row1-column2;
    }

    .production-container > .production-block-1 {
         grid-area: zone-row1-column1;
    }

    .production-container > .production-block-2 {
        grid-area: zone-row2-column1;
    }

    .production-container > .production-block-5 {
        grid-area: zone-row2-column2;
    }

    .production-container > .production-block-3 {
        grid-area: zone-row3-column1;
    }
}

You must add "zone-row3-column2" even if it does not use inside grid-template-areas because there are 2 columns anyway.

@media screen and (min-width: 1024px) {
    .production-container{      
       padding: 0 var(--standard-margin) 0 var(--standard-margin);      
       min-height: 200px;
    }
    
    .production-block {
        border: 1px solid blue;
        width:50%;
    }
    .production-block-1{
        float: left;
        clear:left
    }
    .production-block-2{
        float: left;
        clear:left
    }
    .production-block-3{
        float: left;
        clear:left
    }
    .production-block-4{
        margin-left:50%
    }
    .production-block-5{
        margin-left:50%
    }
}

I don´t manage to force each block to be on the first or second column, they place thereself naturally based on height content.

In that case, you can manage the grid with grid-row-start and grid-row-end

when I used "grid", each row got a height that made big blank spaces.

For this solution you try to set height with height: min-content. If the block doesn't have any contents it's collapse. But, should be remember about padding, they give extra height without the content.

*,
::after,
::before {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}

:root {
  --bg1: hsl(34, 96%, 54%);
  --bg2: hsl(189, 99%, 60%);
  --bg3: hsl(345, 100%, 60%);
  --bg4: hsl(128, 65%, 48%);
  --bg5: hsl(210, 99%, 60%);
  --standard-margin: 1rem;
}

.production-block-1,
.production-block-2,
.production-block-3,
.production-block-4,
.production-block-5 {
  height: min-content;
  display: flex;
  justify-content: center;
  align-items: center;
  color: white;
  padding: 1rem;
}

.production-block-1 {
  grid-row-start: 2;
  background-color: var(--bg1);
}

.production-block-2 {
  grid-row-start: 3;
  background-color: var(--bg2);
}

.production-block-3 {
  grid-row-start: 5;
  background-color: var(--bg3);
}

.production-block-4 {
  grid-row-start: 1;
  background-color: var(--bg4);
}

.production-block-5 {
  grid-row-start: 4;
  background-color: var(--bg5);
}

.production-container {
  display: grid;
  gap: 1rem;
}

@media screen and (max-width: 1023px) {
  .production-container {
    grid-template-columns: repeat(1, 1fr);
    padding: 0 var(--standard-margin) 0 var(--standard-margin);
  }
}

@media screen and (min-width: 1024px) {
  .production-container {
    grid-template-columns: repeat(2, 1fr);
  }
  .production-block-1 {
    grid-row-start: 1;
  }
  .production-block-2 {
    grid-row-start: 2;
  }
  .production-block-3 {
    grid-row-start: 3;
  }
  .production-block-4 {
    grid-row-start: 1;
  }
  .production-block-5 {
    grid-row-start: 2;
  }
}
<div class="production-container">
  <div class="production-block-1">1</div>
  <div class="production-block-2">2</div>
  <div class="production-block-3">3</div>
  <div class="production-block-4">4</div>
  <div class="production-block-5">5</div>
</div>

I found a better solution that used grid to make two columns.

Notice : when you use grid, that forces the template to be aligned with columns and rows as well that can make blank space when blocks on the same row have not a similar height...

Template that makes blank spaces

*,
::after,
::before {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}

:root {
  --bg1: hsl(34, 96%, 54%);
  --bg2: hsl(189, 99%, 60%);
  --bg3: hsl(345, 100%, 60%);
  --bg4: hsl(128, 65%, 48%);
  --bg5: hsl(210, 99%, 60%);
  --standard-margin: 1rem;
}

.production-block-1,
.production-block-2,
.production-block-3,
.production-block-4,
.production-block-5 {
  height: min-content;
  display: flex;
  justify-content: center;
  align-items: center;
  color: white;
  padding: 1rem;
}

.production-block-1 {
  grid-row-start: 2;
  background-color: var(--bg1);
}

.production-block-2 {
  grid-row-start: 3;
  background-color: var(--bg2);
}

.production-block-3 {
  grid-row-start: 5;
  background-color: var(--bg3);
}

.production-block-4 {
  grid-row-start: 1;
  background-color: var(--bg4);
}

.production-block-5 {
  grid-row-start: 4;
  background-color: var(--bg5);
}

.production-container {
  display: grid;
  gap: 1rem;
}

@media screen and (max-width: 1023px) {
  .production-container {
    grid-template-columns: repeat(1, 1fr);
    padding: 0 var(--standard-margin) 0 var(--standard-margin);
  }
}

@media screen and (min-width: 1024px) {
  .production-container {
    grid-template-columns: repeat(2, 1fr);
  }
  .production-block-1 {
    grid-row-start: 1;
    height: 150px;
  }
  .production-block-2 {
    grid-row-start: 2;
    height: 200px;
  }
  .production-block-3 {
    grid-row-start: 3;
  }
  .production-block-4 {
    grid-row-start: 1;
    height: 300px;
  }
  .production-block-5 {
    grid-row-start: 2;
    height: 250px;
  }
}
<h1>Grid template with blank spaces</h1>
<div class="production-container">
  <div class="production-block-1">1</div>
  <div class="production-block-2">2</div>
  <div class="production-block-3">3</div>
  <div class="production-block-4">4</div>
  <div class="production-block-5">5</div>
</div>

My Solution (Masonry + break column)

To avoid blank spaces, you have a solution based on Masonry with flexbox and add a break column inside the HTML template.

Notice : That solution needs :

  1. add a html tag with break-column class
  2. use height: 100%; on wrappers html tags.
  3. The orders of the biggest resolution is the order in the html template, it is for the smallest resolution, you change the order.

*,
::after,
::before {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}

:root {
  --bg1: hsl(34, 96%, 54%);
  --bg2: hsl(189, 99%, 60%);
  --bg3: hsl(345, 100%, 60%);
  --bg4: hsl(128, 65%, 48%);
  --bg5: hsl(210, 99%, 60%);
  --standard-margin: 1rem;
}

body, html{
    height: 100%;
}

.production-block-1,
.production-block-2,
.production-block-3,
.production-block-4,
.production-block-5 {
  height: min-content;
  display: flex;
  justify-content: center;
  align-items: center;
  color: white;
  padding: 1rem;
}

.production-block-1 {
  grid-row-start: 2;
  background-color: var(--bg1);
}

.production-block-2 {
  grid-row-start: 3;
  background-color: var(--bg2);
}

.production-block-3 {
  grid-row-start: 5;
  background-color: var(--bg3);
}

.production-block-4 {
  grid-row-start: 1;
  background-color: var(--bg4);
}

.production-block-5 {
  grid-row-start: 4;
  background-color: var(--bg5);
}

.production-container {
  display: grid;
  gap: 1rem;
}

@media screen and (max-width: 1023px) {
  .production-container {
    grid-template-columns: repeat(1, 1fr);
    padding: 0 var(--standard-margin) 0 var(--standard-margin);
  }
}

@media screen and (min-width: 1024px) {
  .production-container {
      display: flex;
      flex-flow: column wrap;
      max-width: 1024px;
      height: 100%;
      background: linear-gradient( var(--text-light-color), var(--text-light-color) ) no-repeat center/1px 100%;
  }
  /* Force new columns */
 .production-container::before,
 .production-container::after {
    content: "";
    flex-basis: 100%;
    width: 0;
    order: 2;
  }
  .break-column {
    flex-basis: 100%;
    width: 0 !important;
  } 
  .production-container > .production-block{
    width: 500px;
  } 
  .production-block-1 {
    height: 150px;
  }
  .production-block-2 {
    height: 200px;
  }
  .production-block-4 {
    height: 300px;
  }
  .production-block-5 {
    height: 250px;
  }
}
<h1>Masonry solution without blank space</h1>
<div class="production-container">
  <div class="production-block production-block-1">1</div>
  <div class="production-block production-block-2">2</div>
  <div class="production-block production-block-3">3</div>
  <div class="break-column"></div>
  <div class="production-block production-block-4">4</div>
  <div class="production-block production-block-5">5</div>
</div>

Related