How to change order in flex box with just CSS [duplicate] - css

This question already has an answer here:
Change div order with CSS depending on device-width
(1 answer)
Closed 3 months ago.
Isn't there a way to change the order of the children of a flex box with just CSS?
<div> flex 2 </div> <div>
flex 3
</div>
<div style="flex-order:-1"> flex 1 </div>

you can use the property order
.div1 { order: 0; }
But to make it work you should set order to all childrens
Also you should now: 0 for first position, and 1, 2 and so on for other positions

You can use order attribute example:
order: 1;
order: 2;
order: 4;
order: 3;
You can find more here in MDN documentation

Having an HTML code like this:
<div class="wrapper">
<div class="item-2">Flex 2</div>
<div class="item-3">Flex 3</div>
<div class="item-1">Flex 1</div>
</div>
If you want to change the order of a specific item, you can use the order attribute like this:
.wrapper {
display: flex;
}
.item-1 {
order: 1;
}
.item-2 {
order: 2;
}
.item-3 {
order: 3;
}
This code will reorder elements: Flex 1 - Flex 2 - Flex 3.
But, if you want to change the order of all items at same time, simply use flex-direction on the wrapper:
.wrapper {
display: flex;
flex-direction: row-reverse;
}
This code will reorder elements: Flex 1 - Flex 3 - Flex 2.

Related

CSS-grid: automatically span items

Is there a way to make a grid item span over all free space automatically?
For example here, the grid has two rows and two columns. In the first row, the second column is free, so I'd like to span the item (as it does when I explicitly set grid-column-end: 3).
But I do not want to calculate the spans, but let the browser do that.
Edit: to make the question clearer: the container is only allowed to specify the number of rows and cols. The items are only allowed to specify the row- and col-start but no spans and -ends so if there is an item with row-start: i followed by an item with row-start: i+1+n and no items with row-start: i+1+m with m<n the item with row-start: i should automatically span n.
<div style="display: grid; gap: 5px;">
<div style="
background: red;
grid-row-start: 1;
grid-column-start: 1;
/* how can I get rid of this */
grid-column-end: 3;">1 1</div>
<div style="
background: red;
grid-row-start: 2;
grid-column-start: 1;">2 1</div>
<div style="
background: red;
grid-row-start: 2;
grid-column-start: 2;">2 2</div>
</div>
First off,
You cannot automatically span grid items over all free space.
Without explicitly setting the grid-column-end property or calculating the spans yourself - it would be best to resort to something like flexbox.
The way the grid layout works is that it uses the grid-row-start, grid-column-start, grid-row-end and grid-column-end properties to determine the size and position of each item within the grid. Without explicitly setting these properties, the browser will not know how to position the items and you'll inevitably end up with a gigantic mess. Grids aren't like flexbox since they aren't really smart and require you to explicitly set nearly every aspect of it in order to be rendered properly. They aren't really responsive either.
If you do decide to continue sticking with CSS Grid, one option would be to use JavaScript to calculate the spans based on the position of the other items on the grid and then set these properties dynamically. This is more complex and will add more overhead to your code - making it less easy to maintain
Another option (which I personally recommend) is to use flexbox instead of CSS Grid. A flexbox automatically adjusts the size of its flex items based on the available space, and you can use the flex-wrap property to wrap the items onto new rows if there is not enough space.
Flexbox is also responsive. CSS Grid is not.
Therefore, the pros weigh out the cons when compared to CSS Grid.
I don't know if that can totally suits you but one way would be to defined class with span 2 and span1.
.row {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: 1fr auto;
}
.col1 {
grid-column: auto / span 2;
}
.col2 {
grid-column: auto / span 1;
}
<div class="row">
<div class="col1" style="background-color: red">
1 1
</div>
</div>
<div class="row">
<div class="col2" style="background-color: green">
2 1
</div>
<div class="col2" style="background-color: blue">
2 2
</div>
</div>
we can put css grid-column: 1 / -1; as it will automatically fill the cell to the last. So basically we don't need to provide grid-column-end with specific number.
.row {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.col-stretch{
grid-column: 1 / -1;
}
<div class="row">
<div class="col-stretch" style="background-color: red">
1 1
</div>
</div>
<div class="row">
<div class="col" style="background-color: green">
2 1
</div>
<div class="col" style="background-color: gray">
2 2
</div>
<div class="col" style="background-color: yellow">
2 3
</div>
</div>

How to place nested DIVs in a CSS grid with variable row heights?

I need to place 4 div containers in a 2 by 2 matrix. The width of the columns must be equal (and is therefore fixed), while the height of the rows must adapt itself to the content of the cells (and is therefore variable).
This is simple to do as long as the markup structure looks something like this:
<div class="wrapper">
<div class="cell a1">...</div>
<div class="cell a2">...</div>
<div class="cell b1">...</div>
<div class="cell b2">...</div>
</div>
The corresponding CSS would look like this:
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr;
}
Unfortunately, my markup (which I cannot change easily) contains the cells in a nested markup structure:
<div class="wrapper">
<div class="container">
<div class="cell a1">...</div>
<div class="cell a2">...</div>
</div>
<div class="container">
<div class="cell b1">...</div>
<div class="cell b2">...</div>
</div>
</div>
As long as the height of the two rows can be equal, declaring .container as secondary grid solves the issue. But since the row height must be adjusted according to the cell content, this doesn't work.
Is there a way to place all four div.cell in the same grid defined by div.wrapper, although they are not direct child elements?
What you are looking for is Subgrid, feature currently (December 2021) only tested on Firefox Nightly.
Info about this CSS attribute (from the Mozilla Web Docs page) :
When you add display: grid to a grid container, only the direct children become grid items and can then be placed on the grid that you have created.
You can "nest" grids by making a grid item a grid container. These grids however are independent of the parent grid and of each other, meaning that they do not take their track sizing from the parent grid. This makes it difficult to line nested grid items up with the main grid.
For example, if you use grid-template-columns: subgrid and the nested grid spans three column tracks of the parent, the nested grid will have three column tracks of the same size as the parent grid.
When the feature will be available and supported by multiple browsers this example below will work (I guess):
html, body {
width: 100%;
height: 100%;
margin: 0;
}
.wrapper {
display: grid;
height: 100vh;
width: 100vw;
background: grey;
grid-auto-flow: rows;
grid-template-columns: auto auto;
grid-template-rows: auto auto;
}
.container {
display: grid;
grid-column: 1 / 3;
grid-row: 1 / 3;
grid-template-columns: subgrid;
grid-template-rows: subgrid;
}
.a1{
background-color: blue;
grid-row: 1;
grid-column: 1;
}
.a2{
background-color: yellow;
grid-row: 1;
grid-column: 2;
}
.b1 {
background-color: red;
grid-row: 2;
grid-column: 1;
}
.b2 {
background-color: green;
grid-row: 2;
grid-column: 2;
}
<div class="wrapper">
<div class="container a">
<div class="cell a1">A1</div>
<div class="cell a2">A2</div>
</div>
<div class="container a">
<div class="cell b1">B1</div>
<div class="cell b2">B2</div>
</div>
</div>
And will render something like this :

How do I set flex properties of the innerText of a flex box container?

If your flex box container itself has text inside it (innerText), then that text apparently becomes part of the flex layout. But how do I control it with settings such as flex-basis and flex-grow?
Is there any way to control it?
HTML:
<div class="a">
Sample text
<div class="b"></div>
<div class="c"></div>
</div>
CSS:
.a {
display: flex;
}
.b {
flex: 0 0 200px;
}
.c {
flex: 0 0 100px;
}
I want to control the flex properties of "Sample text".
And yes, I know the problem would be solved by just putting that text in a node of it's own, but I'm dealing with a list of +10k items so I'm trying to keep the node count at a minimum.
On idea to control the text is to consider both pseudo element that you wrap around the text where you can apply the flex properties and achieve what you want:
.a {
display: flex;
}
.a:before,
.a:after{
content:"";
background:pink;
flex: 1 0 0%;
}
.b {
flex: 1 0 200px;
background:blue;
order:2; /*we place them at the end*/
}
.c {
flex: 0 1 100px;
background:red;
order:2; /*we place them at the end*/
}
<div class="a">
Sample text
<div class="b"></div>
<div class="c"></div>
</div>
You simply need to imagine the correct values to apply to the pseudo elements in order to achieve the needed result.

Put element above another for small screen

Trying to put a sidebar on top of content text for small screens.
What I tried did not work.
#media(max-width: 820px) {
.head {
display: -webkit-box;
}
.text > .sidebar {
-ms-flex-order: 1;
}
<div class='container'>
<div class='head'>
<aside class='sidebar'>
</aside>
</div>
using flex you can change the flex-direction to column then change the order of the flex items as needed.
you can also use grid in combination with grid-template-areas to set and rearrange the order of grid cells as you see fit. for example, in conjunction with #media
...
grid-template-areas:
"content"
"header";
...
#media (max-width: 500px) {
...
grid-template-areas:
"header"
"content";
...
}
You have a number of problems:
An erroneous <body> tag (simply remove this).
A selector (.text > .sidebar) that will never match the target element.You don't actually need any styling on .sidebar, so I also just removed this.
A logical error -- .head contains no order; I assume you want this below .sidebar in the mobile view, meaning it is .head that would need order: 2 (not .sidebar).
Once all of these are corrected, you simply need to give .container display: flex and flex-direction: column, and the swap will work as expected.
This can be seen in the following (simplified) example:
#media(max-width: 820px) {
.container {
display: flex;
flex-direction: column;
}
.head {
order: 2;
}
}
<div class='container'>
<div class='head'>
<div class="text">
TeXt
</div>
</div>
<aside class='sidebar'>
wordS
</aside>
</div>

Grid Columns Without Rows?

I'm trying to create a 3 column layout using the CSS Grid spec but I'm running into an issue with rows and element sizing. My columns need to contain an unspecified amount of content with varying heights.
This is my ideal layout:
Problems:
1) If I tell element A and B to use row 1, column 1 then they stack on top of one another rather than B below A.
2) If I specify element B to use the second row, then it gets pushed below element C due to element C making row 1 tall.
3) If I specify element B to use the second row, then element A stretches to fill row 1.
Is there any way to get elements to behave like in the first picture?
The only solution I know of is to create "scaffolding" divs inside the columns like this:
<div class="grid">
<div class="col">
<div class="itemA"></div>
<div class="itemB"></div>
</div>
<div class="col">
<div class="itemC"></div>
</div>
<div class="col">
<div class="itemD"></div>
<div class="itemE"></div>
<div class="itemF"></div>
</div>
</div>
But I dislike doing that and I thought the grid spec was supposed to allow for layout creation without scaffolding.
Questions:
1) Is there any way to prevent elements from stretching to fill the row vertically?
2) Is it possible to put two elements on the same row and have them appear one below the other instead of conflicting?
Here's my 2 pens where I'm attempting to find a solution with and without scaffolding:
Without scaffolding
With scaffolding
The closest i could have, but i do recommend you to use flexbox, You can't only define columns in CSS grids, the browsers will define rows for you, if you don't, and you don't manage them, you will get weird layout.
I hard coded the difference in heights between elements.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.grid {
background: brown;
display: grid;
grid-template-columns: auto 1fr auto;
grid-gap: 10px;
padding: 10px;
}
.grid>div {
background-color: orange;
}
.itemA {
grid-column-start: 1;
grid-row: 1 / 1;
width: 100px;
height: 100px;
}
.itemB {
grid-column-start: 1;
grid-row: 2 / 4;
height: 200px;
}
.itemC {
grid-column-start: 2;
grid-row: 1 / 3;
height: 200px;
}
.itemD {
grid-column-start: 3;
width: 100px;
height: 100px;
}
.itemE {
grid-column-start: 3;
height: 100px;
}
.itemF {
grid-column-start: 3;
grid-row: 3 / 4;
height: 200px;
}
<div class="grid">
<div class="itemA">A</div>
<div class="itemB">B</div>
<div class="itemC">C</div>
<div class="itemD">D</div>
<div class="itemE">E</div>
<div class="itemF">F</div>
</div>

Resources