I'm trying to make flex aligned items share all space, after the last item. The last (red) is a div with buttons and fixed size. Other items (blue) are selects and need to share the space left, considering the other rows. Other way to understand this, would be considering that the blue items need to grow after the red item, with the same width, preferably occupying all space left, but the red item needs to be always in the end of last row.
On this example I'm using flex, but I could use grid or other thing either.
Example:
.container{
display: inline-flex;
flex-wrap: wrap;
}
.child{
flex: 1 1 auto;
max-width: 25%;
}
With this code you could do it in one line... but I know there was a possibility to automatically create a second line, if the div get too tiny. I will update this snippet in a few minutes.
.container{
display: grid;
grid-auto-flow: column dense;
grid-template-rows: 1fr;
background: blue;
}
.container div {
border: 1px solid black;
}
.container div.red {
width: 310px;
background: red;
}
<html>
<body>
<div class="container">
<div>MENU RANDOM</div>
<div>MENU CONTENT</div>
<div>MENU DIVS</div>
<div>MENU IN</div>
<div>MENU THIS</div>
<div>MENU LAYOUT</div>
<div>MENU AND</div>
<div class="red">EXACT 210px</div>
</div>
</body>
</html>
Related
I have a grid that's two columns side by side. However, there's an odd number of elements, so I would like to offset the right column so it's centered vertically against the left column.
What would be the best way to do that using grid?
Here's an example how i want the layout to look:
Here's an example: https://codepen.io/patricktm/pen/JjMzQWj
body {
max-width: 1000px;
margin: auto;
}
.grid-item {
background-color: #ccc;
border: 1px solid;
height: 200px;
}
.grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1em;
}
<body>
<div class='grid'>
<div class='grid-item'>1</div>
<div class='grid-item'>2</div>
<div class='grid-item'>3</div>
<div class='grid-item'>4</div>
<div class='grid-item'>5</div>
<div class='grid-item'>6</div>
<div class='grid-item'>7</div>
</div>
</body>
This layout isn't really feasible with Grid because there are fix row tracks that prevent the free flow of items across the column.
You're basically asking the top item in the second column to somehow space itself down in the first row track and cross into the second track, pushing down the other items along the way.
Grid doesn't work this way. The matter is discussed in detail in this post:
Aligning grid items across the entire row/column (like flex items can)
One simple way to make this layout work uses flexbox, which has no column or row tracks crossing through the flex lines. (You'll have to tweak it though, as my simple example will only work on taller screens. On shorter screens additional columns will be generated.)
.grid {
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: center; /* key */
height: 100vh;
gap: 1em;
}
.grid-item {
background-color: #ccc;
border: 1px solid;
height: 21%; /* prevents a 5th item in the column */
}
body {
max-width: 1000px;
margin: auto;
}
<div class='grid'>
<div class='grid-item'>1</div>
<div class='grid-item'>2</div>
<div class='grid-item'>3</div>
<div class='grid-item'>4</div>
<div class='grid-item'>5</div>
<div class='grid-item'>6</div>
<div class='grid-item'>7</div>
</div>
I have a grid that varies in width and number of results.
Each cell in the grid is 200x200 px.
As the grid expands, I want the column width to remain fixed and for new columns to be added in. You could imagine the grid initially having 3 columns, and when the user expands the window, a fourth column is added in to use the new whitespace.
This grid is rendering a set of search results.
So I need to be able to vary the number of rows depending on number of results.
I need to be able to have the columns fill up the horizontal space dynamically.
I need results to first fill up each row before moving to the next row.
Here is what I've been trying, but it is not currently working as it only renders a single column (CSS in JS, but it's just CSS):
ResultsGrid: {
display: grid,
gridAutoRows: 280px,
gridAutoColumns: 280px,
gap: 20px,
gridAutoFlow: row-dense,
}
Result: {
border: 1px solid #EAEAEA,
}
Desired Result
Here's my implementation:
The auto-fit argument with repeat CSS function
.grid-item {
border: 2px solid red;
background: orange;
color: red;
padding: 10px;
border-radius: 8px;
}
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, 200px);
grid-auto-rows: 200px;
gap: 6px;
}
<div class="wrapper">
<div class="grid-item">html</div>
<div class="grid-item">html</div>
<div class="grid-item">html</div>
<div class="grid-item">html</div>
<div class="grid-item">html</div>
<div class="grid-item">html</div>
</div>
I faced the same problem before, here is what you need:
ResultsGrid {
display: grid;
gridTemplateColumns: repeat(auto-fill, 200px);
gridAutoRows: 10rem;
gap: 20px;
}
I basically have the question as this one, except that every answer seems to think the OP wants the container .row element to grow to effectively have width: 100% (which they never state that they want, but nor have they corrected the assumption of any of the answers). This question also seems to be similar, if not the same, as mine, but has no accepted answer and the upvoted answer didn't work for me.
I'm trying to achieve sibling elements in a row where each sibling's width is the width of the widest sibling (auto-fit to its contents), but crucially where the parent row element itself does not grow to 100% of its own parent but rather grows only to the total combined width of its children.
I've tried dozens of suggestions without any success. Here's what I consider the closest I've managed:
.full-width-banner {
width: 100%;
background-color: #aaa;
padding: 5px;
margin-bottom: 5px;
}
.days-of-week {
display: grid;
grid-auto-columns: max-content;
}
.item {
padding: 2px;
border: 1px solid #ccc;
}
<div class="container">
<div class="full-width-banner">Hi there!</div>
<div class="days-of-week">
<div class="item">Monday</div>
<div class="item">Tuesday</div>
<div class="item">Wednesday</div>
<div class="item">Thurdsday</div>
<div class="item">Friday</div>
<div class="item">Saturday</div>
<div class="item">Sunday</div>
</div>
</div>
This does set all of the siblings - the days of the week - to have equal widths as required, but it stacks them rather than showing them inline. I thought adding grid-auto-flow: column; to the .days-of-week element might fix it, but whilst that does cause the days to be displayed inline, their widths revert to match their respective contents.
So, using CSS grid, how can I get the days of the week elements to all have equal widths no greater than the natural width (as prescribed by its content) of the widest element?
You need to do like below:
.full-width-banner {
background-color: #aaa;
padding: 5px;
margin-bottom: 5px;
}
.days-of-week {
display: inline-grid; /* inline grid */
grid-auto-columns: 1fr; /* all of them the same size */
grid-auto-flow:column; /* a column flow */
}
.item {
padding: 2px;
border: 1px solid #ccc;
}
<div class="container">
<div class="full-width-banner">Hi there!</div>
<div class="days-of-week">
<div class="item">Monday</div>
<div class="item">Tuesday</div>
<div class="item">Wednesday</div>
<div class="item">Thurdsday</div>
<div class="item">Friday</div>
<div class="item">Saturday</div>
<div class="item">Sunday</div>
</div>
I'm working for a client that had the super good idea to integrate a horizontal scroll effect into his one pager flow layout. That means that the user keeps scrolling down, but at some point the page starts moving from right to left instead of bottom to top. I implemented that via ScrollMagic.
So the problem starts when it gets responsive. When I start scrolling horizontally, the screen is now fixed to the device height and I need to extend my page content to the right when it flows out, instead of the normal "my content just flows out of the bottom, which I can follow by vertically scrolling".
My first idea was to kind of manually solve the problem when managing the content. I.E. giving different versions of content for mobile and desktop content. But it seems devices are just too different and I need a CSS solution.
My Question is: Do you have any idea of how to make content grow horizontally? Like height auto, but width "auto" (which doesn't work bc it's not the same)? Or like display: inline-block in the following example, but the outer wrapper (yellow border) wrapping all sub-boxes, not just the first column.
#wrapper {
display: inline-block;
border: 2px solid #ffff00;
}
#main {
width: 100%;
height: 200px;
border: 1px solid #0000ff;
display: flex;
flex-flow: column wrap;
}
#main div {
width: 100%;
height: 50px;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="wrapper">
<div id="main">
<div style="background-color:coral;">A</div>
<div style="background-color:lightblue;">B</div>
<div style="background-color:khaki;">C</div>
<div style="background-color:pink;">D</div>
<div style="background-color:lightgrey;">E</div>
<div style="background-color:lightgreen;">F</div>
</div>
</div>
</body>
</html>
EDIT:
After reading Temani Afifs Answer I found an additional specification of my problem: I need it to work with "column-width", so that I am able to write text which automatically expands to a second column when using up all vertical space. Pretty much just like here. The only reason the linked example is not perfect for me is that the wrapping container div does not expand and a scrollbar appears. I want to be able to add another .container-div to the right.
Maybe using CSS grid:
#wrapper {
display: inline-block;
background:yellow;
}
#main {
max-height: 100vh; /* don't take more than the screen height */
border: 1px solid #0000ff;
box-sizing:border-box;
display: grid;
grid-auto-flow: column; /* column flow */
/* fill all the column and wrap to the next one if no more space */
grid-template-rows: repeat(auto-fill, minmax(50px, 1fr));
}
#main div {
padding:20px;
}
body {
margin: 0;
}
<div id="wrapper">
<div id="main">
<div style="background-color:coral;">A</div>
<div style="background-color:lightblue;">B</div>
<div style="background-color:khaki;">C</div>
<div style="background-color:pink;">D</div>
<div style="background-color:lightgrey;">E</div>
<div style="background-color:lightgreen;">F</div>
</div>
</div>
My problem is that I want the flexbox with variable range width, and all works well, but not on the last row. I want the same dimension for all children even where the row is not full of children (the last row).
#products-list {
position:relative;
display: flex;
flex-flow: row wrap;
width:100%;
}
#products-list .product {
min-width:150px;
max-width:250px;
margin:10px 10px 20px 10px;
flex:1;
}
I created a dynamic situation in jsFiddle
My flex divs can shrink until 150px and grow up to 250px, but all must be with the same size (and obviously I want a CSS solution, with JS I know the way).
Unfortunately, in the current iteration of flexbox (Level 1), there is no clean way to solve the last-row alignment problem. It's a common problem.
It would be useful to have a flex property along the lines of:
last-row
last-column
only-child-in-a-row
alone-in-a-column
This problem does appear to be a high priority for Flexbox Level 2:
CSS Working Group Wiki - Specification Issues and Planning
https://lists.w3.org/Archives/Public/www-style/2015Jan/0150.html
Although this behavior is difficult to achieve in flexbox, it's simple and easy in CSS Grid Layout:
Equal width flex items even after they wrap
In case Grid is not an option, here's a list of similar questions containing various flexbox hacks:
Properly sizing and aligning the flex item(s) on the last row
Flex-box: Align last row to grid
Flexbox wrap - different alignment for last row
How can a flex item keep the same dimensions when it is forced to a new row?
Selector for an element alone in a row?
Aligning elements in last flexbox row
How can I allow flex-items to grow while keeping the same size?
Left-align last row of flexbox using space-between and margins
Inconsistent margin between flex items on last row
How to keep wrapped flex-items the same width as the elements on the previous row?
How to align left last row/line in multiple line flexbox
Last children of grid get giant gutter cause of flexbox space-between
Managing justify-content: space-between on last row
Flexbox space between behavior combined with wrap
Possible to use CSS Flexbox to stretch elements on every row while maintaining consistent widths?
As a quick and dirty solution one can use:
.my-flex-child:last-child/*.product:last-child*/ {
flex-grow: 100;/*Or any number big enough*/
}
You could try using grid instead of flexbox here:
#products-list {
display: grid;
grid-gap: 5px;
grid-template-columns: repeat(auto-fit, minmax(100px, 250px)); //grid automagic
justify-content: start; //start left
}
Fiddle link
There is a great solution that works always.
add a div with class product (The same class for other items that are under flex) and add a style for this div:height:0px;
you need to add as many dives that are possible to be in one row.
<div class="product" style="height:0px">
as many that can be in one row.
That's all. Works always.
If all your rows have the same number of items, you can use :nth-last-child. For example, if all the rows have 3 items, you can do something like this to remove the margin of the last 3 items:
.container{
display: flex;
flex-wrap: wrap;
background: yellow;
}
.item{
width: calc((100% - 2*10px)/3);
height: 50px;
background: blue;
color: white;
margin-right: 10px;
margin-bottom: 10px;
padding: 5px;
box-sizing: border-box;
}
/* last item of each row */
.item:nth-child(3n){
margin-right: 0;
font-size: 150%;
}
/* last 3 items */
.item:nth-last-child(-n+3){
margin-bottom: 0;
background: green;
}
<div class="container">
<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>
A simple trick adds a flexible space to fill the rest of the last row:
#products-list{
display:flex;
flex-flow: row wrap;
justify-content:space-between;
}
#products-list::after {
content: "";
flex: auto;
flex-basis: 200px;/*your item width*/
flex-grow: 0;
}
But you shouldn't use margins on items then. Rather wrap them into containers with padding.
I used this workaround, even if it's not very elegant and it doesn't use the power of Flexbox.
It can be carried out on the following conditions:
All the items have the same width
The items have a fixed width
You use SCSS/SASS (can be avoided though)
If this is the case, you can use the following snippet:
$itemWidth: 400px;
$itemMargin: 10px;
html, body {
margin: 0;
padding: 0;
}
.flex-container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 0 auto;
border: solid 1px blue;
}
#for $i from 1 through 10 {
#media only screen and (min-width: $i * $itemWidth + 2 * $i * $itemMargin) {
.flex-container {
width: $i * $itemWidth + 2 * $i * $itemMargin;
}
}
}
.item {
flex: 0 0 $itemWidth;
height: 100px;
margin: $itemMargin;
background: red;
}
<div class="flex-container">
<div class="item"></div>
<div class="item" style="flex: 500 0 200px"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Here I have created an example on codepen which also implements margin.
The second and the third conditions can be avoided respectively using css variables (if you decided to provide support for it) and compiling the above scss snippet.
Well, it's true, we could do it also before flexbox, but display: flex can be still essential for a responsive design.
I was facing this same issue where I wanted to have a variable number of items in a resizable container.
I wanted to use all of the horizontal space, but have all of the flex items at the same size.
I ultimately came up with a javascript approach that dynamically added padding spacers as the container was resized.
function padLastFormRow() {
let topList = [];
let nSpacersToAdd = 0;
$('#flexContainer').find('.formSpacer').remove();
$('#flexContainer').find('.formItem').each(function(i, formItem) {
topList.push($(formItem).position().top);
});
let allRowLengths = getFlexLineLengths(topList);
let firstRowLength = allRowLengths[0];
let lastRowLength = allRowLengths[((allRowLengths.length) - 1)];
if (lastRowLength < firstRowLength) {
nSpacersToAdd = firstRowLength - lastRowLength ;
}
for (var i = 1; i <= nSpacersToAdd; i ++) {
$('#flexContainer').append(formSpacerItem);
}
}
Please see my Fiddle:
http://jsfiddle.net/Harold_Buchman/z5r3ogye/11/
I was having a similar challenge with menu rows. I wanted more spacing on the top of the second row of menu items.
The use of flex-box's row-gap worked well.
https://developer.mozilla.org/en-US/docs/Web/CSS/row-gap
.menu {
display: flex;
flex-wrap: wrap;
row-gap: 10px;
}
This added a margin-top type effect to menu items were wrapped to the second line.
If all your rows have the same number of items, you can use :nth-last-child. For example, if all the rows have 3 items, you can do something like this:
.container{
display: flex;
flex-wrap: wrap;
background: yellow;
}
.item{
width: calc((100% - 2*10px)/3);
height: 50px;
background: blue;
color: white;
margin-right: 10px;
margin-bottom: 10px;
padding: 5px;
box-sizing: border-box;
}
// last item of each row
.item:nth-child(3n){
margin-right: 0;
background: green;
}
// last 3 items
.item:nth-last-child(-n+3){
margin-bottom: 0;
font-size: 150%;
}
<div class="container">
<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>