With a flex container and flex-wrap: wrap set you can align overflowing items to the center using justify-content: center.
Is there a way to achieve the same behaviour for overflowing grid items using CSS grid?
I've created a pen showing the desired flex behavior
.container-flex {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.container-flex .item {
width: 33.33%;
background: green;
border: 1px solid;
}
.container-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.container-grid .item {
background: red;
border: 1px solid;
}
* {
box-sizing: border-box;
}
<h3>Flex</h3>
<div class="container-flex">
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
</div>
<h3>Grid</h3>
<div class="container-grid">
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
</div>
https://codepen.io/JoeHastings/pen/PeEjjR
Flex and Grid are different animals, so a behavior that's simple in flex may not translate well to grid.
A flex item can center across the container because flex layout works with flex lines. A flex line is a row or column.
When a flex item is asked to center in a row/column, it has access to the available space on the entire line, from beginning to end.
In grid layout, however, rows and columns have to contend with something that flex lines don't: track walls (a/k/a grid lines). For example, in your code there are three columns. These columns divide the track into three separate sections, and grid items are confined to a section.
Therefore, a grid item cannot automatically be centered on a row using keyword alignment properties (such as justify-content or justify-self) because the track walls restrict movement.
It is possible to make a grid area span the entire row/column, which then clears the way across the entire track, allowing a grid item to be centered horizontally (justify-content: center) or vertically (align-self: center), but this behavior must be explicitly defined.
For the grid item to be centered across the row in a dynamic layout the container would need to have only one column (i.e., no dividers), or the item would need to be explicitly moved to the center using something like line-based placement. Otherwise, use flexbox.
Not the way you want with flex. You have to be precise with CSS-Grid,
<h3>Grid</h3>
<div class="container-grid">
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item-mid">item</div>
</div>
.container-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.item {
background: red;
border: 1px solid;
}
.item-mid{
background:purple;
grid-column:2/1;
}
Also, look here,
Centering in CSS Grid
(this is not wrapping, however)
Late to this party. But at least in 3 grid row scenarios like this you can use a mixture of :nth-of-type and :last-of-type to target the trailing item and place it in the column. Kind of piggy backing off of the answer above you get:
.container-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.item {
background: red;
border: 1px solid;
}
/* target the last item, if its the only one in the row */
.item:last-of-type:nth-of-type(3n+1) {
background:purple;
grid-column:2;
}
This, unfortunately, doesn't scale out super well to any other row count due to the problems listed in the above answers, but maybe will help someone.
Related
How could i make sure my <p class="title"></p> and
<p class="subtitle"></p> are displayed underneath of eachother because right now they are being displayed next to eachother
You can make use of flexbox, it'll definitely solve your problem.
Example
If you want to arrange two items underlying with each other:
.container {
display: flex;
flex-direction: column;
}
<div class="container">
<p class="title">Hello</p>
<p class="subtitle">World</p>
</div>
If you want to arrange two items next to each other.
.container {
display: flex; /*by default it will align items in one row*/
}
<div class="container">
<p class="title">Hello</p>
<p class="subtitle">World</p>
</div>
I’d like to set up a page with multiple entries consisting of some description text and associated icons. The icons may vary in size and should be aligned. (I use letters “i” and “w” instead of icons for simplicity in my examples below.)
When the page is wide enough, I’d like them to be set up as a grid with a wide left column and the icons to the right, that should take as few horizontal space as possible. Here is an example with two “icons”.
.container {
display: grid;
grid-template-columns: 1fr repeat(2, max-content);
}
.content {
justify-self: center;
}
<div class="container">
<div class="header">Some text</div>
<div class="content">i</div>
<div class="content">i</div>
<div class="header">Some more text</div>
<div class="content">w</div>
<div class="content">w</div>
</div>
When the viewport is too small, so that the left column would be reduced, say, below 200 px, I’d like to switch responsively the layout and have it displayed as a stack, as in this example.
.container {
display: grid;
grid-template-columns: 1fr repeat(2, max-content) 1fr;
}
.container > div {
justify-self: center;
}
.header {
grid-column-start: 1;
grid-column-end: 5;
}
.content1 {
grid-column-start: 2;
}
.content2 {
grid-column-start: 3;
}
<div class="container">
<div class="header">Some text</div>
<div class="content1">i</div>
<div class="content2">i</div>
<div class="header">Some more text</div>
<div class="content1">w</div>
<div class="content2">w</div>
</div>
This approach works, but there are multiple aspects that I’d like to improve, if possible.
My web site uses bootstrap, so I could use their “row” and “col” functionalities (or other bootstrap concepts). Designing my own grid instead feels like not using the right tools for the job. But I could not find out how to design such a grid with bootstrap’s rows and columns. (This question raises a similar problem.)
My approach requires an explicit media query and uses two completely different designs depending on the available space. This feels more complex than necessary. Is it possible to make better use of the grid module responsiveness (or any other appropriate html or css trickery), so that the icons would automatically flow below the text when the viewport is too small? I thought about using auto-fill, but as my columns do not all have the same size, I ignore how to proceed.
My current design for the small viewport case uses classes content1, content2, and so on, and repetitive CSS instructions to place them in successive columns. This problem will be exacerbated if I want more icons. Can I avoid such repetition?
The display classes are responsive. Therefore you can use d-flex d-md-grid on the container. When it switches to display:flex the grid-template-columns will be ignored.
.container {
grid-template-columns: 1fr repeat(2, max-content);
}
.content {
justify-self: center;
}
<div class="container d-flex d-md-grid flex-wrap align-items-center justify-content-center text-md-start text-center">
<div class="header w-100">Some text</div>
<div class="content">i</div>
<div class="content">i</div>
<div class="header w-100">Some more text</div>
<div class="content">w</div>
<div class="content">w</div>
</div>
Demo on Codeply
Of course, you could use d-sm-grid, d-lg-grid or d-xl-grid instead of d-md-grid to set the breakpoint as desired.
Suppose we have a responsive grid container with indefinite number of child cells. Cells' widths and heights vary. Using only CSS (probably CSS Grid), how can we create such grid, that number of columns / rows and the width / height of each column / row is determined dynamically based on the container's size (without overflowing it) and cells' sizes in one of the following two ways:
Width / height for each column / row is determined based on the widest / tallest cell in that column / row,
Width / height for all the columns / rows is determined based on the widest / tallest cell in the grid?
When applied to column width, these two cases loosely correspond to, respectively, automatic and fixed layout algorithms for tables. Except we don't know the number of columns and rows; it needs to be somehow determined automatically.
The following examples demonstrate these two cases applied to column width. For each case there are two possible flow directions: row or column. Note that in the examples we had to set the number of columns and their sizes specifically. I would like those to be determined automatically.
Please try to replicate these examples in your answer without setting the exact number of columns, rows and any widths or heights.
* {
box-sizing: border-box;
}
.container {
display: grid;
flex-wrap: wrap;
grid-template-rows: repeat(3, auto);
justify-content: space-between;
border: 3px solid teal;
font-size: 20px;
}
.flex {
grid-template-columns: repeat(3, auto);
width: min-content;
}
.fixed {
grid-template-columns: repeat(3, 33.33%);
width: 28em;
}
.column {
grid-auto-flow: column;
}
.cell {
padding: 1em;
background: pink;
border: 1px dashed teal;
white-space: nowrap;
}
h3:not(:first-of-type) {
margin-top: 3em;
}
<h3>Flexible column width. Flow in rows</h3>
<div class="container flex row">
<div class="cell">One</div>
<div class="cell">Two</div>
<div class="cell">Buckle my shoe</div>
<div class="cell">Three</div>
<div class="cell">Four</div>
<div class="cell">Knock at the door</div>
<div class="cell">Five</div>
<div class="cell">Six</div>
</div>
<h3>Flexible column width. Flow in columns</h3>
<div class="container flex column">
<div class="cell">One</div>
<div class="cell">Two</div>
<div class="cell">Buckle my shoe</div>
<div class="cell">Three</div>
<div class="cell">Four</div>
<div class="cell">Knock at the door</div>
<div class="cell">Five</div>
<div class="cell">Six</div>
</div>
<h3>Fixed column width. Flow in rows</h3>
<div class="container fixed row">
<div class="cell">One</div>
<div class="cell">Two</div>
<div class="cell">Buckle my shoe</div>
<div class="cell">Three</div>
<div class="cell">Four</div>
<div class="cell">Knock at the door</div>
<div class="cell">Five</div>
<div class="cell">Six</div>
</div>
<h3>Fixed column width. Flow in columns</h3>
<div class="container fixed column">
<div class="cell">One</div>
<div class="cell">Two</div>
<div class="cell">Buckle my shoe</div>
<div class="cell">Three</div>
<div class="cell">Four</div>
<div class="cell">Knock at the door</div>
<div class="cell">Five</div>
<div class="cell">Six</div>
</div>
I had the same problem, using column, and this was fixed by adding grid-template-columns: repeat(auto-fit, minmax(baseValue,maxValue)); to the parent element
I have two nested grids - one for the layout and one for the part of my site (let's say it's a list of goods in the shop). My layout grid creates a container for the whole site, including navbar, sidebar, content, etc. And nested grid is responsible for the list of goods only. The problem is that auto-fit and minmax functions don't work in the nested grid. You can check this pen to see the case.
At first, try to change width of the content, you'll see that items are changing its position according to the auto-fit algorithm. But as soon as you uncomment display: grid; for the outer grid, it responsiveness gets broken. Could you please explain why this is happening and how I can fix it?
.outer-grid {
/* display: grid; */
grid-template-columns: 1fr 700px 1fr;
}
.inner-grid {
grid-column: 2;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}
.item {
background: red;
border: 1px solid black;
}
<div class="outer-grid">
<div class="inner-grid">
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
</div>
</div>
The problem is that auto-fit and minmax functions don't work in the nested grid.
I think they do work. The problem appears to be something else.
Your nested grid exists in a column with a fixed width (700px). The primary container sees no reason to shrink that column, which would trigger the auto-fit function in the nested grid.
Here's something you may want to consider:
revised codepen
.outer-grid {
display: grid;
grid-template-columns: 1fr repeat(1, minmax(100px, 700px)) 1fr;
}
.inner-grid {
grid-column: 2;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}
.item {
background: red;
border: 1px solid black;
}
<div class="outer-grid">
<div class="inner-grid">
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
</div>
</div>
Consider the following snippet:
#container{
border: solid 1px black;
display: inline-grid;
grid-template-columns: repeat(3, auto);
}
<div id="container">
<div class="row">
<div class="item">A1111</div>
<div class="item">B1</div>
<div class="item">C1</div>
</div>
<div class="row">
<div class="item">A2</div>
<div class="item">B2222</div>
<div class="item">C2</div>
</div>
<div class="row">
<div class="item">A3</div>
<div class="item">B3</div>
<div class="item">C3333</div>
</div>
</div>
The end result is a table-like display where each item of every row is the width of the widest item in that column.
A1111 A2 A3
B1 B2222 B3
C1 C2 C3333
Which is great - but I need the table laid out as rows...
A1111 B1 C1
A2 B2222 C2
A3 B3 C3333
display: table solves this - but table has some drawbacks around spacing, alignments and so-on. Therefore, grid and flex looks attractive.
Alas I cannot figure out how to get the information laid out as desired.
Adding display: grid to .row helps the order of information, but doesn't retain the equal column widths.
The item content will vary, and so cannot use fixed widths and it is not desired that the grid/flex spans the entire page/containing width.
You can define which column the grid item should be using grid-column. This means the row doesn't require a containing row div.
Working example...
#container{
border: solid 1px black;
display: inline-grid;
grid-auto-flow: row;
grid-gap: 10px;
padding: 10px;
}
.col1{
grid-column: 1;
}
.col2{
grid-column: 2;
}
.col3{
grid-column: 3;
}
<div id="container">
<div class="col1">A11111</div>
<div class="col2">B1</div>
<div class="col3">C1</div>
<div class="col1">A2</div>
<div class="col2">B2222222</div>
<div class="col3">C2</div>
<div class="col1">A3</div>
<div class="col2">B3</div>
<div class="col3">C33333333</div>
</div>
</div>
Your main problem is your markup is too deep. You have table-like markup, three levels deep: table, rows, and cells. For grid layout, you don’t need the “row” elements at all.
When you use display: grid or display: inline-grid on an element, it makes that element a grid container. Each of its child elements then become grid items. Grid items will be laid out in the grid defined by their container.
You also said you want columns of equal width. For this, you should use the fr unit rather than auto for your column sizes:
grid-template-columns: repeat(3, 1fr);
…this will make each column one “fraction” unit wide.
#container{
border: solid 1px black;
display: inline-grid;
grid-template-columns: repeat(3, 1fr);
}
<div id="container">
<div class="item">A1111</div>
<div class="item">B1</div>
<div class="item">C1</div>
<div class="item">A2</div>
<div class="item">B2222</div>
<div class="item">C2</div>
<div class="item">A3</div>
<div class="item">B3</div>
<div class="item">C3333</div>
</div>
There's way which I would make it.
Attached JSFiddle(click)
.row {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
}
.row > .item {
display:block;
flex: 1 1;
border: 1px solid #000;
}
There's such great guide about flex; Click here.