Creating a nestable CSS grid that maintains centering without losing background - css

I'm trying to create a CSS Grid which centers all its items both horizontally and vertically and maintains a background which takes up the whole grid.
To do this, I am first creating CSS for each item which looks something like this:
.item1 {
grid-area: header;
background:yellow;
text-align: center;
align-items: center;
display: grid;
}
The only difference between each item is its item number (in the class), the grid-area name, and the background color. I added display: grid; because without it I can't seem to both center and have the background color cover the whole grid. I don't understand why this is, but it seems to work.
My container CSS looks like this:
.container {
display: grid;
grid-template-columns: 20vw 20vw 20vw 20vw;
grid-template-rows: 25vh 25vh 25vh;
grid-template-areas:
"header header header header"
"main main subg sidebar"
"footer footer footer footer";
}
Now when I create the grid everything looks the way I want it to:
<div class="container">
<div class="item1"><H1>Header</H1></div>
<div class="item2">Main</div>
<div class="item3">Sidebar</div>
<div class="item4">Footer</div>
<div class="item5">X</div>
</div>
Now I want to achieve the exact same effect in the central item. So first I create nearly identical CSS tags for the sub-items and sub-containers. The only differences are in the naming and changing the dimensions from absolute screen based (vh/vw) to percentages:
.sub_item1 {
grid-area: header1;
background:yellow;
text-align: center;
align-items: center;
display: grid;
}
...
.sub_container {
display: grid;
grid-template-columns: 25% 25% 25% 25%;
grid-template-rows: 33% 33% 33%;
grid-template-areas:
"header1 header1 header1 header1"
"main1 main1 subg1 sidebar1"
"footer1 footer1 footer1 footer1";
}
I nest the sub-container in the center item in the top-level container:
<div class="container">
<div class="item1"><H1>Header</H1></div>
<div class="item2">Main</div>
<div class="item3">Sidebar</div>
<div class="item4">Footer</div>
<div class="item5 sub_container">
<div class="sub_item1">Header</div>
<div class="sub_item2">Main</div>
<div class="sub_item3">Side</div>
<div class="sub_item4">Footer</div>
<div class="sub_item5">X</div>
</div>
</div>
I have created a fiddle to demonstrate how it fails. The sub-container does not stretch the background color to fit the cells like the top-level does.
I tried changing the dimensions to screen based (e.g. 5vw, 11vh) and this does not work either.

Remove the "item5" class from the sub-container div.
<div class="sub_container">
Here is the updated fiddle.

Related

Having a 3 divs layout. How can I make the middle div to stay below the other two?

I was searching a way to make a responsive design like so
I have 3 divs inside a parent div
<div style="display: flex">
<div class="logo">some image here</div>
<div class="menu-items">
Home
...
</div>
<div class="login-logout">Here is the login component</div>
</div>
How can I make a responsive version of this to be something like this using only css and sass?
<div style="display: flex; flex-direction: column">
<div style="display: flex">
<div class="logo">some image here</div>
<div class="login-logout">Here is the login component</div>
</div>
<div class="menu-items">
Home
...
</div>
</div>
I want the middle div to stay bellow the other two
I have a guess that this can be possible using grid layout, but honestly I don't understand very much about it and prefer using flex. So if this could be achieved using flex I would be very much appreciated
Edit:
An image of how I want the layout to be.
flex is basically one dimensional whereas grid allows layout in two dimensions.
This snippet takes your code but sets the container to display grid.
grid-template areas are laid out for the wider screens in the ratio 2/3/1 and in the narrower ones in the ratio 2/1 in the top line.
Obviously you'll want to set the relative sizes suitable for your particular case.
.container {
width: 100vw;
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-template-areas: 'logo logo menu menu menu login';
gap: 2vw;
padding: 2vw;
box-sizing: border-box;
}
.container>* {
border: 3px solid;
box-sizing: border-box;
}
#media (max-width: 768px) {
.container {
grid-template-columns: repeat(3, 1fr);
grid-template-areas: 'logo logo login' 'menu menu menu';
}
}
.logo {
grid-area: logo;
}
.menu-items {
grid-area: menu;
}
.login-logout {
grid-area: login;
}
/* borders added fordemo */
.logo {
border-color: red;
}
.menu-items {
border-color: blue;
}
.login-logout {
border-color: green;
}
<div class="container">
<div class="logo">some image here</div>
<div class="menu-items">
Home ...
</div>
<div class="login-logout">Here is the login component</div>
</div>

Grid item not expanding with inner content height

I have a menu grid layout with an inner item (in this case it's the .metadata div) that I want to expand and push down another item. See example here :
.wrapper {
display: grid;
grid-column-gap: 8px;
grid-row-gap: 4px;
grid-template-columns: 48px minmax(0px, 3fr) 1fr;
grid-template-rows: 24px 20px 44px;
grid-template-areas:
"icon title action-bar"
"icon metadata action-bar"
"tabs .... bottom-right";
padding: 16px 16px 0 16px;
}
.metadata {
grid-area: metadata;
display: flex;
align-items: baseline;
direction: ltr;
}
.innterTest {
height: 100px;
background-color: red;
}
.metadataItem {
display: flex;
}
.tabs {
grid-area: tabs;
grid-column-end: 3;
padding-top: 4px;
}
<div class="wrapper">
<div class="icon">icon
</div>
<div class="title">TITLE
</div>
<div class="action-bar">action bar
</div>
<div class="metadata">
<div class="metadataItem">
data node 1
<div class="innterTest">
testing
</div>
</div>
<div class="metadataItem">
data node 2
</div>
<div class="metadataItem">
data node 3
</div>
<div class="metadataItem">
data node 4
</div>
</div>
<div class="tabs">tabs
</div>
</div>
https://jsfiddle.net/c8wx2bgn/
If you inspect the outer .metadata wrapping div it seems to stay a small size. What I would like to happen is for it to expand and push down the .tabs grid item. The general grid layout has been working as I had hoped, but I've added more items inside metadata and want it to push tabs down when it expands.
I've tried enforcing a height on the metadata and metadata divs but this does not seem to effect the layout. New to grid so unsure what I am missing here.
You have grid-template-rows: 24px 20px 44px.
This means that the second row, which contains your metadata div, is limited in height to 20px.
Try this: grid-template-rows: 24px auto 44px.

How do I best use CSS to make a page with tall nested elements to be limited to the height of the viewport?

How do I best enforce a page to be limited to the height of the viewport? I would like to manage the overflow-y on children elements, but it seems I cannot get the height to constrain--I can only manage a max-height in pixels or a percentage. I think I need to constrain the height of certain elements to the remaining portion (not a percentage) of the viewport height, but I can't find a way to do that.
(I am using bootstrap, but I suspect the answer isn't bootstrap-centric.)
I thought maybe I could use flex with flex-grow, but that doesn't constrain the height either. What am I missing?
<div class="container d-flex flex-column ">
<div>
My full-width page title goes here
</div>
<div class="row flex-grow-1">
<div class="col col-4">
potentially long content here
</div>
<div class="col-8">
main content
</div>
</div>
</div>
With CSS
body {
height: 100vh;
}
.row {
margin-top: 20px;
}
.col {
border: solid 1px black;
padding: 10px;
overflow-y: scroll;
}
(Fiddle)
Actual: Page is unlimited height; inner scroll bar is moot; viewport scroll bar is on
Desired: Page uses the whole height of the viewport and no more; inner scroll bar effective; no viewport scroll bar
If you aren't married to using bootstrap/flexbox, css grid makes this pretty easy.
HTML
<div class="wrapper">
<div class="header">
My full-width page title goes here
</div>
<div class="sidebar">
sidebar content
</div>
<div class="main">
main content
</div>
</div>
CSS
html, body, .wrapper {
height: 100%;
}
.wrapper {
display: grid;
grid-template-columns: 1fr 2fr;
grid-auto-rows: min-content auto;
grid-template-areas:
"header header"
"sidebar main";
}
.header {
grid-area: header;
background: red;
}
.sidebar {
grid-area: sidebar;
overflow: auto;
}
.main {
grid-area: main;
}
fiddle

CSS Grid Column Flexible for Collapsible Content

I am using CSS grid for my layout. 2 columns and three rows.
I would like the left column to be flexible so that the left column can contain a navigation bar that is collapsible, meaning that it opens/closes when I click a hamburger-menu button.
So far I have not found any examples.
Is it possible to make a column flexible from width 0 to any pixel width?
You can use min-content in grid-template-columns property and set width of sidebar div, then if you change width of this element, content div should fill the empty space. Check snippet below.
var collapsed = false
$('#btn').click(function() {
$('.sidebar').css('width', !collapsed ? '100px' : '150px')
collapsed = !collapsed
})
.grid-container {
display: grid;
grid-template-columns: min-content 1fr;
grid-template-rows: 1fr;
gap: 0px 0px;
grid-template-areas: "sidebar content";
width: 400px;
height: 300px;
}
.sidebar {
grid-area: sidebar;
background-color: red;
width: 150px;
}
.content {
grid-area: content;
background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="grid-container">
<div class="sidebar">
<button id='btn'>collapse</button>
</div>
<div class="content">content</div>
</div>

Can't work out how to align logo and nav in a row using CSS grid

I'm trying to align a logo and navigation bar in one row across the top of a website using CSS grid.
I've written out the code but can't work out what I'm doing wrong as to why it's not working: https://codepen.io/chloewb/pen/wRRewQ
.logo{
grid-area: logo;
background:white;}
.navi{
grid-area: navi;
background:Yellow;}
.section1{
grid-area: features;
background:LightSalmon;}
.section2{
grid-area: technology;
background:PaleTurquoise;}
.section3{
grid-area: pricing;
background:LightPink;}
.section4{
grid-area: email;
background:PaleGreen;}
.container {
display: grid;
grid-template-rows: repeat (5, auto);
grid-template-columns: 1fr 1fr 1fr;
font-size: 40px;
width: 100%;
background: grey;
grid-template-areas:
"logo navi navi"
"features features features"
"technology technology technology"
"pricing pricing pricing"
"email email email";}
The first thing to notice is that, when you use display: grid on a container element, its direct children will become grid-items, and to these items is that the grid layout you build will apply.
So let's say we have the following:
<div class="container">
<div class="child-1">
<div class="child-2"></div>
<div class="child-2"></div>
</div>
<div class="child-1"></div>
<div class="child-1"></div>
<div class="child-1"></div>
</div>
And this CSS:
.container{
display: grid;
}
Then only the child-1 will become grid items and be able to get properties like grid-area applied to them; everything else inside .child-1, like .child-2 will behave normally, as if there's no Grid. Unless you also specify the .child-1 element to be a grid with display: grid.
In your case, you header element is a direct child of the .container element, so it is a grid item and can be positioned on any place on the grid, but the logo and navi elements are children of header, so the grid layout does not apply to them. You would either have to take them out of the header so the rules you wrote take effect, or create another grid in the header and let it use the full first row. See this example and notice how the nesting of the elements affect them.
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: minmax(50px, auto);
grid-template-areas: "logo navi navi";
margin-bottom: 20px;
border: 1px solid black;
}
.logo {
border: 1px solid red;
grid-area: logo;
}
.navi {
border: 1px solid blue;
grid-area: navi;
}
<div class="container">
<div class="logo">Logo</div>
<div class="navi">Nav</div>
</div>
<div class="container">
<header>
<div class="logo">Logo</div>
<div class="navi">Nav</div>
</header>
</div>

Resources