Adaptive 3-columns layout with flexible height of the items without JS? - html

I have a layout for the whole website which is quite standard - header/footer, two side blocks and the main content in the center. Let's put footer/header away, they're not really interesting. What I want to achieve is two things:
Make adaptive layout on mobile phones by putting red block between cyan and green.
In the same time keep the layout on desktops flexible. Namely, I don't want to have extra spaces between blue and red blocks (when cyan block has a lot of content), nor I want extra spaces between cyan and green blocks (when blue block has a lot of content)
First I did it with flexbox, but bullet #1 was not possible in Flex. Now I rewrote it to using Grid and faced issues with #2.
Question - how do I make grid elements in each column "independent" from each other in terms of height (keeping the deterministic behavior, of course)?
Here is the schematic layout (top - desktop, bottom - mobile):
And here is the CodePen example (click on magenta block to check how does it behave and what's the issue)
var testing = true;
function startTime() {
if (testing) {
document.getElementById('info').innerHTML = "<br>LongLongContent<br>LongLongContent<br><br>LongLongContent<br>LongLongContent<br>LongLongContent<br>LongLongContent<br>LongLongContent<br>LongLongContent<br>LongLongContent<br>LongLongContent<br>";
document.getElementById('content').innerHTML = "Short content (logs block should start just after me)";
} else {
document.getElementById('content').innerHTML = "<br>LongLongContent<br>LongLongContent<br>LongLongContent<br>LongLongContent<br>LongLongContent<br>LongLongContent<br>LongLongContent<br>LongLongContent<br>";
document.getElementById('info').innerHTML = "Short content (photos block should start just after me)";
}
testing = !testing;
}
.grid-container {
display: grid;
grid-template-columns: 210px 1fr 200px;
grid-template-rows: repeat(4, auto);
gap: 0px 0px;
grid-template-areas: "header header header"
"info content sidebar"
"photos logs sidebar"
"footer footer footer";
}
.grid-container>* {
border: 1px solid red;
}
.header {
grid-area: header;
}
.info {
grid-area: info;
background-color: blue;
color: white;
}
.photos {
grid-area: photos;
background-color: red;
}
.footer {
grid-area: footer;
}
.sidebar {
grid-area: sidebar;
background-color: magenta;
}
.content {
grid-area: content;
background-color: cyan;
}
.logs {
grid-area: logs;
background-color: green;
}
<header class="grid-container">
<header class="header">Header</header>
<div class="info" id="info">Info<br>Info<br>Info<br>Info<br>Info<br>Info<br><br>Info<br></div>
<div class="photos">Photos<br>Photos<br>Photos<br>Photos<br>Photos<br></div>
<div class="content" id="content">content<br>asdasd<br><br><br>[I'm some random empty space =(]</div>
<div class="logs">logs</div>
<div class="sidebar" id="sidebar" onclick="startTime()">Click me to toggle between different sizes of content</div>
<footer class="footer">Footer</footer>
</div>

The following code shows the implementation of the structure of a variable height grid. Note that the corresponding columns must be the same height.
Using grid-template-areas: you can implement your desired structure.
Pay attention to how to implement the grid-container class
.grid-container {
display: grid;
grid-template-columns: 25% 50% 25%;
grid-gap: 0px;
background-color: black;
grid-template-areas:
"one two three"
"one four three"
"five six three"
}
With grid-template-columns: 25% 50% 25%; 3 columns are defined.
Then with
grid-template-areas:
"one two three"
"one four three"
"five six three"
3 rows are defined by 3 columns.
I used the following code for the responsive mode
#media only screen and (max-width: 600px) {
.grid-container {
display: grid;
grid-template-columns: 100%;
grid-gap: 10px;
background-color: black;
grid-template-areas:
"two"
"four"
"five"
"six"
}
}
Full code:
.grid-container {
display: grid;
grid-template-columns: 25% 50% 25%;
grid-gap: 0px;
background-color: black;
grid-template-areas: "one two three" "one four three" "five six three"
}
#one {
grid-area: one;
height: auto;
width: 100%;
background-color: blue;
}
#two {
grid-area: two;
height: 50px;
width: 100%;
background-color: yellow;
}
#three {
grid-area: three;
height: auto;
width: 100%;
background-color: #365263;
}
#four {
grid-area: four;
height: auto;
width: 100%;
background-color: aqua;
}
#five {
grid-area: five;
height: auto;
width: 100%;
background-color: red;
}
#six {
grid-area: six;
height: auto;
width: 100%;
background-color: green;
}
.grid-container>div {
text-align: center;
padding: 20px 0;
font-size: 30px;
}
#media only screen and (max-width: 600px) {
.grid-container {
display: grid;
grid-template-columns: 100%;
grid-gap: 10px;
background-color: black;
grid-template-areas: "two" "four" "five" "six"
}
}
<h1>The grid-column Property</h1>
<div class="grid-container">
<div id="one">2<br>2<br>2<br>2<br>2<br>2<br>2<br>2<br>1</div>
<div id="two"></div>
<div id="three">3</div>
<div id="four">4<br>4<br>4<br>4<br>4<br>4<br>4<br>4<br>4<br>4<br>4<br>4<br>4<br>4<br>4<br></div>
<div id="five">5</div>
<div id="six">6</div>
</div>

Related

How can I get my grid column to stay the same size (height and width) when resizing viewports?

I have a container that will have a picture of the day. When changing viewport sizes (mobile screen size) the container gets squashed so much that the image is not readable.. How can I get the containers in my grid system to stay the exact same size relative to the viewport? Thank you!!
html,
body,
form,
main {
height: 100%;
}
body {
background-color: #232A35;
padding: 10px;
}
.content {
height: 100%;
margin-left: auto;
margin-right: auto;
}
.mainheader {
border: 1px red solid;
width: 100%;
}
.iotd {
grid-area: iotd;
}
.banner {
grid-area: banner;
}
.solutions {
grid-area: solutions;
}
.services {
grid-area: services;
}
.tud {
grid-area: tud;
}
.resources {
grid-area: resources;
}
.grid-container {
display: grid;
grid-template-areas: 'iotd banner banner banner banner banner' 'iotd solutions services resources tud tud';
gap: 10px;
background-color: #2196F3;
padding: 10px;
height: 100%;
}
.grid-container>div {
background-color: rgba(255, 255, 255, 0.8);
text-align: center;
padding: 20px 0;
font-size: 30px;
}
#media screen and (max-width: 900px) {
.grid-container>div {
font-size: 10px;
}
}
<div class="content">
<div class="container-fluid mainheader">
<div class="grid-container">
<div class="iotd col">IOTD</div>
<div class="banner col">Banner</div>
<div class="solutions col">Solutions</div>
<div class="services col">Services</div>
<div class="tud col">The Unrecovery Difference</div>
<div class="resources col">Resources</div>
</div>
</div>
</div>
The container that will hold the image is labeled as "IOTD"
Any help is appreciated
resolved the issue by changing the image size rather than the container size when the viewport reaches 900px. I also change the font size to a smaller size which in turn makes all of the containers smaller
One approach might be to include a grid-template-columns rule to specify how you want the horizontal space apportioned, this can include a minimum absolute (px) width for the first column with the option of allowing it to grow when more space is available using minmax.
For example, I've added the following rule to your css:
grid-template-columns: minmax(150px, 1fr) repeat(5, 1fr);
This divides the grid into 6 columns to be consistent with your area template (which remains in operation) but makes the first column at least 150px wide with the option of expanding with the other columns when extra width is available. The remaining five columns are allocated 1/5 of the available space by specifying 5 1fr fractions.
Here's the rule added to your example:
html,
body,
form,
main {
height: 100%;
}
body {
background-color: #232A35;
padding: 10px;
}
.content {
height: 100%;
margin-left: auto;
margin-right: auto;
}
.mainheader {
border: 1px red solid;
width: 100%;
}
.iotd {
grid-area: iotd;
}
.banner {
grid-area: banner;
}
.solutions {
grid-area: solutions;
}
.services {
grid-area: services;
}
.tud {
grid-area: tud;
}
.resources {
grid-area: resources;
}
.grid-container {
display: grid;
grid-template-areas: 'iotd banner banner banner banner banner' 'iotd solutions services resources tud tud';
grid-template-columns: minmax(150px, 1fr) repeat(5, 1fr);
gap: 10px;
background-color: #2196F3;
padding: 10px;
height: 100%;
}
.grid-container>div {
background-color: rgba(255, 255, 255, 0.8);
text-align: center;
padding: 20px 0;
font-size: 30px;
}
#media screen and (max-width: 900px) {
.grid-container>div {
font-size: 10px;
}
}
<div class="content">
<div class="container-fluid mainheader">
<div class="grid-container">
<div class="iotd col">IOTD</div>
<div class="banner col">Banner</div>
<div class="solutions col">Solutions</div>
<div class="services col">Services</div>
<div class="tud col">The Unrecovery Difference</div>
<div class="resources col">Resources</div>
</div>
</div>
</div>
This page https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Grid_Template_Areas has examples where grid-template-areas are combined with grid-template-columns (it also has some ideas on using media queries to suit different view ports).

how to use css grid to display components at particular area

here's my html code
<div>
<div id="navbar" class="box">Navbar</div>
<div id="sidenav " class="box">Side Navbar</div>
<div id="main " class="box">Main</div>
<div id="footer " class="box">Footer</div>
</div>
and here's my scss code
div{
display: grid;
width:100%;
height: 100%;
grid-template-columns: 25% 75% 25%;
grid-gap: 15px;
grid-template-rows:25% 50% 25% ;
// grid-gap: 15px;
grid-template-areas:
"hd hd hd "
"sd ma ma "
"ft ft ft ";
.box{
display: flex;
// text-align: center;
border: 3px solid red;
/* width:150px;
height: 150px; */
margin: auto;
align-items: center;
justify-content: center;
}
#navbar{
grid-area: hd;
}
#sidenav{
grid-area: sd;
}
#main{
grid-area: ma;
}
#footer{
grid-area: ft;
}
}
the problem is the footer div doesn't display in the bottom here's a screenshot
what i want is to make the footer display at the bottom so what seems to be the problem here
There are some issues that I found in your code which makes the layout little wonky.
grid-template-columns: 25% 75% 25%;
The column total is more than 100%, so it will not work perfectly.
I would highly recommend you to use a CSS grid generator online like https://grid.layoutit.com/
For your layout, I would also not recommend structure 3x3 (columns and rows) - As from the image you shared above it looks like the following
1 row - For "Navbar" (this doesnt need any sub columns)
1 row - For Content -> this has 2 columns 1 for "SideNav" and 1 for "Main"
1 row - For "Footer" (again you dont need sub columns)
Based on this your HTML structure will end up looking like
<div class="container">
<div class="navbar">Navbar</div>
<div class="Content">
<div class="SideNav">Side Nav</div>
<div class="Main">Main</div>
</div>
<div class="Footer">Footer</div>
</div>
And your CSS will look like this
body{
padding: 0;
margin: 0;
}
.container {
width: 100vw;
height: 100vh;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 25% 50% 25%;
gap: 0px 0px;
grid-template-areas:
"navbar"
"Content"
"Footer";
}
.navbar {
grid-area: navbar;
background-color: #f5f5f5;
padding: 16px;
text-align: center;
}
.Content {
display: grid;
grid-template-columns: 360px 1fr;
grid-template-rows: 1fr;
gap: 0px 0px;
grid-template-areas:
"SideNav Main";
grid-area: Content;
}
.SideNav {
grid-area: SideNav;
background-color: #e5e5e5;
padding: 16px;
}
.Main {
grid-area: Main;
background-color: salmon;
padding: 16px;
}
.Footer {
grid-area: Footer;
background-color: #d5d5d5;
padding: 16px;
text-align: center;
}
Here, if you check the code well, the container has 3 rows (25% - navbar, 50% - content, 25% - footer)
And then content has 2 columns (360px - Sidenav, 1fr - Main)
Hope this helps :)
You can also see the code live on my codepen : https://codepen.io/raunaqpatel/pen/WNyQqmm
Or here:
body{
padding: 0;
margin: 0;
}
.container {
width: 100vw;
height: 100vh;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 25% 50% 25%;
gap: 0px 0px;
grid-template-areas:
"navbar"
"Content"
"Footer";
}
.navbar {
grid-area: navbar;
background-color: #f5f5f5;
padding: 16px;
text-align: center;
}
.Content {
display: grid;
grid-template-columns: 360px 1fr;
grid-template-rows: 1fr;
gap: 0px 0px;
grid-template-areas:
"SideNav Main";
grid-area: Content;
}
.SideNav {
grid-area: SideNav;
background-color: #e5e5e5;
padding: 16px;
}
.Main {
grid-area: Main;
background-color: salmon;
padding: 16px;
}
.Footer {
grid-area: Footer;
background-color: #d5d5d5;
padding: 16px;
text-align: center;
}
<div class="container">
<div class="navbar">Navbar</div>
<div class="Content">
<div class="SideNav">Side Nav</div>
<div class="Main">Main</div>
</div>
<div class="Footer">Footer</div>
</div>

CSS "grid-template-areas" not working as desired

I thought that when I type . (blank field) inside grid-template-areas property, .item5 will show inside under field. However it showing inside . field. Why does it works like that?
body {
margin: 0;
}
.item1 {
grid-area: header;
}
.item2 {
grid-area: content;
}
.item3 {
grid-area: left;
}
.item4 {
grid-area: footer;
}
.grid-container {
display: grid;
grid-template-columns: 300px 1fr;
grid-template-areas: "header header"
"content ."
"left ."
"footer footer"
"under under";
grid-gap: 10px;
background-color: #2196F3;
padding: 10px;
}
.grid-container > div {
background-color: rgba(255, 255, 255, 0.8);
text-align: center;
padding: 20px 0;
font-size: 30px;
}
<div class="grid-container">
<div class="item1">1</div>
<div class="item2">2</div>
<div class="item3">3</div>
<div class="item4">4</div>
<div class="item5">5</div>
</div>
From the specification:
A sequence of one or more "." (U+002E FULL STOP), representing a null cell token.
and
A null cell token represents an unnamed area in the grid container.
unnamed area doesn't mean that an item cannot be placed there. It simply mean unnamed and the automatic placement algorithm will start from the top to the bottom so the first empty area for item5 is an unnamed area.
You can follow the full algorithm here: https://www.w3.org/TR/css-grid-1/#auto-placement-algo where you will find no restriction about unnamed area or the named one. If your item5 was alone it will get placed into the first row/column (the one named "header")
body {
margin: 0;
}
.item1 {
grid-area: header;
}
.item2 {
grid-area: content;
}
.item3 {
grid-area: left;
}
.item4 {
grid-area: footer;
}
.grid-container {
display: grid;
grid-template-columns: 300px 1fr;
grid-template-areas: "header header"
"content ."
"left ."
"footer footer"
"under under";
grid-gap: 10px;
background-color: #2196F3;
padding: 10px;
}
.grid-container > div {
background-color: rgba(255, 255, 255, 0.8);
text-align: center;
padding: 20px 0;
font-size: 30px;
}
<div class="grid-container">
<div class="item5">5</div>
</div>
Related question where I am giving a more detailed explanation about the placement algorithm:
CSS Grid : How Auto placement algorithm works
Based on your last comment, I think that you are expecting to have grid-auto-flow: column;, but this is not the default style.
I added it to the snippet:
body {
margin: 0;
}
.item1 {
grid-area: header;
}
.item2 {
grid-area: content;
}
.item3 {
grid-area: left;
}
.item4 {
grid-area: footer;
}
.grid-container {
grid-auto-flow: column;
display: grid;
grid-template-columns: 300px 1fr;
grid-template-areas: "header header"
"content ."
"left ."
"footer footer"
"under under";
grid-gap: 10px;
background-color: #2196F3;
padding: 10px;
}
.grid-container > div {
background-color: rgba(255, 255, 255, 0.8);
text-align: center;
padding: 20px 0;
font-size: 30px;
}
<div class="grid-container">
<div class="item1">1</div>
<div class="item2">2</div>
<div class="item3">3</div>
<div class="item4">4</div>
<div class="item5">5</div>
</div>

When using CSS grid, i don't want some grid areas to expand

I'm starting to use CSS grid. So far, so good. I want some grid areas NOT to expand when other areas do.
This is what i have now
I'm designing mobile first, then desktop. The grid on the desktop, if you notice, the 'album' area expands when the body expands. I don't want that. I want the areas 'album', 'credits', 'version' to retain the height even if the 'body' or the 'comment' area expand. In other words, when a grid area expands, the other areas height remain intact.
https://jsfiddle.net/e9n4ac5d/
.grid {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto;
grid-template-areas: "body" "album" "credit" "version" "comment";
}
#media screen and (min-width: 400px) {
.grid {
grid-template-columns: 2fr 1fr;
grid-template-rows: auto;
grid-template-areas: "body album" "comment credit" "comment version";
}
}
.body {
grid-area: body;
background-color: red;
}
.album {
grid-area: album;
background-color: pink;
}
.credit {
grid-area: credit;
background-color: green;
}
.version {
grid-area: version;
background-color: yellow;
}
.comment {
grid-area: comment;
background-color: #eee;
}
<div class="grid">
<div class="body">body
<br><br><br><br><br><br>
</div>
<div class="album">album</div>
<div class="credit">credits</div>
<div class="version">version</div>
<div class="comment">comments</div>
</div>
You can change your HTML structure like this:
.grid {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto;
grid-template-areas: "body" "album" "credit" "version" "comment";
}
#media screen and (min-width: 400px) {
.right {
grid-area: right;
}
.grid {
grid-template-columns: 2fr 1fr;
grid-template-rows: auto;
grid-template-areas: "body right" "comment right";
}
}
.body {
grid-area: body;
background-color: red;
}
.album {
grid-area: album;
background-color: pink;
height: 50px;
}
.credit {
grid-area: credit;
background-color: green;
height: 50px;
}
.version {
grid-area: version;
background-color: yellow;
height: 50px;
}
.comment {
grid-area: comment;
background-color: #eee;
}
<div class="grid">
<div class="body">body
<br><br><br><br><br><br>
</div>
<div class="right">
<div class="album">album</div>
<div class="credit">credits</div>
<div class="version">version</div>
</div>
<div class="comment">comments</div>
</div>
Just set fixed height and width... To make it non expandable and non compressible...

Move elements from nested "CSS Grid" to the outside

I want to bring out the elements from a nested grid at a smaller screen width. In the example, the elements are all set to one another when the screen reaches a certain pixel width.
I would like the elements to be displayed one after the other, and to return to the original area with a larger pixel width. Probably this is a fairly simple solution but I could not find any tip yet. Maybe someone has an idea?
body {
margin: 40px;
}
.sidebar {
grid-area: sidebar;
}
.sidebar2 {
grid-area: sidebar2;
}
.content {
grid-area: content;
}
.header {
grid-area: header;
}
.footer {
grid-area: footer;
}
.wrapper {
background-color: #fff;
color: #444;
}
.wrapper {
display: grid;
grid-gap: 1em;
grid-template-areas: "header" "sidebar" "content" "sidebar2" "footer"
}
#media only screen and (min-width: 500px) {
.wrapper {
grid-template-columns: 20% auto;
grid-template-areas: "header header" "sidebar content" "sidebar2 sidebar2" "footer footer";
}
}
#media only screen and (min-width: 600px) {
.wrapper {
grid-gap: 20px;
grid-template-columns: 120px auto 120px;
grid-template-areas: "header header header" "sidebar content sidebar2" "footer footer footer";
max-width: 600px;
}
}
.box {
background-color: #444;
color: #fff;
border-radius: 5px;
padding: 10px;
font-size: 150%;
}
.header,
.footer {
background-color: #999;
}
.sidebar2 {
background-color: #ccc;
color: #444;
}
<div class="wrapper">
<div class="box header">Header</div>
<div class="box sidebar">Sidebar</div>
<div class="box sidebar2">Sidebar 2</div>
<div class="box content"> Content
<div class="box nested_sidebar">Sidebar 2</div>
<div class="box nested_sidebar">Sidebar 2</div>
</div>
<div class="box footer">Footer</div>
</div>
The grid container is the parent element.
The grid items are the child elements (and only the child elements; descendants beyond the children are not grid items).
The child elements of grid items are, well, whatever they may be, they are not children of the main container, so they are not grid items and cannot accept grid properties like their grid item parents.
Therefore, unless you want to use absolute positioning, there is no clean CSS method for moving nested elements into the main grid container.
However, how about removing the nesting? Grid is very good at allowing elements to overlap.
jsFiddle demo
.wrapper {
display: grid;
grid-template-rows: 1fr;
grid-gap: 1em;
grid-template-areas: "header"
"sidebar"
"content"
"..."
"..."
"sidebar2"
"footer"
}
#media only screen and (min-width: 500px) {
.wrapper {
grid-template-columns: 20% 1fr;
grid-template-rows: 100px repeat(3, 50px) 100px;
grid-template-areas: "header header"
"sidebar content"
"sidebar content"
"sidebar content"
"sidebar2 sidebar2"
"footer footer";
}
.nested_sidebar1 {
grid-row: 3 / 4;
grid-column: 2 / 3;
}
.nested_sidebar2 {
grid-row: 4 / 5;
grid-column: 2 / 3;
}
}
#media only screen and (min-width: 800px) {
.wrapper {
grid-gap: 20px;
grid-template-columns: 120px auto 120px;
grid-template-rows: 100px repeat(3, 50px) 100px;
grid-template-areas: "header header header"
"sidebar content sidebar2"
"sidebar content sidebar2"
"sidebar content sidebar2"
"footer footer footer";
}
}
.box {
background-color: #444;
color: #fff;
border-radius: 5px;
padding: 10px;
font-size: 150%;
}
.header {
grid-area: header;
background-color: #999;
}
.sidebar {
grid-area: sidebar;
}
.sidebar2 {
grid-area: sidebar2;
background-color: #ccc;
color: #444;
}
.content {
grid-area: content;
}
.nested_sidebar1 {
background-color: orange;
}
.nested_sidebar2 {
background-color: tomato;
}
.footer {
grid-area: footer;
background-color: #999;
}
<div class="wrapper">
<div class="box header">Header</div>
<div class="box sidebar">Sidebar</div>
<div class="box sidebar2">Sidebar 2</div>
<div class="box content">Content</div>
<div class="box nested_sidebar1">Sidebar 2a</div>
<div class="box nested_sidebar2">Sidebar 2b</div>
<div class="box footer">Footer</div>
</div>
I would play around with using fr instead of % as well as including grid-template-rows to get your desired result.
If you post a wire-frame of what you're hoping to achieve I'd be happy to give it a shot.