Why flex-shrink behaves this way in my example? - html

Could you give me an explanation of what is going here? (If it's possible attach links to the CSS spec)
When I set flex-shrink to 0 on #grid-container (flex: 1 0 auto), there appears a scroll bar for the whole page
But when I set flex-shrink to 1 on #grid-container (flex: 1 1 auto), the bar scroll bar appears only for the #grid-container
In the code snippet below flex-shrink on #grid-container is set to to 0 (flex: 1 0 auto). Change it to 1(flex: 1 1 auto) to see the difference
html {
height: 100%;
}
body {
display: flex;
flex-direction: column;
height: 100%;
margin: 0;
}
#header {
background-color: brown;
flex: 0 0 100px;
}
#grid-container {
flex: 1 1 auto;
display: grid;
overflow: hidden;
grid-template-rows: 1fr;
grid-template-columns: 1fr;
}
#grid-item {
grid-column: 1/2;
grid-row: 1/2;
overflow: auto;
}
#list {
overflow: auto;
}
#list-item {
font-size: 140px;
}
<html>
<head>
<meta charset="utf-8">
<title>Page Title</title>
</head>
<body>
<div id="header"></div>
<div id="grid-container">
<div id="grid-item">
<div id="list">
<div id="list-item">1</div>
<div id="list-item">2</div>
<div id="list-item">3</div>
<div id="list-item">4</div>
<div id="list-item">5</div>
<div id="list-item">6</div>
</div>
</div>
</div>
</body>
</html>

By setting flex-shrink:1 (the default value) you allow your element to shrink inside its flex container and since you set the body (the flex container) to be height:100% it will shrink to fit inside it creating the scroll bar only on the container because its content is overflowing. Te be more accurate the scroll bar is on #grid-item and not the container which is logical since this one is having overflow:auto.
Add border to better see this:
html {
height: 100%;
background:#fff;
}
body {
display: flex;
flex-direction: column;
height: 100%;
margin: 0;
background:red;
}
#header {
background-color: brown;
flex: 0 0 100px;
}
#grid-container {
flex: 1 1 auto;
display: grid;
overflow: hidden;
grid-template-rows: 1fr;
grid-template-columns: 1fr;
border:5px solid green;
}
#grid-item {
grid-column: 1/2;
grid-row: 1/2;
overflow: auto;
border:5px solid blue;
}
#list {
/* overflow: auto; not needed*/
border:5px solid yellow;
}
#list-item {
font-size: 140px;
}
<html>
<head>
<meta charset="utf-8">
<title>Page Title</title>
</head>
<body>
<div id="header"></div>
<div id="grid-container">
<div id="grid-item">
<div id="list">
<div id="list-item">1</div>
<div id="list-item">2</div>
<div id="list-item">3</div>
<div id="list-item">4</div>
<div id="list-item">5</div>
<div id="list-item">6</div>
</div>
</div>
</div>
</body>
</html>
You can also set overflow:auto to the container and you will have the scroll on the container and almost the same result
html {
height: 100%;
background:#fff;
}
body {
display: flex;
flex-direction: column;
height: 100%;
margin: 0;
background:red;
}
#header {
background-color: brown;
flex: 0 0 100px;
}
#grid-container {
flex: 1 1 auto;
display: grid;
overflow: auto;
grid-template-rows: 1fr;
grid-template-columns: 1fr;
border:5px solid green;
}
#grid-item {
grid-column: 1/2;
grid-row: 1/2;
border:5px solid blue;
}
#list {
/* overflow: auto; not needed*/
border:5px solid yellow;
}
#list-item {
font-size: 140px;
}
<html>
<head>
<meta charset="utf-8">
<title>Page Title</title>
</head>
<body>
<div id="header"></div>
<div id="grid-container">
<div id="grid-item">
<div id="list">
<div id="list-item">1</div>
<div id="list-item">2</div>
<div id="list-item">3</div>
<div id="list-item">4</div>
<div id="list-item">5</div>
<div id="list-item">6</div>
</div>
</div>
</div>
</body>
</html>
By disabling the shrink, the element and its content will overflow outside the body and also the html which will create a scroll bar on the viewport to be able to see the overflowing content. Adding overflow:auto is useless in this case since the parent height is the same as the content height.
Add background to body/html elements to better see the overflow when disabling the shrink
html {
height: 100%;
background:#fff; /*to stop the propagation of the red color*/
border:5px dotted purple;
}
body {
display: flex;
flex-direction: column;
height: 100%;
margin: 0;
background:red;
}
#header {
background-color: brown;
flex: 0 0 100px;
}
#grid-container {
flex: 1 0 auto;
display: grid;
overflow: hidden;
grid-template-rows: 1fr;
grid-template-columns: 1fr;
border:5px solid green;
}
#grid-item {
grid-column: 1/2;
grid-row: 1/2;
overflow: auto;
border:5px solid blue;
}
#list {
/* overflow: auto; not needed*/
}
#list-item {
font-size: 140px;
}
<html>
<head>
<meta charset="utf-8">
<title>Page Title</title>
</head>
<body>
<div id="header"></div>
<div id="grid-container">
<div id="grid-item">
<div id="list">
<div id="list-item">1</div>
<div id="list-item">2</div>
<div id="list-item">3</div>
<div id="list-item">4</div>
<div id="list-item">5</div>
<div id="list-item">6</div>
</div>
</div>
</div>
</body>
</html>
Related: Why is a flex-child limited to parent size?
As a side note, if you remove overflow:hidden from the container the result will be the same for both cases:
html {
height: 100%;
background:#fff;
}
body {
display: flex;
flex-direction: column;
height: 100%;
margin: 0;
background:red;
}
#header {
background-color: brown;
flex: 0 0 100px;
}
#grid-container {
flex: 1 1 auto;
display: grid;
grid-template-rows: 1fr;
grid-template-columns: 1fr;
border:5px solid green;
}
#grid-item {
grid-column: 1/2;
grid-row: 1/2;
overflow: auto; /*will do nothing*/
border:5px solid blue;
}
#list {
/* overflow: auto; not needed*/
border:5px solid yellow;
}
#list-item {
font-size: 140px;
}
<html>
<head>
<meta charset="utf-8">
<title>Page Title</title>
</head>
<body>
<div id="header"></div>
<div id="grid-container">
<div id="grid-item">
<div id="list">
<div id="list-item">1</div>
<div id="list-item">2</div>
<div id="list-item">3</div>
<div id="list-item">4</div>
<div id="list-item">5</div>
<div id="list-item">6</div>
</div>
</div>
</div>
</body>
</html>
This is due to The Automatic Minimum Size of Flex Items that will prevent the shrink effect.

Related

Make a div in a grid stretch to full height

I have a very simple grid layout of the menu, header, and content.
I would like the content (blue box) to stretch vertically. As you can see, the grid element (yellow box) already stretches vertically, but the blue element inside of it (which should be dynamic content) does not.
Is there a way to achieve this 1) without switching the whole grid structure to flexbox and 2) without using calc to give the blue content 100vh minus the header height?
.container {
height: 100vh;
display: grid;
grid-template-rows: min-content 1fr;
grid-template-columns: min-content 1fr;
grid-template-areas: "menu header" "menu content";
box-sizing: border-box;
overflow: hidden;
}
.mainMenuWrapper {
grid-area: menu;
height: auto;
}
.headerWrapper {
grid-area: header;
height: auto;
}
.contentWrapper {
grid-area: content;
overflow-y: auto;
height: auto;
background-color: yellow;
}
.menu {
height: 100vh;
background-color: red;
width: 50px;
}
.header {
height: 80px;
background-color: green;
}
.content {
background-color: blue;
width: 100%;
height: ???
}
<div class="container">
<div class="mainMenuWrapper">
<div class="menu">
menu
</div>
</div>
<div class="headerWrapper">
<div class="header">
header
</div>
</div>
<div class="contentWrapper">
<div class="content">
content
</div>
</div>
</div>
Image:
JSFiddle link: https://jsfiddle.net/the2sj1n/3/
You can apply height: 100% on that blue box .content
body {
margin: 0; /*Removed unexpected margins from browsers' default styles*/
}
.container {
height: 100vh;
display: grid;
grid-template-rows: min-content 1fr;
grid-template-columns: min-content 1fr;
grid-template-areas: "menu header" "menu content";
box-sizing: border-box;
overflow: hidden;
}
.mainMenuWrapper {
grid-area: menu;
height: auto;
}
.headerWrapper {
grid-area: header;
height: auto;
}
.contentWrapper {
grid-area: content;
overflow-y: auto;
height: auto;
background-color: yellow;
}
.menu {
height: 100vh;
background-color: red;
width: 50px;
}
.header {
height: 80px;
background-color: green;
}
.content {
background-color: blue;
width: 100%;
height: 100%; /*The change here*/
}
<div class="container">
<div class="mainMenuWrapper">
<div class="menu">
menu
</div>
</div>
<div class="headerWrapper">
<div class="header">
header
</div>
</div>
<div class="contentWrapper">
<div class="content">
content
</div>
</div>
</div>

make grid child scrollable when it's content is overflown

I'm trying to make the div with the class side-panel-content scrollable when it's content is big, overflow-y: scroll; doesn't work in this case.
The idea here, is to make the full page take the viewport, which works when the .long-content div has no height, but if it has a long height this shouldn't make it's container to grow more, and should be scrollable instead.
Here is a full example:
html, body {
height: 100%;
}
.main {
height: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
}
header, footer {
height: 80px;
background-color: yellow;
}
.content-wrapper {
height: 100%;
width: 100%;
display: grid;
grid-template-rows: auto 1fr;
}
.title {
padding: 24px;
width: 100%;
}
.main-content {
width: 100%;
display: grid;
gap: 24px;
grid-template-columns: 1fr 350px;
justify-content: space-around;
}
.main-panel {
display: grid;
grid-template-rows: auto 1fr;
border: 2px solid red;
}
.side-panel {
height: 100%;
width: 100%;
}
.side-panel-wrapper {
height: 100%;
background: #f8f9fa;
box-shadow: 0px 4px 10px rgb(0 0 0 / 10%);
display: grid;
grid-template-rows: auto 1fr;
}
.side-panel-header {
background-color: #ffffff;
padding: 24px;
border-bottom: 2px solid #e6e9f0;
}
.side-panel-content {
overflow-y: scroll;
}
.long-content {
height: 3000px;
}
<html>
<body>
<div class="main">
<header><h1>Header</h1></header>
<div class="content">
<div class="content-wrapper">
<div class="title">
<h1>Title</h1>
</div>
<div class="main-content">
<div class="main-panel">
<div>
<h2>
Main panel title
</h2>
<p>
Main panel content
</p>
</div>
</div>
<div class="side-panel">
<div class="side-panel-wrapper">
<div class="side-panel-header">
Side panel header
</div>
<div class="side-panel-content">
<div class="long-content">
long content
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<footer><h1>Footer</h1></footer>
</div>
</body>
</html>
The solution for this is to use an absolute positioning for the child div that has a long height.
html, body {
height: 100%;
}
.main {
height: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
}
header, footer {
height: 80px;
background-color: yellow;
}
.content-wrapper {
height: 100%;
width: 100%;
display: grid;
grid-template-rows: auto 1fr;
}
.title {
padding: 24px;
width: 100%;
}
.main-content {
width: 100%;
display: grid;
gap: 24px;
grid-template-columns: 1fr 350px;
justify-content: space-around;
}
.main-panel {
display: grid;
grid-template-rows: auto 1fr;
border: 2px solid red;
}
.side-panel {
height: 100%;
width: 100%;
}
.side-panel-wrapper {
height: 100%;
background: #f8f9fa;
box-shadow: 0px 4px 10px rgb(0 0 0 / 10%);
display: grid;
grid-template-rows: auto 1fr;
}
.side-panel-header {
background-color: #ffffff;
padding: 24px;
border-bottom: 2px solid #e6e9f0;
}
.side-panel-content {
overflow: auto;
position: relative;
height: 100%;
}
.long-content {
position: absolute;
top: 0;
height: 3000px;
}
<html>
<body>
<div class="main">
<header><h1>Header</h1></header>
<div class="content">
<div class="content-wrapper">
<div class="title">
<h1>Title</h1>
</div>
<div class="main-content">
<div class="main-panel">
<div>
<h2>
Main panel title
</h2>
<p>
Main panel content
</p>
</div>
</div>
<div class="side-panel">
<div class="side-panel-wrapper">
<div class="side-panel-header">
Side panel header
</div>
<div class="side-panel-content">
<div class="long-content">
long content
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<footer><h1>Footer</h1></footer>
</div>
</body>
</html>

setting a margin or padding for a 100% height grid without scrollbars [duplicate]

This question already has answers here:
CSS 100% height with padding/margin
(15 answers)
100% width minus margin and padding [duplicate]
(6 answers)
Closed 1 year ago.
I've got a grid layout. I want to add a 5px margin all around it but doing so adds a scrollbar.
Is it possible to set a margin without having a scrollbar added?
function toggle() {
document.querySelector(".container").classList.toggle("withMargin");
}
html,
body,
.container {
height: 100%;
margin: 0;
}
.container {
display: grid;
grid-template-rows: 50px 1fr 1fr;
grid-template-columns: 300px 1fr 1fr;
gap: 5px 5px;
grid-auto-flow: row;
grid-template-areas: "logo header header" "nav-one main main" "nav-two main main";
background-color: black;
}
.main {
grid-area: main;
background-color: lightcoral;
}
.logo {
grid-area: logo;
background-color: lightcyan;
}
.header {
grid-area: header;
background-color: lightgoldenrodyellow;
}
.nav-one {
grid-area: nav-one;
background-color: lightgray;
}
.nav-two {
grid-area: nav-two;
background-color: lightgreen;
}
.container.withMargin {
margin: 5px;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div class="container">
<div class="main">
<br /><button onclick="toggle()">toggle .container margin</button>
</div>
<div class="logo">logo</div>
<div class="header">header</div>
<div class="nav-one">nav one</div>
<div class="nav-two">nav two</div>
</div>
</body>
</html>
Use padding instead of margin for selector .container.withMargin:
.container.withMargin {
padding: 5px;
}
And add box-sizing: border-box for the .container selector.
function toggle() {
document.querySelector(".container").classList.toggle("withMargin");
}
html,
body,
.container {
height: 100%;
margin: 0;
}
.container {
display: grid;
grid-template-rows: 50px 1fr 1fr;
grid-template-columns: 300px 1fr 1fr;
gap: 5px 5px;
grid-auto-flow: row;
grid-template-areas: "logo header header" "nav-one main main" "nav-two main main";
background-color: black;
box-sizing: border-box;
}
.main {
grid-area: main;
background-color: lightcoral;
}
.logo {
grid-area: logo;
background-color: lightcyan;
}
.header {
grid-area: header;
background-color: lightgoldenrodyellow;
}
.nav-one {
grid-area: nav-one;
background-color: lightgray;
}
.nav-two {
grid-area: nav-two;
background-color: lightgreen;
}
.container.withMargin {
padding: 5px;
}
<!DOCTYPE html>
<html>
<head> </head>
<body>
<div class="container">
<div class="main">
<br />
<button onclick="toggle()">toggle .container margin</button>
</div>
<div class="logo">logo</div>
<div class="header">header</div>
<div class="nav-one">nav one</div>
<div class="nav-two">nav two</div>
</div>
</body>
</html>

Shrink grid container to number of rows

I have a flexbox with a grid and a div in it, and I'd like to collapse the grid container's height to the height of the rows, so that the buttons below it are just below the grid items. The number of rows is also dynamic, because I'm using grid-template-columns: repeat(auto-fit, minmax(250px, 1fr). I can set a max-height of the grid items, like in this image, but that only makes the items smaller and doesn't make the grid container any shorter.
I've tried changing the flexbox they're in so the flex-direction is row, and set flex-wrap to wrap, but that causes other problems and overlapping text when the window size changes. Setting the height or max-height of the grid container to fit-content seems to do nothing as well.
Here is what I have:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Boardgame Database</title>
<style>
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
aside {
background-color: red;
flex: 1;
min-width: 250px;
}
.grid-container {
flex: 4;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
.grid-item {
border: 1px solid rgba(0, 0, 0, 0.8);
padding: 20px;
font-size: 24px;
text-align: center;
overflow: hidden;
min-height: 100px;
}
#main-container {
display: flex;
flex-direction: row;
min-height: 100vh;
}
#section-container {
display: flex;
flex-direction: column;
width: 100%;
}
#page-buttons {
height: 50px;
text-align: center;
font-size: 20px;
}
</style>
</head>
<body>
<div id="main-container">
<aside class="sidebar">
</aside>
<div id="section-container">
<section class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
</section>
<div id="page-buttons">
first
prev
page
next
last
</div>
</div>
</div>
</body>
</html>
The style
.grid-container {
flex: 4;
}
is equivalent to flex-grow: 4;
so it makes the container grow. Just remove it and it will keep its dimension
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
aside {
background-color: red;
flex: 1;
min-width: 250px;
}
.grid-container {
/* flex: 4; */
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
.grid-item {
border: 1px solid rgba(0, 0, 0, 0.8);
padding: 20px;
font-size: 24px;
text-align: center;
overflow: hidden;
min-height: 100px;
}
#main-container {
display: flex;
flex-direction: row;
min-height: 100vh;
}
#section-container {
display: flex;
flex-direction: column;
width: 100%;
}
#page-buttons {
height: 50px;
text-align: center;
font-size: 20px;
}
<body>
<div id="main-container">
<aside class="sidebar">
</aside>
<div id="section-container">
<section class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
</section>
<div id="page-buttons">
first
prev
page
next
last
</div>
</div>
</div>
</body>

How to make horizontal scroll on page

I have div in which placed inner divs i need to make all inner divs in line and horizontal scrollbar should be displayed (i know it sounds crazy, but i need that). I tried container width auto and overflow scroll but nothing.
How to accomplish that?
my markup:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>text-overflow</title>
<style>
body{
width: auto;
}
#items{
overflow-x: scroll;
width: auto;
}
.item{
display: inline-block;
width: 400px;
height: 100px;
border:1px solid;
}
</style>
</head>
<body>
<div id="items">
<div class="item">
Item content
</div>
<div class="item">
Item content
</div>
<div class="item">
Item content
</div>
<div class="item">
Item content
</div>
<div class="item">
Item content
</div>
<div class="item">
Item content
</div>
</div>
</body>
</html>
Use white-space: nowrap; on #items
#items{
overflow-x: scroll;
width: auto;
white-space: nowrap;
}
DEMO
simply give #items to height and overflow-x:auto.
#items{
overflow-x: auto;
width: auto;
height: 200px;
}
<div style="overflow-x:scroll;">
<div style="width:1600px;">
<div style="width:1500px;">
<table>
<tr>
<td> Your Value </td>
</tr>
</table>
</div>
</div>
</div>
I think you want something like this...
:root {
--gutter: 20px;
}
.app {
padding: var(--gutter) 0;
display: grid;
grid-gap: var(--gutter) 0;
grid-template-columns: var(--gutter) 1fr var(--gutter);
align-content: start;
}
.app > * {
grid-column: 2 / -2;
}
.app > .full {
grid-column: 1 / -1;
}
.hs {
display: grid;
grid-gap: calc(var(--gutter) / 2);
grid-template-columns: repeat(6, calc(50% - var(--gutter) * 2));
grid-template-rows: minmax(150px, 1fr);
overflow-x: scroll;
scroll-snap-type: x proximity;
padding-bottom: calc(.75 * var(--gutter));
margin-bottom: calc(-.25 * var(--gutter));
}
/* Demo styles */
html,
body {
height: 100%;
}
body {
display: grid;
place-items: center;
background: #456173;
}
ul {
list-style: none;
padding: 0;
}
h1,
h2,
h3 {
margin: 0;
}
.app {
width: 375px;
height: 667px;
background: #DBD0BC;
overflow-y: scroll;
}
.hs > li,
.item {
scroll-snap-align: center;
padding: calc(var(--gutter) / 2 * 1.5);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: #fff;
border-radius: 8px;
}
<div class="app">
<h1>Some headline</h1>
<ul class="hs">
<li class="item">test</li>
<li class="item">test</li>
<li class="item">test</li>
<li class="item">test</li>
<li class="item">test</li>
<li class="item">test</li>
</ul>
<div class="container">
<div class="item">
<h3>Block for context</h3>
</div>
</div>
</div>