I want to achieve the following layout in CSS Grid.
Notice how row "C" has a blue background that is full width but the content inside it is wrapped, and not full width. But I don't know what's the most optimal way of achieving this?
So here's my code:
container {
display: grid;
grid-template-columns: 0.5fr 1fr 1fr 0.5fr;
grid-template-areas:
"A A A A"
". B B ."
"C C C C"
". D D .";
}
What I've tried:
I've tried 16.66% padding to both sides for row "C".
I've tried making the row C be a Grid itself. Inside it, I'd have columns 0.5fr, 1fr, 1fr, 0.5fr. But this is lot of repeated code, and is lot of work for a simple thing.
What is the most CSS Grid way of approaching this? All the tutorials I've seen, doesn't seem to cover this special case.
One option is to make C span the two columns in the center which seems in line with your layout and use a pseudo element that takes care of the background
add grid-row: 3 and grid-column: 1 / -1 to the pseudo element to place it in the same position as C but spanning the whole width
push it to the back using z-index: -1 and position: relative
See demo below:
body {
margin: 0;
}
* {
box-sizing: border-box;
}
.wrapper{
display: grid;
grid-template-columns: 0.5fr 1fr 1fr 0.5fr;
grid-template-areas:
"A A A A"
". B B ."
". C C ."
". D D .";
height: 100vh;
}
.wrapper:after {
content: '';
display: block;
grid-column: 1 / -1;
grid-row: 3;
background: cadetblue;
position: relative;
z-index: -1;
}
.A {
grid-area: A;
background: pink;
}
.B {
grid-area: B;
background: orange;
}
.C {
grid-area: C;
background: lightgreen;
}
.D {
grid-area: D;
background: orange;
}
<div class="wrapper">
<div class="A">A</div>
<div class="B">B</div>
<div class="C">C</div>
<div class="D">D</div>
</div>
Related
I have a CSS grid with several columns and many rows (I'm building a timetable view). The rows and columns are defined on the grid element itself, and then on the elements within the grid I set their column (always only one column) and their rows (might be more than one row).
An example is as follows:
.grid {
display: grid;
grid-template-rows: [row-a] 1fr [row-b] 1fr [row-c] 1fr [row-d] 1fr;
grid-template-columns: [col] 1fr;
flex-grow: 1;
}
.entry-one {
grid-column: col;
grid-row: row-a/row-d;
background-color: red;
}
.entry-two {
grid-column: col;
grid-row: row-b;
background-color: green;
}
<div class='grid'>
<div class='entry-one'>
Foobar
</div>
<div class='entry-two'>
Barfoo
</div>
</div>
Now, what I would like to have is that the elements resize themselves and flow nicely, such that they fit next to each other. I can mock this using width and margin on the elements:
.grid {
display: grid;
grid-template-rows: [row-a] 1fr [row-b] 1fr [row-c] 1fr [row-d] 1fr;
grid-template-columns: [col] 1fr;
flex-grow: 1;
}
.entry-one {
grid-column: col;
grid-row: row-a/row-d;
background-color: red;
width: 50%; /* ADDED */
}
.entry-two {
grid-column: col;
grid-row: row-b;
background-color: green;
width: 50%; /* ADDED */
margin-left: 50%; /* ADDED */
}
<div class='grid'>
<div class='entry-one'>
Foobar
</div>
<div class='entry-two'>
Barfoo
</div>
</div>
However this is not optimal, especially as the elements are inserted dynamically. Is there a way to have the elements size & align themselves automatically using CSS? I've tried to use display: flex on the entries, but that did not result in what I want (or maybe I forgot to add another rule).
Thank you for any ideas, and have a nice day!
I made this to see if that is what you are looking for
.grid{
display: flex;
grid-template-rows: [row-a] 1fr [row-b] 1fr [row-c] 1fr [row-d] 1fr;
grid-template-columns: [col] 1fr;
flex-grow: 1;
}
I just changed your display to flex and delete your margin-left: 50%; on the entry two, hope it is what you are looking for
I am trying out some very basic grids using display: grid. I have a simple grid with one row, divided into 6 columns. In the HTML I have a div containing the grid, then 6 nested divs containing the 6 items, which should display along one row in 6 columns.
However, instead, they stack on top of each other - why?
This is what it looks like when run:
.gridnav {
display: grid;
/*Gap between columns cells*/
grid-column-gap: 15px;
grid-row-gap: 2px;
/*Padding on left and right edges*/
padding: 0px 10px 0px;
/*Centres items vertically and horizontally*/
align-items: center;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
grid-template-areas: '1 2 3 4 5 6';
}
.navitem1 { grid-area: 1; }
.navitem2 { grid-area: 2; }
.navitem3 { grid-area: 3; }
.navitem4 { grid-area: 4; }
.navitem5 { grid-area: 5; }
.navitem6 { grid-area: 6; }
<div class="gridnav">
<div class="navitem1">1</div>
<div class="navitem2">2</div>
<div class="navitem3">3</div>
<div class="navitem4">4</div>
<div class="navitem5">5</div>
<div class="navitem6">6</div>
</div>
Any ideas most welcome, thanks
I have a simple grid with one row, divided into 6 columns.
Actually, you have the reverse. You have a grid with one column, divided into 6 rows.
The grid-area property is a shorthand property. It breaks down like this:
grid-row-start
grid-column-start
grid-row-end
grid-column-end
Therefore, your code:
.navitem1 { grid-area: 1; }
.navitem2 { grid-area: 2; }
.navitem3 { grid-area: 3; }
.navitem4 { grid-area: 4; }
.navitem5 { grid-area: 5; }
.navitem6 { grid-area: 6; }
Is equivalent to this:
.navitem1 {
grid-row-start: 1;
grid-column-start: auto;
grid-row-end: auto;
grid-column-end: auto;
}
.navitem2 {
grid-row-start: 2;
grid-column-start: auto;
grid-row-end: auto;
grid-column-end: auto;
}
...
So here's what's really happening:
This rule in the container is doing exactly what you expect.
grid-template-areas: '1 2 3 4 5 6'
But then the grid-area rules are overriding grid-template-areas. Above is what it looks like in Chrome dev tools.
As you can see, the items are originally lined up in one row and six columns (as you expect). But in the end, all items line up on six rows in a one column (because of the grid-area overrides).
However, if you use a non-integer value, like this:
.navitem1 { grid-area: a; }
It would translate to this:
.navitem1 {
grid-row-start: a;
grid-column-start: a;
grid-row-end: a;
grid-column-end: a;
}
... which would work for your purposes, as the values of grid-template-areas and grid-area are fully aligned.
Spec reference for the grid-area property.
It seems that grid template areas can't be named integers. Changing them to a, b, c, etc. makes it work.
.gridnav {
display: grid;
/*Gap between columns cells*/
grid-column-gap: 15px;
grid-row-gap: 2px;
/*Padding on left and right edges*/
padding: 0px 10px 0px;
/*Centres items vertically and horizontally*/
align-items: center;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
grid-template-areas: 'a b c d e f';
}
.navitem1 { grid-area: a; }
.navitem2 { grid-area: b; }
.navitem3 { grid-area: c; }
.navitem4 { grid-area: d; }
.navitem5 { grid-area: e; }
.navitem6 { grid-area: f; }
<div class="gridnav">
<div class="navitem1">1</div>
<div class="navitem2">2</div>
<div class="navitem3">3</div>
<div class="navitem4">4</div>
<div class="navitem5">5</div>
<div class="navitem6">6</div>
</div>
The solution can be achieved without writing these many lines of code. You don't need to use grid-template-area until and unless you want to switch the div positions. Let me take you to the solution real quick.
.gridnav {
width: 90%;
margin: 0 auto;
display: grid;
grid-template-rows: 1fr; /* Optional */
grid-template-columns: repeat(6,1fr);
grid-column-gap: 15px;
grid-row-gap: 2px;
align-items: center;
}
.gridnav div {
border: 2px solid red;
text-align: center;
}
First thing, define some width to the parent container. In your case it is div with class .gridnav. Since you already defined this section as a grid, I would define the rows and columns first. Since you don't need many rows but just one, it is okay not to define row.
For columns, you can have 1fr 1fr 1fr 1fr 1fr 1fr; but I would reduce code to grid-template-columns: repeat(6,1fr);
Further styling you can have as you want. Let me know if you have any further questions regarding this.
For more details you can always visit these two links:
https://mozilladevelopers.github.io/playground/css-grid/02-first-grid/
https://css-tricks.com/snippets/css/complete-guide-grid/
Hope you will find your answer in this. You can see code working here : Hit that Run Code Snippet button
.gridnav {
width: 90%;
margin: 0 auto;
display: grid;
grid-template-rows: 1fr; /* Optional */
grid-template-columns: repeat(6,1fr);
grid-column-gap: 15px;
grid-row-gap: 2px;
align-items: center;
}
.gridnav div {
border: 2px solid red;
text-align: center;
}
<div class="gridnav">
<div class="navitem1">1</div>
<div class="navitem2">2</div>
<div class="navitem3">3</div>
<div class="navitem4">4</div>
<div class="navitem5">5</div>
<div class="navitem6">6</div>
</div>
So yesterday I started learning grids in css. I thought that mimicking the main windows 8 metro panel would be great exercise (my reference photo:
https://prnt.sc/orgusg). I defined all of the panels, got them properly arranged. Here's some reference code showing what I've tried for template columns.
.boxes{
margin: 50px 150px;
display: grid;
/* grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
grid-template-columns: 2fr 2fr 2fr 2fr;
grid-template-columns: 1fr 1fr 1fr 1fr; This is what I've tried here*/
grid-auto-rows: 50%;
grid-gap: 10px;
}
For the first command of "grid-template-columns" I tried making all of the boxes that look wide span from their initial position (e.g 1) to the position where they should look wide (e.g 2).
.mail{
grid-column: 1/2;
}
For the second command of "grid-template-columns" I tried splitting the boxes.
.ie{
grid-column: 3/4;
}
But it gave me weird bugs.
My problem: I can't get the boxes to look different sizes, I would appreciate if you could help me, thanks!
One option is to use grid-template-area as suggested in Kareem's answer.
However, in this case I don't think it's a good solution, because it requires you to specify where every app goes in your grid. I don't actually think you want that. You want to be able to say "this box should take up N rows and N columns" and let the browser do that for you. This is actually easy to do.
If you have a grid element that should span two columns, you can do grid-column: span 2, or grid-row: span 2 for rows. Or, of course, both, or a higher number.
By default, the browser will only put the elements in order. If a grid element won't fit in the next space, it will move to a new row and everything afterwards will be on that row. In this case, I don't think you want that, so you can do grid-auto-flow: dense, which will always put the content in the first available box, no matter what order they end up in. For example, here:
.boxes {
margin: 50px;
height: max-content;
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
grid-auto-rows: 100px;
grid-gap: 10px;
grid-auto-flow: dense;
}
.boxes>div {
background: darkblue;
color: white;
font-weight: bold;
padding: 5px;
}
.mail {
grid-column: span 2;
}
.edge {
grid-row: span 2;
}
<div class=boxes>
<div>Word</div>
<div class=mail>Mail</div>
<div class=edge>Edge</div>
<div>Excel</div>
<div>cmd</div>
<div class=mail>Mail</div>
<div>Solitaire</div>
</div>
Incidentally, the problem you were having in the first place is a fairly simple one. Your code says:
.mail{
grid-column: 1/2;
}
The reason this comes up with a box that only uses one column is... because that's what grid-column: 1/2 means! The numbers don't refer to the columns in the page, but to the lines that separate them. For example, look at this diagram:
1 2 3 4
| | | |
| | | |
| | | |
| | | |
| | | |
You might think that 1/2 refers to filling up the first two columns: it doesn't. It refers to the first two lines: i.e. the first "column". Is this confusing? Perhaps. Now you know, it won't be!
Finally, I've also changed your grid-template-columns to repeat(auto-fill, 100px). You don't know how wide the screen is, so why would you specifically want four columns? This code says "as many 100px columns as you can fit in the space provided".
You can use grid-template-area property, This will make it much more easier for you:
Here is Full Description About CSS Grid
First: define your areas in grid container, something like:
.grid {
display: grid;
grid-template-areas:
"mail mail calender calender"
"ie chrome message message"
"store store store camera";
}
Each "" contain one row. For the first row we have 4 columns:
Mail: took 2 from 4 columns
Calender: took 2 from 4 columns
Now to make each div take it's actual position:
1- add the div in HTML
<div class="mail"></div>
2- For the CSS:
.mail{
grid-area: mail;
}
And So on,
Working Demo:
body {
display: flex;
}
.grid {
display: grid;
width: 700px;
height: 525px;
margin: auto;
grid-template-areas: "mail mail calender calender" "ie chrome message message" "store store store camera";
grid-gap: 10px;
}
.mail {
grid-area: mail;
background-color: #0399AA;
}
.calender {
grid-area: calender;
background-color: #5B479C;
}
.ie {
grid-area: ie;
background-color: #4473B9;
}
.chrome {
grid-area: chrome;
background-color: #FFCD42
}
.message {
grid-area: message;
background-color: #963294
}
.store {
grid-area: store;
background-color: #099648
}
.camera {
grid-area: camera;
background-color: #B01D3A
}
<div class="grid">
<div class="mail"></div>
<div class="calender"></div>
<div class="ie"></div>
<div class="chrome"></div>
<div class="message"></div>
<div class="store"></div>
<div class="camera"></div>
</div>
I am trying to create a layout with 5 columns using css grid. The first and the last columns should have white space.
I try to create it but somehow it turns out to be three rows instead of columns.
.grid_container{
grid-template-columns: 1fr 2fr 4fr 2fr 1fr;
grid-template-areas: ". A B C ."
}
#column1 {
grid-area: A;
background:red;
padding: 100px;
}
#column2 {
grid-area: B;
background:blue;
}
#column3{
grid-area: C;
background: orange;
}
I have the 5 columns but the first and the fifth columns should have whitespace.
You're missing the most important property display: grid. The example in CodePen Grid columns. Cheers, sigfried.
I was hoping to use CSS Grid to reverse the apparent order of two side-by-side divs, where one of the divs grows arbitrarily (I don't want to use floats).
I've created a plunkr here: http://plnkr.co/edit/6WZBnHbwhD7Sjx2ovCO7?p=preview
#container {
grid-template-columns: 240px 1fr;
display: grid;
}
.a {
background: yellow;
}
.b {
background: blue;
color: white;
}
#container>.a {
grid-column: 1;
}
#container>.b {
grid-column: 2;
}
#container.reverse>.a {
grid-column: 2;
}
#container.reverse>.b {
grid-column: 1;
}
<div id="container" class="reverse" style="width: 800px;">
<div class="a">A</div>
<div class="b">B</div>
</div>
The crux of it is that when I have the .reverse class applied (so that you should see B | A), B is offset to a new line so it looks more like:
| A
B
If I invert the document ordering of .a with .b, this goes back to normal (but of course, if I drop the .reverse class, I get the same problem).
Why is this, and how can I address?
As the Grid auto-placement algorithm lays out items in the container, it uses next available empty cells (source).
In your source code the A element comes before the B element:
<div id="container" class="reverse" style="width: 800px;">
<div class="a">A</div>
<div class="b">B</div>
</div>
Therefore, the grid container first places A, then uses the next available space to place B.
By default, the auto-placement algorithm looks linearly through the grid without backtracking; if it has to skip some empty spaces to place a larger item, it will not return to fill those spaces. To change this behavior, specify the dense keyword in grid-auto-flow.
http://www.w3.org/TR/css3-grid-layout/#common-uses-auto-placement
grid-auto-flow: dense
One solution to this problem (as you have noted) is to override the default grid-auto-flow: row with grid-auto-flow: dense.
With grid-auto-flow: dense, the Grid auto-placement algorithm will look to back-fill unoccupied cells with items that fit.
#container {
display: grid;
grid-template-columns: 240px 1fr;
grid-auto-flow: dense; /* NEW */
}
7.7. Automatic Placement: the grid-auto-flow
property
Grid items that aren’t explicitly placed are automatically placed into
an unoccupied space in the grid container by the auto-placement
algorithm.
grid-auto-flow controls how the auto-placement algorithm works,
specifying exactly how auto-placed items get flowed into the grid.
dense
If specified, the auto-placement algorithm uses a “dense” packing
algorithm, which attempts to fill in holes earlier in the grid if
smaller items come up later. This may cause items to appear
out-of-order, when doing so would fill in holes left by larger items.
#container {
display: grid;
grid-template-columns: 240px 1fr;
grid-auto-flow: dense; /* NEW */
}
.a {
background: yellow;
}
.b {
background: blue;
color: white;
}
#container>.a {
grid-column: 1;
}
#container>.b {
grid-column: 2;
}
#container.reverse>.a {
grid-column: 2;
}
#container.reverse>.b {
grid-row: 1;
grid-column: 1;
}
<div id="container" class="reverse" style="width: 800px;">
<div class="a">A</div>
<div class="b">B</div>
</div>
grid-row: 1
Another solution would be to simply define the row for the second item.
#container>.b {
grid-column: 2;
grid-row: 1; /* NEW */
}
#container {
display: grid;
grid-template-columns: 240px 1fr;
}
.a {
background: yellow;
}
.b {
background: blue;
color: white;
}
#container>.a {
grid-column: 1;
}
#container>.b {
grid-column: 2;
grid-row: 1; /* NEW */
}
#container.reverse>.a {
grid-column: 2;
}
#container.reverse>.b {
grid-row: 1;
grid-column: 1;
}
<div id="container" class="reverse" style="width: 800px;">
<div class="a">A</div>
<div class="b">B</div>
</div>
The simplest way is to add order: 1 to element B or order: -1 to element A in .reverse
It's also correct CSS rather than hack-y
I'm not sure how to reverse more grid items. But if you have 2 grid items in your grid, you can simply position 2nd grid item using below code.
#container > .b {
grid-column-start: 1;
grid-row-start: 1;
}
I had this same issue just now. I tried auto-row-dense and then set the direction of the container parent to rtl. It worked.
Just this, on the plunker link, seemed to do the trick.
.reverse{
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-auto-flow: dense;
direction: rtl;
}
You can use direction property to reverse a grid x-axis order.
Nested elements will be reversed too so you have to make sure to add additional styles to fix this behavior.
<div class="grid">
<div class="grid-item"><div>
</div>
<style>
.grid { direction : rtl; }
.grid-item { direction : ltr; }
</style>
Edit: this may work but could cause accessibilty issues.
Round peg in square hole
Remember even if you're using fancy 'new' grid features the older flex layout will still work. You can combine them, nest them and sometime you have to admit that certain problems like this may just be better solved with good old
flex-direction: row-reverse
But I know some people will want to downvote me for that so here's another way with grid.
Use named template regions
You can use named template regions and reverse them in the definition.
#container
{
grid-template-areas: a b;
grid-template-rows: 240px 1fr;
display: grid;
}
#container.reverse
{
// note the order is flipped for both these properties
grid-template-areas: b a;
grid-template-rows: 1fr 240px;
}
.a {
grid-area: a;
background: yellow;
}
.b {
grid-area: b;
background: blue;
color: white;
}
Here's an more complex example that uses that technique with media queries
I found out: I need to apply grid-auto-flow: dense; on the container:
#container {
grid-template-columns: 240px 1fr;
display: grid;
grid-auto-flow: dense;
}
According to MDN, this algorithm attempts to fill in holes earlier in the grid.
I want to mention a solution which is also relevant to this question in some cases. When having a multi-row layout, and you want a reversed look of how you grid fills up.
You can play with grid-start combined with some :nth-child & :last-child selectors to achieve a reverse auto flow.
Reversed grid-auto-flow: column
.container{
display: grid;
width: 10rem;
gap: 0.5rem;
grid-template-rows: repeat(2, 1fr);
grid-auto-flow: column; /* => vertical grid*/
}
/* REMOVE THIS TO SEE THE DIFFERENCE */
.pixel:nth-child(odd):last-child { /* reversed auto-flow: column */
grid-row-start: 2;
}
.pixel{
width: 2rem;
height: 2rem;
background: red;
border: 1px solid black
}
<div class="container">
<!-- ADD/REMOVE SOME PIXELS to see the result -->
<div class="pixel"></div>
<div class="pixel"></div>
<div class="pixel"></div>
<div class="pixel"></div>
<div class="pixel"></div>
<div class="pixel"></div>
<div class="pixel"></div>
</div>
Reversed: horizontal & vertical
.container{
display: grid;
width: 10rem;
gap: 0.5rem;
grid-template-rows: repeat(2, 1fr);
grid-auto-flow: column;
direction: rtl; /* reversed horizontal */
}
/* REMOVE THIS TO SEE THE DIFFERENCE */
.pixel:nth-child(odd):last-child { /* reversed vertical */
grid-row-start: 2;
}
.pixel{
width: 2rem;
height: 2rem;
background: red;
border: 1px solid black
}
<div class="container">
<!-- ADD/REMOVE SOME PIXELS to see the result -->
<div class="pixel">1</div>
<div class="pixel">2</div>
<div class="pixel">3</div>
<div class="pixel">4</div>
<div class="pixel">5</div>
<div class="pixel">6</div>
<div class="pixel">7</div>
</div>
I found out: I need to apply grid-auto-flow: dense; on the container: