I am trying to make two divs, one inside the other. The inner div is larger than the outer div, the outer div has overflow:scroll
, and the inner div has margin:25px
. So I do this:
#outer { width: 200px; height: 100px; overflow: scroll; } #inner { width: 400px; height: 200px; margin: 25px; }
...
<div id="outer"> <div id="inner"> </div> </div>
Instead of the inner div having a margin of 25px all the way around as expected, there is a 25px margin on THREE sides, but on the right side there is none. This is extremely counter-intuitive in my opinion.
If I add a middle div with a width large enough width to contain the inner div + 50px, we can make it look right, but that seems like a hacky workaround.
See my example on JSFiddle: http://jsfiddle.net/d3Nhu/16/
This happens the same way in every major browser. Is there any good reason for this behavior? Is this correct behavior according to the CSS specification?
NOTE: As you'd expect in this example, it makes no difference if you use overflow:auto
instead of overflow:scroll
.
EDIT: Please note that I'm not looking for a workaround for this behavior. (I already found one.) I'm looking for any insight as to the reason for this behavior, especially if it is documented in the CSS specification anywhere.
You cannot see the effect of margin-right because the 'width' property of div causes the margin of div to have more than 10px distance from the right wall of the body. Consequently, it causes the margin-right property not to have any visual effect.
To change this, set the min-width or min-height property.” This means that a flex item with a long word won't shrink below its minimum content size. To fix this, we can either use an overflow value other than visible , or we can set min-width: 0 on the flex item.
The CSS overflow property controls what happens to content that is too big to fit into an area. This text is really long and the height of its container is only 100 pixels. Therefore, a scrollbar is added to help the reader to scroll the content.
Margins are for moving an element in from the wrapper, not expanding the wrapper outwards.
This behavior is consistent with specifying a width
in addition to a horizontal margin
anywhere in the document. To break it down, consider the following snippet, where I specificity a wrapper without an overflow
property, and the margin
does not expand the wrapper element.
body { padding: 20px; } .outer { width: 400px; border: 1px solid black; } .inner { width: 400px; height: 40px; margin: 0 20px; background: grey; }
<div class="outer"> <div class="inner"> </div> </div>
As you can see, the margin
did not cause the wrapper to expand in size, the element just continued to overflow. This behavior is documented under Visual formatting model details of the is documented in the CSS 2.1 specification.
The following constraints must hold among the used values of the other properties:
'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block
[...]
If all of the above have a computed value other than 'auto', the values are said to be "over-constrained" and one of the used values will have to be different from its computed value. If the 'direction' property of the containing block has the value 'ltr', the specified value of 'margin-right' is ignored and the value is calculated so as to make the equality true. If the value of 'direction' is 'rtl', this happens to 'margin-left' instead.
That excerpt is quite dense, so to simply, let's ignore the width of border
and padding
, both of which are 0
, leaving us with width
, margin-left
, and margin-right
.
Now since the you have a fixed width
and values for margin-left
and margin-right
, the values are "over-constrained". Now in our example, since the direction is ltr
by default, the margin-right
is forced to compensate.
To see the effects of the direction, let's try adding a dir="rtl"
attribute to the wrapper element.
body { padding: 20px; } .outer { width: 400px; border: 1px solid black; } .inner { width: 400px; height: 40px; margin: 0 20px; background: grey; }
<div class="outer" dir="rtl"> <div class="inner"> </div> </div>
Now the element is overflowing to the left. Let's see if this dir="rtl"
attribute has the same effect on your overflow: scroll
example.
#outer { border: 1px solid #00F; width: 200px; height: 100px; overflow: scroll; } #inner { border: 1px solid #F0F; margin: 25px; width: 400px; height: 200px; }
<div id="outer" dir="rtl"> <div id="inner"> </div> </div>
Yep, it does. The margin is now missing on the left, rather than the right.
overflow: scroll
include the margins?Mainly because the specification does not say it should. Let's take a look at the CSS 2 specification for the overflow
property.
Whenever overflow occurs, the 'overflow' property specifies whether a box is clipped to its padding edge, and if so, whether a scrolling mechanism is provided to access any clipped out content.
See how it specifically says "clipped out content". For an explanation of "content", lets refer to the following graphic from the CSS 2 specification.
As we can see, the margin
is separate from the content
. However, at this point it's worth noting that padding and borders are included in the scrolling area, so when the spec says "content", it is likely referring to border-box, or at least, that seems to be how it was interpreted.
display: inline-block
work?Basically, margins behave differently on inline-block
elements, because they are content level rather than block level, and they do not have a concept of being "over-constrained".
add display:inline-block;
to #inner
div
see this fiddle
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With