Css flex overflow issue - css

I have:
.container {
display:flex;
align-items:center
}
.content {
flex-grow:1
}
in order to align the .content div vertically with css only. The content changes dynamically and that's why I can't use position:absolute; margin-top:50%... styling. Because I never know the exact height of div on each content update.
But in a scenario where .container width changes but height remains, .content overflows .container top because it wraps the text within.
What I'm trying to do is never let .content exceed the top position less than 0. Even the most ideal situation will be preserving the padding-top value of .container and margin-top value of .content. Overflowing bottom will be OK, in fact it'll be my preference.
Any workarounds?

You can make .container height flexible: use min-height instead of height.
.container {
display: flex;
align-items:center;
min-height: 75px;
border: 3px solid blue;
}
.content {
height: 150px;
flex-grow: 1;
border: 3px solid red;
resize: vertical;
overflow: auto;
}
<div class="container">
<div class="content"></div>
</div>
Another possibility is using overflow: auto. However, instead of centering using align-items:center, use margin: auto 0.
.container {
display: flex;
height: 75px;
border: 3px solid blue;
overflow: auto;
resize: vertical;
}
.content {
height: 150px;
flex-grow: 1;
margin: auto 0;
border: 3px solid red;
}
<div class="container">
<div class="content"></div>
</div>

Related

Child of Full Screen Container is Trimmed If Taller Than Parent [duplicate]

This question already has answers here:
Can't scroll to top of flex item that is overflowing container
(12 answers)
Closed 4 years ago.
I must be forgetting something fundamental with my vertically and horizontally centered flexbox.
The container is within a parent with vertical scroll, and when the container becomes too tall, it grows beyond the parent top, clipping the content. The bottom stays put.
Try adjusting the height of the view or adding more lines to see it in action.
body,
html {
height: 100%;
width: 100%;
margin: 0;
}
* {
box-sizing: border-box;
}
#wrapper {
background: grey;
height: 100%;
width: 100%;
max-height: 100%;
display: flex;
overflow-y: auto;
align-items: center;
justify-content: center;
}
#box {
margin: 30px 0;
background: white;
border: 1px solid #dfdfdf;
}
<div id="wrapper">
<div id="box">
First line
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br> Last linje
</div>
</div>
How do I keep it from getting clipped? Additionally I'm trying to have a 30px margin above and below the container.
Thanks!
You forgot nothing but you simply need to understand what is happening. First you made your wrapper to be 100% height of screen and then you made the box to be centred vertically and horizontally. When the box has a big height you will have something like this:
Now, when you add overflow-y: auto you will create a scroll that will start from the top of the wrapper until the bottom overflowed content. So it will be like this:
That's why you are able to scroll to the bottom to see the bottom part and not able to see the top part.
To avoid this, use margin:auto to center your element and in this case we will have two situations:
When box-height < wrapper-height we will have the space spread equally on each side because of the margin:auto thus your element will be centred like expected.
When box-height > wrapper-height we will have the normal behavior and your element will overflow and his top edge will stick to the top edge of the wrapper.
You may also notice the same can happen horizontally that's why I will use margin to center on both directions.
body,
html {
height: 100%;
width: 100%;
margin: 0;
}
* {
box-sizing: border-box;
}
#wrapper {
background: grey;
height: 100%;
width: 100%;
max-height: 100%;
padding:30px 0;
display: flex;
overflow-y: auto;
}
#box {
margin: auto;
background: white;
border: 1px solid #dfdfdf;
}
<div id="wrapper">
<div id="box">
First line
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br> Last linje
</div>
</div>
I think what you want is to make your flex item (#box) have a height and set it's overflow, not the flex container. Also, to add your 30px above and below I would remove the margin from the box and instead add padding to the container.
So, updated styles would look like this:
#wrapper {
background: grey;
height: 100%;
width: 100%;
max-height: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 30px 0; /*added*/
}
#box {
background: white;
border: 1px solid #dfdfdf;
overflow-y: auto; /*added*/
height: 100%; /*added*/
}
body,
html {
height: 100%;
width: 100%;
margin: 0;
}
* {
box-sizing: border-box;
}
#wrapper {
background: grey;
height: 100%;
width: 100%;
max-height: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 30px 0;
}
#box {
background: white;
border: 1px solid #dfdfdf;
overflow-y: auto;
height: 100%;
}
<div id="wrapper">
<div id="box">
First line
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br> Last linje
</div>
</div>
I think you set the top margin in the box class which extends the height of the container. You can maybe set it to padding instead of margin. Hope this helps. Thanks.

when i set div style overflow is scroll, justify-content is flex-start, flex layout wrap is incorrect

If I set #main.overflow is none, I get what I want.
And if I set #main.overflow is scroll, which is not what I want, the last element is broken by error.
Why do scroll bars cause Flex layout errors?
right result
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
#main {
overflow: none;
width: 200px;
background-color: #321;
display: flex;
flex-direction: row;
padding: 10px;
flex-wrap: wrap;
justify-content: flex-start;
}
.el {
width: 50px;
height: 50px;
background-color: red;
margin: 5px;
}
<div id="main">
<div class="el"></div>
<div class="el"></div>
<div class="el"></div>
</div>
incorrect result
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
#main {
overflow: scroll;
width: 200px;
background-color: #321;
display: flex;
flex-direction: row;
padding: 10px;
flex-wrap: wrap;
justify-content: flex-start;
}
.el {
width: 50px;
height: 50px;
background-color: red;
margin: 5px;
}
<div id="main">
<div class="el"></div>
<div class="el"></div>
<div class="el"></div>
</div>
The simple answer is: The scrollbars take up space inside the div. If you force them to render by setting overflow: scroll you take up some of the space inside the flexbox and flex: wrap property causes the content to wrap.
Your main flexbox can handle content of 180px width*.
The content width is also exactly 180px**
This allows no space for the scrollbars and the content ends up wrapping onto the next line.
There is a deprecated property: overflow: overlay which causes the scrollbars to not take up space but it has very limited support and is deprecated so I would not recommend using it.
*Because the width is set to 200px which includes 10px padding on each side. The box-sizing: border-box property makes it so the padding is included in the height and width calculation
**Each el has 60px width including the margin on both sides.

Center div vertically without overflowing when content is larger [duplicate]

This question already has answers here:
Can't scroll to top of flex item that is overflowing container
(12 answers)
Closed 4 years ago.
I must be forgetting something fundamental with my vertically and horizontally centered flexbox.
The container is within a parent with vertical scroll, and when the container becomes too tall, it grows beyond the parent top, clipping the content. The bottom stays put.
Try adjusting the height of the view or adding more lines to see it in action.
body,
html {
height: 100%;
width: 100%;
margin: 0;
}
* {
box-sizing: border-box;
}
#wrapper {
background: grey;
height: 100%;
width: 100%;
max-height: 100%;
display: flex;
overflow-y: auto;
align-items: center;
justify-content: center;
}
#box {
margin: 30px 0;
background: white;
border: 1px solid #dfdfdf;
}
<div id="wrapper">
<div id="box">
First line
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br> Last linje
</div>
</div>
How do I keep it from getting clipped? Additionally I'm trying to have a 30px margin above and below the container.
Thanks!
You forgot nothing but you simply need to understand what is happening. First you made your wrapper to be 100% height of screen and then you made the box to be centred vertically and horizontally. When the box has a big height you will have something like this:
Now, when you add overflow-y: auto you will create a scroll that will start from the top of the wrapper until the bottom overflowed content. So it will be like this:
That's why you are able to scroll to the bottom to see the bottom part and not able to see the top part.
To avoid this, use margin:auto to center your element and in this case we will have two situations:
When box-height < wrapper-height we will have the space spread equally on each side because of the margin:auto thus your element will be centred like expected.
When box-height > wrapper-height we will have the normal behavior and your element will overflow and his top edge will stick to the top edge of the wrapper.
You may also notice the same can happen horizontally that's why I will use margin to center on both directions.
body,
html {
height: 100%;
width: 100%;
margin: 0;
}
* {
box-sizing: border-box;
}
#wrapper {
background: grey;
height: 100%;
width: 100%;
max-height: 100%;
padding:30px 0;
display: flex;
overflow-y: auto;
}
#box {
margin: auto;
background: white;
border: 1px solid #dfdfdf;
}
<div id="wrapper">
<div id="box">
First line
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br> Last linje
</div>
</div>
I think what you want is to make your flex item (#box) have a height and set it's overflow, not the flex container. Also, to add your 30px above and below I would remove the margin from the box and instead add padding to the container.
So, updated styles would look like this:
#wrapper {
background: grey;
height: 100%;
width: 100%;
max-height: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 30px 0; /*added*/
}
#box {
background: white;
border: 1px solid #dfdfdf;
overflow-y: auto; /*added*/
height: 100%; /*added*/
}
body,
html {
height: 100%;
width: 100%;
margin: 0;
}
* {
box-sizing: border-box;
}
#wrapper {
background: grey;
height: 100%;
width: 100%;
max-height: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 30px 0;
}
#box {
background: white;
border: 1px solid #dfdfdf;
overflow-y: auto;
height: 100%;
}
<div id="wrapper">
<div id="box">
First line
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br> Last linje
</div>
</div>
I think you set the top margin in the box class which extends the height of the container. You can maybe set it to padding instead of margin. Hope this helps. Thanks.

How to enable a scrollbar on a flex item?

I have a flexbox-based layout with two panels (top and bottom) occupying 1/3 and 2/3 of the viewport, respectively. (Actually there are more panels, but I've distilled it to the minimal example).
The top panel is also a flex container, because I want its children to flow top to bottom and be vertically centered when there is room. When there is more stuff in top panel than would fit in it, I want it to be scrollable, hence overflow: auto.
The problem: the contents of top shrink to its size, even with flex-shrink: 0, and the scrollbar never pops up.
Observe how the content is shrunk in the following demo, even though it has an explicitly specified height:
html, body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.main {
display: flex;
height: 100%;
flex-direction: column;
}
.top {
display: flex;
flex-direction: column;
flex-basis: 33%;
border-bottom: 1px solid #ccc;
overflow: auto;
justify-content: center;
padding: 20px;
}
.bottom {
overflow: auto;
flex-basis: 67%;
}
.content {
height: 500px;
background-color: #eee;
}
<div class="main">
<div class="top">
<div class="content">Content</div>
</div>
<div class="bottom"></div>
</div>
The questions:
How to fix this while preserving the layout requirements? Disabling display: flex for the top panel gives the desired effect in the demo. I could position contents of top in a flexboxless way, but I lose the benefits of flex layout and the automatic vertical centering.
Why does this happen? References to CSS spec would be welcome.
You wrote:
The problem: the contents of top shrink to its size, even with flex-shrink: 0, and the scrollbar never pops up.
Actually, the solution is flex-shrink: 0. So the question becomes, where did you apply it?
It wouldn't work if you applied it to top – a flex item in the primary container with flex-basis: 33% (i.e., height: 33%, in this case) – because the length of top is a percentage. As such, it will shrink / expand naturally as percentage lengths are relative to the parent container.
You need to apply flex-shrink: 0 to .content – a flex item in the nested container with a fixed height (height: 500px / flex-basis: 500px).
So this will work:
.content {
height: 500px;
flex-shrink: 0;
}
or this:
.content {
flex-basis: 500px;
flex-shrink: 0;
}
or, better yet, this:
.content {
flex: 0 0 500px; /* don't grow, don't shrink, stay fixed at 500px */
}
From the spec:
7.2. Components of
Flexibility
Authors are encouraged to control flexibility using the flex shorthand
rather than with its longhand properties directly, as the shorthand
correctly resets any unspecified components to accommodate common
uses.
body {
margin: 0;
}
.main {
display: flex;
flex-direction: column;
height: 100vh;
}
.top {
display: flex;
flex-direction: column;
flex-basis: 33%;
border-bottom: 1px solid #ccc;
overflow: auto;
justify-content: center;
padding: 20px;
}
.bottom {
overflow: auto;
flex-basis: 67%;
}
.content {
flex: 0 0 500px;
background-color: #eee;
}
<div class="main">
<div class="top">
<div class="content">Content</div>
</div>
<div class="bottom"></div>
</div>
Then you have a second problem, which is that the upper section of the top element gets cut off and is inaccessible via scroll. This is caused by justify-content: center on the container.
This is a known issue. It is solved by using flex auto margins.
So instead of this:
.top {
display: flex;
flex-direction: column;
flex-basis: 33%;
border-bottom: 1px solid #ccc;
overflow: auto;
/* justify-content: center; <--- REMOVE */
padding: 20px;
}
do this:
.content {
flex: 0 0 500px;
margin: auto 0; /* top & bottom auto margins */
background-color: #eee;
}
body {
margin: 0;
}
.main {
display: flex;
flex-direction: column;
height: 100vh;
}
.top {
display: flex;
flex-direction: column;
flex-basis: 33%;
border-bottom: 1px solid #ccc;
overflow: auto;
/* justify-content: center; USE AUTO MARGINS ON FLEX ITEM INSTEAD */
padding: 20px;
}
.bottom {
overflow: auto;
flex-basis: 67%;
}
.content {
flex: 0 0 500px;
margin: auto 0;
background-color: #eee;
}
<div class="main">
<div class="top">
<div class="content">Content</div>
</div>
<div class="bottom"></div>
</div>
Here's a complete explanation:
Can't scroll to top of flex item that is overflowing container
The scrollbar appears when there are enough .content element shrinked to their very minimal height (one line height in this case).
That's not really how things work with flex. height is not strictly respected. If you still want to work with height, you can fix this by setting a min-height to .content according to the minimum height you want for them.
Or you can instead set flex on .content (and get rid of height):
css
flex: 100px 1 0;
Which will set a minimum height (flex-basis) of 100px, flex-grow at 1 so that it takes all the available space, and flex-shrink at 0 so that the element is always at least 100px tall.

Position last flex item at the end of container

This question concerns a browser with full css3 support including flexbox.
I have a flex container with some items in it. They are all justified to flex-start but I want the last .end item to be justified to flex-end. Is there a good way to do this without modifying the HTML and without resorting to absolute positioning?
.container {
display: flex;
flex-direction: column;
outline: 1px solid green;
min-height: 400px;
width: 100px;
justify-content: flex-start;
}
p {
height: 50px;
background-color: blue;
margin: 5px;
}
<div class="container">
<p></p>
<p></p>
<p></p>
<p class="end"></p>
</div>
Flexible Box Layout Module - 8.1. Aligning with auto margins
Auto margins on flex items have an effect very similar to auto margins in block flow:
During calculations of flex bases and flexible lengths, auto margins are treated as 0.
Prior to alignment via justify-content and align-self, any positive free space is distributed to auto margins in that dimension.
Therefore you could use margin-top: auto to distribute the space between the other elements and the last element.
This will position the last element at the bottom.
p:last-of-type {
margin-top: auto;
}
.container {
display: flex;
flex-direction: column;
border: 1px solid #000;
min-height: 200px;
width: 100px;
}
p {
height: 30px;
background-color: blue;
margin: 5px;
}
p:last-of-type {
margin-top: auto;
}
<div class="container">
<p></p>
<p></p>
<p></p>
</div>
Likewise, you can also use margin-left: auto or margin-right: auto for the same alignment horizontally.
p:last-of-type {
margin-left: auto;
}
.container {
display: flex;
width: 100%;
border: 1px solid #000;
}
p {
height: 50px;
width: 50px;
background-color: blue;
margin: 5px;
}
p:last-of-type {
margin-left: auto;
}
<div class="container">
<p></p>
<p></p>
<p></p>
<p></p>
</div>
This flexbox principle also works horizontally
During calculations of flex bases and flexible lengths, auto margins
are treated as 0. Prior to alignment via justify-content and
align-self, any positive free space is distributed to auto margins in
that dimension.
Setting an automatic left margin for the Last Item will do the work.
.last-item {
margin-left: auto;
}
Code Example:
.container {
display: flex;
width: 400px;
outline: 1px solid black;
}
p {
height: 50px;
width: 50px;
margin: 5px;
background-color: blue;
}
.last-item {
margin-left: auto;
}
<div class="container">
<p></p>
<p></p>
<p></p>
<p class="last-item"></p>
</div>
Codepen Snippet
This can be very useful for Desktop Footers.
As Envato did here with the company logo.
Codepen Snippet

Resources