我如何才能有一个位置: 固定; 行为的一个柔性盒大小的元素?

我有个叫 Div 的。我想在一个位置有一个侧面: 固定; 行为,但一旦我应用位置固定的宽度交替从右边。正确的宽度将是一个由柔性箱设置。我怎样才能达到这个目标?

.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>

145250 次浏览

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)

@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;
}

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.

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.

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.

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! :)

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>

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:

  1. 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).
  2. Set the flex container's (.container) height to that of it's parent.
  3. 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;
}

I have found best solution at below site, please go through it.

https://itecnote.com/tecnote/html-preventing-fixed-footer-from-overlapping-content/

A modern "sticky footer" solution would use flexbox.

tl;dr:: set container (body) to display:flex;flex-direction:column and the child (footer) you want to move down to margin-top:auto.

First, we set the body to "flex" its items vertically, making sure that it is 100% height.

Then we set flex: 0 0 50px on the footer element, which means: "don't grow, don't shrink, and have a height of 50px". We could in fact, omit flex attribute entirely and just go with height:50px.

We can set display:flex on things like the itself somewhat recklessly, because children of a flex container have a implicit value of flex: 0 1 auto (aka flex:initial) if omitted, which is (almost) equivalent to flex:none (which is shorthand for flex:0 0 auto):

The item is sized according to its width and height properties. It shrinks to its minimum size to fit the container, but does not grow to absorb any extra free space in the flex container.(MDN)

As far as the sticky part, it's the margin-top:auto on the footer that gives us what we want. Applied within a flex container, auto margins take on a new meaning, instead of the usual "get equal amount of free space", they mean "absorb ALL available free space".

From the spec (8.1. Aligning with auto margins):

Prior to alignment via justify-content and align-self, any positive free space is distributed to auto margins in that dimension.

Stated more simply:

If you apply auto margins to a flex item, that item will automatically extend its specified margin to occupy the extra space in the flex container

Aside: the "normal" flexbox layout approach would probably be to flex a middle section ala <div id="main>... to 100% vertically, which also would make a footer "stick" to the bottom. This approach shows us the flexible box model is, in fact, flexible enough to let us resize/move isolated elements.

body {
display: flex;
flex-direction: column;
min-height: 100vh;
}


#footer {
background-color: #efefef;
flex: 0 0 50px;/*or just height:50px;*/
margin-top: auto;
}


<p>we've assumed only that there's random space-taking content above the footer...</p>


<p>lorem ipsum dolor flex...</p>
<div>
<p>random content.</p><p>random content.</p><p>random content.</p><p>random content.</p>
</div>
<div id="footer">FOOTER</div>

You can achieve this without position: fixed; by just adding overflow: auto; and height: 100%; to the flex-item that contains the long content:

.container {
display: flex;
}


.main-el {
padding:0 2em;
width: 70%;
overflow: auto;
height: 100%;
}


.side-el {
width: 30%;
}     
<div class="container" style="background-color: blue; height: 300px;">
<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>