I'm trying to use CSS grid to layout some content in the following constraints.
I have three divs - all should be 50% wide but div two and three should stack on top of each other next to div 1.
I've managed to achieve this using grid-template-areas, but I'm using PHP to dynamically populate this, so there's no guarantee that there will always be three divs, so if it goes over this amount, I simply want the grid to repeat.
I'm using the following code right now:
.container {
display: grid;
grid-template-columns: 50% 50% 50%;
gap: 0px 0px;
grid-auto-flow: row;
grid-template-areas:
"Grid-1 Grid-2 ."
"Grid-1 Grid-3 ."
". . .";
}
.Grid-2 { grid-area: Grid-2; }
.Grid-3 { grid-area: Grid-3; }
.Grid-1 { grid-area: Grid-1; }
html, body , .container {
height: 100%;
margin: 0;
}
.container * {
border: 1px solid red;
position: relative;
}
.container *:after {
content:attr(class);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: grid;
align-items: center;
justify-content: center;
}
<div class="container">
<div class="Grid-1"></div>
<div class="Grid-2"></div>
<div class="Grid-3"></div>
</div>
It would also ne nice to not have to give each div that I'm generating a PHP the specific area class. Is this achievable using grid?
Simply like below:
.container {
display: grid;
grid-template-columns: 50% 50%; /* 2 columns */
grid-auto-rows:50vh; /* size of one row*/
}
/* for each 3 divs make the first one span 2 rows */
.container > :nth-child(3n + 1) { grid-row:span 2 }
.container * {
border: 1px solid red;
display: grid;
place-items: center;
}
.container *:after {
content:"some content";
}
body {
margin: 0;
}
<div class="container">
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
</div>
Related
I have a two column layout. Left has an image. Right has 2 images on top of each other. My goal is to have the images increase as much as possible but have to keep their aspect ratio. And of cause can't overflow outside the containing height.
Right now if you change the width of the browser window, the image resize respecively in a correct way. But if you decrease the height of the window, the images does not decrease in size.
Any tips.
outer-container has height calc(100vh -100px). it is suppose to simulate having a sticky footer.
.outer-container {
display: flex;
background-color: green;
height: calc(100vh - 100px);
clear: auto;
}
.left-column {
}
.right-column {
display:flex;
justify-content: top;
flex-direction: column;
}
.left-image {
width: 100%;
}
.right-image {
width: 100%;
}
/* Currently using image tag but meant to work with video as well, easier to create a snippet for img though!*/
<div class="outer-container">
<div class="left-column">
<img class="left-image" src="https://via.placeholder.com/200x500/333300">
</div>
<div class="right-column">
<img class="right-image" src="https://via.placeholder.com/500X250/33000">
<img class="right-image" src="https://via.placeholder.com/500x250/003300">
</image>
</div>
</div>
Just add max-height properties to the .left-image and .right-image rules so they do not overflow their parent containers.
.outer-container {
display: flex;
background-color: green;
height: calc(100vh - 100px);
clear: auto;
}
.left-column {
}
.right-column {
display:flex;
justify-content: top;
flex-direction: column;
}
.left-image {
width: 100%;
max-height: 100%;
}
.right-image {
width: 100%;
max-height: 50%;
}
/* Currently using image tag but meant to work with video as well, easier to create a snippet for img though!*/
<div class="outer-container">
<div class="left-column">
<img class="left-image" src="https://via.placeholder.com/200x500/333300">
</div>
<div class="right-column">
<img class="right-image" src="https://via.placeholder.com/500X250/33000">
<img class="right-image" src="https://via.placeholder.com/500x250/003300">
</image>
</div>
</div>
This might work as a starting point. Not 100% sure how you want the first column in relation to the second.
I added a footer since you seemed to indicate that?
.outer-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 1fr) 100px;
background-color: green;
height: 100vh;
}
.left-column {
/* keeps the left image in the box */
min-height: 0;
grid-row: 1 / 2;
grid-column: 1 / 1;
border: solid cyan 2px;
display: flex;
justify-content: center;
}
.right-column {
border: solid yellow 2px;
display: flex;
align-items: start;
justify-content: top;
flex-direction: column;
}
.left-image {
height: 100%;
}
.right-image {
width: 100%;
}
.footer {
/* put accross all columns of last row and super center content */
grid-column: 1 / 3;
grid-row: 3 / 3;
background-color: #ffdd88;
display: grid;
align-items: center;
justify-content: center;
}
<div class="outer-container">
<div class="left-column">
<img class="left-image" src="https://via.placeholder.com/200x500/333300">
</div>
<div class="right-column">
<img class="right-image" src="https://via.placeholder.com/500X250/33000">
<img class="right-image" src="https://via.placeholder.com/500x250/003300">
</div>
<div class="footer"> I am the footer thing</div>
</div>
Here, I have a red container, yellow container, and a navbar component.
When the navbar component(blue) is present, I want to reduce the width of both the red and yellow container so that it doesn't overlap.
I tried using fr so that red and blue container takes only the available space but it doesn't seem to work.
.flexrow {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.pagetoplayout {
display: grid;
flex-grow: 1;
grid-template-columns: 70fr 30fr;
grid-template-rows: auto auto;
overflow: auto;
grid-template-areas:
'tophalf tophalf'
'bottomside bottomside';
}
.tophalf{
grid-area: tophalf;
background: red;
}
.bookingside {
grid-area: bottomside;
background: yellow;
}
.navbar--visible {
width: 500px;
position: absolute;
top: 0;
right: 0;
display: block;
background-color: var(--color-black);
overflow: auto;
padding: 30px 20px;
opacity: 1;
background: blue;
opacity:0.8;
}
<div class="flexrow">
<div class="pagetoplayout">
<div class="tophalf">Container 1</div>
<div class="bookingside">Container 2 </div>
</div>
<div class="navbar--visible">
asa
</div>
<div>
Your navbar(blue) has position: absolute; applied which removes it from layout calculations. That's the reason it is shown over top of the other elements and doesn't affect the layout.
I'm trying to use the grid layout for two columns in one row which can be easily achieved by flex. I have to create one more div for flex but the grid doesn't need one more div.
The problem with the grid is that it will divide the width space by 2 (cannot align to start/left) and that's not what I want, please refer to the first example below and you will understand.
Is there any way to use the grid in this situation but we can align the items to the left like in the second example?
#main-1 {
display: grid;
gap: 30px;
grid-teplate-column: repeat(2, minmax(0, 1fr));
}
.test-1 {
background-color: orange;
grid-area: span 1 / span 2;
}
.test-2 {
background-color: gray;
width: 150px;
}
#main-2 {
display: flex;
gap: 30px;
margin-top: 30px;
}
.test-3 {
background-color: orange;
width: 100%;
}
.test-4 {
background-color: gray;
width: 150px;
}
.test-1,
.test-2,
.test-3,
.test-4 {
height: 60px;
}
<h1>Grid</h1>
<div id="main-1">
<div class="test-1"></div>
<div class="test-2"></div>
<div class="test-2"></div>
</div>
<h1 style="margin:30px 0 0 0;padding-top:15px;border-top: 3px solid #000;">Flex</h1>
<p style="margin:0 0 30px 0;">This is the desired layout but with one more extra div</p>
<div>
<div class="test-3"></div>
<div id="main-2">
<div class="test-4"></div>
<div class="test-4"></div>
</div>
</div>
Edited
Inline-block might work but we cannot control how many items should be on each row. Imagine the width of the first div .first is dynamic and we do not know how wide it would be(but I will make it 30px for illustration). Now the desired layout should be only one .first and one .second on each row.
By inline-block it would appear that now each row is one .first, one .second, and one .first. Check out the example below. Because we cannot control the amount like grid on each row.
#main {
width: 120px;
}
.first,
.second {
display: inline-block;
height: 60px;
}
.first {
background-color: orange;
width: 30px;
}
<div id="main">
<div class="first"></div>
<p class="second">hhhhhh</p>
<div class="first"></div>
<p class="second">hhhhhh</p>
<div class="first"></div>
<p class="second">hhhhhh</p>
</div>
Define the columns as auto and keep only one at 1fr then you can align to the left.
#main-1 {
display: grid;
gap: 30px;
/* update "5" based on your needs */
grid-template-columns: repeat(5,auto) 1fr;
justify-content: left; /* align to left */
}
.test-1 {
background-color: orange;
grid-column: 1/-1; /* take all the columns */
}
.test-2 {
background-color: gray;
width: 150px;
}
#main-2 {
display: flex;
gap: 30px;
margin-top: 30px;
}
.test-3 {
background-color: orange;
width: 100%;
}
.test-4 {
background-color: gray;
width: 150px;
}
.test-1,
.test-2,
.test-3,
.test-4 {
height: 60px;
}
<h1>Grid</h1>
<div id="main-1">
<div class="test-1"></div>
<div class="test-2"></div>
<div class="test-2"></div>
</div>
<h1 style="margin:30px 0 0 0;padding-top:15px;border-top: 3px solid #000;">Flex</h1>
<p style="margin:0 0 30px 0;">This is the desired layout but with one more extra div</p>
<div>
<div class="test-3"></div>
<div id="main-2">
<div class="test-4"></div>
<div class="test-4"></div>
</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
I have a CSS grid that occupies 100% width and 100% height of a window (the body element has display: grid;). The grid has row and column templates and elements which occupy 100% of their allocated space. However, when I add a grid-gap to the grid, it makes the grid too large for the window, forcing scrollbars to appear. How can I stop the grid-gap from adding to the dimensions of the grid - similar to how box-sizing: border-box; stops padding from adding to the dimensions of an element? Instead, I want the gaps to shrink the cells of the grid.
Thanks.
When you use "fr" it works.
Example:
HTML:
<section>
<article class="a">A</article>
<article class="b">B</article>
<article class="c">C</article>
<article class="d">D</article>
</section>
SCSS:
section {
display: grid;
grid-template-columns: 1fr 1fr;
grid-auto-flow: column;
grid-gap: 20px;
border: 10px solid blue;
article {
background-color: tomato;
&.d {
grid-column: 2;
grid-row-start: 1;
grid-row-end: 4;
background-color: olive;
}
}
}
It works same as if you used box-sizing: border-box and padding as you can see in this demo. Height is set to 100vh and you can see that if you remove or add grid-gap there is no scrollbar, you just need to remove margin from body.
body {
margin: 0;
}
.grid {
display: grid;
height: 100vh;
grid-gap: 20px;
background: #FF7D7D;
grid-template-columns: 1fr 2fr; /* Use Fractions, don't use % or vw */
}
.grid > div {
background: black;
color: white;
}
div.a, div.d {
color: black;
background: white;
}
<div class="grid">
<div class="a">A</div>
<div class="b">B</div>
<div class="c">C</div>
<div class="d">D</div>
</div>
You could use view-port units:
vw (1% of window's width)
vh (1% of window's height)
* {
margin: 0;
padding: 0;
box-sizing: border-box;
height: 100%;
}
.first { height: 40vh; }
.hori { height: 10vh; }
.second { height: 50vh; }
div > div {
float: left;
}
.left { width: 40vw; }
.vert { width: 10vw }
.right { width: 50vw; }
.first .left,
.second .right {
background: #ccc;
}
.first .right,
.second .left {
background: #000;
}
<div class="first">
<div class="left"></div>
<div class="grid-break vert"></div>
<div class="right"></div>
</div>
<div class="grid-break hori"></div>
<div class="second">
<div class="left"></div>
<div class="grid-break vert"></div>
<div class="right"></div>
</div>