Display: Flex loses right padding when overflowing?

21.9k Views Asked by At

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.

6

There are 6 best solutions below

0
On BEST ANSWER

Update 2023

This seems to have been fixed in recent browser versions, as right padding is clearly visible here:

.outer{width:500px; display:flex; padding:20px; overflow:auto; background:#ccc;}
.inner{width:600px; height:50px; flex-shrink:0; background:darkblue;}
<div class="outer">
  <div class="inner"></div>
</div>

The problem still exists though in cases where the overflow is applied to a wrapping element (note also how the gray background doesn't expand to fill the wrapper when scrolled to the right side):

.wrapper{width:500px; overflow:auto; border:1px solid red;}
.outer{display:flex; padding:20px; background:#ccc;}
.inner{width:600px; height:50px; flex-shrink:0; background:darkblue;}
<div class="wrapper">
  <div class="outer">
    <div class="inner"></div>
  </div>
</div>

But this can be fixed by adding width:fit-content to the outer element:

.wrapper{width:500px; overflow:auto; border:1px solid red;}
.outer{width:fit-content; display:flex; padding:20px; background:#ccc;}
.inner{width:600px; height:50px; flex-shrink:0; background:darkblue;}
<div class="wrapper">
  <div class="outer">
    <div class="inner"></div>
  </div>
</div>

5
On

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>

0
On

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>
4
On

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>

0
On

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.

0
On

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.