I have a CSS Grid with two areas (left & right). I want to put multiple spans inside these areas, but when I do the following, the items appear on top of each other, as if they were taken out of document flow.
How do I put them back into document flow, so they appear next to each other?
div {
display: grid;
grid-template: 1fr 1fr / 1fr;
grid-template-areas: "left right"
}
div .left {
grid-area: left;
}
div .right {
grid-area: right;
}
<div>
<span class="left">First</span>
<span class="left">Second</span>
<span class="left">Third</span>
<span class="right">Fourth</span>
<span class="right">Fifth</span>
</div>
Codepen
Full On Grid
Grids are all about columns and rows, so the version without area names (which are only an alias for a location) is:
div {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 50px 50px 50px;
}
div .left {
grid-column: 1/1;
}
.la {
grid-row: 1/1;
}
.lb {
grid-row: 2/2;
}
.lc {
grid-row: 3/3;
}
div .right {
grid-column: 2/2;
}
<div>
<span class="left la">First</span>
<span class="left lb">Second</span>
<span class="left lc">Third</span>
<span class="right la">Fourth</span>
<span class="right lb">Fifth</span>
</div>
Two Columns, Spans Wherever!
If you just want "two columns" and don't care about positioning the span elements, this might be better for you.
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto;
}
.left {
grid-column: 1/1;
grid-row: 1/1;
}
.right {
grid-column: 2/2;
grid-row: 1/1;
}
span {
display: block;
}
<div class="grid">
<div class="left">
<span>First</span>
<span>Second</span>
<span>Third</span>
</div>
<div class="right">
<span>Fourth</span>
<span>Fifth</span>
</div>
</div>
Each grid item must get a unique grid-area name.
If you apply the same name to multiple elements then, per the cascade, the last item will be displayed, overlaying the others with the same name.
Here's an example of a proper set-up just for illustration purposes:
div {
display: grid;
grid-template-areas: "left1 right1"
"left2 right2"
"left3 right3"
"left4 right4"
"left5 right5";
}
span:nth-child(1) { grid-area: left1; }
span:nth-child(2) { grid-area: left2; }
span:nth-child(3) { grid-area: left3; }
span:nth-child(4) { grid-area: right1; }
span:nth-child(5) { grid-area: right2; }
<div>
<span>First</span>
<span>Second</span>
<span>Third</span>
<span>Fourth</span>
<span>Fifth</span>
</div>
It appears that you're looking for a vertically flowing grid that wraps after the third row. In that case, here's all you need:
div {
display: grid;
grid-template: repeat(3, auto) / 1fr 1fr;
grid-auto-flow: column;
}
<div>
<span>First</span>
<span>Second</span>
<span>Third</span>
<span>Fourth</span>
<span>Fifth</span>
</div>
Learn more about grid-auto-flow: column here: Make grid container fill columns not rows
Related
I'm trying to achieve the following layout:
As you can see, the cards in the middle column occupy multiple grids, in order to give it that effect.
What I have:
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
gap: 0px 0px;
grid-template-areas:
". . ."
". . ."
". . .";
}
.grid-item {
border: 1px solid black;
}
.grid-item:nth-child(3) {
grid-column: 2;
grid-row: 2;
}
.grid-item:nth-child(4) {
grid-column: 2;
grid-row: 3;
}
.grid-item:nth-child(5) {
grid-column: 2;
grid-row: 4;
}
.grid-item:nth-child(6) {
grid-column: 3;
grid-row: 1;
}
<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>
However, my approach definitely isn't the most sustainable, nor are my cards rendering in the correct order (cards go from 1, 7, 2, 3 etc ..).
I haven't seen an approach where using CSS grid, a layout like the image has been achieved, so wondering if CSS grid is the best solution here?
To achieve this you mostly have to change the behavior of your grid container.
Adding grid-auto-flow: column; fixes the issue of the elements moving in rows.
Doubling the number of rows means that you can work "by halves" when positioning our elements.
On the grid elements, adding grid-row: span 2 sets them to occupy a whole area in your design
Then all you have to do is tell the first one and second to last one to start on the second row.
If you were going to iterate this over more than 3 columns, it would by every 7th element minus the first one ( .grid-item:nth-child(7n-1)) instead of nth-to-last. In that case, you'd also have to define your grid differently, similar to below.
grid-template-rows: repeat( 6, auto );
grid-auto-columns: 1fr;
You can also remove the grid-area definition.
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: repeat(6, auto);
grid-auto-flow: column;
gap: 0px 0px;
}
.grid-item {
border: 1px solid black;
grid-row: span 2;
}
.grid-item:nth-child(1), .grid-item:nth-last-child(2) {
grid-row: 2 / span 2;
}
<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>
Is it possible in CSS Grid Layout to modify the template for say a specific row or column without having to rewrite the grid? Something like this:
.grid {
display: grid;
grid-template:
"a a"
"b b";
}
.grid .grid.row-2 {
grid-template-row-2: "b a";
}
You can approximate this using CSS variables:
.grid {
display: grid;
grid-template-areas:
var(--row1,"a a")
var(--row2,"b b");
grid-auto-columns:40px;
grid-auto-rows:40px;
margin:10px;
}
.grid.row-2 {
--row2:"b c";
}
.a {
grid-area:a;
background:red;
}
.b {
grid-area:b;
background:blue;
}
<div class="grid">
<div class="a"></div>
<div class="b"></div>
</div>
<div class="grid row-2">
<div class="a"></div>
<div class="b"></div>
</div>
Absolutely - you can use grid-row-start and grid-row-end:
https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row-start
Or even grid-row: 1 / span 2;:
https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row
So you'd do something like this:
.grid > div {
border: 1px solid red;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
.grid .row-2 {
grid-row: 1 / span 2;
}
<div class="grid">
<div class="row-2">Hello</div>
<div>Hello</div>
<div>Hello</div>
</div>
Why does this:
div {
width: 200px;
display: grid;
grid: "first second" / 1fr 1fr;
background-color: #ccc;
padding: 8px;
}
#first {
grid-area: first;
}
#second {
grid-area: second;
}
<div>
<input id="first" />
<input id="second" />
</div>
Behave differently from this:
div {
width: 200px;
display: grid;
grid: "first first second second" / 1fr 1fr 1fr 1fr;
background-color: #ccc;
padding: 8px;
}
#first {
grid-area: first;
}
#second {
grid-area: second;
}
<div>
<input id="first" />
<input id="second" />
</div>
Note that the only thing I changed was the number of columns and the area each input occupies.
This is an issue with the spec and how 1fr is intepreted.
From a W3C bug/issue report
The "problem" is that 1fr resolves to minmax(auto, 1fr) and this means that we need to know the size of (the parent) before resolving the size of the 1fr track (because the min track sizing function is content sized, it's auto).
There is a quick solution to this issue from the author POV, just replacing 1fr by minmax(0px, 1fr) for example.
..or in this case just setting min-width:0 to the child elements.
I think its a rendering issue casued by the default width set by the browser for the inputs. Its fixed by adding 100% width for the inputs and setting up the border-box box model.
div {
width: 200px;
display: grid;
grid: "first second" / 1fr 1fr;
background-color: #ccc;
padding: 8px;
}
#first {
grid-area: first;
}
#second {
grid-area: second;
}
input {
width: 100%;
}
* {
box-sizing: border-box;
}
<div>
<input id="first" />
<input id="second" />
</div>
Note that this problem is not really a CSS Grid issue. It's more a matter related to input elements.
Here's your code, using input elements:
div {
display: grid;
width: 200px;
background-color: #ccc;
padding: 8px;
}
div[one] {
grid: "first second" / 1fr 1fr;
}
div[two] {
grid: "first first second second" / 1fr 1fr 1fr 1fr;
}
#first {
grid-area: first;
}
#second {
grid-area: second;
}
<div one>
<input id="first" />
<input id="second" />
</div>
<hr>
<div two>
<input id="first" />
<input id="second" />
</div>
There's a difference in the two layouts.
Now here's your code using section elements instead of inputs:
article {
display: grid;
width: 200px;
background-color: #ccc;
}
article[one] {
grid: "first second" / 1fr 1fr;
}
article[two] {
grid: "first first second second" / 1fr 1fr 1fr 1fr;
}
#first {
grid-area: first;
height: 25px;
background-color: green;
}
#second {
grid-area: second;
height: 25px;
background-color: red;
}
<article one>
<section id="first"></section>
<section id="second"></section>
</article>
<hr>
<article two>
<section id="first"></section>
<section id="second"></section>
</article>
There's no difference.
This essentially boils down to the intrinsic width of input elements, which is a standard feature in most browsers. The issue is discussed in more detail here:
input / button elements not shrinking in a flex container
The simple way to disable this feature is by:
overriding the default min-width: auto on grid items by adding min-width: 0 (explanation) or,
by switching from 1fr (which represents minmax(auto, 1fr)) to minmax(0px, 1fr).
I have an article and an aside (sidebar) element - easy, except the title and sub-heading of the article need to span the entire row. If I take the title/sub-heading out of the article, the article element is no longer semantically complete.
Is there a way, using CSS Grid, to have the format below, where Title, Sub and Content are all a part of an "Article" element, and "Aside" is the second in a 2 column grid?
From my research so far, it seems this is not possible.
You can hack your way through using nested CSS grid if you know:
The width of the aside section
The height of the title and sub heading sections
(in many layouts, these dimensions are fixed)
You can use a pseudo element that create a space for the aside element and then sneak it inside the outer grid container - check out the demo below:
body {
margin: 0;
}
* {
box-sizing: border-box;
}
article,
aside {
border: 1px solid;
display: flex;
align-items: center;
justify-content: center;
}
div {
display: grid;
grid-template-areas: "section aside";
}
section {
grid-area: section;
display: grid;
grid-template-areas: "header header" "subhead subhead" "content empty";
grid-template-rows: 50px 50px auto;
grid-template-columns: 80vw auto;
height: 100vh;
width: 100vw;
}
section article:first-child {
grid-area: header;
}
section article:nth-child(2) {
grid-area: subhead;
}
section article:last-child {
grid-area: content;
}
section:after {
content: '';
display: block;
grid-area: empty;
}
aside {
grid-area: aside;
height: calc(100vh - 100px);
width: 20vw;
align-self: flex-end;
position:relative;
transform: translateX(-100%);
}
<div>
<section>
<article>Article title</article>
<article>Article sub-heading</article>
<article>Article content</article>
</section>
<aside>Aside</aside>
</div>
You can use something like this.
* {box-sizing: border-box;}
.wrapper {
max-width: 940px;
margin: 0 auto;
}
.wrapper > div {
border: 2px solid rgb(233,171,88);
border-radius: 5px;
background-color: rgba(233,171,88,.5);
padding: 10px;
color: #d9480f;
}.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 10px;
grid-auto-rows: minmax(100px, auto);
}
.one {
grid-column: 1 / 4;
grid-row: 1;
}
.two {
grid-column: 1 / 4;
grid-row: 2;
}
.three {
grid-column: 1 / 3;
grid-row: 3;
min-height:200px;
}
.four {
grid-column: 3;
grid-row: 3;
min-height:200px;
}
<div class="wrapper">
<div class="one">One</div>
<div class="two">Two</div>
<div class="three">Three</div>
<div class="four">Four</div>
</div>
Also check Fiddle.
And for more details please visit https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout
You can achieve that by simply floating all the cells, as long as the article doesn't float - https://jsfiddle.net/yxbckzcq/1/
<div class="wrapper">
<article>
<div style="float:left;width:100%" class="one">One</div>
<div style="float:left;width:100%" class="two">Two</div>
<div style="float:left;width:70%" class="three">Three</div>
</article>
<div style="float:left;width:30%" class="four">Four</div>
</div>
I'm currently working on some layout and I have an issue with image width exceeding the container width when applying CSS grid rules.
Please, take a look at the code below.
img {
max-width: 100%;
height: auto;
display: block;
}
.page {
display: grid;
grid-template-columns: auto minmax(300px, 400px);
grid-column-gap: 1rem;
height: 100vh;
}
.content {
grid-column: 1 / 2;
background: red;
width: 100%;
}
.sidebar {
grid-column: 3;
background: lime;
}
<div class="page">
<div class="content">
<img src="http://via.placeholder.com/900x400" alt="" width="900" height="400">
<p>content</p>
</div>
<div class="sidebar">
<p>sidebar</p>
</div>
</div>
I'm wondering what might cause that issue. The sidebar has to be between 300px and 400px. The content container should take the rest.
For some reason, the image is breaking this layout setup.
https://codepen.io/sunpietro/pen/ZyNgqe
Fixed grid-template-columns. It should be grid-template-columns: auto 1fr minmax(300px, 400px). auto for image, 1fr for content, and minmax(300px, 400px) forsidebar` (it resides in 3rd column). Demo:
img {
max-width: 100%;
height: auto;
display: block;
}
.page {
display: grid;
grid-template-columns: auto 1fr minmax(300px, 400px);
grid-column-gap: 1rem;
height: 100vh;
}
.content {
grid-column: 1 / 2;
background: red;
width: 100%;
}
.sidebar {
grid-column: 3;
background: lime;
}
<div class="page">
<div class="content">
<img src="http://via.placeholder.com/900x400" alt="" width="900" height="400">
<p>content</p>
</div>
<div class="sidebar">
<p>sidebar</p>
</div>
</div>
You have a two-column grid.
grid-template-columns: auto minmax(300px, 400px);
This means there are three grid column lines: 1, 2 and 3.
The image is nested in a grid item which occupies the first column:
.content {
grid-column: 1 / 2;
}
But you have the sidebar skipping the second column and starting at grid column line 3 (the end of the explicit grid):
.sidebar {
grid-column: 3;
}
This breaks down to:
grid-column-start: 3;
grid-column-end: auto;
So there's nothing in the second column.
Try this instead:
.sidebar {
grid-column: 2 / 3;
}
revised codepen