How to use position fixed in flex layout? - html

I have a flexbox layout with two columns.
The left column be fixed, while the right is scrollable.
How can you do that?
Take a look at the following code:
#parent {
display: flex;
}
#left {
flex-grow: 1;
}
#left div {
position: fixed;
background: blue;
top: 0;
left: 0;
height: 100vh;
}
#right {
flex-grow: 5;
background: red;
height: 300vh;
}
<div id="parent">
<div class="child" id ="left">
<div>
ABC
</div>
</div>
<div class="child" id ="right">
DEF
</div>
</div>
Fiddle

If I understand your requirements, you want make the right scroll and the left be fixed. That can be done without the use of fixed position.
I would also personally recommend to not use fixed position, unless it is absolutely necessary, as it can have some unwanted behavior on mobile device, and you kind of loose the benefit non positioned solutions like flexbox offer.
html, body {
margin: 0;
}
#parent {
display: flex;
height: 100vh;
}
#left {
flex-grow: 1;
background: blue;
}
#right {
flex-grow: 5;
background: red;
overflow: auto;
}
#right div {
height: 300vh;
}
<div id="parent">
<div class="child" id ="left">
ABC
</div>
<div class="child" id ="right">
<div>
DEF
</div>
</div>
</div>

here you go
#parent {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: flex;
align-items: stretch;
}
#left {
flex-grow: 1;
background: lightgray;
}
#right {
flex-grow: 5;
background: red;
overflow-y: auto;
}
.scroll {
height: 300vw;
}
<div id="parent">
<div class="child" id="left">
<div>
ABC
</div>
</div>
<div class="child" id="right">
<div class="scroll">
DEF
</div>
</div>
</div>

You wrote in the comments:
the width of the fixed div is not the parents width.
When you add position: fixed to an element, you remove it from the normal flow of the document and position it relative to the viewport.
The fixed element has no reason to recognize the parent's width in the HTML structure.
You may be able to achieve what you want by making the entire layout fixed (like in this answer). Otherwise, you'll need a JavaScript alternative.

Related

Dynamic size of footer with full screen web page

image wireframe
I would like to recreate messaging phone app in html and css. So the app must be full frame without any overflow.
The trick is the bottom part (in red) must be resizable according to the child content. So I used flex (with flex-direction: column) to manage my layout.
The problem is : when the content (in yellow) grow up, the core part will compress the red part. My goal is to overflow, with a scrollbar, the content inside the core part and don't change the size of the red div.
index.html
<body>
<div id="header">
</div>
<div id="core">
<div class="conainer" style="">
<div class="row">
<div class="two columns"></div>
<div class="ten columns">
<div class="msgright">
.
</div>
</div>
</div>
<div class="row">
<div class="ten columns">
<div class="msgright">
.
</div>
</div>
<div class="two columns"></div>
</div>
</div>
</div>
<div id="footer">
</div>
index.css
html, body, div {
margin: 0;
padding: 0;
}
html, body {
height: 100%;
max-height: 100%;
overflow: hidden;
}
body {
display: flex;
flex-direction: column;
}
#header {
height: 50px;
background: #2A9D8F;
flex: 0 0 auto;
}
#core {
background-color: #264653;
flex: 1;
display: flex;
align-items: flex-end;
}
#footer {
height: auto;
background-color: red;
min-height: 50px;
flex: 0 0 auto;
}
.conainer {
flex: 0 0 100%;
}
.row {
margin: 5px;
background-color: yellow;
height: 130px;
}
https://codepen.io/jln_brtn/pen/pobVZBv
Best regards and thank you for your help.
I'm not sure if I understand the problem correctly but since your .row elements have a fixed height: 130px, the element should not be able to grow any further. Overflow styling to .row elements can be added like this:
.row {
overflow-y: scroll;
}
If it is just the #core element, then you can do something like this:
#core {
overflow-y: scroll;
}
For this instance I would suggest to use CSS Grid instead of Flexbox, and giving both <header> and <footer> the space they need, while the <main> gets the rest. This means that both <header> and <footer> stay were they are, even if <main> needs more space for its content, meaning <main> will get a scrollbar.
You can achieve the same by using position: fixed and setting a margin to top and bottom, with fixed heights of <header> and <footer>, and sizing <main> with height: calc(100% - HEIGHT_OF_HEADER - HEIGHT_OF_FOOTER). The problem with this is maintenance, as you would always have to check and revalidate the heights when changing something.
html, body {
margin: 0;
width: 100%;
height: 100%;
}
body {
display: grid;
grid-template-rows: auto 1fr auto;
}
header {
height: 3.125rem;
background: #2A9D8F;
}
main {
padding: 0.3125rem;
display: flex;
flex-flow: column;
gap: 0.3125rem;
background: #264653;
overflow: hidden auto;
}
footer {
height: 3.125rem;
background: red;
}
main > div {
flex-shrink: 0;
height: 8.125rem;
background: yellow;
}
<header></header>
<main>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</main>
<footer></footer>

Flexbox with flex:1 child and grandchild with 100%

Imagine having this situation: a simple 3 rows layout made with flexbox, with the central row filling all the space available. Pretty standard stuff.
<body>
<div class="container">
<div class="flex-container">
<div>header</div>
<div class="content">
<div class="item red">asdasd</div>
<div class="item yellow">asdasd</div>
<div class="item green">asdasd</div>
</div>
<div>footer</div>
</div>
<div>
<body>
Here the CSS:
html,
body,
.container {
height: 100%;
}
.flex-container {
height: 100%;
display: flex;
flex-direction: column;
}
.flex-container .content {
flex: 1;
}
.flex-container .content .item {
height: 100%;
}
(omitting css for background colors, you can guess it).
The problem is that the "content" div does not push down the footer div, keeping it at the bottom of the page, like is position:fixed with bottom: 0.
Scrolling the page show, except for this problem, the correct behavior, with 3 div with different color all sizing 100% the browser window.
What I'm missing?
EDIT: look at this jsfiddle
https://jsfiddle.net/rq1xywng/
I am not sure about what you are looking for. May be it will be help for you.
html,
body {
margin: 0;
padding: 0;
box-sizing: border-box;
height: 100vh;
min-height: 100vh;
}
.container {
height: 100vh;
min-height: 100vh;
background-color: fuchsia;
}
.header, .footer {
height: 30px;
}
.flex-container .content {
display: flex;
height: 100%;
height: calc(100vh - 60px);
}
.flex-container .content .item {
width: 100%;
height: 100%;
}
.red {
background-color: red;
}
.yellow {
background-color: yellow;
}
.green {
background-color: green;
}
<div class="container">
<div class="flex-container">
<div class="header">header</div>
<div class="content">
<div class="item red">asdasd</div>
<div class="item yellow">asdasd</div>
<div class="item green">asdasd</div>
</div>
<div class="footer">footer</div>
</div>
<div>
So you have couple of errors here:
you set EVERY ITEM IN THE CONTAINER to be 100% - this amounts to 300% :)
their parent is "only" 100%
footer will be hidden unless given height
you used vh and % combined in an unhealthy way.
you should have 2 flex components:
.flex-container - to match to screen size
.flex-container .content - to be able to stretch the items
You should set .item to flex: 1;
Here is a working version: https://jsfiddle.net/oj0thmv7/5/
Here is a working example with scroll: https://jsfiddle.net/oyLbxsrc/
If you change the 100% to 100vh this works
.flex-container .content .item {
height: 100vh;
}
Or have I misunderstood the issue?

Scrollbar and its content is hidden outside of div

So I have a problem where I have 2 divs inside of another div with a fixed size. I the second of the two is too large to fit in the fixed height div so I want a scroll bara to appear. But the scrollbar goes outside of the content. How do I fix this?
html:
<div class="main">
<div class="first-child">
<div class="small-content">
Content
</div>
</div>
<div class="second-child">
<div class="large-content">
Content
</div>
</div>
</div>
css:
.main {
height: 250px;
overflow: hidden;
}
.first-child {
background-color: red;
}
.second-child {
max-height: 100%;
background-color: blue;
overflow-y: scroll;
}
.large-content {
padding-top: 300px;
}
.small-content {
padding: 10px;
}
https://codepen.io/RilleJ/pen/JeBVpz
I added an example as well to show what I mean. Basically I want to be able to scroll all the way down in the blue box and see the content without setting a fixed height. (Not that the content above, the red box, can be different sizes)
Use flexbox to divide the space of the container among the children.
Add flex-grow: 0, and flex-shrink: 0 for a child that just needs to take the space it needs for its content.
Add flex-grow: 1, and flex-shrink: 1 on the other children to divide the remaining space equally (each child will take at least the size of its content).
.main {
height: 250px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.first-child {
flex-grow: 0;
flex-shrink: 0;
background-color: red;
}
.second-child {
flex-grow: 1;
flex-shrink: 1;
background-color: blue;
overflow-y: scroll;
}
.large-content {
padding-top: 300px;
}
.small-content {
padding: 10px;
}
<div class="main">
<div class="first-child">
<div class="small-content">
Content
</div>
</div>
<div class="second-child">
<div class="large-content">
Content
</div>
</div>
</div>

Why does div with "display: flex" and "position: fixed" doesn't occupy the full available width?

I noticed that when div has position: fixed and display: flex, it doesn't occupy the full available width like normal divs do.
.container {
display: flex;
background-color: #ddd;
margin-top: 50px;
}
.fixed {
position: fixed;
}
.content {
background-color: #bbb;
flex-grow: 1;
}
<div class="container">
<div>Title</div>
<div class="content">Content</div>
</div>
<div class="container fixed">
<div>Title</div>
<div class="content">Content</div>
</div>
How could I change my CSS so that the second container occupy the full available width like that first one does?
Why? is already answered by Michael_B
... it is out-of-flow ...
What you can also do is to size the fixed element from left and right coordonates instead width:100%; that is more often a trouble maker than helpfull.
If it is a direct-child of body, it can also inherits margins .
.container {
display: flex;
background-color: #ddd;
margin-top: 50px;
}
.fixed {
position: fixed;
left:0;
right:0;
margin-left:inherit;
margin-right:inherit;
}
.content {
background-color: #bbb;
flex-grow: 1;
}
<div class="container">
<div>Title</div>
<div class="content">Content</div>
</div>
<div class="container fixed">
<div>Title</div>
<div class="content">Content</div>
</div>
The first container represents an in-flow block-level element. Such elements are designed to stack vertically. This means they occupy the full width of their parent container.
The second container represents an absolutely-positioned element (fixed positioning is a form of absolute positioning). This means the element is out-of-flow and doesn't take up any space.
Unlike in-flow block-level elements, absolutely-positioned elements are not designed to stack vertically. So there's no automatic full width. The default width and height of an absolutely-positioned element is based on its content. To override default sizing, set your own lengths.
.container {
display: flex;
background-color: #ddd;
margin-top: 50px;
}
.fixed {
position: fixed;
width: 100%; /* new */
/* alternatively, you can use left: 0 and right: 0 */
}
.content {
background-color: #bbb;
flex-grow: 1;
}
<div class="container">
<div>Title</div>
<div class="content">Content</div>
</div>
<div class="container fixed">
<div>Title</div>
<div class="content">Content</div>
</div>
You have to add width: 100%; , otherwise the width will be just as wide as the contents of the element.
Also, you should add html, body { margin: 0; } to avoid the default margins.
BTW: That has nothing to do with display: flex, but only with position: fixed...
html, body {
margin: 0;
}
.container {
display: flex;
background-color: #ddd;
margin-top: 50px;
}
.fixed {
position: fixed;
width: 100%;
}
.content {
background-color: #bbb;
flex-grow: 1;
}
<div class="container">
<div>Title</div>
<div class="content">Content</div>
</div>
<div class="container fixed">
<div>Title</div>
<div class="content">Content</div>
</div>

How can I make the left div expand and the right div have constant width?

So as the title says, I want to put two divs right next to each other, and have the left one expand if the window is expanded, while the right one stays at a constant width.
Here is what I've got so far:
<body>
<div id="content" style="background-color: red">
<div id="left" style="margin-right: 100px; background-color: blue">
This</br>is</br>left.
</div>
<div id="right" style="float: right; width: 100px; height: 100px; background-color: green">
This</br>is</br>right.
</div>
<div style="clear:both"></div>
</div>
</bod>
Which produces this:
Ideally, the green square and blue square should have their tops aligned with each other. One solution I found was putting a negative margin-top setting on the green div, which works... but only as long as the blue div never changes in height. Unfortunately, the blue div can in fact change height in my situation.
Any ideas on how I'd fix this? I'm having some difficulty understanding the intricacies of CSS positioning :(
If you can use position:absolute, you can do something like this:
<div class="left">This is the left box.</div>
<div class="right">This is the right box.</div>
And the CSS:
.left {
position: absolute;
left: 0px;
right: 100px;
}
.right {
position: absolute;
right: 0px;
width: 100px;
}
http://jsfiddle.net/Q2TKU/
Have you considered nesting them ?
http://jsfiddle.net/bonatoc/N3xWn/
<div id="content" style="background-color: red">
<div id="left" style=" background-color: blue">
<div id="right" style="display:inline-block; float: right; width: 100px; height: 100px; background-color: green">
This</br>is</br>right.
</div>
This</br>is</br>left.
</div>
<div style="clear:both"></div>
You could do it this way.
If this is your HTML:
<div id="content">
<div id="left">This</br>is</br>left.</div>
<div id="right">This</br>is</br>right.</div>
</div>
Try the following CSS:
#content {
background-color: red;
position: relative;
min-height: 100px;
}
#left {
margin-right: 100px;
background-color: blue;
width: auto;
}
#right {
position: absolute;
top: 0;
right: 0;
width: 100px;
height: 100px;
background-color: green;
}
See demo at: http://jsfiddle.net/audetwebdesign/GfpyL/
Your logo in the #right element has specific dimensions, so position it absolutely to the top right of the parent #content element which has position: relative to set the point of reference for the absolute positioning.
Add a min-height to the parent block to prevent it from collapsing for those cases where the #left block is less than 100px in height.
How about using flexbox? flexbox help you control these width flexibility.
If you set left content as a 100px, right box width is flexibility.
HTML below :
<div id="content" >
<div id="left">
This<br>is<br>left.
</div>
<div id="right">
This<br>is</br>right.
</div>
</div>
CSS below:
#content {
/* old*/
display: -webkit-box;
display: -moz-box;
display: -ms-box;
display: box;
/* New */
display: -webkit-flexbox;
display: -moz-flexbox;
display: -ms-flexbox;
display: flexbox;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
#left {
/* old */
-webkit-box-ordinal-group: 1;
-moz-box-ordinal-group: 1;
-ms-box-ordinal-group: 1;
box-ordinal-group: 1;
/* New */
-webkit-flex-order: 1;
-moz-flex-order: 1;
-ms-flex-order: 1;
flex-order: 1;
/* Old */
-webkit-box-flex: 1;
-moz-box-flex: 1;
-ms-box-flex: 1;
box-flex: 1;
/* New */
width: -webkit-flex(1);
width: -moz-flex(1);
width: -ms-flex(1);
width: flex(1);
}
#right {
width: 100px;
/* Old */
-webkit-box-ordinal-group: 2;
-moz-box-ordinal-group: 2;
-ms-box-ordinal-group: 2;
box-ordinal-group: 2;
/* New */
-webkit-flex-order: 2;
-moz-flex-order: 2;
-ms-flex-order: 2;
flex-order: 2;
}
Here is jsfiddle code below :
http://jsfiddle.net/sota0805/kykU7/
I hope it help you.
You could use make use of block formatting contexts to fill remaining width.
1) Float the first child of a div
2) Set overflow:auto (or hidden) on the second child to fill remaining width
So this would work too:
FIDDLE
Markup:
<div class="wpr">
<div class="rFloat"></div>
<div class="blue overflow" contenteditable>this is left</div>
<div class="rFloat green">This is right</div>
<div class="overflow"></div>
</div>
CSS
.wpr {
background: red;
min-width: 200px;
}
div {
min-height: 20px;
}
.rFloat {
width: 100px;
float:right;
}
.blue {
background: blue;
}
.green {
background: green;
}
.overflow {
overflow: auto;
}
Notice that in the fiddle I have set the contenteditable attribute to true on the blue div - so you can type in the blue area and see that it expands as required.