How to prevent grid-row span from changing column placement? - html

I have a 3 X 3 CSS Grid.
I have a row in which I have three items A, B & C.
I want item C to have a rowspan of 2.
To do so, I am using grid-row: 1 / span 2;. It is taking two rows, but it's being placed in the first column instead of simply lying in the 3rd column. I don't know why this is happening.
I want item C to stay at the place where it is in the HTML.
One work around to this problem is to explicitly setting grid-column: 3 / span 1 which I don't want to do. I want items to be placed the way they are in HTML.
Is there any way to suppress this behavior?
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
}
h1 {
border: 2px solid;
padding: 0;
margin: 0;
font-size: 20px;
}
.a {
grid-row: 1 / span 2;
background: orange;
}
<div class="grid-container">
<div>
<h1>A</h1>
</div>
<div>
<h1>B</h1>
</div>
<div class="a">
<h1>C</h1>
</div>
</div>

Another way of solving it (That points to the reason why is stating a row for the other items):
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
}
h1 {
border: 2px solid;
padding: 0;
margin: 0;
font-size: 20px;
}
.a {
grid-row: 1 / span 2;
background: orange;
}
.b {
grid-row: 1;
}
<div class="grid-container">
<div class="b">
<h1>A</h1>
</div>
<div class="b">
<h1>B</h1>
</div>
<div class="a">
<h1>C</h1>
</div>
</div>
And the reason of this behaviour is that the more restrictive elements get positioned first. This way, the possibilities of the grid algorithm to achieve a solution are bigger.
That is, an element that has a requirement will be positioned first, elements that don't have a requirement last.
Steps 2 (for a item) and 4 (for the remaining items) in this part of the spec

If only one gets stock to a row number it will come first and stick there ahead in the flow. To avoid this, other grid items needs to be set to a defaut row as well.
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
}
div {
grid-row: 1;/* here is the basic fix but will set each item on first row */
}
h1 {
border: 2px solid;
padding: 0;
margin: 0;
font-size: 20px;
}
.a {
grid-row: 1 / span 2;
background: orange;
}
<div class="grid-container">
<div>
<h1>A</h1>
</div>
<div>
<h1>B</h1>
</div>
<div class="a">
<h1>C</h1>
</div>
</div>
Else you need also to tell in which grid-column it should stand
.a {
grid-row: 1 / span 2;
grid-column:3;
background: orange;
}
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
}
h1 {
border: 2px solid;
padding: 0;
margin: 0;
font-size: 20px;
}
.a {
grid-row: 1 / span 2;
grid-column:3;
background: orange;
}
<div class="grid-container">
<div>
<h1>A</h1>
</div>
<div>
<h1>B</h1>
</div>
<div class="a">
<h1>C</h1>
</div>
</div>
or let auto placement do its job while only setting how many rows to span, wich is here, in my own opinion, the most flexible way with a minimum of css rules/selector to set, too much grid kills grid :) , make it simple :
.a {
grid-row: span 2;
background: orange;
}
snippet with a few example letting the .aclass do its job without setting the column nor the row number where to stand, it will just be spanning where it stans in the flow
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
}
h1 {
border: 2px solid;
padding: 0;
margin: 0;
font-size: 20px;
}
.a {
grid-row: span 2;
background: orange;
}
<div class="grid-container">
<div>
<h1>A</h1>
</div>
<div>
<h1>B</h1>
</div>
<div class="a">
<h1>C</h1>
</div>
</div>
<div class="grid-container">
<div>
<h1>A</h1>
</div>
<div class="a">
<h1>B</h1>
</div>
<div>
<h1>C</h1>
</div>
</div>
<div class="grid-container">
<div>
<h1>A</h1>
</div>
<div>
<h1>B</h1>
</div>
<div>
<h1>C</h1>
</div>
<div>
<h1>D</h1>
</div>
<div>
<h1>E</h1>
</div>
<div class="a">
<h1>F</h1>
</div>
<div>
<h1>G</h1>
</div>
<div>
<h1>H</h1>
</div>
</div>
<hr/>
<div class="grid-container">
<div>
<h1>A</h1>
</div>
<div>
<h1>B</h1>
</div>
<div class="a">
<h1>C</h1>
</div>
<div>
<h1>D</h1>
</div>
<div>
<h1>E</h1>
</div>
<div>
<h1>F</h1>
</div>
<div>
<h1>G</h1>
</div>
<div>
<h1>H</h1>
</div>
</div>

Clearly, there's something in the spec that causes this behavior. I'm not yet sure what it is. (Update: see #Vals' answer for an explanation.)
However, here's a valid and simple solution:
Instead of:
.a {
grid-row: 1 / span 2;
}
Use:
.a {
grid-row-end: span 2;
}
From the spec:
9.3. Line-based Placement: the grid-row-start,
grid-column-start, grid-row-end, and grid-column-end
properties
The grid-row-start, grid-column-start, grid-row-end, and
grid-column-end properties determine a grid item’s size and location
within the grid by contributing a line, a span, or nothing (automatic)
to its grid placement, thereby specifying the inline-start,
block-start, inline-end, and block-end edges of its grid area.
...
For example, grid-column-end: span 2 indicates the second grid line
in the endward direction from the grid-column-start line.
Also, consider this single rule that gives you full control and makes it all work:
.a {
grid-area: 1 / 3 / 3 / 4;
}
jsFiddle
The grid-area shorthand property parses values in this order:
grid-row-start
grid-column-start
grid-row-end
grid-column-end
Note the counter-clockwise direction, which is the opposite of margin and padding.

Related

How to make second column be the largest but also able to shrink?

I am new to CSS grid and trying to implement the second row only in the below picture.
I've tried to create six sections but have the second section spread out longer. For example I've tried:
grid-column: 2 / span 5;
But it seems to push the last four section to the next line cause it to wrap which I do not want.
my unsuccessful code:
.container {
border: solid black 3px;
height: 100px;
display: grid;
grid-template-columns: repeat(6, 1fr);
}
.item {
border: solid skyblue 1px;
}
.item:nth-of-type(2) {
/* grid-column: 2 / span 5; */
}
<div class="container">
<div class="item"></div>
<div class="item">Totals</div>
<div class="item">6000</div>
<div class="item">-</div>
<div class="item">194</div>
<div class="item">12.5%</div>
</div>
Try auto on the columns, with 1fr on the flexible one.
.container {
border: solid black 3px;
height: 100px;
display: grid;
grid-template-columns: minmax(100px, auto) 1fr repeat(4, minmax(100px, auto));
}
.item {
border: solid skyblue 1px;
}
<div class="container">
<div class="item"></div>
<div class="item">Totals</div>
<div class="item">6000</div>
<div class="item">-</div>
<div class="item">194</div>
<div class="item">12.5%</div>
</div>
jsFiddle demo
Try adding grid-auto-flow: column; to your .container and change grid-column: 2 / span 5; to grid-column: 2 / span 3;

Make a grid as big as the screen

I need the grid ad big as the page (it should touch the top the bottom and both sides) and I'd like it to be non-scrollable.
HTML:
<div class="wrapper">
<div class="prova">One</div>
<div class="prova"> </div>
<div class="prova">Three</div>
<div class="prova">Four</div>
<div class="prova"> five </div>
<div class="prova">Six</div>
<div class="prova">Seven</div>
<div class="prova">Eight</div>
<div class="prova">Nine</div>
<div class="prova">Ten</div>
<div class="prova">Eleven</div>
<div class="prova">Twelve</div>
</div>
CSS:
.wrapper {
padding-top: 10%;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 100px;
}
.prova{
border: 1px solid;
}
.wrapper div:nth-child(2) {
grid-column: 3;
grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
I've read multiple questions but I couldn't find any solution that works fine for me.
As you can see in the picture above the grid doesn't touch neither the top or the bottom!
Set gird-auto-rows to use a percentage of the viewport height. Equal amounts per expected row. So in your case 25vh. Then remove any padding or margin around the grid.
html, body {
margin: 0
}
.wrapper {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 25vh;
width: 100%;
}
.prova{
border: 1px solid;
}
.wrapper div:nth-child(2) {
grid-column: 3;
grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
<div class="wrapper">
<div class="prova">One</div>
<div class="prova"> </div>
<div class="prova">Three</div>
<div class="prova">Four</div>
<div class="prova"> five </div>
<div class="prova">Six</div>
<div class="prova">Seven</div>
<div class="prova">Eight</div>
<div class="prova">Nine</div>
<div class="prova">Ten</div>
<div class="prova">Eleven</div>
<div class="prova">Twelve</div>
</div>
If you want it to touches the top just remove the padding
And for other sides just set the width and height of the wrapper to 100vh and 100vw

Design a layout with one div on 2 columns and 2 rows at the left, and 4 divs on 2 columns and 2 rows at the right, similar to BBC website

I want to design a hero section similar to BBC website. I started working on this using CSS Grid which I thought could get the same design with minimal code.
I have managed to base design but I want item1 to take 50% of the container's width and rest of the items to take 25% of space each so that it looks like the image above. I can span rows but I am not sure how I can span columns correctly, I tried this :
.item1 {
grid-column-end: span 2;
}
But it broke the design and same did happen with:
.item1 {
grid-column: auto / span 2;
}
My code:
.grid-container {
display: grid;
grid-template-columns: auto auto auto;
grid-gap: 10px;
background-color: #2196F3;
padding: 0px;
}
.grid-container > div {
background-color: rgba(255, 255, 255, 0.8);
text-align: center;
padding: 0px 0;
font-size: 30px;
}
.item1 {
grid-row-end: span 2;
}
.grid-container div img {width:100%; max-width:600px;}
<div class="grid-container">
<div class="item1">
<img src="https://dummyimage.com/600x400/f09c00/fafafa&text=1"/>
</div>
<div class="item2">
<img src="https://dummyimage.com/600x400/0010f0/fafafa&text=2"/>
</div>
<div class="item3">
<img src="https://dummyimage.com/600x400/5310f0/fafafa&text=3"/>
</div>
<div class="item4">
<img src="https://dummyimage.com/600x400/0010f0/fafafa&text=4"/>
</div>
<div class="item5">
<img src="https://dummyimage.com/600x400/0010f0/fafafa&text=5"/>
</div>
</div>
You could do it as below. I simplified the code by removing irrelevant code for the desired layout and added comments.
.grid-container {
background-color: #2196f3;
/* with these 3 lines below, I'm creating a grid of 4 columns and 2 rows*/
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: auto auto;
grid-gap: 10px;
}
.grid-container > div:nth-of-type(1){ /* I grab the first div */
grid-column: 1 / 3; /* I tell him to take 2 columns, 1 -> 3 with 3 excluded */
grid-row: 1 / 3; /* I tell him to take 2 rows, 1 -> 3 with 3 excluded */
}
.grid-container div img {
width: 100%;
height:100%;
object-fit:cover;
}
<div class="grid-container">
<div class="item1">
<img src="https://dummyimage.com/600x400/f09c00/fafafa&text=1" />
</div>
<div class="item2">
<img src="https://dummyimage.com/600x400/0010f0/fafafa&text=2" />
</div>
<div class="item3">
<img src="https://dummyimage.com/600x400/5310f0/fafafa&text=3" />
</div>
<div class="item4">
<img src="https://dummyimage.com/600x400/0010f0/fafafa&text=4" />
</div>
<div class="item5">
<img src="https://dummyimage.com/600x400/0010f0/fafafa&text=5" />
</div>
</div>

How to have a grid in CSS with columns of different sizes? [duplicate]

I tried to achieve the masonry style using css with the column layout like the markup below.
I want to know if it's possible to make the .green one to take two columns instead of one?
Thank you in advance!
.parent{
column-gap: 1rem;
column-count: 2;
}
.element{
display:inline-block;
background:red;
width:100%;
height:100px;
}
.green{
background:green;
}
<div class="parent">
<div class="element green">
</div>
<div class="element">
</div>
<div class="element">
</div>
<div class="element">
</div>
</div>
With CSS grid you can use grid-column: span 2:
.wrapper {
display: grid;
grid-gap: 0.5rem;
grid-template-columns: 1fr 1fr 1fr;
grid-auto-flow: dense;
padding: 0.5rem;
}
.box {
background-color: lightblue;
padding: 0.5rem;
}
.a,
.d,
.e,
.f {
background-color: lightcoral;
grid-column: span 2; /* <-- here is the trick */
}
<div class="wrapper">
<div class="box a">A</div>
<div class="box b">B</div>
<div class="box c">C</div>
<div class="box d">D</div>
<div class="box e">E</div>
<div class="box f">F</div>
<div class="box g">G</div>
<div class="box h">H</div>
</div>
Learn more about it here: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column
Regarding masonry style: At the time of writing, Level 3 of the CSS Grid Layout specification includes a masonry value for grid-template-columns and grid-template-rows layout, though browser support is pretty non-existent: https://caniuse.com/?search=masonry
Learn about it here: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout
So instead I used grid-auto-flow: dense; on the grid, which makes grid item G come before grid item F. It's not really masonry style (placing elements in optimal position based on available vertical space), but it comes close by making the grid dense filling up all available horizontal space with the next grid item that fits that space.
"dense" packing algorithm attempts to fill in holes earlier in the grid
Learn about it here: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow
Oh, if you are new to CSS grid, I recommend watching Wes Bos' talk “CSS Grid in 45 Minutes!”: https://www.youtube.com/watch?v=DCZdCKjnBCs
CSS Grid layout provides a simple, easy and efficient solution.
.parent {
display: grid;
grid-template-columns: 1fr 1fr;
grid-auto-rows: 100px;
grid-gap: 1rem;
}
.element.green {
grid-column: 1 / -1;
background: green;
}
.element {
background: red;
}
<div class="parent">
<div class="element green"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
</div>
More information:
Make a grid column span the entire row
CSS-only masonry layout
I would say, no you can't make the single .green element take up two columns, becuase you are specifically telling the browser to use two columns. If you need it to span the two columns, then I would suggest using a separate element. Perhaps a more suitable solution for this would be to use the CSS grid layout. The snippet below contains an example of both of these solutions:
.parent {
column-gap: 1rem;
column-count: 2;
}
.element {
display: inline-block;
background: red;
width: 100%;
height: 100px;
}
.green {
background: green;
width: 100%;
height: 100px;
margin-bottom: 1rem;
}
.grid-container {
margin-top: 20px;
display: grid;
grid-template-columns: auto auto;
grid-gap: 1rem;
}
.greenGrid {
background: green;
height: 100px;
grid-column-start: 1;
grid-column-end: 3;
}
.redGrid {
background: red;
height: 100px;
}
<div class="green">
</div>
<div class="parent">
<div class="element">
</div>
<div class="element">
</div>
<div class="element">
</div>
</div>
<div class='grid-container'>
<div class='greenGrid'></div>
<div class='redGrid'></div>
<div class='redGrid'></div>
<div class='redGrid'></div>
</div>

Make a child element take a third of the parent container (Parent is styled using grid-layout)

I'd want one child element to be 1/3 the size of its parent container and the other 2/3. The parent container is in a main container that uses grid-layout.
The parent container in question spans 2 columns of the main container it is contained in.
I've tried using margin, but it doesn't work: when I switch from a small screen to a large screen it moves to leave a gap.
<div class="main-container" style="display:grid; grid-template-columns: 1fr 2fr 1fr"> 1
<div></div>
<div class="parent-container" style="grid-column:span 2">
<div class="child-1"></div>
<div class="child-2"></div>
</div>
</div>
css code I've tried:
.child-1{
margin-left:-20%;
}
Child-1 must be 1/3 of parent-container and child-2 2/3 of parent-container
You can make use of the nested grid container. The dotted borders signify the width that the child elements take from the parent container. The solid borders are for the main container's child elements. Rest is explained in comments.
.main-container {
display: grid;
grid-template-columns: 1fr 2fr 1fr; /* 1/4th for Extra, 2/4th for Parent, 1/4th for Extra */
grid-auto-flow: column; /* Normal flow is row */
}
.parent-container {
display: grid; /* Nested Grid */
grid-template-columns: 1fr 2fr; /* 1/3rd for Child 1, 2/3rd for Child 2 of parent container*/
grid-auto-flow: column;
}
/* Extra styling for snippet, you just need the above logic */
.main-container {
font-size: 1.15em;
font-family: Sans-Serif;
}
.parent-container {
border: 2px solid black;
}
.parent-container>div {
background: #6660CE;
padding: 10px;
color: #fff;
text-align: center;
border: 2px dotted black;
}
.main-container>div {
background: #6660CE;
padding: 10px;
color: #fff;
text-align: center;
}
<div class="main-container">
<div class="extra">Extra</div>
<div class="parent-container">
<div class="child-1">Child 1 </div>
<div class="child-2">Child 2</div>
</div>
<div class="extra">Extra</div>
</div>
Simply give the parent element two columns with grid-template-columns, where the second column is twice the size of the first column (i.e. 1fr and 2fr).
This can be seen in the following:
.container {
display: grid;
grid-template-columns: 1fr 2fr;
}
.child-1 {
background: red;
}
.child-2 {
background: blue;
}
.child {
height: 50px;
}
<div class="container">
<div class="child child-1"></div>
<div class="child child-2"></div>
</div>
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.child:nth-child(1) {
grid-area: 1 / 1;
background-color: #9341aa;
}
.child:nth-child(2) {
grid-area: 2 / 1 / span 1 / span 2;
background-color: #ab41aa;
}
.child:nth-child(3) {
grid-area: 3 / 1 / span 1 / span 3;
background-color: #cab332;
}
<div class="container">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
</div>
Using calc, something like this should do the trick:
HTML:
<div class="main-container">
<div></div>
<div class="parent-container">
<div class="child-1"></div>
<div class="child-2"></div>
</div>
</div>
CSS:
.parent-container{
position: relative;
width: 100%;
height: 100%;
}
.parent-container .child-1,
.parent-container .child-2{
width: calc(100% / 3);
height: 100%;
float: left;
}