Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to change the order of items when wrapping?

Tags:

html

css

flexbox

I'm trying to create a part of a website, with 3 parts (let's call them A, B, C), where A and B are beside each other (aligned to touch opposite sides of a container), and below them is C, but when A, and B don't fit beside each other in the container, B wraps below C instead of between A and C.

A, B and C all have expanding-collapsing components, and the container can be resized by other elements, so all their sizes are unknown. This means that using @media is out of the question.

Expected result:
When A and B fit beside each other:
When A and B fit beside each other
When they don't:
When they don't

Is this possible to achieve with flexbox or grid?

This is as far as I got:

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>flexbox black magic</title>
</head>
<body>
    <div style="width:50%; border:4px solid blue; margin:8px; display: flex; justify-content: space-between; flex-wrap: wrap;">
        <div style="width: 100px; height: 60px; border: 4px solid red; margin:8px;">a</div>
        <div style="width: 70px; height: 30px; border: 4px solid green; margin:8px;">b</div>
        <div style="width: 100%">
            <div style="width: 100%; max-width: 240px; height: 100px; border: 4px solid orange; margin:8px;">c</div>
        </div>
    </div>
</body>
</html>

But this not only wraps the elements in the wrong order, it also makes C stick out of the container.
like image 962
vitrack Avatar asked Nov 21 '20 21:11

vitrack


People also ask

How do I move my flex item to the top?

1 Answer. Show activity on this post. Switch from flex-direction: row to column . In column mode the elements stack, just like in standard block layout, which is the reason why your layout is "fixed" when you disable the #about CSS rules.

What flexbox property changes the order of the Flex items?

The order property and accessibility Use of the order property has exactly the same implications for accessibility as changing the direction with flex-direction . Using order changes the order in which items are painted, and the order in which they appear visually.

What gets reversed when using the flex wrap wrap reverse option?

The flex items break into multiple lines. The cross-start is either equivalent to start or before depending flex-direction value and the cross-end is the opposite of the specified cross-start. wrap-reverse. Behaves the same as wrap but cross-start and cross-end are permuted.


3 Answers

Here is an idea using float, yes float. Resize the blue container and see the result:

.box {
  width: 50%;
  border: 4px solid blue;
  margin: 8px;
  text-align: justify;
  font-size:0; /* this will make sure the pseudo element won't have any size */
  overflow: auto;
  resize: horizontal;
}
.box > * {
  font-size:initial; /* we reset the font for child element */
  margin:8px;
  box-sizing:border-box;
}
/* the below is used with text-align:justify to have the correct alignment on wrap */
.box::before {
  content:"";
  display:inline-block;
}
.box::after {
  content:"";
  display:inline-block;
  width:100%;
}
/**/
.a {
  max-width: 100px;
  width: calc(100% - 16px);
  height: 60px;
  float:left; /* we float a */
}

.b {
  width: 70px;
  height: 30px;
  display: inline-block;
}

.c {
  height: 100px;
  width: calc(100% - 16px);
  max-width: 240px;
  float:left; /* and we float c */
  clear:left; /* don't forget this to make "c" always below "a" */
}
<div class="box">
  <div class="a" style="border: 4px solid red;">a</div>
  <div class="c" style="border: 4px solid orange;">c</div>
  <div class="b" style="border: 4px solid green;">b</div>
</div>
like image 117
Temani Afif Avatar answered Oct 20 '22 06:10

Temani Afif


One way (using mobile-first approach) would be set the .c as your second element in the HTML

Then inside the media query you would set display:flex to parent and the order: 1 to .c

* {
  box-sizing: border-box;
  margin: 0
}

.wrap {
  width: 50%;
  border: 4px solid blue;
}

.wrap>div {
  border-width: 4px;
  border-style: solid;
  margin: 8px;
}

.a {
  width: 100px;
  height: 60px;
  border-color: red
}

.b {
  width: 70px;
  height: 30px;
  border-color: green
}

.c {
  width: calc(100% - 16px);
  height: 100px;
  border-color: orange;
}

@media (min-width: 600px) {
  .wrap {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
  }
  .c {
    order: 1
  }
}
<div class="wrap">
  <div class="a">a</div>
  <div class="c">c</div>
  <div class="b">b</div>
</div>
like image 25
dippas Avatar answered Oct 20 '22 04:10

dippas


One good rule of thumb is to always start from the mobile layout. Use grid-template-areas and make sure that the sizes of the surrounding areas are well defined, using grid-template-columns and grid-template-rows. Always use fr values when specifying the columns and rows.

Please consider reading MDN Docs on CSS Grid and MDN Docs on Media queries for responsive design. CSS Grid will make your life easier but it takes time learning.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            box-sizing: border-box;
        }
        .container {
            width: auto;
            height: 300px;
            border: 4px solid blue; 
            margin: 8px;
            display: grid;
            grid-template-columns: 1fr;
            grid-template-rows: auto auto auto;
            grid-template-areas: 
            "a"
            "c"
            "b";
        }
        .red-box {
            grid-area: a;
            width: 100px;
            height: 60px;
            border: 4px solid red;
            margin: 8px;
        }     
        .green-box {
            grid-area: b;
            width: 70px;
            height: 30px;
            border: 4px solid green;
            margin: 8px;
            
        }   
        .orange-box {
            grid-area: c;
            width: 100%; 
            max-width: 240px; 
            height: 100px; 
            border: 4px solid orange; 
            margin: 8px;
        }
        @media screen and (min-width: 768px) {
            .container {
                grid-template-columns: 1fr 1fr 1fr;
                grid-template-rows: 1fr 1fr;
                grid-template-areas: 
                "a . b"
                "c c .";
                margin: 0;
                padding: 8px;
                grid-gap: 21px;
            }
            .red-box {
                width: 100%;
                margin: 0;
            }
            .green-box {
                width: 100%;
                height: 100%;
                margin: 0;
            }
            .orange-box {
                padding-top: 21px;
                max-width: 100%;
                height: 100%;
                margin: 0;
            }
        }
    </style>
</head>

<body>

        <div class="container">
            <div class="red-box">a</div> <!-- red ends -->
            <div class="green-box">b</div> <!-- green ends -->
            <div class="orange-box">c</div> <!-- orange ends -->
        </div> <!-- container ends -->

</body>
</html>
like image 20
Eduardo Avatar answered Oct 20 '22 05:10

Eduardo