How can I arrange elements inside a wrapper like the example below? - html

I need to arrange following elements as This sample Image with CSS Flexbox.
.wrapper {
width: 60%;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.element {
width: 200px;
height: 200px;
background: green;
margin-bottom: 20px;
}
<div class="wrapper">
<div class="element large"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element large"></div>
</div>
I have tried few styles but couldn't get successful. Is there any way to fix this with css flex?

In case you change your mind, the Grid solution:
.grid {
width: 60%;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(4, 100px); /* "width" */
grid-template-rows: repeat(4, 100px); /* "height" */
grid-gap: 10px; /* gap between items */
justify-content: center; /* horizontally centered */
}
.item {
background: green;
}
.larger {
grid-column: 1 / span 2; /* starts at the 1st column & spans two */
grid-row: 1 / span 2; /* starts at the 1st row & spans two */
/* can also omit the 1's since it's the first child */
}
.larger2 {
grid-column: 3 / span 2;
grid-row: 3 / span 2;
}
<div class="grid">
<div class="item larger"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item larger2"></div>
</div>

Related

Horizontal list of items: the next to last item is centered, while the last item takes all of the remaining space

I'm building a horizontal list of items:
Once scrolled to the end of the list, the second last item needs to be in center, and the last item takes all of the remaining space after it.
I've had a success in making the list of items, but not sure what's the best way to implement the desired behaviour of having second last item centered and last item taking remaining space. Here is my current code:
I would appreciate any help or advice for guiding me in the right direction. Thank you!
/* layout */
.container {
display: flex;
overflow-x: auto;
gap: 21px;
}
.item {
min-width: 212px;
height: 254px;
}
/* visuals */
.container {
padding-left: 11px;
}
.item {
background: #D9D9D9;
}
.item.green {
background: #099F9F;
}
.item.red {
background: #FF6262;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item green"></div>
<div class="item red"></div>
</div>
You can define the width as calc((100% - item_wdith - 2*gap)/2)
.container {
display: flex;
overflow-x: auto;
padding-left: 10px;
gap: 20px;
}
.item {
width: 220px;
flex-shrink: 0;
height: 254px;
background: #D9D9D9;
}
.item.green {
background: #099F9F;
}
.item.red {
background: #FF6262;
width: calc((100% - 220px - 2*20px)/2);
}
/* to illustrate the center */
html {
background: linear-gradient(red 0 0) 50%/2px 100% no-repeat;
min-height: 100%;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item green"></div>
<div class="item red"></div>
</div>

How to set 3 items in row FLEXBOX [duplicate]

This question already has answers here:
How to add 1px margin to a flex item that is flex: 0 0 25%?
(4 answers)
Closed 9 months ago.
I would like to display 3 items per row, but I want to include margin and border.
Here's is a simple example, but I need to set valid flex property
.box {
display: flex;
flex-wrap: wrap;
width: 1200px;
}
.item {
display: flex;
border: 1px solid #000;
margin: 5px;
flex: // ???
}
<div class="box">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
As far as I understood your question.
Instead of margin use gap property
.box {
width: 100%;
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.item {
flex: 1;
width: 100%;
height: 200px;
border: 1px solid #000;
}
.item:nth-child(4),
.item:nth-child(5),
.item:nth-child(6) {
flex: 0 1 100%;
}
<div class="box">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
I would probably do it like this:
Seeing as you have specified a fixed width-value, you could just make each item have a max-width of 400px - border and margin. However, for a more dynamic layout, you could just use max-width: 1200px on box, so its resizable and responsive.
I prefer to use gap instead of margin in flex-layouts. With this, you can set each items max-width to 33.33% (for a 3 row layout), minus the 5px gap and the 1px border. Also, you don't have to use display: flex on the items, as they are already children of a flex-container (unless you plan to have more content inside them).
This would produce this:
.box {
display: flex;
flex-wrap: wrap;
max-width: 1200px;
flex: 1; /* equal items */
gap: 5px;
}
.item {
border: 1px solid #000;
width: 100%;
max-width: calc(33.33% - 6px);
}
<div class="box">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
</div>
However, this is also achievable by using margin and a fixed width. Then you just have to use the items margin and border in the max-width calculation (5px + 5px + 1px + 1px). Keep in mind when using margin in the layout, its also going to affect the margin between the container and the items - not just the gap between the items.
.box {
display: flex;
flex-wrap: wrap;
width: 1200px;
flex: 1; /* equal items */
}
.item {
border: 1px solid #000;
height: 20px;
margin: 5px;
width: 100%;
max-width: calc(33.33% - 12px);
}
<div class="box">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
</div>
I rather use flex-basis on child.
.box {
display: flex;
flex-wrap: wrap;
width: 1200px;
}
.item {
display: flex;
border: 1px solid #000;
margin: 5px;
flex-basis: 30%
}
<div class="box">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>

Orphaned Inline Divs

I have a series of inline-block divs that can wrap onto a second line depending on how wide the browser is at a given time. Here's a fiddle example. For example, it might look like this:
However if the viewport is of a certain width, it can end up with just one orphaned inline-block on the next line:
Is there a CSS method that is essentially some form of "orphan control" (CSS orphan doesn't seem to apply in this situation) so that if there are fewer than a certain number of elements on the second line, it'd wrap more of them down there to even things out?
.container {
width: 100%;
}
.item {
display: inline-block;
width: 50px;
background-color: blue;
}
<div class="container">
<div class="item">
Item 1
</div>
<div class="item">
Item 2
</div>
<div class="item">
Item 3
</div>
<div class="item">
Item 4
</div>
<div class="item">
Item 5
</div>
<div class="item">
Item 6
</div>
<div class="item">
Item 7
</div>
</div>
Here is an idea using CSS grid where the trick is to make sure your div has a width expressed as a multiple of a fixed amount to make sure you never have an orphan element.
.wrapper {
--w: 100px; /* width of one item */
display: grid;
grid-template-columns: repeat(auto-fit, calc(2*var(--w))); /* the item will break two by two*/
justify-content:center;
}
.container {
grid-column: 1/-1;
display:flex;
flex-wrap:wrap;
justify-content:center;
}
.item {
width: calc(var(--w) - 10px);
margin: 5px;
}
/* irrelevant styles */
.container {
counter-reset: num;
}
.item {
height: 150px;
background-color: blue;
color: #fff;
}
.item::before {
color: #fff;
content: attr(class) " " counter(num);
counter-increment: num;
}
<div class="wrapper">
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
If we use 3
.wrapper {
--w: 100px; /* width of one item */
display: grid;
grid-template-columns: repeat(auto-fit, calc(3*var(--w)));
justify-content:center;
}
.container {
grid-column: 1/-1;
display:flex;
flex-wrap:wrap;
justify-content:center;
}
.item {
width: calc(var(--w) - 10px);
margin: 5px;
}
/* irrelevant styles */
.container {
counter-reset: num;
}
.item {
height: 150px;
background-color: blue;
color: #fff;
}
.item::before {
color: #fff;
content: attr(class) " " counter(num);
counter-increment: num;
}
<div class="wrapper">
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
You could use flex and flex-wrap for this with break points so you can decide how many items are in the top row on each width. Where it is inevitable that there is a single item on the last row this snippet goes for minimising the number of rows.
It would have been nice to use CSS variables for all of this so the choice is easily altered, but you can't use variables in media queries so we have to put them in by hand.
.container {
width: 104px; /* item width plus 2 lots of padding */
margin: 0;
padding: 0;
justify-content: center;
display: flex;
flex-wrap: wrap;
}
#media (min-width: 312px) {
.container {
width: 312px;
}
}
#media (min-width: 416px) {
.container {
width: 416px;
}
}
#media (min-width: 728px) {
.container {
width: 728px;
}
}
.item {
r-sizing: border-box;
width: 100px;
background-color: cyan;
text-align: center;
flex: 0 0 100px; /* made 100px so easier to test on different widthe */
margin: 2px;
}
<div class="container">
<div class="item">
Item 1
</div>
<div class="item">
Item 2
</div>
<div class="item">
Item 3
</div>
<div class="item">
Item 4
</div>
<div class="item">
Item 5
</div>
<div class="item">
Item 6
</div>
<div class="item">
Item 7
</div>
</div>

Centering in CSS grid with a fixed width column

Im trying to make a simple CSS centered grid layout.
I know that when I use justify-items: center, the items inside a grid container are supposed to align horizontally, but when I specify a column width in pixels like this grid-template-columns: repeat(3, 100px) the whole grid return to normal. So is there any way to make the grid items centered but in same time specify the column width in pixels?
Here are my example:
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
.container {
background-color: #aa96da;
display: grid;
justify-items: center;
grid-gap: 20px;
grid-template-rows: repeat(3, 1fr);
/*Only if I change this 100px to '1fr' the justify-items will work */
grid-template-columns: repeat(3, 100px);
}
.item {
width: 100px;
height: 100px;
background-color: green;
}
Change the justify-items to justify-content and it should work.
.container {
background-color: #aa96da;
display: grid;
/* justify-items: center; */
justify-content: center;
grid-gap: 20px;
grid-template-rows: repeat(3, 1fr);
/*Only if I change this 100px to '1fr' the justify-items will work */
grid-template-columns: repeat(3, 100px);
}
.item {
width: 100px;
height: 100px;
background-color: green;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Short answer: You want justify-content not justify-items
.container {
background-color: #aa96da;
display: grid;
justify-content: center; /* -items to -content */
grid-gap: 20px;
grid-template-rows: repeat(3, 1fr);
/*Only if I change this 100px to '1fr' the justify-items will work */
grid-template-columns: repeat(3, 100px);
}
.item {
width: 100px;
height: 100px;
background-color: green;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Long answer:
There's a difference between the grid item and the space it lives in.
When you define a grid, you're only defining rows/columns of the grid called tracks, Not actually defining where each element goes etc.
The DOM elements only follow the flow of the grid and are placed accordingly, which we can alter using properties like grid-column grid-row
You can look at it like this:
As you can see there's The Grid container, The Grid, The Columns, The Rows and then The Grid items.
The Grid items lives in the intersection between the two called The Grid Area (this what makes css grid better than flexbox in some ways)
And justify-items aligns the grid items within that area.
So grid-template-columns: repeat(3, 1fr); This means 3 columns their width is the width of the grid split evenly between them.
Demo
Don't look at the code just the preview
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
[grid] {
height: 300px;
display: flex;
border: 2px solid;
padding: 10px;
flex-wrap: wrap;
}
[column] {
flex: 1 0 calc(100% / 3);
border: 2px solid;
display: flex;
flex-direction:column;
align-items:center;
}
[column]>div {
width: 100px;
flex:1;
background-color: green;
}
<div grid>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
</div>
As you can see the grid columns are wider than the grid items 100px which means there space to center stuff, So justify-items: center; will center them inside.
That's why it looks like the grid is centered, But it's actually not reasons why changing to grid-template-columns: repeat(3, 100px); breaks it.
In the case of grid-template-columns: repeat(3, 100px);
Demo
Don't look at the code just the preview
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
[ctr] {
border: 2px solid;
padding: 10px;
}
[grid] {
height: 300px;
width: 340px;
display: flex;
padding: 10px;
flex-wrap: wrap;
}
[column] {
flex: 0 0 100px;
border: 2px solid;
display: flex;
flex-direction: column;
align-items: center;
}
[column]>div {
width: 100px;
flex: 1;
background-color: green;
}
<div ctr>
<div grid>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
</div>
</div>
As you can see the columns width equal the grid item's so they all fit snugly within the columns and the grid is still empty.
You can try adding the flex property on top of those grid elements and then center it with justify-content:center;
index.html:
<div class="centering_items">
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
style.css
.centering_items {
display: flex;
justify-content: center;
}
.container {
background-color: #aa96da;
display: grid;
grid-gap: 20px;
grid-template-rows: repeat(3, 1fr);
/*Only if I change this 100px to '1fr' the justify-items will work */
grid-template-columns: repeat(3, 100px);
}
.item {
width: 100px;
height: 100px;
background-color: green;
}

margins and flex-wrap in a flexbox

I have a problem with flex-wrap property of a flexbox.
Here is my code:
.container {
display: flex;
flex-wrap: wrap;
}
.item {
width: 50%;
margin: 0 10px;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
</div>
What I want to do is to let some space margin between items but without wrapping them. I want them horizontally two by two and every item with width of 50% margin included to prevent flex-wrap.
.container {
display: flex;
flex-wrap: wrap;
}
.item {
flex: 1 0 34%; /* fg, fs, fb */
margin: 10px;
height: 50px;
background-color: gray;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
With flex-grow: 1 defined in the flex shorthand, there's no need for flex-basis (width) to be 50%, which results in one item per row due to the margins.
Since flex-grow will consume free space on the row, flex-basis only needs to be large enough to enforce a wrap.
In this case, with flex-basis: 34%, there's plenty of space for the margins, but not enough space for a third item on each line.
You can use calc for this, so for example you can set flex-basis: calc(50% - margin x 2).
.container {
display: flex;
flex-wrap: wrap;
}
.item {
flex-basis: calc(50% - 20px);
margin: 10px;
background: lightblue;
height: 50px;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
You may use calc to exclude margin from the width:
.container {
display: flex;
flex-wrap: wrap;
}
.item {
width: calc(50% - 20px);
margin: 5px 10px;
height:20px;
background:red;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>