How can I have a position: fixed; behaviour for a flexbox sized element?
CssFlexboxCss Problem Overview
I have a div called .side-el which I would like to have in a position: fixed; behavior, but as soon as I apply position fixed the width alternates from the right one. The right width would be the one set by flexbox. How can I achieve this goal?
.container {
-webkit-align-content: flex-start;
align-content: flex-start;
-webkit-align-items: flex-start;
align-items: flex-start;
display: -webkit-flex;
display: flex;
-webkit-flex-direction: row;
flex-direction: row;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-justify-content: flex-start;
justify-content: flex-start;
* {
box-sizing: border-box;
-webkit-flex-grow: 1;
flex-grow: 1;
-webkit-flex-shrink: 0;
flex-shrink: 0;
}
}
.main-el {
box-sizing: border-box;
padding:0 2em;
width: 70%;
}
.side-el {
box-sizing: border-box;
width: 30%;
}
<div class="container" style="background-color: blue; height: 100px;">
<div class="main-el">
<div style="background-color: red; height: 1000px;">content</div>
</div>
<div class="side-el" >
<div style="background-color: red; height: 100px;">content</div>
</div>
</div>
Css Solutions
Solution 1 - Css
Here's a way to do this inspired by bootstrap:
.fixed-top {
display: flex;
position: fixed;
top: 0;
left: 0;
right: 0;
}
This gives your flex-box room to breathe and do it's flex-box thing. If your flex-direction is column, you could use top, left, bottom
instead.
This works because when you give an element a fixed position and a left
and right
of 0 or a top
and bottom
of 0, the element is stretched to fill the space from left to right, or top to bottom. That in turn allows a flex-box to use the amount of space you would expect without position fixed.
Solution 2 - Css
You can't.
As explained by the CSS2.1 spec:
> Absolutely positioned boxes are taken out of the normal flow.
And the Flexible Box Layout spec confirms that:
> An absolutely-positioned child of a flex container does not > participate in flex layout. However, it does participate in the > reordering step (see order), which has an effect in their > painting order.
(Emphasis mine)
Solution 3 - Css
@Daniel , I know this is very late but ... while the accepted answer is correct, I don't feel it's very helpful. I had the same question (which is how I came across this post), and the solution I think I'll go with is to wrap the position fixed element within the flex element. Here's a (very ugly) example
Relevant Markup
<aside class="Layout-aside" ng-class="{'isCollapsed': collapsed}" ng-controller="AsideCtrl">
<div class="Layout-aside-inner">
<button ng-click="collapsed = !collapsed">
<span ng-show="collapsed">></span>
<span ng-hide="collapsed"><</span>
</button>
<ul class="Layout-aside-content">
<li ng-repeat="i in items">{{i}}</li>
</ul>
</div>
</aside>
Relevant CSS
.Layout-aside {
order: 0;
min-width: 140px;
width: 140px;
background-color: rgba(0, 255, 0, .4);
transition: width .4s, min-width .4s;
}
.Layout-aside.isCollapsed {
min-width: 25px;
width: 25px;
}
.Layout-aside-inner {
position: fixed;
}
.Layout-aside.isCollapsed .Layout-aside-inner {
width: 25px;
}
.Layout-aside.isCollapsed .Layout-aside-content {
opacity: 0;
}
Solution 4 - Css
You can achieve it with a css alternative position: sticky
It acts great but the only problem is browser support (June 2018): https://caniuse.com/#feat=css-sticky
Hope it gets better soon.
Solution 5 - Css
position:sticky
was mentioned by Juozas Rastenis above but without code example.
Here's a minimalist example:
* {
box-sizing: border-box;
}
body {
display: flex;
margin: 0;
}
nav {
width: 20%;
height: 100vh;
top: 0; /* this is required for "sticky" to work */
position: sticky;
background: lightblue;
padding: 1rem;
}
main {
height: 3000px; /* cause scroll */
background: lightpink;
flex-grow: 1;
padding: 1rem;
}
<body>
<nav>
sidebar here
</nav>
<main>
content here
</main>
</body>
Solution 6 - Css
A far simpler solution would be to use overflow-y:scroll
and height: 100vh
on the main-el
container. This will give the appearance of fixed position to the side-el
container without resorting to position: fixed.
Solution 7 - Css
I had the same issue, I actually just found a way to have flex-box, a width for the nav bar, and center it while in a fixed position.
nav {
display: flex;
height: 50px;
width: 90%;
left: 5%;
position: fixed;
}
I wanted to be able to have a flex-box nav bar in a fixed position but centered. So what I did was do the left 5% since that's equal to half of the 10% width left over. Try it out, it might help you! :)
Solution 8 - Css
You are saying you want position:fixed;
-like behavior that plays together with flexbox. As mentioned in the accepted answer, applying this property to an element drops it out of the normal flow, so this isn't really possible.
If what you want is to have a fixed sidebar .side-el
and a scrollable content box .main-el
as the items of a flex container, here's how you might do this:
- Disable scrolling in the flex container's parent; let's assume it's
<body>
, as you don't provide div.container's parent. Also, hard-set it's height to viewport-height (100vh) so that no part of the body's box remains outside view (imagine the body's box normally extending beyond your screen to contain the entire document; you don't want that, if you are to disable the ability to move the viewport via scrolling). - Set the flex container's (
.container
) height to that of it's parent. - Selectively re-enable scrolling for the content box (
.main-el
).
In CSS:
body{
overflow: hidden;
height: 100vh;
}
.container {
display: flex;
height: 100%;
}
.main-el {
overflow-y: auto;
}