I'm using the following grid layout:
grid-template-columns: 10em 1fr 10em;
grid-template-rows: 2em 1fr 2em;
To create a centered area that fills most of the screen while leaving some padding around it. Inside this 1fr x 1fr grid area is a pane div which contains an editor div which contains a content div.
The content div can be any height, and the editor div has overflow: scroll set. My problem is that instead of pane staying the same size and editor handling the overflow, pane grows and causes the whole page to scroll.
I can keep pane from growing by setting its overflow: scroll, but this causes the editor itself to scroll, rather than its content. This is unacceptable because the editor has buttons which must always be on screen.
Is there a way, within grid layout, to allow this functionality? I originally had it working with a flex layout, where the pane div was a single item within a 100% x 100% flexbox. I switched to grid to allow me to easily resize side-menus, so implementing this without grid is not preferable.
Also, multi-browser support would be amazing, but my target browser is Chrome.
Here's a jsfiddle with my reproducing my problem.
body, html {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
#site {
width: 100%;
height: 100%;
background-color: #000;
display: grid;
grid-template-rows: 10em 1fr 10em;
grid-template-columns: 2em 1fr 2em;
grid-template-areas:
'top top top'
'lpn mid rpn'
'bot bot bot';
}
#pane {
grid-area: mid;
height: 100%;
width: 100%;
background-color: #f0f;
}
#editor {
display: relative;
overflow: scroll;
}
#content {
height: 2000px;
}
<div id='site'>
<div id='pane'>
<div id='editor'>
<div id='content'>
</div>
</div>
</div>
</div>
min-width: auto / min-height: auto
Generally speaking, a grid item cannot be smaller than its content. The default minimum size of grid items is min-width: auto and min-height: auto.
This often causes grid items to overflow their grid areas or grid containers. It also prevents scrollbars from rendering on the items, since an overflow condition can't be triggered (the grid item just keeps expanding).
To override this default (and allow grid items to shrink past their content size) you can use min-width: 0, min-height: 0 or overflow with any value other than visible.
This behavior, with references to official documentation, is explained in this post:
Prevent content from expanding grid items
1fr
Another thing to note is that 1fr means minmax(auto, 1fr). This means, again, that the track to which it is applied cannot shrink below the content size (i.e., the min value in the minmax() function is auto, meaning content-based).
Therefore, to override this setting, use minmax(0, 1fr) instead of 1fr.
More details here: https://github.com/w3c/csswg-drafts/issues/1777
revised demo (tested in Chrome, Firefox and Edge)
body, html {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
#site {
width: 100%;
height: 100%;
background-color: #000;
display: grid;
/* grid-template-rows: 10em 1fr 10em; */
grid-template-rows: 10em minmax(0, 1fr) 10em; /* new */
grid-template-columns: 2em 1fr 2em;
grid-template-areas:
'top top top'
'lpn mid rpn'
'bot bot bot';
}
#pane {
grid-area: mid;
height: 100%;
width: 100%;
background-color: #f0f;
overflow: auto; /* new */
}
#editor {
/* display: relative; */
/* overflow: scroll; */
}
#content {
height: 2000px;
}
<div id='site'>
<div id='pane'>
<div id='editor'>
<div id='content'></div>
</div>
</div>
</div>
jsFiddle demo
Not 100% sure if this is what you're asking. I added a wrapper to content to make it scrollable, and set a vh height on it, which you could adjust.
#content-scroll {
height: 40vh;
overflow: scroll;
}
#content {
height: 2000px;
}
<div id='site'>
<div id='pane'>
<div id='editor'>
<div id='content-scroll'>
<div id='content'>
</div>
</div>
</div>
</div>
</div>
https://jsfiddle.net/16owL8x0/
Related
I am new to CSS and HTML and have a setup of divs in CSS, something like this:
#topBar {
margin-top: 0;
height: 100px;
width: 100%
}
#sideBar {
width: 50px;
margin-left: 0;
margin-top: 100px;
height: 100%;
}
#main {
margin-left: 50px;
margin-top: 100px;
margin-bottom: 50px;
}
#footer {
margin-bottom: 0;
width: 100%;
}
<div id="container">
<div id="topbar" />
<div id="sidebar" />
<div id="main" />
<div id="footer" />
</div>
But that does not look anything like how I want it. It leaves space for every div, even though their space is restricted to x width and x height.
How could I set up divs to look as desired? Ie have a footer, main, sidebar, and topbar in CSS?
CSS actually has built in grid "builder" that you can use. I was doing something similar not long ago and ended up doing it like this:
#container {
display: grid; //uses grid
height: 100vh; // vh and vw is percentages of the screens width and height, nice for scaling for different devices
width: 100vw;
grid-template-columns: 1fr 9fr; // sets how big columns are, this sets the column quantity to two, and the first one gets 1 fraction of the are, and column two gets 9 fractions. 1fr is for sidebar
grid-template-rows: 1.5fr 15fr 3fr; // Same as with column, but this includes footer, so 1.5 fraction goes to top bar, 15 fractions to sidebar and main area, and 3 fractions to footer
grid-template-areas:
"header header" // sets area to use, the same area given space in above lines. They can be directly referenced in other parts of the css documents.
"navbar main"
"footer footer";
}
#topbar {
grid-area: header; // Referencing previous made areas
display: flex; // I used this to make the top bar, as this would align the items in the bar horizontally with same amount of space between
justify-content: space-between;
align-items: center; //used this to center items vertically
}
#sidebar {
grid-area: sidebar;
text-align: center; // used this to align the text center horizontally
}
#main {
grid-area: main;
}
#footer {
grid-area: footer;
}
You should use the semantic tags such as the header, nav, aside, footer and main.
Then apply the grid directly to the body element instead of wrapping them in an extra container:
body {
margin: 0; /* removes default margin */
display: grid; /* uses grid */
min-height: 100vh; /* will expend the grid to the entire viewport */
grid-template-columns: 1fr 2fr; /* sets the column width and amount */
grid-template-rows: min-content auto min-content; /* sets the row height to push the footer at the bottom and let the main fill the rest */
gap: 5px; /* placing the items apart */
}
header,
footer {
grid-column: 1 / -1; /* letting those element span the entire row */
}
/* for styling purpose only */
header,
aside,
main,
footer {
border: 2px dashed red;
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
}
<header>Topbar</header>
<aside>Sidebar</aside>
<main>Main</main>
<footer>Footer</footer>
This question already has an answer here:
Why does minmax(0, 1fr) work for long elements while 1fr doesn't?
(1 answer)
Closed last year.
Problem: I am having a problem with sizing images inside css grid column/rows. I essentially object-fit: contain the imagesinside their individual cells.
The image in "SPOT 4" is not filling the given space
If you uncomment the image in "SPOT 1", it will cover the entire grid and is not confined to its own css grid cell.
I have tried setting max-width, object-fit and others on the video level and .channel-container level with no success.
Background: The .parent-trap css class is just an example height/width. This will vary, it may be the entire browser window, or it may be small so I cannot depend on any specific min/max dimensions. There are also other .display4 in the full version that sometimes shows a single video that fills the whole grid, side by side that only shows 2 at a time etc, so any specific dimensions also tend to break individual .display*
html,
body {
border: 0;
margin: 0;
height: 100%;
}
.parent-trap {
height: 540px;
width: 960px;
}
/* container for player */
.video-player {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
max-height: 100%;
max-width: 100%;
min-height: 100%;
min-width: 100%;
}
/* container for plaback control bar */
.container-controls {
height: 50px;
background-color: red;
}
/* contains all the .channel-container s */
.channel-layout-container {
display: grid;
background: #000;
background-color: blue;
flex: 1;
}
/****
**** FIX HERE
****/
.channel-container {}
img {}
/** THERE ARE OTHER DYNAMIC LAYOUTS, ISSUE IS SAME ON ALL */
/** display4 **/
.channel-layout-container.display4 {
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
.channel-layout-container.display4 .channel-container:nth-child(n+5) {
flex: none;
display: none;
}
<!-- try restricting various sizes -->
<div class="parent-trap">
<!-- the classcommes that need to be transferred back over-->
<div class="video-player">
<div class="channel-layout-container display4">
<div class="channel-container" style="background-color: khaki;">
<!-- <img src="https://w.wallhaven.cc/full/3z/wallhaven-3zgz2y.png" />-->
</div>
<div class="channel-container" style="background-color: lavender;">
SPOT 2
</div>
<div class="channel-container" style="background-color: lightcoral;">
SPOT 3
</div>
<div class="channel-container" style="background-color: lightseagreen;">
<img src="https://www.google.com/favicon.ico" />
</div>
</div>
<div class="container-controls">
common controls and other info goes here
</div>
</div>
</div>
Your issue results from your grid template definition.
Replace 1fr 1fr with repeat(2, minmax(0, 1fr)).
The reason for your problem is that 1fr effectively means minmax(auto, 1fr). minmax works such that if the first argument is greater than the second, the whole minmax expression is replaced by the first argument, so your whole definition becomes
grid-template-columns: auto auto;
grid-template-rows: auto auto;
Setting minmax(0, 1fr) prevents this and effectively sets what you did by setting min-width/-height to 0.
I ended up needing 3 things, I'm not entirely sure what the min-width/height: 0 are doing to fix my issue but it works
.channel-layout-container {
min-height: 0; /* NEW */
min-width: 0; /* NEW; needed for Firefox */
}
.channel-container {
min-height: 0; /* NEW */
min-width: 0; /* NEW; needed for Firefox */
}
img {
display:block;
width :100%;
height:100%;
object-fit:cover;
}
html,
body {
border: 0;
margin: 0;
height: 100%;
}
.parent-trap {
height: 540px;
width: 960px;
}
/* container for player */
.video-player {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
max-height: 100%;
max-width: 100%;
min-height: 100%;
min-width: 100%;
}
/* container for plaback control bar */
.container-controls {
height: 50px;
min-height: 50px;
max-height: 50px;
background-color: red;
}
/* contains all the .channel-container s */
.channel-layout-container {
display: grid;
background: #000;
background-color: blue;
flex: 1;
min-height: 0; /* NEW */
min-width: 0; /* NEW; needed for Firefox */
}
/****
**** FIX HERE
****/
.channel-container {
min-height: 0; /* NEW */
min-width: 0; /* NEW; needed for Firefox */
}
img {
display:block;
width :100%;
height:100%;
object-fit:cover;
}
/** THERE ARE OTHER DYNAMIC LAYOUTS, ISSUE IS SAME ON ALL */
/** display4 **/
.channel-layout-container.display4 {
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
.channel-layout-container.display4 .channel-container:nth-child(n+5) {
flex: none;
display: none;
}
<div class="parent-trap">
<!-- the classcommes that need to be transferred back over-->
<div class="video-player">
<div class="channel-layout-container display4">
<div class="channel-container" style="background-color: khaki;">
<img src="https://w.wallhaven.cc/full/3z/wallhaven-3zgz2y.png" />
</div>
<div class="channel-container" style="background-color: lavender;">
SPOT 2
</div>
<div class="channel-container" style="background-color: lightcoral;">
SPOT 3
</div>
<div class="channel-container" style="background-color: lightseagreen;">
<img src="https://www.google.com/favicon.ico" />
</div>
</div>
<div class="container-controls">
common controls and other info goes here
</div>
</div>
</div>
You can see now that changing .parent-trap dimensions keep the proper proportions , control bar is always available and just the displays adjust as necessary.
I have an svg image (with the class content__img) has a default width of 760.7 and height of 687.08,
in the grid container there are 2 columns and 2 rows of `` `1fr```, this image is found
in the first cell, and since the image size is bigger than the first row,
the image enlarges the height of the row:
taking this into account
1.- If I specify that the image has a height
from 100% the image does not fit the height of the first row
Why is this happening? Shouldn't it be the size of the row at that moment?
Because with block type elements (and the other elements in general)
if they take the size of the current row, as far as I know, by default they take the width and height of the cell
(it also doesn't work assigning display: block to the image)
HTML:
<body>
<div class="content">
<img class="content__img" src="../../assets/images/test.svg" alt="Test">
</div>
</body>
CSS:
.content {
width: 80%;
height: 80%;
background-color: beige;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
.content__img {
height: 100%;
}
2.- If I wrap the image in a container div
(with class content__img-box), this also doesn't work, despite
that the div takes the width and height of 100% of the cell, therefore, if I set the height of the image to 100%, why does the image
doesn't take the 100% from the div (content__img-box)?
HTML:
<body>
<div class="content">
<div class="content__img-box">
<img class="content__img" src="../../assets/images/test.svg" alt="Test">
</div>
</div>
</body>
CSS:
.content {
width: 80%;
height: 80%;
background-color: beige;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
.content__img {
height: 100%;
}
This is the result I want (obviously you can give a fixed or non-dynamic size to the row and that works, but the purpose is that the image is attacked if the grid container grows):
As promised, the explaination:
The grid-template-rows: 1fr 1fr; will not work as you intend to. Unfortunatly 1fr as template-row is counter-intuitive. It will not care for the parents height at all. 1fr 1fr will take the heighest row height of both rows and add the same height for the other row aswell. As such the containers height will be overwritten and as such broken. for 50% 50% to work, you need to to give the grid-contaienr a specific height!
I wrapped the images inside a <div>. The whole reason to do this, is to add a the object-fit property. This will allow me to resize the image to fit inside the containing <div> without breaking its aspect-ratio and without being clipped. I added a max-height-width: 100%; to the image itself. This will down-size the image to fit inside the container (not overflow the container). But also allows the image to be smaller then the container. If I wouldnt add this but use a fixed 100%, the image aspect-ratio would be changed as the image then would fill the entire height and width no matter of the aspect ratio.
Also I added display:flex, justify-content: center; align-items: center;. This will move the image into the center of the grid-card if the image does not fill out the entire grid-card.
.content {
height: 100vh;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 50% 50%;
}
.content > div {
display: flex;
justify-content: center;
align-items: center;
object-fit: contain;
}
.content > div > img {
max-height: 100%;
max-width: 100%;
}
/*for demonstration purpose only */
body {
margin: 0;
}
.content > div {
border: 2px solid red;
}
<div class="content">
<div>
<img src="https://via.placeholder.com/1024x720.svg">
</div>
<div>
<img src="https://via.placeholder.com/800.svg">
</div>
<div>
<img src="https://via.placeholder.com/1920x1080.svg">
</div>
<div>
<img src="https://via.placeholder.com/150x300.svg">
</div>
</div>
This question already has answers here:
Percentage Height HTML 5/CSS
(7 answers)
Closed 2 years ago.
I am pretty new to Web development and I am trying to learn CSS grids. While learning the CSS grid I tried to make one simple layout. It has one header section, one menu section, one sidebar section, and one footer section.
I used auto while defining grid template rows for the 2nd row, and gave conatiner height as 100%, so that 2nd row will stretch fully in the remaining space left by row 1 and 2.
But it didn't work that way, i am trying to figure out why 2nd row is not stretching vertically in the remaning space left.
Here is the conatiner css in which i defined the 2nd row as auto and conatiner height as 100%.
.container {
height: 100%;
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 40px auto 40px;
}
fiddle link:
https://jsfiddle.net/791vtd4z/
That is because you did not give body a fixed height, yet you have .container a relative height: therefore, when the child .container simply stretches to its content height and not any further, since there's nothing absolute to compare against by using 100% (ask yourself: "100% of what?").
A solution will be to set .container { min-height: 100vh; } to fix that, which tells the element to at least be as tall as the viewport, and allow it to grow should the content inside menu or sidebar grow beyond what the viewport can contain.
* {
margin: 0;
top: 0;
bottom: 0;
font-family: sans-serif;
font-size: 1.2em;
}
title {
display: none;
}
.container {
min-height: 100vh;
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 40px auto 40px;
}
.Header {
background-color: beige;
grid-column: 1/-1;
}
.Menu {
background-color: red;
}
.Sidebar {
background-color: burlywood;
grid-column: 2/-1;
}
.Footer {
background-color: aquamarine;
grid-column: 1/-1;
}
<div class="container">
<div class="Header">Header</div>
<div class="Menu">Menu</div>
<div class="Sidebar">Sidebar</div>
<div class="Footer">Footer</div>
</div>
To build on Terry's answer, you can achieve your desired result by giving body a height of 100vh, you could change the height of .container to 100vh, or you could give html and body a height of 100% (and keep the 100% height of .container).
This is because 100vh gives an element the full height of the viewport regardless of the height of its parents, while setting an element's full height using a percentage (i.e. 100%) means the element takes the full height of its parent, whatever that is. So an element with a height of 100% could still be zero, if its parent has no height.
To put this another way, when setting an element's height to 100% all of its parents need to be 100% as well for that element to take up the full viewport.
html, body{
height: 100%;
}
* {
margin: 0;
top: 0;
bottom: 0;
font-family: sans-serif;
font-size: 1.2em;
}
title {
display: none;
}
.container {
height: 100%;
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 40px auto 40px;
}
.Header {
background-color: beige;
grid-column: 1/-1;
}
.Menu {
background-color: red;
}
.Sidebar {
background-color: burlywood;
grid-column: 2/-1;
}
.Footer {
background-color: aquamarine;
grid-column: 1/-1;
}
<div class="container">
<div class="Header">Header</div>
<div class="Menu">Menu</div>
<div class="Sidebar">Sidebar</div>
<div class="Footer">Footer</div>
</div>
Goal is to build a page the expands the height of the main content to remaining height of page but not to exceed the visible area. Instead it should max out and start vertically scrolling instead.
Is this possible in css grid without using max-height: 80vh for example? I don't always know what the max-height should be. (.app-main is large content that should expand but be capped at remaining height and then start scrolling vertically.)
body {
display: grid;
grid-template-rows: auto 1fr auto;
grid-row-gap: 1em;
height: 100vh;
}
.app-main {
height: 1800px;
background-color: yellow;
overflow-y: auto;
}
<header>
<h1>Header</h1>
</header>
<section class="app-main">
<p>
my large content
</p>
</section>
<footer>
<h2>Footer</h2>
</footer>
Setting the height on the children of section will achieve what you want. For example:
body {
display: grid;
grid-template-rows: auto 1fr auto;
grid-row-gap: 1em;
height: 100vh;
}
.app-main {
height: 100%;
background-color: yellow;
overflow-y: auto;
}
.app-main p {
height: 1200px;
}