Grid and flex layout for a card container - css

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

Related

CSS Flex item spanning two rows without fixed height

I am trying to create a flex container layout whereby one of the flex items should span two rows. See image below for a better explanation:
Here is my markup:
<div class="container">
<div class="item item-1">ITEM 1</div>
<div class="item item-2">ITEM 2</div>
<div class="item item-3">ITEM 3</div>
</div>
I cannot seem to achieve this, I have tried using flex-wrap and different combinations of the flex property.
I was able to achieve this by putting ITEM 1 & ITEM 2 in a separate <div>, but this presents a problem on a smaller screen, whereby ITEM 3 needs to appear BETWEEN ITEM 1 & ITEM 2. So I would rather keep the markup as is and use the order property to move things around as necessary.
You can use display: contents on your extra div to achieve what you want:
* {
box-sizing: border-box;
}
.container {
display: flex;
width: 100%;
}
.holder {
width: 67%;
}
.item {
border: 1px solid black;
}
.item-1 {
margin-bottom: 40px;
}
.item-3 {
width: 33%;
}
#media screen and (max-width: 700px) {
.container {
flex-direction: column;
}
.item {
margin-bottom: 20px;
}
.item-1 {
order: 1;
}
.item-2 {
order: 3;
}
.item-3 {
order: 2;
width: 100%;
}
.holder {
width: 100%;
display: contents;
}
}
<div class="container">
<div class="holder">
<div class="item item-1">ITEM 1</div>
<div class="item item-2">ITEM 2</div>
</div>
<div class="item item-3">ITEM 3</div>
</div>
You can't achieve it using flexbox. Instead, you should have two parents which are better.
Use Css-grid. Actually, css-grid is the best option in this case.
Flex-Box
* {
color: #fff;
}
.flex {
display: flex;
justify-content: center;
align-items: center;
}
.child {
border-radius: 10px;
}
.container {
display: flex;
width: 500px;
height: 200px;
border: 1px solid #ff0000;
}
.container .first-item {
flex-direction: column;
justify-content: space-between;
align-items: start;
width: 50%;
height: 100%;
margin-right: 10px;
}
.first-item .child {
width: 100%;
height: 50%;
background-color: blue;
}
.first-item .child:first-child {
margin-bottom: 10px;
}
.container .second-item {
width: 50%;
height: 100%;
}
.second-item .child {
width: 100%;
height: 100%;
background-color: blue;
}
<div class="container">
<div class="first-item flex">
<div class="child flex">Item 1</div>
<div class="child flex">Item 2</div>
</div>
<div class="second-item flex">
<div class="child flex">Item 3</div>
</div>
</div>
Grid
.flex {
display: flex;
justify-content: center;
align-items: center;
}
.child {
background-color: blue;
border-radius: 10px;
}
.container {
display: grid;
grid-template-columns: 1fr 10px 1fr;
grid-template-rows: 1fr 10px 1fr;
grid-template-areas: "c1 . c3"
". . c3"
"c2 . c3";
width: 500px;
height: 300px;
border: 1px solid red;
}
.container .child {
border: 1px solid blue;
}
.child1 {
grid-area: c1;
}
.child2 {
grid-area: c2;
}
.child3 {
grid-area: c3;
}
<div class="container">
<div class="child child1 flex">Item 1</div>
<div class="child child3 flex">Item 3</div>
<div class="child child2 flex">Item 2</div>
</div>
i dont know if its a good solution but
put two item3 codes one in the individual div (item1&2) and one outside then put the one in the div to display none in non-small screens and switch between them with mediaquery
#media (max-width: 40rem) {
.item3 {
display: none;
}
.mobile-item3{
display: block;
}
}

CSS Grid: Grid stretches the content – How is it possible to avoid that if one item uses "align-self: end;"?

This is my code:
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
}
#grid {
height: 100%;
display: grid;
grid-template-columns: repeat(6, 1fr);
}
#one,
#two,
#three {
grid-column-start: 1;
grid-column-end: 7;
}
#three {
align-self: end;
}
<div id="grid">
<div id="one">Hello</div>
<div id="two">How are you?</div>
<div id="three">See you.</div>
</div>
I would like to use align-self: end; for the last item. But the second item (#two) should stand directly under the first item (#one) without a gap.
How is it possible to avoid that gap? I have tried it with grid-auto-rows: min-content;, but then align-self: end; does not work anymore.
Would be very thankful for help! <3
You need 1fr for the middle one:
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
}
#grid {
height: 100%;
display: grid;
grid-template-rows:auto 1fr auto;
grid-template-columns: repeat(6, 1fr);
}
#one,
#two,
#three {
grid-column-start: 1;
grid-column-end: 7;
}
<div id="grid">
<div id="one">Hello</div>
<div id="two">How are you?</div>
<div id="three">See you.</div>
</div>

Repeating CSS grid without defining more grid areas

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>

CSS Grid - Centering header section (Logo + Menu)

I am investigating into CSS and Grid right now, as I want to learn new things. Actually, I do have a very simple question (I guess) but I am unable to resolve this. I am trying to use CSS grid for making a simple responsive design. For that purpose, I want to have a header section in which I do have a logo and a menu centered with a maximum width of 1170 px. However, I am unable to center the header-wrapper. Maybe I am doing things wrong here. For a better understanding, I just put a jsiddler here.
https://jsfiddle.net/f7ywrg93/
.wrapper {
display: grid;
grid-template-columns: auto;
grid-template-rows: 100px auto;
grid-template-areas:
"header"
"promo";
grid-gap: 10px;
}
.header {
grid-area: header;
background-color: #20262e;
color: #fff;
font-size: 14px;
}
.promo {
grid-area: promo;
background-color: #c0ff3e;
}
.wrapper-header {
display: grid;
grid-template-columns: auto auto;
grid-template-rows: auto;
grid-template-areas: "logo menu";
max-width:1170px;
grid-gap: 20px;
background-color: #447666;
}
.logo {
grid-area: logo;
place-self: start;
max-width: 300px;
background-color: #545454;
}
.menu {
grid-area: menu;
place-self: end;
background-color: #eadead;
}
<div class="wrapper">
<div class="header">
<div class="wrapper-header">
<div class="logo">Logo</div>
<div class="menu">Menu</div>
</div>
</div>
<div class="promo">Promo</div>
</div>
Hope that one can give me some give me some idea what I am doing wrong.
If you swap place-self: start and place-self: end for the logo and menu it will center them:
.wrapper {
display: grid;
grid-template-columns: auto;
grid-template-rows: 100px auto;
grid-template-areas:
"header"
"promo";
grid-gap: 10px;
}
.header {
grid-area: header;
background-color: #20262e;
position: relative;
color: #fff;
font-size: 14px;
}
.promo {
grid-area: promo;
background-color: #c0ff3e;
}
.wrapper-header {
display: grid;
grid-template-columns: auto auto;
grid-template-rows: auto;
grid-template-areas: "logo menu";
max-width:1170px;
width: 100%;
grid-gap: 20px;
margin: 0 auto;
background-color: #447666;
}
.logo {
grid-area: logo;
place-self: end;
max-width: 300px;
background-color: #545454;
}
.menu {
grid-area: menu;
place-self: start;
background-color: #eadead;
}
<div class="wrapper">
<div class="header">
<div class="wrapper-header">
<div class="logo">Logo</div>
<div class="menu">Menu</div>
</div>
</div>
<div class="promo">Promo</div>
</div>
place-self positions the elements within their respective grid blocks and not within the container element itself.

Is it possible to split a grid item to allow different spans?

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>

Resources