How can I have a position: fixed; behaviour for a flexbox sized element?

Solution 1:

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:

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:

@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">&gt;</span>
        <span ng-hide="collapsed">&lt;</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:

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:

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.