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.
Related
I'm using a grid layout. I used grid-template-column and grid-template-rows to define its structure. I want the first cell to contain an image. Since I want to center it horizontally, my idea was to place it inside a div which itself can be a flex or grid container.
I'm having problems scaling the image. When not using the div, I'm basically placing the image directly inside the grid, I can use height: 100%; and it scales down so that the height fits the cell.
But when using an extra div container that does not work anymore. Using height: 100% seems to reference the height of the whole grid layout, not just the div. Google says I should use max-height and max-width, but I can't get it to work. Below is a simple test project (HTML and CSS) to show the problem. When using width: 25px; you can see, how big the sections of the grid should be.
I appreciate any help. Keep in mind, this is a simple test project, so don't mind the naming of my classes and IDs.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body,
html {
height: 100%;
}
.class {
background-color: blue;
}
.container {
height: 100vh;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr 3fr 3fr;
gap: 10px;
background-color: green;
}
#image-container>img {
max-height: 100%;
}
<div class="container">
<div class="class" id="image-container">
<img src="https://www.industrialempathy.com/img/remote/ZiClJf-1920w.jpg" alt="">
</div>
<div class="class" id="2">Good</div>
<div class="class" id="3">Day</div>
</div>
Check out the overflow on the child element class and max-height on the parent to achieve the desired result.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body,
html {
min-height: 100%;
}
.parent {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr repeat(2, 3fr);
gap: 1rem;
background: orchid;
max-width: 100%;
max-height: 100vh;
}
.class{
background: teal;
overflow: hidden;
}
img{
display:block;
width: 100%;
height: 100%;
object-fit: cover;
}
<div class="parent">
<div class="class">
<img src="https://www.industrialempathy.com/img/remote/ZiClJf-1920w.jpg" alt="">
</div>
<div class="class">
<p>Good</p>
</div>
<div class="class">
<p>Day</p>
</div>
</div>
My preferred method is setting it as background image, with the background-size:contain (or cover). This applies logic from the browser instead of trying to get it right yourself and is fully responsive.
.exampleA, .exampleB{
width: 34%;
height: 150px;
background-position: center;
background-repeat: no-repeat;
background-color: pink; /* Just for this demo: to display canvas size */
border: 1px solid black; /* Just for this demo */
display: inline-block;
}
.exampleA {
background-size: contain;
}
.exampleB {
background-size: cover;
}
<div class="exampleA"
style="background-image: url('https://www.industrialempathy.com/img/remote/ZiClJf-1920w.jpg');"
></div>
<div class="exampleB"
style="background-image: url('https://www.industrialempathy.com/img/remote/ZiClJf-1920w.jpg');"
></div>
I have a css grid with a single column and two rows.
I want the first row to expand when there is space and to scroll when there is no space.
I want the second row to remain at the bottom of the div.
I have tried using display: flex; in the first row.
HTML:
<div class="parent">
<span class="top">my<br>long<br>long<br>long<br>content</span>
<span class="bottom">always visible</span>
</div>
CSS:
body {
overflow-y: hidden;
}
.parent {
display: grid;
grid-template-columns: auto;
grid-template-rows: 1fr 0fr;
}
.top {
overflow-y: scroll;
display: flex;
flex-direction: column;
}
span {
border: solid;
}
https://jsfiddle.net/9re86f2a/
I expect the first row to scroll when there is no space, but it actually remains the same size.
I expect the first row to expand when there is space, but it actually remains the same size.
I would use the flex model for this kind of behavior even if grid does it fine ;)
html * {
box-sizing:border-box;
padding:0.25em;
margin:0;
}
body {
height:100vh;
}
.parent {
display: flex;
flex-direction: column;
max-height: 100%;
overflow: hidden;
}
.top {
flex-grow: 1;
overflow: auto;
/* style aside */
background:lightblue;
margin:2px;/* or 0 */
border:solid;
}
.bottom {
flex-shrink: 0;
/* style aside */
background:tomato;
margin:2px;/* or 0 */
border:solid;
}
/* demo purpose */
.top .demo {
display: block;
max-height: 0;
overflow: hidden;
transition: 1.5s;
}
.top:hover .demo {
max-height: 300vh;
}
<div class="parent">
<span class="top"><b>Hover me to show my long content</b>
<span class="demo"><br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content</span>
</span>
<span class="bottom">always visible</span>
</div>
There's nothing in your code that triggers an overflow condition.
In order for content to overflow, it needs to exceed a width or height limitation (e.g. height: 300px), which then triggers the scrollbar.
From MDN:
In order for overflow to have an effect, the block-level container must have either a set height (height or max-height) or white-space set to nowrap.
In other words, without a fixed height, you won't get the vertical scrollbar... in Chrome! Ironically, however, in Firefox, a product of MDN, and Edge, the MDN rule above doesn't apply, and your layout works just fine.
.parent {
display: grid;
grid-template-columns: auto;
grid-template-rows: 1fr 0fr;
grid-gap: 2px;
background-color: black;
height: 100vh;
}
.top {
overflow-y: auto;
}
span {
background-color: white;
}
body {
margin: 0;
}
<div class="parent">
<span class="top">my<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content<br>long<br>long<br>long<br>content</span>
<span class="bottom">always visible</span>
</div>
jsFiddle demo
Note on browser rendering differences: I can only speculate as to why Firefox and Edge render a scrollbar on a block-level container that doesn't have a defined height or max-height, as specified by MDN (see above). They could be engaging in an intervention or may have a different interpretation of the specification than the MDN contributors.
So I have this basic setup - a canvas area and an animator in a parent grid.
The parent grid is also inside another grid with one 1fr row.
I can resize the animator by dragging a resizer up and down.
canvas {
background-color: blue;
}
#grid1 {
grid-template-rows: 1fr;
}
#grid2 {
background-color: black;
display: grid;
grid-template-rows: 1fr auto;
overflow: hidden;
}
#canvas-area {
grid-row: 1;
background-color: red;
}
#animator {
grid-row: 2;
height: 200px;
}
<div id="grid1">
<div id="grid2">
<div id="canvas-area">
<canvas/>
</div>
<div id="animator"></div>
</div>
</div>
I want the canvas to be bigger than its parent and hide its overflow, but that seems to also expand the parent element.
I've already tried overflow: hidden, but that doesn't work
As a side question: I also noticed that there is a space of 4px under the canvas, why is that?
I want the canvas to be bigger than its parent and hide its overflow, but that seems to also expand the parent element.
Normally you'd add a height to the grid container so that the the 1fr in the grid-template-rows: 1fr auto is meaningful; otherwise the grid item auto-adjusts to the dimensions of its contents.
Add overflow: hidden to the grid item #canvas-area along with a fixed height to the container (say 400px as your previous jsFiddle had) - see demo below:
document.querySelector('button').onclick = () => {
document.querySelector('canvas').height = 300;
}
canvas {
background-color: blue;
}
#grid {
background-color: black;
display: grid;
grid-template-rows: 1fr auto;
width: 400px;
height: 400px; /* added a fixed height */
}
#canvas-area {
grid-row: 1;
background-color: red;
overflow: hidden; /* added */
}
#animator {
grid-row: 2;
height: 200px;
}
<div id="grid">
<div id="canvas-area">
<canvas/>
</div>
<div id="animator"></div>
</div>
<button>Change Canvas Height</button>
Note that adding min-height: 0 also does not grow the container:
document.querySelector('button').onclick = () => {
document.querySelector('canvas').height = 300;
}
canvas {
background-color: blue;
}
#grid {
background-color: black;
display: grid;
grid-template-rows: 1fr auto;
width: 400px;
height: 400px;
}
#canvas-area {
grid-row: 1;
background-color: red;
min-height: 0; /* added */
}
#animator {
grid-row: 2;
height: 200px;
}
<div id="grid">
<div id="canvas-area">
<canvas/>
</div>
<div id="animator"></div>
</div>
<button>Change Canvas Height</button>
Why so?
By default grid items have min-width: auto and min-height: auto (just like flex items). You can see some examples of of this behaviour below:
css-grid creates an imaginary column
How to make images stay within the rows of a css grid container?
and from the specs:
To provide a more reasonable default minimum size for grid items, this
specification defines that the auto value of min-width/min-height also
applies an automatic minimum size in the specified axis to grid items
whose overflow is visible and which span at least one track whose min
track sizing function is auto.
W3C
Space below canvas element?
I also noticed that there is a space of 4px under the canvas, why is that?
That is the whitespace, a characteristic of inline elements - you can remove that by making it a block element (add display: block) or adjusting vertical-align property (add vertical-align: top):
document.querySelector('button').onclick = () => {
document.querySelector('canvas').height = 300;
}
canvas {
background-color: blue;
display: block; /* added */
}
#grid {
background-color: black;
display: grid;
grid-template-rows: 1fr auto;
width: 400px;
height: 400px;
}
#canvas-area {
grid-row: 1;
background-color: red;
min-height: 0; /* added */
overflow: auto; /* added */
}
#animator {
grid-row: 2;
height: 200px;
}
<div id="grid">
<div id="canvas-area">
<canvas/>
</div>
<div id="animator"></div>
</div>
<button>Change Canvas Height</button>
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/
This question already has answers here:
Is it possible for flex items to align tightly to the items above them?
(5 answers)
Make a div span two rows in a grid
(2 answers)
Closed 5 years ago.
I have this structure ... it's similar to the WordPress administration area ... the point is that I need .main taking all the space available in width and height and .foot remains down while there is no content that lowers it. I want to use flex because I will have columns inside the .main and I need these columns take full height as well... Maybe someone can give me another solution, but I can NOT change the html, only the CSS
.wrap {
display: flex;
}
.sidebar {
position: fixed;
top: 0;
bottom: -100px;
background-color: #00a0d2;
width: 200px;
}
.main {
background-color: #66BB6A;
display: flex;
}
.foot {
margin-left: -200px;
background-color: #9999dd;
height: 60px;
}
<div class="wrap">
<div class="sidebar">Menu</div>
<div class="main">Content</div>
<div class="foot">Footer</div>
</div>
where the final result would be something like this, thx
A fixed position sidebar will not be affected by flexbox, so you need to adjust your margins to make room for it.
html,
body {
height: 100%;
}
body {
min-height: 100%;
}
.wrap {
display: flex;
flex-direction: column; /* required to establish column layout */
min-height: 100%;
}
.sidebar {
position: fixed;
top: 0;
bottom: 0; /* full height - change if required */
background-color: #00a0d2;
width: 200px;
opacity: .5/* for demo purposes */
;
}
.main {
background-color: #66BB6A;
display: flex;
flex: 1; /* take remaining height*/
margin-left: 200px; /* width of sidebar */
}
.foot {
margin-left: 200px; /* width of sidebar */
background-color: #9999dd;
height: 60px;
}
<div class="wrap">
<div class="sidebar">Menu</div>
<div class="main">Content</div>
<div class="foot">Footer</div>
</div>
You could use css grid. It allows room for 2d grid with minimal code.
.wrap {
display: grid;
/*Make 2 columns with the first having a min width of 200px*/
grid-template-columns: minmax(200px, 1fr) 10fr;
}
.sidebar {
background-color: #00a0d2;
/*Make sidebar take up the space of the 2 rows*/
grid-row: 1/3;
}
.main {
background-color: #66BB6A;
/*Let the main content take up the space of view height*/
height: 100vh;
}
.foot {
/*set footer to span the last row leaving the space for the sidebar*/
grid-column: 2/3;
background-color: #9999dd;
height: 60px;
}
<div class="wrap">
<div class="sidebar">Menu</div>
<div class="main">Content</div>
<div class="foot">Footer</div>
</div>