52

I have an issue with a CSS3 flexbox.

If I set the flexbox element to overflow and set a min-width value for the children, the right padding on the parent is lost? This is consistent on all supporting browsers.

Here is an example of the error. If you scroll to the right of the container you will see the last child is hard up against the right edge of the container instead of honoring the padding value.

.outer {
    display: flex;
    flex-direction: row;
    width: 300px;
    height: 80px;
    border:1px #ccc solid;
    overflow-x: auto;
    padding: 5px;
}
.outer > div {
    flex: 1 1 auto;
    border: 1px #ccc solid;
    text-align: center;
    min-width: 50px;
    margin: 5px;
}
<div class="outer">
    <div>text1</div>
    <div>text2</div>
    <div>text3</div>
    <div>text4</div>
    <div>text5</div>
    <div>text6</div>
    <div>text7</div>
    <div>text8</div>
    <div>text9</div>
    <div>text10</div>
</div>

Does anyone know why this is and how I would go about correcting it? I've messed around with padding and margin values in different combinations without success.

Chris Spittles
  • 15,023
  • 10
  • 61
  • 85
  • 2
    At least in Firefox, this is not a flexbox-specific behavior -- it happens with block layout as well, and is correct according to the CSS spec. See https://bugzilla.mozilla.org/show_bug.cgi?id=748518 for more. – dholbert Nov 12 '14 at 17:09
  • Thanks for that I wasnt sure if it was something specific to flex. – Chris Spittles Nov 12 '14 at 19:33

5 Answers5

44

You need to add another layer of wrapping, if you want to have both "overflow-x:auto" with scrollable padding at the end.

Something like this:

.scroll {
    overflow-x: auto;
    width: 300px;
    border:1px #ccc solid;
}
.outer {
    display: flex;
    flex-direction: row;
    box-sizing: border-box;
    min-width: 100%;
    height: 80px;
    padding: 5px;
    float: left; /* To size to content, & not be clamped to available width. (Vendor-prefixed intrinsic sizing keywords for "width" should work here, too.) */
}
.outer > div {
    flex: 1 1 auto;
    border: 1px #ccc solid;
    text-align: center;
    min-width: 50px;
    margin: 5px;
}
<div class="scroll">
  <div class="outer">
    <div>text1</div>
    <div>text2</div>
    <div>text3</div>
    <div>text4</div>
    <div>text5</div>
    <div>text6</div>
    <div>text7</div>
    <div>text8</div>
    <div>text9</div>
    <div>text10</div>
  </div>
</div>
dholbert
  • 11,386
  • 3
  • 42
  • 31
  • 3
    Thansk! Made a bit simpler example: https://jsfiddle.net/rckd/237dgLjj/ – rcd Jan 09 '17 at 15:34
  • Why does float: left work? According to documentation in MDN, it's not supposed to do anything when applied to display: flex elements. Would it be better to use display: inline-flex instead? It seems to work in my tests, but I'm not sure if it has any drawbacks – xgrtl Jan 22 '19 at 21:09
  • `float:left` absolutely has an effect on **flex containers** (`display:flex` elements), in general. The spot where `float` has no effect is on flex *items* (**children** of `display:flex` elements). I see the MDN page that you mentioned -- that seems to be https://developer.mozilla.org/en-US/docs/Web/CSS/float and it's wrong. I'll fix it up -- thanks for the heads-up about that wrongness. – dholbert Feb 26 '19 at 21:51
  • 2
    But, answering your question about `inline-flex`: it looks like `display:inline-flex` would work too (instead of `float`). I forget the details here, but based on my /**/ code-comment in the text snippet, I had only suggested `float:left` in order to trigger intrinsic sizing. And `inline-flex` also does intrinsic sizing, so that probably works well here too. – dholbert Feb 26 '19 at 21:53
  • Your code snippet still has no padding on the "text10"? – James May 05 '21 at 15:12
19

Alternatively it's possible to create the margins with pseudo-elements:

.outer::before { content: ''; min-width: 5px; }
.outer::after { content: ''; min-width: 5px; }

.outer {
    display: flex;
    flex-direction: row;
    width: 300px;
    height: 80px;
    border:1px #ccc solid;
    overflow-x: auto;
    padding: 5px;
}
.outer::after { content: ''; min-width: 5px; }
.outer > div {
    flex: 1 1 auto;
    border: 1px #ccc solid;
    text-align: center;
    min-width: 50px;
    margin: 5px;
}
<div class="outer">
    <div>text1</div>
    <div>text2</div>
    <div>text3</div>
    <div>text4</div>
    <div>text5</div>
    <div>text6</div>
    <div>text7</div>
    <div>text8</div>
    <div>text9</div>
    <div>text10</div>
</div>
Artur K.
  • 3,263
  • 3
  • 38
  • 54
  • This one does work, unless you use a align-items: center; because then it breaks again. Do you know any solution for that? – BonifatiusK Jun 11 '19 at 14:42
  • 1
    After trying several methods from stack, this was the closest to working for my situation. I had to add `border-top: 1px solid transparent;` to the `::after` to make the padding show up. – OXiGEN Sep 09 '20 at 09:24
  • Just found this answer today! Very useful. If you use right margin to space your elements in a flex container, you need to make sure you remove it from the last child as you will end up with the pseudo content as well as the margin. Good fix. – John E May 10 '21 at 21:53
  • man, briliant!! – yzfdjzwl Nov 25 '21 at 12:39
1

Both solutions from Arthur Käpp and dholbert are working. However, if you choose to use any 'align-items' (accept for stretch) in the main flex box it will break again. It took me a while but eventually I cooked up a solution which works fine.

This solution is using the pseudo elements:

.outer {
    display: flex;
    flex-direction: row;
    width: 300px;
    height: 80px;
    border:1px #ccc solid;
    overflow-x: auto;
    padding: 5px;
    align-items: center;
    position: relative;
}
.outer > div {
    flex: 1 1 auto;
    border: 1px #ccc solid;
    text-align: center;
    min-width: 50px;
    margin: 5px;
}

.outer > div:last-child::after {
    content: '';
    position: absolute;
    height: 100%;
    width: 10px;
    display: inline-block;
    margin-left: 10px;
}
<div class="outer">
    <div>text1</div>
    <div>text2</div>
    <div>text3</div>
    <div>text4</div>
    <div>text5</div>
    <div>text6</div>
    <div>text7</div>
    <div>text8</div>
    <div>text9</div>
    <div>text10</div>
</div>

Be aware that in some cases the margin-left: 10px in the psuedo-element does not work. You can use a right: -10px which would also work.

BonifatiusK
  • 2,281
  • 5
  • 29
  • 43
1

There is another way: You can have another DIV item-flex -> TEXT_11, then set MarginLeft = PaddingRight, you want

<div class="outer">
    <div>text1</div>
    <div>text2</div>
    <div>text3</div>
    <div>text4</div>
    <div>text5</div>
    <div>text6</div>
    <div>text7</div>
    <div>text8</div>
    <div>text9</div>
    <div>text10</div>

    <div style="margin-left: 5px" class="TEXT_11">&nbsp;</div>

</div>
0

The best way I've found to handle this is using ::after (and ::before) pseudo-elements.

.parent::after {
  content: "";
  padding: 10px;
}

Apply this also to .parent::before for consistent spacing at the beginning and end of the scrolled container.

Mike Hamilton
  • 1,519
  • 16
  • 24