Angular component destroys flexbox height information for its child elements - html

I have a flexbox parent container whose flex-grow gives my containing div element as much height as is available. The children of this div element of course have height:100%. This works fine.
<div style="display:flex; flex-direction:column;">
<div style="flex-grow:1;background:green;" id="parentContainer">
<div style="height:100%;overflow:auto;background:red;" id="contentContainer">
<!-- content of whatever size confined to space allocated -->
</div>
</div>
</div>
But when I have an angular component in-between the parentContainer and contentContainer like so:
<div style="display:flex; flex-direction:column;">
<div style="flex-grow:1;background:green;" id="parentContainer">
<my-ng-component style="height:100%; display:block; background:blue;">
<div style="height:100%;overflow:auto;background:red;" id="contentContainer">
<!-- content of whatever size confined to space allocated -->
</div>
</my-ng-component>
</div>
</div>
The angular component resets the height to 0px, so the contentContainer ends up with 0px height as well.
How do I fix the angular component to not destroy the height information?
Plunk: http://plnkr.co/edit/0eai5HFZh7o2Vguzd5j6?p=preview

Generally, height: 100% doesn't work properly on child of a flex child, and the main reason is that Flexbox stretch to fit its flex parent but still resolve its height to auto, as shown here in this answer:
Why height=100% doesn't work?
In your case though, when using flex column direction, it is possible.
The now used flex-grow: 1 will leave the flex-shrink and flex-basis to their default, 1 and auto, and here it is the auto that cause the issue.
By changing it to, and here using the recommended shorthand flex, flex: 1 100% the child and its descendants will have a height to pick up their 100% from.
Note 1, simply using flex: 1 (same as flex: 1 1 0) works too on Chrome/FF/Edge/IE11, but if I'm not wrong, Safari 10 had some issues when flex-basis becomes 0.
Updated plnkr
With the following updated code fragments
app.component.html
<div style="display:flex;flex-direction:column;height:324px;">
<div style="flex:1 100%; background:black; color: white;">
foo
<app-list style="height:100%;display:block; background:blue;"></app-list>
</div>
</div>

Related

Image inside a flexbox overflows, and setting max-height does not work

This is the demo of my problem.
And this is the outline of my HTML:
<div class="container">
<div class="f1">
TITLE
</div>
<div class="f2">
<div class="f2-child">
<img/>
</div>
</div>
</div>
Basically it's a flex container which contains two flex items. The first flex item(f1) is the title, which takes up some fixed height. And the second flex item(f2) fill the rest of the height. So far so good.
And I put another flex container(f2-child) inside of f2, just to create some margin space. And I want an image to fit inside f2-child. The image should be as wide as f2-child, but its maximum height should be the same as f2-child.
It works fine when the viewport's width is low, but when the width gets higher, the image would overflow. I tried setting f2 and f2-child's max-height to 100%, but it does not work.
To solve the issue of the image overflowing, you can try setting the max-width property of the image to 100% and the width property to auto. This will ensure that the image's width is equal to the width of the parent container (f2-child) and its height is proportional to its width, preventing overflow.
You can also add overflow: hidden to the f2-child container to clip any content that exceeds its boundaries.
Here's the updated code:
<div class="container">
<div class="f1">
TITLE
</div>
<div class="f2">
<div class="f2-child" style="overflow: hidden;">
<img style="max-width: 100%; width: auto;" />
</div>
</div>
</div>
Add the two tailwind classes h-full object-cover to your image tag.
<img src="https://source.unsplash.com/04X1Yp9hNH8/1600x900" alt="img" class="w-full h-full object-cover"/>
I've figured out myself by learning more about how flexbox works.
This is my final outcome: codepen link. I use tailwind so you need to know a little bit about it.
Now my layout looks like this:
<div class="container">
<div class="f1">
TITLE
</div>
<div class="f2">
<img/>
</div>
</div>
I removed f2-child from the last version.
The flex direction of the container is column, so after determining the height of f1, f2 would stretch itself. f2 is also a flex container, but with row flex direction. The image is its flex item.
Notice how f2 has multiple tailwind classes. flex items-center justify-center make sure image is horizontally and vertically aligned in f2.
And f2's grow-0 shrink-1 basis-auto h-full min-h-0 plus img's max-h-full make sure that when the view port is wider, the content won't overflow.
For more details you could see this post: Prevent flex items from overflowing a container

How the width of a inline-flex div is decided?

for an inline-flex div, the width is depending on its children elements' width. Here is the code, I don't set the parent div with specified width. So, it is decieded by inside elements.
For the three children elements, one is with width:50%, others are width:50px, but the final width for 2 is 31.75, how does it come?
<div style="display: inline-flex;flex-wrap: nowrap;">
<div style="width:50%;color:red">1</div>
<div style="width:50px;color:blue">2</div>
<div style="width:50px;color:black">3</div>
<span>hello</span>
</div>
Here is a step by step illustration to understand what the browser is doing:
div div {
outline:1px solid green
}
<p>The browser will first ignore the width:50% and use auto instead</p>
<div style="display: inline-flex;flex-wrap: nowrap;border:2px solid red">
<div style="width:auto;color:red">1</div>
<div style="width:50px;color:blue">2</div>
<div style="width:50px;color:black">3</div>
<span>hello</span>
</div>
<p>Now that we have the width of the parent, it will no more change and we resolve width:50%</p>
<div style="display: inline-flex;flex-wrap: nowrap;border:2px solid red">
<div style="width:50%;color:red">1</div>
<div style="width:50px;color:blue">2</div>
<div style="width:50px;color:black">3</div>
<span>hello</span>
</div>
<p>all the div will shrink because there is not enough space for them (50% + 50px + 50px + hello > 100%). A shrink that you can disable if you use flex-shrink:0 and you will have overflow</p>
<p>Only "hello" will not shrink because a flex item cannot shrink past its content size</p>
<div style="display: inline-flex;flex-wrap: nowrap;border:2px solid red">
<div style="width:50%;color:red;flex-shrink:0;">1</div>
<div style="width:50px;color:blue;flex-shrink:0;">2</div>
<div style="width:50px;color:black;flex-shrink:0;">3</div>
<span>hello</span>
</div>
For more detail about the shrink algorithm if you want to understand the calculation:
How flexbox calculates flex-item's width if no flex-basis or width are set?
Why is a flex item limited to parent size?
To understand why "hello" will not shrink:
Why don't flex items shrink past content size?
The purple area you see in the dev tools is the width before the shrink effect. You can notice it's equal to 50px for the 2nd and 3rd div

flex box make items 100% width of itself

I have the following html structure which I'm trying to arrange with a flex-box approach, with a row flex-direction. This is more or less the idea
<!-- 100% viewport width -->
<body>
<!-- This toolbar should have whatever width may remain from parent -->
<div class="toolbar-1 width-remain">
<!-- This toolbar should have whatever width may remain from parent -->
<div class="tb1-item1 width-remain">Some content</div>
<!-- This toolbar should have 100% of its content -->
<div class="tb1-item2 width-content">
<!-- This toolbar should have 100% of its content -->
<div class="tb1-item2-inner1 width-content">Some content</div>
<!-- This toolbar should have 100% of its content -->
<div class="tb1-item2-inner2 width-content">Some content</div>
<!-- This toolbar should have 100% of its content -->
<div class="tb1-item2-inner3 width-content">Some content</div>
</div>
<!-- This toolbar should have 100% of its content -->
<div class="tb1-item3 width-content">Some content</div>
</div>
<!-- This toolbar should have 100% of its content -->
<div class="toolbar-2 width-content">
<div class="tb2-item1 width-content">Some content</div>
</div>
</body>
I was hoping to have two toolbars where one may grow in width (the second one, and the first one may occupy whatever space is left). Also, inside the first toolbar I have some extra items which I'd like to be able to grow in width, and one item which may occupy whatever space is left).
In general the width set in the inner items as
flex: 1 1 100%; takes the 100% of its parent, and not of its width. Setting flex: 1 1 auto; makes the items to have an even width. Also tried putting 0 to the flex-growth and flex-shrink properties. I've tried setting justify-content: stretch; to the toolbar parent, and justify-self: stretch to the inner items that may grow based on its content but with no success.
does anyone know how I can achieve this? Thanks in advance!
It sounds like there's a misunderstanding on how to use the flex property with child elements within an element with display:flex;.
Essentially you need to tell .toolbar-1 it's okay to grow, and .toolbar-2 it's okay to shrink. To accomplish that you can certainly use the flex property like so:
.toolbar-1 {
flex: 1 0 auto; /* grow shrink basis */
}
.toolbar-2 {
flex: 0 1 auto;
}
Alternatively you can just use the grow and shrink properties:
.toolbar-1 {
flex-grow: 1;
}
.toolbar-2 {
flex-shrink: 1;
}
I threw together this example based on what I understand from the question: Flexible Toolbars

Form with variable content and control button in fixed area

The main issue that is not treated in similar questions listed below is a FORM object that has a variable part and a non variable footer (submit buttons)
The aim is to display:
A header (a table (width:100%) with a logo and a text in second cell): size should be the smallest possible with all content displayed
A FORM (containing 2 parts):
Fields are in a div that will expand to all space remaining and will scroll if it lack space. (minimum size: 1 text line)
Submit / Rest buttons are in a table and should ALWAYS be visible and not resized in anyway. At worst the stick to bottom of browser window.(except if browser window becomes ridiculously small of course)
Nothing should go below bottom of browser window (except if user resize to a ridiculous size).
Hardcoded height is NOT an option (except the 100% for technical reasons - body or column parent for example). Header and footer height MUST be autocomputed by browser to use minimum space while displaying all content. If user reduce the width of the browser window increasing the header or footer text to wrap on more lines, the height must grow accordingly. Thus percentage or viewport heigh is not an option as it is arbitrary and can't take car of the user zoom, the browser width resize and such.
I've tried the following layout:
<div id="column">
<div id="header>
<table><tbody>
<tr><td>LOGO</td><td>Some intro text on a few lines</td></tr>
</tbody></table>
<!-- optionnel error line (arbitrary length) if previous form submission failed -->
</div>
<form>
<div id="variable_scrollable_content">
<!-- multiple field sets hosting some input (text, select, ...) -->
</div>
<div id="footer">
<table><tbody>
<tr><td>Save button</td><td>Reset button</td></tr>
</tbody></table>
<!-- A few lines of text -->
</div>
</form>
</div>
After I gave a careful view to similar questions (see below), I was unable to find something that could handle the FORM object that has a variable size scrollable part and a fixed footer.
I also gave a careful look at https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox with no more success.
I tried the flex approach for classes header, variable_scrollable_content and footer with no success. I also tried to put the form object in flex class but that doesn't work.
As I can't separate the FORM submit/reset buttons from the fields they manage, I don't know how to solve this.
header should stick to top of browser windows
footer (containing form control buttons) should stick to bottom of browser window at worst or stick at the end of the last fields if browser windows is big enough.
fields should be in a variable size container that uses all the remaining space between header and footer and has overflow-y:scroll; so it can scroll if it can't display its whole content.
In case the above simplified code is not sufficient, the "real" code can be found here:
https://github.com/finley/SystemImager/blob/initrd-from-imageserver-and-dont-package-initrd/webgui/edit_config.php
The full css is here:
https://github.com/finley/SystemImager/blob/initrd-from-imageserver-and-dont-package-initrd/webgui/css/screen.css
Similar questions
I have checked the following similar questions, and I believe my question is different as the main problem is the FORM object interfering with the layout:
scrolling content between fixed header & footer with variable height
Content height expand between fixed header and fixed footer
Make a div fill the height of the remaining screen space
Original question was here: variable height div between header and footer
I've just found the solution.
In this situation, the problem was the FORM object that would interfere with flex column children not at the same Dom level tree.
The simple solution was to move the FORM object so it includes the flex column it its whole content.
The above code becomes:
<form>
<div id="column">
<div id="header>
<table><tbody>
<tr><td>LOGO</td><td>Some intro text on a few lines</td></tr>
</tbody></table>
<!-- optionnal error line (arbitrary length) if previous form submission failed -->
</div>
<div id="variable_scrollable_content">
<!-- multiple field sets hosting some input (text, select, ...) -->
</div>
<div id="footer">
<table><tbody>
<tr><td>Save button</td><td>Reset button</td></tr>
</tbody></table>
<!-- A few lines of text -->
</div>
</div>
</form>
But this was not sufficient because setting flex column height to 100% (when body is also set to 100%) won't work. maybe the form object doesn't propagate the height?
The solution was to set height of column with vh (viewport height) unit.
So I set it to 100vh. Unfortunately, there are some glitches due to some border size and padding from parent objects and itself. So as a fallback I put it to 96vh, but this is ugly and I'll investigate and will remove the parasite border size padding that makes the body bigger than 100vh.
<body style="height: 100%">
<form>
<div style="display: flex; flex-flow: column; height: 100vh;">
<div id="header" style="flex: 0 0 auto;">foo bar</div>
<div id="content" style="flex: 1 1 auto; overflow-y: scroll;">Input fields</div>
<div id="footer" style="flex: 0 0 auto;">Control buttons</div>
</div>
</form>
</body>
The above sump is bigger than 100vh in height.
There are 2 solution to fix that:
Remove any border padding or such from parent object.
Set the column to an absolute position (0,0)
Alternative solution to scrollable FORM in flex content with fixed footer containing control buttons is to move FORM control buttons outside the form.
The code then looks like:
<body style="height: 100%">
<div style="display: flex; flex-flow: column; height: 100%;">
<div id="header" style="flex: 0 0 auto;">foo bar</div>
<div id="content" style="flex: 1 1 auto; overflow-y: scroll;">
<form id="foobar">
Input fields
</form>
</div>
<div id="footer" style="flex: 0 0 auto;">
<button form="foobar" type="submit" formmethod="POST">Submit</button>
<button form="foobar" type="reset">Reset</button>
</div>
</div>
</body>
The advantage is that it works with height 100% as it takes account of margin borders and padding of parent (while vh is an absolute viewport size).

Issue getting child to fill vertically within a Flex container

I have a child div with a table inside it. I want this div to fill out vertically within the parent container.
I have tried different methods, positions, flex, margins, etc., but I cannot get it to stretch out vertically within the parent container.
Essentially I have the following:
<div class="container">
<div class="content">
<div class="GridViewContainer wrapper">
</div>
</div>
</div>
I want GridViewContainer wrapper to fill out the rest of content
I have set up a demo here: ( I set the table div to a fixed height of 400px for demo purposes)
DEMO - https://jsfiddle.net/7ashn3b5/
You're missing display:flex on the parent container.
Since you haven't made .content a flex container, flex-direction:column is being ignored, and flex items are ignoring flex properties.
Once you add display:flex to .content (and remove the height:400px), you can apply flex:1 to .GridViewContainer wrapper, which tells it to stretch the full available height of its parent.
Revised Fiddle