How to force display flex to stay inside [duplicate] - html

This question already has an answer here:
Fitting child into parent
(1 answer)
Closed 3 years ago.
I am trying to add two divs to an element. The first div should have a fixed height and position. The second div should take up the rest of the space (if needed), but never exceed it. I've prepared the following example, to display the desired output.
#container {
border: 1px solid black;
height: 200px;
width: 200px;
display: flex;
flex-direction: column;
}
#fixed {
flex: 0 0 50px;
background: red;
}
#free {
flex: 1;
}
#scroll {
max-height: 100%;
overflow-y: scroll;
background: blue;
}
<div id="container">
<div id="fixed">Should always appear</div>
<div id="free">
<span>Should always appear</span>
<div id="scroll">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
</div>
This example displays the problem that arises when the contents of the second div are too large.
#container {
border: 1px solid black;
height: 200px;
width: 200px;
display: flex;
flex-direction: column;
}
#fixed {
flex: 0 0 50px;
background: red;
}
#free {
flex: 1;
}
#scroll {
max-height: 100%;
overflow-y: scroll;
background: blue;
}
<div id="container">
<div id="fixed">Should always appear</div>
<div id="free">
<span>Should always appear</span>
<div id="scroll">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse porta nec dolor a dignissim. Nunc auctor felis a turpis tincidunt auctor. Suspendisse venenatis volutpat sodales. Maecenas sodales est non quam vestibulum fermentum. Nulla venenatis
sapien sit amet augue ultricies molestie. Sed neque nulla, venenatis non est a, imperdiet dictum tortor. Nam at odio rutrum, convallis neque blandit, viverra urna. Maecenas scelerisque risus eu mollis ornare. Nullam tincidunt tempus vehicula. Aenean
at porttitor ex. Fusce tincidunt nulla velit, id gravida lacus vestibulum nec.
</div>
</div>
</div>
I would accept any answer that solves this problem regardless of what combination of css and html is used (that doesn't change the order of the elements), as long as no javascript and no more height properties are added (i.e top: 40px;, min-height: calc(100% - 40px); ...), with the exception of 0, auto and 100%.

Edit: Added min-height: 0 to div's css as well as an updated fiddle.
If I understand the question correctly, is this what you're looking for?
#free {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
}
Jsfiddle: https://jsfiddle.net/nick_zoum/Lod38e9a/3/

Related

Make grid row take up 100% of leftover space but scroll if more space is needed

Need to make grid item take up 100% of leftover space but scroll if it needs more space than that.
Below is an example from the scenario. The main part which I can't work out is the CSS line labelled: '/* DOESN'T WORK */' where I try to set overflow-y to scroll.
Requirements:
Cart should take up 100% of its container.
Cart should position the checkout button at the bottom, no matter how many cart items there are.
Cart items should fill up available space then overflow and scroll once space is filled.
const item = `
<div class="cart__item">
T-Shirt
</div>
`;
const cartItems = document.getElementById("cart__items");
const renderItems = (n) => {
if (n < 1) {
cartItems.innerHTML = "cart emtpy";
return;
}
cartItems.innerHTML = item.repeat(n);
}
let numItems = 1;
const incItems = document.getElementById("inc_items");
incItems.addEventListener("click", () => {
numItems++;
renderItems(numItems);
});
const decItems = document.getElementById("dec_items");
decItems.addEventListener("click", () => {
if (numItems > 0) { numItems--; }
renderItems(numItems);
});
renderItems(numItems);
.container {
height: 150px;
width: 500px;
background: pink;
}
.cart {
display: grid;
height: 100%;
grid-template-rows: 1fr max-content;
}
.cart__item {
outline: 2px solid red;
color: white;
background: blue;
}
.cart__items {
display: flex;
place-items: center;
flex-direction: column;
/* overflow-y: scroll; */ /* DOESN'T WORK */
outline: 2px solid black;
}
<button id="inc_items">Inc Item</button>
<button id="dec_items">Dec Item</button>
<div class="container">
<div class="cart">
<div id="cart__items" class="cart__items"></div>
<div class="cart__checkout">
<button>Checkout</button>
</div>
</div>
</div>
Adding width and height to 100% in .cart do the job:
width: 100%;
height: 100%;
and you need to un-comment your line in .cart__items:
overflow-y: scroll;
or you can let the browser decide with:
overflow: auto;
Check snippet below :
.container {
height: 150px;
width: 500px;
background: pink;
}
.cart {
display: grid;
grid-template-rows: 1fr max-content;
width: 100%;
height: 100%;
}
.cart__item {
outline: 2px solid red;
color: white;
background: blue;
}
.cart__items {
display: flex;
place-items: center;
flex-direction: column;
overflow: auto;
/* or overflow-y: scroll; */
outline: 2px solid black;
}
<button id="inc_items">Inc Item</button>
<button id="dec_items">Dec Item</button>
<div class="container">
<div class="cart">
<div id="cart__items" class="cart__items">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque dignissim felis non felis mollis, ac pellentesque libero tincidunt. Quisque commodo felis vitae mi facilisis placerat eu a dui. Vestibulum ultrices accumsan elit a sollicitudin. Mauris porta, leo sit amet condimentum tincidunt, velit nunc ultricies nibh, imperdiet elementum felis sem sit amet ex. Proin molestie urna sed vulputate ornare. Sed vel pulvinar sem, sit amet condimentum ante. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque dignissim felis non felis mollis, ac pellentesque libero tincidunt. Quisque commodo felis vitae mi facilisis placerat eu a dui. Vestibulum ultrices accumsan elit a sollicitudin. Mauris porta, leo sit amet condimentum tincidunt, velit nunc ultricies nibh, imperdiet elementum felis sem sit amet ex. Proin molestie urna sed vulputate ornare. Sed vel pulvinar sem, sit amet condimentum ante. </div>
<div class="cart__checkout">
<button>Checkout</button>
</div>
</div>
</div>

How to dynamically push down a second-row div based on the height of the child in the first row div in CSS?

is it possible for a child inside a div to push down other divs outside based on its own height?
Given this simple HTML:
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="app">
<div class="main-section">
<div class="main-form">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi eget
sollicitudin urna. Duis congue mattis risus nec volutpat. Cras ut
risus et diam luctus consectetur. Phasellus aliquam dui nec vehicula
convallis. Donec sit amet nunc lacus. Praesent eget elit commodo,
ultricies felis non, tristique ex.
</div>
</div>
<div class="about-section">Hello World</div>
</div>
<script src="src/index.js"></script>
</body>
</html>
I have this CSS here, there are basically two divs (main-section and about-section) and the main-form is inside the main-section:
.main-section {
background-color: red;
padding: 10px 0 0 10px;
height: 100px;
min-width: 100%;
/* display: table; solution 1*/
/* overflow: auto; solution 2, it cuts off the yellow div, which is not the desired outcome */
}
.main-form {
background-color: yellow;
width: 120px;
min-height: 180px;
/* display: table-col; solution 1*/
}
.about-section {
background-color: blue;
}
The height of the parent .main-section should be fixed at 100px.
The height of the child .main-form varies depending on the length of the text on it, but should have a min-height of 180px.
The width of the .main-form should be fixed at 120px.
I have tried changing the overflow property of the parent but it cuts off the child element.
I have also tried using the display: table on the parent and display: table-col on the child, but this solution adjusts the height of the parent element.
Here is a code sandbox: https://codesandbox.io/s/romantic-wave-29f5f?fontsize=14&hidenavigation=1&theme=dark
Is there a way to do this?
Basically what I wanted to achieve looks something like this:
float and clear can do the job:
.main-section {
background-color: red;
padding: 10px 0 0 10px;
height: 100px;
}
.main-form {
background-color: yellow;
width: 120px;
float:left; /* here */
min-height: 180px;
}
.about-section {
background-color: blue;
clear:left; /* and here */
}
<div class="main-section">
<div class="main-form">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi eget sollicitudin urna. Duis congue mattis risus nec volutpat. Cras ut risus et diam luctus consectetur. Phasellus aliquam dui nec vehicula convallis. Donec sit amet nunc lacus. Praesent eget
elit commodo, ultricies felis non, tristique ex.
</div>
</div>
<div class="about-section">Hello World</div>

Position spans next to each other

What I am trying to do is have a fixed header, fixed footer with a section inbetween. The inbetween section would then get a scrollbar should the content not fit on screen. After much frustration I managed to get the main layout rendering correctly without using tables:
.main-container {
width: 50%;
height: 98vh;
flex-direction: column;
display: flex;
}
.main-container .main-view {
width: 100%;
overflow-y: scroll;
flex: 1 1 auto;
}
.main-container .top-bar {
width: 100%;
flex: 0 0 1em;
text-align: center;
}
.main-container .bottom-bar {
width: 100%;
flex: 0 0 1em;
}
.special {
display: inline;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div class="main-container">
<div class="main-container top-bar">
SOMETHING FIXED HERE
</div>
<div class="main-container main-view">
<span class="special">Lorem</span><span class="special">ipsum</span> dolor sit amet, consectetur adipiscing elit. Pellentesque magna tellus, dictum et luctus ac, laoreet vel justo. Cras at pretium lectus. Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Suspendisse potenti. Maecenas tincidunt efficitur neque, eu elementum purus tincidunt vel. Nunc id dolor bibendum, pharetra erat in, pretium lorem. Donec vitae nulla et lacus porta scelerisque. Praesent blandit, nibh nec vulputate
semper, arcu odio scelerisque velit, at rhoncus lacus dui luctus sapien. Donec venenatis erat libero, vitae lobortis velit finibus ut.
</div>
<div class="main-container bottom-bar" id="bottom-bar">
SOMETHING FIXED HERE
</div>
</div>
</body>
</html>
However elements in the middle area only render correctly if they are not wrapped in any kind of tag. As soon as I wrap them in a div or span, the browser (Chrome at least) insists on having each tag take up the entire line. They do not appear side-by-side as I might expect.
I have tried creating a 'special' class, as noted in the example above, which I have applied to both div and span. Both give the same result: 'Lorem' and 'ipsum' appear on their own lines instead of side-by-side. I tried various things from other stack overflow questions on somewhat related topics including "float: left" and additional nesting using "display: flex".
I simply want to apply some styling and perhaps make some items clickable. To do that they need to be wrapped in something like a div or span. Anyone know how I can get it to render them side-by-side instead of each tag on its own line?
Your particular issue is because your .main-container class has display: flex; on it and then you've added that class to the top, center and bottom divs, this flex property changes the way that child elements are positioned.
As it sounds like you dont want to mess with the positioning of children elements of the main (middle) div, you dont want to add the 'main-container' class to that div.
Actually, you can achieve what you want much more simply:
body {
display: flex;
flex-direction: column;
height: 100vh;
}
.main-view {
flex-grow: 1;
overflow: scroll;
}
Here we're making the body always 100vh (100% viewport height) and changing the display to flex, direction column. Setting these flex properties allows us to tell the main-view container to flex-grow which means fill the remaining space of the parent, this pushes the footer down to the bottom of the body element (which is set to 100vh).
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<style>
body {
display: flex;
flex-direction: column;
height: 100vh;
}
.main-view {
flex-grow: 1;
overflow: scroll;
}
</style>
</head>
<body>
<div class="top-bar">
SOMETHING FIXED HERE
</div>
<div class="main-view">
<span class="special">Lorem</span><span class="special">ipsum</span> dolor sit amet, consectetur adipiscing elit. Pellentesque magna tellus, dictum et luctus ac, laoreet vel justo. Cras at pretium lectus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse potenti. Maecenas tincidunt efficitur neque, eu elementum purus tincidunt vel. Nunc id dolor bibendum, pharetra erat in, pretium lorem. Donec vitae nulla et lacus porta scelerisque. Praesent blandit, nibh nec vulputate semper, arcu odio scelerisque velit, at rhoncus lacus dui luctus sapien. Donec venenatis erat libero, vitae lobortis velit finibus ut.
</div>
<div class="bottom-bar">
SOMETHING FIXED HERE
</div>
</div>
</body>
</html>
This is the nature of the flexbox. You gave the container the property of column for the flex-direction. The .special elements are being treated as flex items and getting arranged in a column. Simply wrap them all in a div so you have a single flex item so the inline display can kick in
.main-container {
width: 50%;
height: 98vh;
flex-direction: column;
display: flex;
}
.main-container .main-view {
width: 100%;
overflow-y: scroll;
flex: 1 1 auto;
}
.main-container .top-bar {
width: 100%;
flex: 0 0 1em;
text-align: center;
}
.main-container .bottom-bar {
width: 100%;
flex: 0 0 1em;
}
.special {
display: inline;
}
<div class="main-container">
<div class="main-container top-bar">
SOMETHING FIXED HERE
</div>
<div class="main-container main-view">
<div>
<span class="special">Lorem</span> <span class="special"> ipsum</span> dolor sit amet, consectetur adipiscing elit. Pellentesque magna tellus, dictum et luctus ac, laoreet vel justo. Cras at pretium lectus. Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Suspendisse potenti. Maecenas tincidunt efficitur neque, eu elementum purus tincidunt vel. Nunc id dolor bibendum, pharetra erat in, pretium lorem. Donec vitae nulla et lacus porta scelerisque. Praesent blandit, nibh nec vulputate
semper, arcu odio scelerisque velit, at rhoncus lacus dui luctus sapien. Donec venenatis erat libero, vitae lobortis velit finibus ut.
</div>
</div>
<div class="main-container bottom-bar" id="bottom-bar">
SOMETHING FIXED HERE
</div>
</div>
Alternatively, you can utilize flex-direction: row on your flex container (in this case .main-view) so your flex items can display "side-by-side" instead of being stacked in a column. See sample below:
.main-container {
width: 50%;
height: 98vh;
flex-direction: column;
display: flex;
}
.main-container .main-view {
width: 100%;
overflow-y: scroll;
flex: 1 1 auto;
flex-direction: row;
}
.main-container .top-bar {
width: 100%;
flex: 0 0 1em;
text-align: center;
}
.main-container .bottom-bar {
width: 100%;
flex: 0 0 1em;
}
.special {
display: inline;
margin-right: 10px;
}
<div class="main-container">
<div class="main-container top-bar">
SOMETHING FIXED HERE
</div>
<div class="main-container main-view">
<span class="special">Lorem</span><span class="special">ipsum</span>Hello
</div>
<div class="main-container bottom-bar" id="bottom-bar">
SOMETHING FIXED HERE
</div>
</div>

How to make Flexbox (flex-grow) take content into account for sizing?

How can we get Flexbox to stop equalizing space in sibling elements when both of the elements are using flex-grow: 1. This is difficult to explain upfront, so here is the code quickly followed by example screenshots of the issue, and desired behavior.
.Parent {
display: flex;
flex-direction: column;
background-color: lightcoral;
width: 400px;
min-height: 200px;
}
.Parent>div {
flex: 1;
}
.child1 {
background-color: lightblue;
}
.child2 {
background-color: lightgreen;
}
<div class="Parent">
<div class="child1">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam sagittis lorem at odio euismod tincidunt. Proin aliquet velit nec augue venenatis laoreet. Etiam nec metus mi. Aliquam sit amet velit non lectus porttitor accumsan sit amet egestas risus.</div>
<div class="child2">Lorem ipsum</div>
</div>
The issue:
Notice the equal space under the content of each div.
Desired:
When there is little content in the children divs, the divs should be of equal height:
When one of the divs has a lot of content, I would expect the div with more content to only be as tall as the content (if it passes the original flex grow allotment).
How can I get this behavior? Seems it should be easy using Flexbox.
flex-basis is the property you're looking for. https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis
The flex-basis CSS property specifies the flex basis which is the initial main size of a flex item. This property determines the size of the content-box unless specified otherwise using box-sizing.
By default, flex will take into account the content in the element when computing flex-grow - to disable that, just specify flex-basis: 0
.Parent {
display: flex;
flex-direction: column;
background-color: lightcoral;
width: 400px;
min-height: 200px;
}
.Parent>div {
flex-grow: 1;
flex-basis: 0;
}
.child1 {
background-color: lightblue;
}
.child2 {
background-color: lightgreen;
}
<div class="Parent">
<div class="child1">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam sagittis lorem at odio euismod tincidunt. Proin aliquet velit nec augue venenatis laoreet. Etiam nec metus mi. Aliquam sit amet velit non lectus porttitor accumsan sit amet egestas risus. Etiam nec metus mi. Aliquam sit amet velit non lectus porttitor accumsan sit amet egestas risus </div>
<div class="child2">Lorem ipsum</div>
</div>
By setting min-height on .Parent (along with setting the flex-direction to column), you're triggering the browser to fill the space with direct descendants of .Parent. It does so by distributing the space amongst all elements equally (that's the feature of Flexbox).
If you don't want that behavior, remove the min-height from .Parent and set a min-height on .Parent > div elements.
.Parent {
display: flex;
flex-direction: column;
background-color: lightcoral;
width: 400px;
}
.Parent>div {
flex: 1;
min-height: 100px;
}
.Parent > div:nth-child(odd) {
background-color: lightblue;
}
.Parent > div:nth-child(even) {
background-color: lightgreen;
}
<div class="Parent">
<div class="child1">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam sagittis lorem at odio euismod tincidunt. Proin aliquet velit nec augue venenatis laoreet. Etiam nec metus mi. Aliquam sit amet velit non lectus porttitor accumsan sit amet egestas risus. Nullam sagittis lorem at odio euismod tincidunt. Proin aliquet velit nec augue venenatis laoreet. Etiam nec metus mi. Aliquam sit amet velit non lectus porttitor accumsan sit amet egestas risus.</div>
<div class="child2">Lorem ipsum</div>
<div>Lorem ipsum doler sit amet</div>
<div>When there is little content in the children divs, the divs should be of equal height.</div>
</div>

Expanding div height in CSS

So on my page, I have a two column layout - 75% (left - blue) and 25% (right - red). I can't get the red column to fill. In Chrome's inspector I see that the container classed <div> has expanded vertically to the size of #left, but I just cannot coax #right to expand appropriately. Here's the jfiddle link for my css and html (followed by the code itself in case you don't want to click to tinker):
Just one quick note: In my actual development code I don't use blue and red (left and right div background colours) - I use white and navy, respectively.
http://jsfiddle.net/EG3zb/
<div class="container">
<div id="left">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam id nunc bibendum ligula tempus interdum a ac urna. Fusce sed nunc molestie, consequat orci eu, vehicula orci. Suspendisse nec leo sit amet tellus varius feugiat. Maecenas lacinia neque euismod, tincidunt nisi et, fermentum ipsum. Vivamus ut gravida velit, vitae ultrices ante. Nullam varius mattis tellus, vitae consectetur tortor porttitor eu. Donec congue eros mauris. Ut consequat aliquam mattis. Aliquam non neque eros.</p>
</div>
<div id="right">
Blah.
</div>
</div>
And the accompanying CSS:
.container {
width: 100%;
min-height: 100%;
overflow: auto;
}
#left, #right {
padding-top: 2%;
}
#left {
float: left;
width: 75%;
color: #fff;
background-color: blue;;
}
#right {
float: right;
width: 25%;
background-color: red;
color: #fff;
}
this is working
.container {
width: 100%;
min-height: 100%;
overflow: auto;
display:flex;
}
.container #left,.container #right{
-webkit-flex: auto;
-ms-flex:auto;
flex:auto;
}
here is working demo
http://jsfiddle.net/mauryaashish945/EG3zb/5/
Instead of default display:block you can use display:table-cell so there is no need for float:left\right :
#left, #right {
display:table-cell;
}
Example