CSS Grid layout with dynamic height - css

I need to create layout 2x2 blocks with min-width 500px and min-height 300px. (first img).
I can collapse blue block (by click on it) to height 100px and the block which is below must fill the gap and become bigger. The same behaviour if lower block collapsed, the upper will stretch. (second img)
if screen width > 1200, turn it into 4 columns with width:300px, height:600px (third img) enter image description here
I tried to do add for parent
width: 100%;
height: 100%;
display: grid;
grid-template-rows: minmax(300px, 1fr) minmax(300px, 1fr);
grid-template-columns: minmax(500px, 1fr) minmax(500px, 1fr);
grid-column-gap: 25px;
grid-row-gap: 25px;
}
and also added
#media (min-width: 1200px) {
.parent {
grid-template-rows: minmax(600px, 1fr);
grid-template-columns: repeat(4, minmax(300px, 1fr));
}
}
but I don't know how to implement collapsing

Try this. I use the columns property on the parent to make a 2 column layout with the children to be flex containers. This means that when the flex children are clicked, we can use flex-grow, flex-shrink and flex-basis to make the clicked one smaller and the unclicked one automatically grow.
For screen sizes greater than 1200px, I've used a media query to flip the flex container to flex-direction: row which makes your four columns. The only bit that's annoying is that the column layout, the middle section is wider than the other parts. You might be able to fix this with a bit of tweaking
window.onload = () => {
document.querySelector('.container').addEventListener('click', (e) => {
e.target.classList.toggle('shrink');
});
}
.container {
columns: 2;
padding: 0.5rem;
border: 3px solid black;
height: 600px;
}
.column {
display: flex;
flex-direction: column;
height: 100%;
}
[id^="b"] {
background-color: #00A8F3;
border: 3px solid black;
margin-bottom: 0.5rem;
display: grid;
place-items: center;
padding: 1rem;
flex-grow: 1;
flex-shrink: 1;
}
.shrink {
flex-basis: 100px;
flex-grow: 0;
}
#media screen and (min-width: 1200px) {
.column {
flex: 1;
flex-direction: row;
justify-content: space-evenly;
}
.container {
display: flex;
}
[id^="b"] {
flex-basis: 300px;
flex-grow: 0;
flex-shrink: 0;
}
}
<div class='container'>
<div class='column'>
<div id='b1'>1</div>
<div id='b2'>2</div>
</div>
<div class='column'>
<div id='b3'>3</div>
<div id='b4'>4</div>
</div>
</div>

You can try like below. I added a checkbox to simulate the switch between (1) and (2)
.container {
display: grid;
grid-template-columns: 1fr 1fr; /* 2 columns */
grid-auto-flow: dense;
gap: 20px;
border:1px solid;
height: 300px;
}
.container > div {
display: flex;
flex-direction: column;
gap: 20px;
}
.container > div > div {
flex-grow: 1; /* fill remaining height */
height: 100%; /* we start with equal div */
background: lightblue;
font-size: 20px;
}
#media (max-width: 1200px) {
/* update the height on toggle */
input:checked ~ .container > div:first-child > div:last-child,
input:checked ~ .container > div:last-child > div:first-child {
height: 80px;
}
}
#media (min-width: 1200px) {
.container {
grid-template-columns: 1fr 1fr 1fr 1fr; /* 4 columns */
}
.container > div {
display: contents; /* remove inner divs */
}
/* rectify the order */
.container > div:first-child > div:last-child {
grid-column: 3;
}
}
<input type="checkbox">
<div class="container">
<div>
<div> 1 </div>
<div> 3 </div>
</div>
<div>
<div> 2 </div>
<div> 4 </div>
</div>
</div>

Related

Grid area with responsive not works as expect

:root {
--min-screen-height:100px;
}
.App {
display: grid;
grid-template-columns: 0.7fr 0.9fr 1.5fr 0.9fr;
grid-template-rows: 2.75rem 3fr;
grid-template-areas:
'nav nav nav nav'
'sidebar leftmenu content rightmenu';
gap: 0.75rem 0.4rem;
}
.navigation {
grid-area: nav;
background-color: yellow;
}
.sidebar {
min-height: var(--min-screen-height);
grid-area: sidebar;
background-color: aliceblue;
}
.leftmenu {
grid-area: leftmenu;
background-color: skyblue;
}
.content {
min-height: var(--min-screen-height);
grid-area: content;
background-color: blanchedalmond;
padding: 0.5em 0.75em 0.5em 0.75em;
}
.rightmenu {
grid-area: rightmenu;
background-color: coral;
}
#media screen and (max-width: 768px) {
.App {
grid-template-columns: 1fr;
grid-template-areas:
'nav'
'content';
}
}
<div class="App">
<div class="navigation">Nav</div>
<div class="sidebar">Side bar</div>
<div class="leftmenu">Left Menu</div>
<main class="content">Main</main>
<div class="rightmenu">Right Menu</div>
</div>
In responsive until 768px I am only showing the nav and container. But still in the 768 I could see the rightmenu.
what is wrong here? or how to fix this? Please check in full page with by resizing it.
https://www.w3.org/TR/css-grid-2/#explicit-grids
The three properties grid-template-rows, grid-template-columns, and grid-template-areas together define the explicit grid of a grid container by specifying its explicit grid tracks. The final grid may end up larger due to grid items placed outside the explicit grid; in this case implicit tracks will be created, these implicit tracks will be sized by the grid-auto-rows and grid-auto-columns properties.
The grid-auto-flow property controls auto-placement of grid items without an explicit position. Once the explicit grid is filled (or if there is no explicit grid) auto-placement will also cause the generation of implicit grid tracks.
So grid-template-areas defines explicit grid. Remaining areas are put in implicit grid.
To get rid of those elements you may use:
#media screen and (max-width: 768px) {
.App {
grid-template-columns: 1fr;
grid-template-areas: "nav" "content";
}
.App :not(.navigation, .content) {
display: none;
}
}
All the divs are still there so the grid does its best to accommodate them although they say they are in grid-areas which are not defined.
To completely get rid of them you will need to set them to display none in the media query.
:root {
--min-screen-height: 100px;
}
.App {
display: grid;
grid-template-columns: 0.7fr 0.9fr 1.5fr 0.9fr;
grid-template-rows: 2.75rem 3fr;
grid-template-areas: 'nav nav nav nav' 'sidebar leftmenu content rightmenu';
gap: 0.75rem 0.4rem;
}
.navigation {
grid-area: nav;
background-color: yellow;
}
.sidebar {
min-height: var(--min-screen-height);
grid-area: sidebar;
background-color: aliceblue;
}
.leftmenu {
grid-area: leftmenu;
background-color: skyblue;
}
.content {
min-height: var(--min-screen-height);
grid-area: content;
background-color: blanchedalmond;
padding: 0.5em 0.75em 0.5em 0.75em;
}
.rightmenu {
grid-area: rightmenu;
background-color: coral;
}
#media screen and (max-width: 768px) {
.App {
grid-template-columns: 1fr;
grid-template-areas: 'nav' 'content';
}
.sidebar,
.rightmenu,
.leftmenu {
display: none;
}
}
<div class="App">
<div class="navigation">Nav</div>
<div class="sidebar">Side bar</div>
<div class="leftmenu">Left Menu</div>
<main class="content">Main</main>
<div class="rightmenu">Right Menu</div>
</div>

How to expand a sibling element of a grid?

I have a list of cards that are displayed in a grid layout.
When I click in one of these cards, a div will appear, displaying the details.
This detail element should have a minimum of 300px and occupy all space but my cards should be displayed as much as possible occupying more than 1 per row if possible.
https://jsfiddle.net/3h1kx9Lz/
.parent {
width: 100%;
gap: 10px;
display:flex;
}
.container {
grid-template-columns: repeat(auto-fit, minmax(100px, 200px));
grid-auto-rows: min-content;
gap: 10px;
display: grid;
flex-grow: 1;
align-items: flex-start;
}
.card {
height: 30px;
background: red;
}
.detail {
min-width:300px;
flex-grow:1;
background: blue;
height: 200px;
}
Here it is
.parent {
width: 100%;
display:flex;
}
and removed the flex-grow from the ,card
https://jsfiddle.net/xbc2vdg9/

Responsive design with CSS Grids

I'd like to have responsive version to this code.
body {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-areas:
"navigation-bar content content content";
margin: 0; padding: 0;
}
.navigation-bar {
grid-area: navigation-bar;
height: 100vh;
background-color: #1a1b20;
}
.content {
grid-area: content;
background-color: #202127;
}
<body>
<div class="navigation-bar"></div>
<div class="content"></div>
</body>
What I have:
#media only screen and (max-width: 600px) {
body {
}
.navigation-bar {
}
.content {
}
}
I'd like to have navigation-bar on the top of the website and content below it.
It means:
grid-template-columns should be 1fr
height of navigation-bar should be about 25vh
But I don't know, what grid-template-rows should be.
It depends on content, but if there is no content in content, it should fill whole screen (navigation-bar and content is a rest).
May you help me with responsive desige, please?
EDIT:
On mobile phone:
I would write the base styles using columnar flex and then a use grid when the screen is larger than 600px. Note that in mobile, .content uses flex-grow: 1, which means it will fill all the remaining vertical space.
.navigation-bar {
height: 15vh;
background-color: #1a1b20;
}
.content {
flex-grow: 1;
background-color: #202127;
}
body {
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
min-height: 100vh;
color: white;
}
#media only screen and (min-width: 600px) {
body {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-areas:
"navigation-bar content content content";
}
.navigation-bar {
grid-area: navigation-bar;
height: 100vh;
}
.content {
grid-area: content;
}
}
<div class="navigation-bar">navbar</div>
<div class="content">content</div>
jsFiddle

A first element should take a free space and next elements should have fixed size

I want to set for fist element '1fr' and any other elements should have fixed size
I'm tried this and it works.
grid-template-columns: 500px repeat(auto-fill, 50px);
This, what I'm trying to do.
.container {
display: grid;
grid-template-columns: 1fr repeat(auto-fill, 50px);
> div {
border: 1px solid red;
}
}
A first element should have a 1fr (any available space)
enter image description here
I think flexbox would be more appropriate here.
.container {
display: flex;
height: 98vh;
margin: 1vh 1vw;
}
.item {
border: 1px solid red;
flex: 0 0 50px;
margin: .5em;
}
.wide {
flex: 1
}
<div class="container">
<div class="item wide">Auto Remaining Width</div>
<div class="item">50px</div>
<div class="item">50px</div>
<div class="item">50px</div>
</div>

Make a grid expand to remaining height inside a flex item

There are lots of similar questions, I have reviewed all of them, but none solved my problem.
Premises:
I have a flexbox layout with flex column and the bottom flex-item filling the remainder of the page height. The flex-item gets stretched to the remainder of the page by flex 1.
Goal:
I need my grid (with its children) inside this flex-item to expand to the height of the flex-item.
Problem:
The html wrapper only has a min-height 100vh set. This makes the grid stretch to the flex-item, but not its children!
The only solution I can find is to also set height 100vh on the html wrapper, but I do not want to do this. Is there any way to solve my problem without setting height?
See the codepen here:
https://codepen.io/mesqueeb/pen/aGeKjm
See the animated GIF here to show you what I mean:
You can try this.
remove the flex-direction: column; in the .remaining and it will expand the height.
main{
min-height: calc(100vh - 51px);
display: flex;
flex-direction: column;
}
div{
border: solid goldenrod thick;
padding: 2px;
margin: 2px;
}
.full-page{
display: flex;
flex-direction: column;
height: 100%;
flex: 1;
}
.top-row{
height: 100px;
}
.remaining{
flex: 1;
display: flex;
}
.grid{
border: solid teal thick;
flex: 1;
display: grid;
grid-template-rows: 1fr 1fr 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr;
}
.key{
border: thin green solid
}
.small{
font-size: .8em
}
<main>
<div class="full-page">
<div class="top-row">
grid below will take full height only if body height is set...
</div>
<div class="remaining">
<div class="grid">
<div class="key">1</div>
<div class="key">2</div>
<div class="key">3</div>
<div class="key">4</div>
<div class="key">5</div>
<div class="key">6</div>
<div class="key">7</div>
<div class="key">8</div>
<div class="key">9</div>
<div class="key">C</div>
<div class="key">0</div>
<div class="key">➕</div>
</div>
</div>
</div>
</main>
Not sure if it solves your problem in the best way, but this works:
.remaining {
flex: 1;
/* display: flex; */
flex-direction: column;
position: relative;
}
.grid {
border: solid #008080 thick;
/* flex: 1; */
display: grid;
grid-template-rows: 1fr 1fr 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}

Resources