How to make last two flex element flow in reverse direction? - css

I've a dynamic list of elements generated by an external library which I do not have any control.
.item-wrapper {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
align-items: flex-start;
position: relative;
}
.item {
background-color: red;
}
.item:nth-last-child(2),
.item:last-child {
position: absolute;
right: 0;
}
.item:last-child {
top: 57px;
}
<div class="item-wrapper">
<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>
And I need to generate a layout where the last two elements always need to wrap and align to right side as below.
I tried using flexbox to achieve the desired layout and here's a bit of snippet I've written.
With the above css, the second last element of top row always overlaps to the last element of top row.
I've aware that whenever absolute positioning is used, it takes the element out of the flow and absolutely position them.
However, I do not have much knowledge on how to achieve the layout as given above.
I'm really flexible with other css approach if it's not possible with flexbox.

So, For your output what I did is I wrap all the items in flexbox layout.
Main logic for this layout is we need all row 3 child. and same space to last 2 child to align them at right.
To get that space I have added .item-wrapper with padding-right: calc(100%/4 - 20px);.
Now need each time last two elements to align right, so I just set .item-wrapper to position:relative and than set both last to child with position:asbolute and set second last to top:0 and last on to bottom:0.
to fulfil the desired width I just divided height for second last by 4 and removed that height from 100% for last child.
* {
box-sizing: border-box;
}
.item-wrapper {
display: flex;
flex-wrap: wrap;
gap: 5px;
padding-right: calc(100%/4 - 20px);
position: relative;
}
.item {
flex: 1 0 calc(100%/3 - 20px);
padding: 20px;
background-color: gray;
}
.item:nth-last-child(2),
.item:last-child {
position: absolute;
right: 0;
width: calc(100%/4 - 25px);
height: calc(50% - 2px);
}
.item:nth-last-child(2) {
top: 0;
height: calc(100%/4 - 5px);
}
.item:last-child {
bottom: 0;
right: 0;
height: calc(100% - 100%/4);
}
<div class="item-wrapper">
<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 class="item">7
</div>
<div class="item">8
</div>
<div class="item">9
</div>
<div class="item">10
</div>
<div class="item">11
</div>
<div class="item">12
</div>
</div>

This may look a bit simpler as a grid.
Each item is placed in its desired column, the last two being special and the grid flow set to dense so the second to last element can start back at the top.
.item-wrapper {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-flow: dense;
}
.item:nth-child(3n+1) {
grid-column: 1;
}
.item:nth-child(3n+2) {
grid-column: 2;
}
.item:nth-child(3n) {
grid-column: 3;
}
.item:nth-last-child(2),
.item:last-child {
grid-column: 4;
}
<div class="item-wrapper">
<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 class="item">7</div>
<div class="item">8</div>
</div>

Related

min-content with justify-self: right?

Is it possible with CSS3 grid to create such a layout?
All of the elements should be as wide as their content. And the last two elements should be right-aligned.
However, the way I've tried does not work. As soon as a column has min-content, the justify-self property doesn't do anything.
.grid {
display: grid;
grid-template-areas: "first second third";
grid-template-columns: min-content min-content min-content;
}
.first {
grid-area: first;
}
.second {
grid-area: second;
justify-self: right; /* doesn't work */
}
.third {
grid-area: third; /* doesn't work */
}
<div class="grid">
<div class="first">first</div>
<div class="second">second</div>
<div class="third">third</div>
</div>
This is only a downsized version of a much more complex layout, therefore:
I'm not looking for workarounds like creating wrappers
Stretching .first is not an option because there will be calculations on that element
The reason I chose grid over flex is because of the gaps
Using flexbox may be more appropriate? note the margin-right on the first element in container 1, and margin-left on the second element in container 2. auto margins are quite powerful in flex containers.
.container-1,
.container-2 {
display: flex;
background: lightgray;
}
.item {
width: max-content;
margin: 1em;
padding: 1em;
background: white;
}
.container-1 .item-1 {
margin-right: auto;
}
.container-2 .item-2 {
margin-left: auto;
}
<div class="container-1">
<div class="item item-1">
item 1
</div>
<div class="item item-2">
item 2
</div>
<div class="item item-3">
item 3
</div>
</div>
<div class="container-2">
<div class="item item-1">
item 1
</div>
<div class="item item-2">
item 2
</div>
<div class="item item-3">
item 3
</div>
</div>

How can I make a responsive css grid (display: grid) that has three equal boxes on the top row and then the rest of the rows are two equal size boxes?

I want to make a responsive css grid that looks like this:
box | box | box
b o x | b o x
b o x | b o x
and then when the screen size gets small enough, all of the columns collapse into a single column with each box on its own row.
Is this possible?
Edit:
For anyone who has this issue, changing the number of columns via media query from 6 to 1 was not working. However, I had the idea to make all of the items span 6 columns at the break point and that worked perfectly. This is an addition to the answer given by lawrence-witt and paulie-d.
By using a SIX column grid
.item {
height: 3em;
border: 2px solid green;
}
.container {
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-gap: 4px;
width: 90%;
margin: 1em auto;
}
.item:nth-child(1),
.item:nth-child(2),
.item:nth-child(3) {
grid-column: span 2
}
.item:nth-child(4),
.item:nth-child(5) {
grid-column: span 3;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
After that it's just a matter of adding a media query to collapse the grid to a single column at the appropriate breakpoint,
Here is one way to do it using the nth-child feature. To make the grid responsive you simply add a media query that changes the styling of cells and grid at a certain screen width.
.grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
}
.cell {
border: 1px solid black;
grid-column: span 3;
}
.cell:nth-child(1),
.cell:nth-child(2),
.cell:nth-child(3){
grid-column: span 2;
}
<div class="grid">
<div class="cell">One</div>
<div class="cell">Two</div>
<div class="cell">Three</div>
<div class="cell">Four</div>
<div class="cell">Five</div>
<div class="cell">Six</div>
<div class="cell">Seven</div>
</div>
By using CSS flex layout and CSS media query you can achieve your need. See the below code, if the screen size reduced to 600px then it will change to single column layout.
.container {
display: flex;
width: 100%;
justify-content: space-between;
flex-direction: row;
margin-bottom: 10px;
}
.three-box-row > div {
width: 33%;
height: 50px;
}
.two-box-row > div {
width: 49%;
height: 50px;
}
#media only screen and (max-width: 600px) {
.container {
flex-direction: column;
}
.container > div {
width: 100%;
}
}
<body>
<div class="three-box-row container">
<div style="background-color: red;">Box 1</div>
<div style="background-color: green;">Box 2</div>
<div style="background-color: blue;">Box 3</div>
</div>
<div class="two-box-row container">
<div style="background-color: red;">Box 1</div>
<div style="background-color: green;">Box 2</div>
</div>
<div class="two-box-row container">
<div style="background-color: green;">Box 1</div>
<div style="background-color: blue;">Box 2</div>
</div>
</body>

A grid layout with responsive squares

I am wanting to create a grid layout with responsive squares.
I feel like I should be able to do this with CSS Grid layout but having trouble setting the height of each square to be equal to the width.
Also having trouble setting a gutter between each square.
Would I be better off using flexbox?
Currently my HTML looks like this but will be dynamic so more squares may be added. And of course it needs to be responsive so will ideally use a media query to collapse it to one column.
<div class="square-container">
<div class="square">
<div class="content">
</div>
</div>
<div class="square">
<div class="content spread">
</div>
</div>
<div class="square">
<div class="content column">
</div>
</div>
</div>
Using css grid, this is as far as I got
.square-container{
display: grid;
grid-template-columns: 30% 30% 30%;
.square {
}
}
I was able to get a bit further with flexbox and able to use space-between to align squares with a nice gutter but was still struggling to get the height to match the width of each square.
I wasn't able to find any examples of this being done with either flexbox or grid but any examples would be appreciated as well.
Thanks
The padding-bottom trick is the most used to accomplish that.
You can combine it with both Flexbox and CSS Grid, and since using percent for margin/padding gives inconsistent result for flex/grid items (on older browser versions, see edit note below), one can add an extra wrapper, or like here, using a pseudo, so the element with percent is not the flex/grid item.
Edit: Note, there's an update made to the specs., that now should give consistent result when used on flex/grid items. Be aware though, the issue still occurs on older versions.
Note, if you will add content to the content element, it need to be position absolute to keep the square's aspect ratio.
Fiddle demo - Flexbox
Edit 2: In a comment I were asked how to have a centered text, so I added that in below snippet.
.square-container {
display: flex;
flex-wrap: wrap;
}
.square {
position: relative;
flex-basis: calc(33.333% - 10px);
margin: 5px;
border: 1px solid;
box-sizing: border-box;
}
.square::before {
content: '';
display: block;
padding-top: 100%;
}
.square .content {
position: absolute;
top: 0; left: 0;
height: 100%;
width: 100%;
display: flex; /* added for centered text */
justify-content: center; /* added for centered text */
align-items: center; /* added for centered text */
}
<div class="square-container">
<div class="square">
<div class="content">
<span>Some centered text</span>
</div>
</div>
<div class="square">
<div class="content spread">
</div>
</div>
<div class="square">
<div class="content column">
</div>
</div>
<div class="square">
<div class="content spread">
</div>
</div>
<div class="square">
<div class="content column">
</div>
</div>
</div>
CSS Grid version
.square-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(30%, 1fr));
grid-gap: 10px;
}
.square {
position: relative;
border: 1px solid;
box-sizing: border-box;
}
.square::before {
content: '';
display: block;
padding-top: 100%;
}
.square .content {
position: absolute;
top: 0; left: 0;
height: 100%;
width: 100%;
}
<div class="square-container">
<div class="square">
<div class="content">
</div>
</div>
<div class="square">
<div class="content spread">
</div>
</div>
<div class="square">
<div class="content column">
</div>
</div>
<div class="square">
<div class="content spread">
</div>
</div>
<div class="square">
<div class="content column">
</div>
</div>
</div>
Try using viewport percentage units.
jsFiddle
.square-container {
display: grid;
grid-template-columns: repeat(3, 30vw);
grid-template-rows: 30vw;
grid-gap: 2.5vw;
padding: 2.5vw;
background-color: gray;
}
.square {
background-color: lightgreen;
}
body {
margin: 0; /* remove default margins */
}
<div class="square-container">
<div class="square">
<div class="content"></div>
</div>
<div class="square">
<div class="content spread"></div>
</div>
<div class="square">
<div class="content column"></div>
</div>
</div>
From the spec:
5.1.2. Viewport-percentage lengths: the vw, vh, vmin, vmax units
The viewport-percentage lengths are relative to the size of the
initial containing block. When the height or width of the initial
containing block is changed, they are scaled accordingly.
vw unit - Equal to 1% of the width of the initial containing block.
vh unit - Equal to 1% of the height of the initial containing
block.
vmin unit - Equal to the smaller of vw or vh.
vmax unit - Equal to the larger of vw or vh.
You can use the fact that padding is calculated based on the width and set padding-top: 100% directly to the square grid items (the grid items would be square now).
2019 update
Note that for flex items as well as grid items earlier this doesn't used to work - see the post linked in the comments to this answer:
Why doesn't percentage padding / margin work on flex items in Firefox and Edge?
Now that there is a consensus between browsers (newer versions) to have the same behaviour for padding for flex items and grid items, you can use this solution.
See demo below:
.square-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(30%, 1fr));
grid-gap: 10px;
}
.square {
background: cadetblue;
padding-top: 100%; /* padding trick directly on the grid item */
box-sizing: border-box;
position: relative;
}
.square .content { /* absolutely positioned */
position: absolute;
top: 0;
right:0;
left: 0;
bottom: 0;
}
<div class="square-container">
<div class="square">
<div class="content"> some content here</div>
</div>
<div class="square">
<div class="content"> some content here</div>
</div>
<div class="square">
<div class="content"> some content here</div>
</div>
<div class="square">
<div class="content"> some content here</div>
</div>
<div class="square">
<div class="content column">some content here and there is a lot of text here</div>
</div>
<div class="square">
<div class="content spread">text</div>
</div>
<div class="square">
<div class="content column">some text here</div>
</div>
</div>
You can achieve this in all modern browsers using CSS aspect-ratio property.
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 5px;
}
.container div {
aspect-ratio: 1 / 1;
/* Styles below just for demo */
background-color: orange;
color: white;
font-family: Arial;
display: flex;
justify-content: center;
align-items: center;
}
<div class="container">
<div>A</div>
<div>B</div>
<div>C</div>
<div>D</div>
<div>E</div>
<div>F</div>
<div>G</div>
</div>
For days I was astonished that in 2020 there is no simple solution for this. I was convinced that with CSS grid this is gonna be a piece of cake... Flexbox solution provided by Ason is the only one that works across browsers. On Stack I found one more solution with CSS grid that uses padding-bottom: 100% but it doesn't work in Firefox (you get a lot of white space beneath the footer).
This is my take on the problem, I think it is the simplest solution of all that I have encountered these days.
CSS Grid solution on Codepen:
https://codepen.io/abudimir/pen/ExKqyGp
<div class="square-container">

Overlapping elements within a square grid

I’ve to implement a layout based on a square grid. As shown on the following image, some elements have to overlap responsive within this grid. (The squares are offset on the x-axis and overlap by one grid cell on the y-axis.)
http://i.stack.imgur.com/9bZ5G.jpg
Does anybody know how to achieve this effect? I'm using the framework Foundation 6. I’d prefer a solution without JavaScript. I can’t use the Foundation .#-push-# and .#pull-# classes because they would shift the elements inwards and the two squares have to be in separate rows.
I’ve set up a JSFiddle containing the two squares.
.square {
background: #f00;
position: relative;
}
.square:after {
content: "";
display: block;
padding-bottom: 100%;
}
.content {
position: absolute;
width: 100%;
height: 100%;
}
.dark {
background: #cbcbcb;
}
.light {
background: #dedede;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.2.0/foundation.css" rel="stylesheet"/>
<div class="row">
<div class="small-12 columns">
<div class="row">
<div class="small-8 columns end">
<div class="square dark">
<div class="content">test</div>
</div>
</div>
</div>
<div class="row">
<div class="small-6 small-offset-6 columns end">
<div class="square light">
<div class="content">test</div>
</div>
</div>
</div>
</div>
</div>
Many thanks in advance for your help.
I know this question is a little bit old, but for the benefit of all this is now very easily and cleanly possible with CSS Grid. Taking the image posted in the original question we define a container and two squares:
<div class="container">
<div class="content square1">Square 1</div>
<div class="content square2">Square 2</div>
</div>
Then in the CSS define the container as a CSS Grid with 6 columns and 6 rows. In the example below I have used the repeat() CSS Method to have the browser create 6 of the same sized columns and rows.
.container {
display: grid;
grid-column-template: repeat(6, 1fr);
grid-row-template: repeat(6, 30px);
width: 100%;
height: 600px;
}
Then for each item you set where the upper left hand corner will be located on that grid. You can use the long handed properties of grid-column-start, grid-column-end, grid-row-start, and grid-row-end, but I find it's easier to use the short hand properties as shown below:
.square1 {
grid-column: 1 / 5;
grid-row: 1 / 5;
background: #cbcbcb;
}
.square2 {
grid-column: 4 / 7;
grid-row: 4 / 7;
background: #dedede;
}
As far as the placement goes, you specify it based on the grid lines you're invisibly drawing in the container. Position 1 / 1 in this case is the upper left-most corner (or where 0,0 would be if you're talking about coordinates). CSS Grid is now widely supported and I believe there are some JS libraries out there that do create fall backs for this if you don't want to hard code your own with feature queries.
Here's the full block of code with the SO Code Snippet runner:
.container {
display: grid;
grid-column-template: repeat(6, 1fr);
grid-row-template: repeat(6, 30px);
width: 100%;
height: 600px;
}
.square1 {
grid-column: 1 / 5;
grid-row: 1 / 5;
background: #cbcbcb;
}
.square2 {
grid-column: 4 / 7;
grid-row: 4 / 7;
background: #dedede;
}
<div class="container">
<div class="content square1">Square 1</div>
<div class="content square2">Square 2</div>
</div>
It seems to work if you calculate the offset with percent and also mind the column spacing. I therefore adjustet the snippet and added another square with 4 colums:
.square {
background: #f00;
position: relative;
}
.square:after {
content: "";
display: block;
padding-bottom: 100%;
}
.content {
position: absolute;
width: 100%;
height: 100%;
}
.dark {
background: #cbcbcb;
}
.light {
background: #dedede;
}
/* NEW */
.small-6.columns.overlap-top > .square {
margin-top: calc(-33.3% + 1.33*0.625rem); // one third is 33.3% minus 1.33 times col spacing
}
.small-4.columns.overlap-top > .square {
margin-top: calc(-50% + 1*0.625rem); // one half is 50% minus 1 times col spacing
}
#media screen and (min-width: 40em) {
.small-6.columns.overlap-top > .square {
margin-top: calc(-33.3% + 1.33*0.9375rem);
}
.small-4.columns.overlap-top > .square {
margin-top: calc(-50% + 1*0.9375rem);
}
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.2.0/foundation.css" rel="stylesheet"/>
<div class="row">
<div class="small-12 columns">
<div class="row">
<div class="small-8 columns end">
<div class="square dark">
<div class="content">Square 1</div>
</div>
</div>
</div>
<div class="row">
<!-- New class overlap-top -->
<div class="small-6 small-offset-6 columns overlap-top end">
<div class="square light">
<div class="content">Square 2</div>
</div>
</div>
</div>
<!-- New square -->
<div class="row">
<div class="small-4 small-offset-4 columns overlap-top end">
<div class="square dark">
<div class="content">Square 3</div>
</div>
</div>
</div>
</div>
</div>
JSFiddle: https://jsfiddle.net/jwt0k1pw/1/
Hope this helps!

How to equalise sibling div heights?

<div class="wrapper">
<div class="sidebar-wrapper"></div>
<div class="content-wrapper"></div>
</div>
The height of content-wrapper is dynamic (auto). Is there any way to get the height of it and use it for the sidebar-wrapper so that it looks nice?
Displaying them like table cells would do it. Table cells can adjust their height automatically to the content, and all cells on the same row get the same height. If you give the side bar a fixed width (which is likely), you can easily get the content wrapper to fill the remaining space.
Whichever has the longest content will determine the height.
.wrapper {
width: 100%;
display: table;
}
.sidebar-wrapper,
.content-wrapper {
display: table-cell
}
.sidebar-wrapper {
width: 200px;
background-color: silver;
}
.content-wrapper {
background-color: yellow;
}
<div class="wrapper">
<div class="sidebar-wrapper">Here is <br>content<br>that is .....<br><br><br><br><br><br>Quite long</div>
<div class="content-wrapper">Smaller content</div>
</div>
Flexbox is an alternative to #GolezTrol's CSS tables.
.wrapper {
display: flex;
}
.sidebar-wrapper {
width: 200px;
background-color: silver;
}
.content-wrapper {
background-color: yellow;
flex: 1;
}
<div class="wrapper">
<div class="sidebar-wrapper">Here is
<br>content
<br>that is .....
<br>
<br>
<br>
<br>
<br>
<br>Quite long</div>
<div class="content-wrapper">Smaller content</div>
</div>

Resources