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
Related
I have the following layout:
.container {
width: 630px;
height: 630px;
display: grid;
column-gap: 10px;
grid-template-columns: 2fr 1fr 1fr;
grid-template-rows: auto auto auto;
}
.first, .second, .third, .fourth, .fifth, .sixth, .seventh {
width: 200px;
height: 200px;
background-color: pink;
}
.first, .second {
height: 400px;
}
.fourth {
grid-column: 3 / 4;
grid-row: 2 / 3;
background-color: yellow;
}
.seventh {
grid-column: 3 / 4;
grid-row: 3 / 4;
}
<div class='container'>
<div class='first'>1</div>
<div class='second'>2</div>
<div class='third'>3</div>
<div class='fourth'>4</div>
<div class='fifth'>5</div>
<div class='sixth'>6</div>
<div class='seventh'>7</div>
</div>
I would like the first and second column to have 2 rows, taking 3fr 1fr and the last column to have 3 rows taking up 2fr 1fr 1fr. The end result would be that box number 4 is nested between number 3 and 7 without breaking out of the rectangle that boxes in the first two columns created.
This final positioning should look like this:
Is this possible using css grid, and how do I do it?
You can try like below:
.container {
width: 700px;
height: 700px;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: auto;
grid-gap: 20px;
}
.first,
.second,
.third,
.fourth,
.fifth,
.sixth,
.seventh {
width: 100%;
height: 100%;
background-color: pink;
}
.first,
.second {
grid-row: 1 / 3;
}
.second,
.sixth {
}
.fourth {
background-color: yellow;
}
<div class='container'>
<div class='first'>1</div>
<div class='second'>2</div>
<div class='third'>3</div>
<div class='fourth'>4</div>
<div class='fifth'>5</div>
<div class='sixth'>6</div>
<div class='seventh'>7</div>
</div>
Is this what you wanted.
You can read more about grid-row here
Run snippet to see it working below
.container {
width: 700px;
height: 700px;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: auto;
grid-gap: 20px;
}
.first,
.second,
.third,
.fifth,
.sixth,
.seventh {
background-color: pink;
}
.first,
.second {
grid-row: 1 / 3;
}
.fourth {
background-color: yellow;
}
<div class='container'>
<div class='first'>1</div>
<div class='second'>2</div>
<div class='third'>3</div>
<div class='fourth'>4</div>
<div class='fifth'>5</div>
<div class='sixth'>6</div>
<div class='seventh'>7</div>
</div>
I am trying make
I tried to do with display: flex but I'm not having success and I can't make it responsive and with grid area the same way.,
code:
const Grid = styled.div`
display: grid;
grid-template-columns: 40wh 1fr;
background: red;
& div:nth-child(1) {
grid-area: 1 / 1 / 5 / 1;
background: yellow;
}
`;
export default function App() {
return (
<div className="App">
<Grid>
<div>a</div>
<div>b</div>
<div>b</div>
</Grid>
</div>
);
}
Could someone help me how would I achieve this with flex or grid system?
example:
https://codesandbox.io/s/withered-river-d6twt
Grid Solution
There are many ways to accomplish this. I like using grid-template-areas to define an explicit grid and place my items exactly where I want them. From the code below, specifically the value for grid-template-areas, you can see that a spans both row 1 and row 2.
Note: you have a CSS error:
grid-template-columns: 40wh 1fr; /* <-- wh is not a valid unit */
I changed that line to:
grid-template-columns: 40vw 1fr 1fr;
Here's the full code.
.grid {
display: grid;
grid-template-areas:
"a b c"
"a d e";
grid-gap: 4px;
grid-template-columns: 40vw 1fr 1fr;
grid-auto-rows: 100px;
}
.grid > * {
background-color: #333;
color: white;
position: relative;
}
.a { grid-area: a; }
.b { grid-area: b; }
.c { grid-area: c; }
.d { grid-area: d; }
.e { grid-area: e; }
.grid > * > span {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
<div class="grid">
<div class="a"><span>a</span></div>
<div class="b"><span>b</span></div>
<div class="c"><span>c</span></div>
<div class="d"><span>d</span></div>
<div class="e"><span>e</span></div>
</div>
jsFiddle
Flex Solution
You'll notice the gaps in the following code are a bit of a hack compared to Grid. With Grid we can express the gaps using grip-gap; Flex gives us no such tool.
.flex {
display: inline-flex;
}
.left,
.right {
flex: 1;
display: flex;
}
.right {
flex-wrap: wrap;
}
.right > img {
width: 50%;
padding-left: 4px;
}
.right > img:nth-child(1),
.right > img:nth-child(2) {
padding-bottom: 2px;
}
.right > img:nth-child(3),
.right > img:nth-child(4) {
padding-top: 2px;
}
img {
max-width: 100%;
height: auto;
}
* {
box-sizing: border-box;
}
<div class="flex">
<div class="left">
<img src="http://placekitten.com/500/600" alt="">
</div>
<div class="right">
<img src="http://placekitten.com/100/150" alt="">
<img src="http://placekitten.com/100/150" alt="">
<img src="http://placekitten.com/100/150" alt="">
<img src="http://placekitten.com/100/150" alt="">
</div>
</div>
jsFiddle
Consider the following 3-column grid layout with max-width constraint on container:
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 56px minmax(56px, auto) 56px;
max-width: 300px;
margin: auto;
}
header {
background-color: grey;
grid-column: 1 / span 3;
grid-row: 1 / 2;
}
main {
background-color: #2E64FE;
grid-column: 1 / span 2;
grid-row: 2 / 3;
}
aside {
background-color: #FF0040;
grid-column: 3 / span 1;
grid-row: 2 / 3;
}
footer {
background-color: grey;
grid-column: 1 / span 3;
grid-row: 3 / 4;
}
header, main, aside, footer {
line-height: 56px;
text-align: center;
vertical-align: middle;
}
<html>
<body>
<div class='container'>
<header>Header</header>
<main>Main</main>
<aside>Sidebar</aside>
<footer>Footer </footer>
</div>
</body>
</html>
Ideally, I would like to bleed background of header and footer outside the container when viewport width is above max-width, but keep grid and its structure within max-width as in example (including inner content of header and footer).
I have considered these approaches:
Forget max-width container, use full width container with minmax'es and position full-span divs with background-color underneath header and footer(https://codepen.io/anon/pen/OaryXj). I don't like this approach because it adds extra elements purely for styling and because it adds two extra columns (I can live with this one probably, using named columns)
Use same approach as above, but instead of adding extra divs, use full-span header and footer with "padding: 0 calc((100% - 900px)/2);" (https://codepen.io/anon/pen/BGvoxx). I don't like this approach either, because I don't understand why it works at all when 100% < 900px (why negative padding is not added) and it adds two extra columns to the grid as well.
Any other ideas? Some calc() magic with negative margins and padding on header / footer?
if it's only about background and coloration you can use pseudo element to have the overflow effect:
body {
overflow-x:hidden;
}
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 56px minmax(56px, auto) 56px;
max-width: 300px;
margin: auto;
}
header {
background-color: grey;
grid-column: 1 / span 3;
grid-row: 1 / 2;
position:relative;
}
header:before,
footer:before{
content:"";
z-index:-1;
position:absolute;
top:0;
bottom:0;
left:-100vw;
right:-100vw;
background:inherit;
}
main {
background-color: #2E64FE;
grid-column: 1 / span 2;
grid-row: 2 / 3;
}
aside {
background-color: #FF0040;
grid-column: 3 / span 1;
grid-row: 2 / 3;
}
footer {
background-color: grey;
grid-column: 1 / span 3;
grid-row: 3 / 4;
position:relative;
}
header, main, aside, footer {
line-height: 56px;
text-align: center;
vertical-align: middle;
}
<html>
<body>
<div class='container'>
<header>Header</header>
<main>Main</main>
<aside>Sidebar</aside>
<footer>Footer </footer>
</div>
</body>
</html>
the accepted answer is amazing, but you can solve your problem by changing your markup a little bit. by changing the order of your divs and splitting the concerns of your container class with that of the grid you get the same result:
body {
margin: 0;
overflow-x:hidden;
}
.container {
max-width: 300px;
margin: auto;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: minmax(56px, auto);
}
header, footer {
background-color: grey;
height: 56px;
}
main {
background-color: #2E64FE;
grid-column: 1 / span 2;
}
aside {
background-color: #FF0040;
grid-column: 3 / span 1;
}
header, main, aside, footer {
line-height: 56px;
text-align: center;
vertical-align: middle;
}
<html>
<body>
<header>
<div class="container">Header</div>
</header>
<div class="container grid">
<main>Main</main>
<aside>Sidebar</aside>
</div>
<footer>
<div class="container">Footer</div>
</footer>
</body>
</html>
the use-case where I see the accepted answer really shine is when you have multiple columns and you don't want to break the grid but extend the background color of one of the columns to the edges of the browser...
body {
overflow-x:hidden;
margin: 0;
}
.container {
max-width: 300px;
margin: auto;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: minmax(56px, auto);
}
header, footer {
background-color: grey;
height: 56px;
}
aside {
background-color: #FF0040;
grid-column: 1 / span 1;
}
main {
background-color: #2E64FE;
grid-column: 2 / span 2;
}
.extend-right {
position: relative;
}
.extend-right:after {
content: '';
position: absolute;
height: 100%;
left: 100%;
right: -100vw;
background-color: inherit;
}
header, main, aside, footer {
line-height: 56px;
text-align: center;
vertical-align: middle;
}
<html>
<body>
<header>
<div class="container">Header</div>
</header>
<div class="container grid">
<aside>Sidebar</aside>
<main class="extend-right">Main</main>
</div>
<footer>
<div class="container">Footer</div>
</footer>
</body>
</html>
seems like an easy task which Im trying to get done since hours. I cant get my grid elements vertical aligned properly. Please take a look at the fiddle to get the idea. Maybe someone could help me with this issue.
HTML
<section class="top">
<div></div>
<div></div>
</section>
<section class="bottom">
<div></div>
<div></div>
<div></div>
</section>
CSS
section {
display: grid;
grid-template-rows:auto;
margin: 40px 0 0 0
}
section.top {
grid-template-columns:2fr 1fr;
grid-column-gap: 50px;
}
section.bottom {
grid-template-columns:1fr 1fr 1fr;
grid-column-gap: 50px;
}
section div {
background:lightblue;
height:400px
}
https://jsfiddle.net/ecj1wrae/
Well, with some thinking and calculation this one here does the trick
CSS
section.top {
grid-template-columns:calc(66% + 2vw) 34%;
grid-column-gap: 2vw;
}
section.bottom {
grid-template-columns:33% 33% 34%;
grid-column-gap: 2vw;
}
https://jsfiddle.net/ecj1wrae/3/
I know this is an old question... But I had a similar problem and I thought I'd share my solution for anyone else that needs some help.
This comment helped push me in the right direction
But you're dividing space using fr units, which applies only free
space in the container. And the bottom section has 50px less free
space than the top. So they cannot be aligned in this manner
As the layout needs to consider the gaps between the columns I found it better to frame the problem as it needs to take up 2 columns of a 3 column layout instead of thinking it needs to take up 2fr of a 3fr layout.
Helpfully grid allows us to specify how many columns an element can span grid-column: span 2;
Using the html in the question we can use a span on the first div in the top section:
section {
display: grid;
margin: 40px 0 0 0;
grid-template-columns: repeat(3, minmax(0, 1fr));
grid-column-gap: 50px;
}
section.top div:first-child {
grid-column: span 2;
}
If you would like to do it with only 1 parent element, this may be a solution:
.wrapper {
display: grid;
grid-template-columns: auto auto auto auto;
grid-row-gap: 50px;
grid-column-gap: 10px;
grid-template-areas:
'item1 item1 item1 item1 item2'
'item3 item3 item4 item4 item5';
}
.wrapper > div {
background: red;
height: 400px;
}
.item1 {
grid-area: item1;
}
.item2 {
grid-area: item2;
}
.item3 {
grid-area: item3;
}
.item4 {
grid-area: item4;
}
.item5 {
grid-area: item5;
}
<div class="wrapper">
<div class="item1"></div>
<div class="item2"></div>
<div class="item3"></div>
<div class="item4"></div>
<div class="item5"></div>
</div>
A really simple solution is change the grid-column-gap by margin (if having space on the sides is not a problem):
HTML
<section class="top">
<div></div>
<div></div>
</section>
<section class="bottom">
<div></div>
<div></div>
<div></div>
</section>
CSS
section {
display: grid;
grid-template-rows:auto;
margin: 4px 0 0 0
}
section.top {
grid-template-columns:2fr 1fr;
}
section.bottom {
grid-template-columns:1fr 1fr 1fr;
}
section div {
background:lightblue;
height:400px;
margin: 5px;
}
https://codepen.io/fillsanches/pen/oNEpKWN
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>