Imagine we have 2 CSS Grid containers with dynamic columns count based on width.
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
The grid works perfectly, but what if we need to have another grid to have the 1st column to be same as in another grid with the code shown above, but it's another column to span through more cells - depending on how many cells are in the current row.
To better understand issue, there are images:
On more narrow wrapper:
We would need to apply something like grid-column: span ALL (if something like that exists), with meaning that ALL = till the end of current row.
What is really important is that "First" column should always align with "1" column.
Code to run example is here:
.grid div {
/* Not important fancy styles */
height: 40px;
text-align: center;
padding-top: 20px;
}
.grid {
width: 350px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
background-color: silver;
}
.grid-second {
background-color: red;
}
.grid-another {
background-color: purple;
border: 1px solid gray;
}
<div class="grid">
<div class="grid-first">
First
</div>
<div class="grid-second">
Second (Want till end)
</div>
</div>
<!-- Another same grid -->
<div class="grid">
<div class="grid-another">
1
</div>
<div class="grid-another">
2
</div>
<div class="grid-another">
3
</div>
<div class="grid-another">
4
</div>
</div>
PS. please do not post solutions using media query. I am interested in any (even little hacky solution), which will work without usage of media queries.
Here are two interesting sections in the CSS Grid specification:
7.1. The Explicit Grid
Numeric indexes in the grid-placement properties count from the edges
of the explicit grid. Positive indexes count from the start side,
while negative indexes count from the end side.
also here...
8.3. Line-based Placement: the grid-row-start, grid-column-start, grid-row-end, and grid-column-end properties
If a negative integer is given, it instead counts in reverse, starting
from the end edge of the explicit grid.
In other words, when dealing with an explicit grid, which means a grid defined by these properties:
grid-template-rows
grid-template-columns
grid-template-areas
grid (which is the shorthand for the three properties above, among others)
... you can make a grid area span all columns by setting this rule:
grid-column: 1 / -1;
That tells the grid area to span from the first column line to the last column line, which I believe meets your stated objective:
"We would need to apply something like grid-column: span ALL (if something like that exists), with meaning that ALL = till the end of current row."
jsFiddle demo
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
background-color: silver;
}
.grid-second {
grid-column: 2 / -1;
background-color: red;
}
/* Not important fancy styles */
.grid div {
height: 40px;
text-align: center;
padding-top: 20px;
}
.grid-another {
background-color: purple;
border: 1px solid gray;
}
<div class="grid">
<div class="grid-first">First</div>
<div class="grid-second">Second (Want till end)</div>
</div>
<!-- Another same grid -->
<div class="grid">
<div class="grid-another">1</div>
<div class="grid-another">2</div>
<div class="grid-another">3</div>
<div class="grid-another">4</div>
<div class="grid-another">1</div>
<div class="grid-another">2</div>
<div class="grid-another">3</div>
<div class="grid-another">4</div>
<div class="grid-another">1</div>
<div class="grid-another">2</div>
<div class="grid-another">3</div>
<div class="grid-another">4</div>
</div>
Related
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 :
.container {
display:grid;
grid-template-columns: 200px 200px;
grid-template-rows: 100px 100px;
grid-auto-flow: row;
grid-gap: 5px 5px;
height:500px;
width:50%;
border: 1px solid;
}
.grid-box {
background-color: skyblue;
padding: 10px 5px;
}
.four {
grid-column: span 2/3;
grid-row: 2;
}
<div class="container">
<div class="grid-box one">First</div>
<div class="grid-box two">two</div>
<div class="grid-box three">three</div>
<div class="grid-box four">Four</div>
<div class="grid-box five">Five</div>
<div class="grid-box six">Six</div>
</div>
From what I read, span 2/3 should be invalid, and not work, and indeed, it doesn't seem to work properly, as the item does not start from the 2nd column, however, it does end at the 3rd.
However, using span 2/4, produces the following outcome:
.container {
display:grid;
grid-template-columns: 200px 200px;
grid-template-rows: 100px 100px;
grid-auto-flow: row;
grid-gap: 5px 5px;
height:500px;
width:50%;
border: 1px solid;
}
.grid-box {
background-color: skyblue;
padding: 10px 5px;
}
.four {
grid-column: span 2/4;
grid-row: 2;
}
<div class="container">
<div class="grid-box one">First</div>
<div class="grid-box two">two</div>
<div class="grid-box three">three</div>
<div class="grid-box four">Four</div>
<div class="grid-box five">Five</div>
<div class="grid-box six">Six</div>
</div>
Seemingly it works exactly as expected. The item starts from the 2nd column and ends the 4rth.
So, does it actually work? Why does it work now, but it doesn't work if the item ends at the 3rd column?
From what I read, span 2/3 should be invalid, and not work
No it's valid and it's working fine.
span 2/3 means end at grid line 3 (and not column 3) and span 2 columns back. Same logic for span 2/4. It's the shorthand of:
grid-column-start: span 2;
grid-column-end: 3;
So in both cases your element will take exactly 2 columns and only the ending line with be different.
Worth to note that in your case you defined a 2 columns layout so you have 3 lines (from 1 to 3). The span 2/4 will force the creation of an extra implicit column to have a total of 3 columns and 4 lines. A third column having an auto width like you can notice.
Without the keyword span it would be a different story and still you cannot consider columns
2/4 means start at line 2 and end at line 4 (covering column 2 and column 3)
2/3 means start at line 2 and end at line 3 (covering only column 2)
Related questions if your are missing the concept of lines:
CSS Grids: Relation between grid gaps(gutters) and grid lines
Understanding grid negative values
I'm trying to align a logo and navigation bar in one row across the top of a website using CSS grid.
I've written out the code but can't work out what I'm doing wrong as to why it's not working: https://codepen.io/chloewb/pen/wRRewQ
.logo{
grid-area: logo;
background:white;}
.navi{
grid-area: navi;
background:Yellow;}
.section1{
grid-area: features;
background:LightSalmon;}
.section2{
grid-area: technology;
background:PaleTurquoise;}
.section3{
grid-area: pricing;
background:LightPink;}
.section4{
grid-area: email;
background:PaleGreen;}
.container {
display: grid;
grid-template-rows: repeat (5, auto);
grid-template-columns: 1fr 1fr 1fr;
font-size: 40px;
width: 100%;
background: grey;
grid-template-areas:
"logo navi navi"
"features features features"
"technology technology technology"
"pricing pricing pricing"
"email email email";}
The first thing to notice is that, when you use display: grid on a container element, its direct children will become grid-items, and to these items is that the grid layout you build will apply.
So let's say we have the following:
<div class="container">
<div class="child-1">
<div class="child-2"></div>
<div class="child-2"></div>
</div>
<div class="child-1"></div>
<div class="child-1"></div>
<div class="child-1"></div>
</div>
And this CSS:
.container{
display: grid;
}
Then only the child-1 will become grid items and be able to get properties like grid-area applied to them; everything else inside .child-1, like .child-2 will behave normally, as if there's no Grid. Unless you also specify the .child-1 element to be a grid with display: grid.
In your case, you header element is a direct child of the .container element, so it is a grid item and can be positioned on any place on the grid, but the logo and navi elements are children of header, so the grid layout does not apply to them. You would either have to take them out of the header so the rules you wrote take effect, or create another grid in the header and let it use the full first row. See this example and notice how the nesting of the elements affect them.
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: minmax(50px, auto);
grid-template-areas: "logo navi navi";
margin-bottom: 20px;
border: 1px solid black;
}
.logo {
border: 1px solid red;
grid-area: logo;
}
.navi {
border: 1px solid blue;
grid-area: navi;
}
<div class="container">
<div class="logo">Logo</div>
<div class="navi">Nav</div>
</div>
<div class="container">
<header>
<div class="logo">Logo</div>
<div class="navi">Nav</div>
</header>
</div>
I'm trying create template for rows in my grid block:
grid-template-rows: repeat(3, 150px);
I know, this template should be work for first 3 rows.
However, from 4 row this template is not work.
Can i make template for all rows?
P.S.
This template work only for 1st row.
grid-template-rows: 150px;
Use grid-auto-rows (automatically generated rows) instead of grid-template-rows (manually generated rows). In current case grid-auto-rows: 150px will do the trick. Demo:
.grid {
display: grid;
grid-auto-rows: 150px;
/* space between columns for demo */
grid-gap: 10px;
}
/* just styles for demo */
.grid__item {
background-color: tomato;
color: white;
}
<div class="grid">
<div class="grid__item">One</div>
<div class="grid__item">Two</div>
<div class="grid__item">Three</div>
<div class="grid__item">Four</div>
<div class="grid__item">Five</div>
<div class="grid__item">Six</div>
<div class="grid__item">Seven</div>
<div class="grid__item">Eight</div>
<div class="grid__item">Nine</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.