Reputation: 2200
Reading the CSS Spec https://drafts.csswg.org/css2/visudet.html#blockwidth I am somewhat scratching my head at section 10.3.3. which supposedly explains how block level non-replaced elements are laid out within their containing block. It reads:
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.
This suggests that an element will always be stretched or somehow shrunk to fit into its containing block, but that's clearly not the case; Setting a width to an explicit value will make an element either narrower or wider than it's containing block, overflowing if necessary. Also I see no sign of the margin-right or margin-left properties changing in accordance with the equation.
So have I misunderstood the spec (admittedly likely!) or are browsers not implementing it properly?
Upvotes: 4
Views: 94
Reputation: 288650
For example, assume the containing block is 400px
wide, and the block has:
margin-left: 15px
border-left-width: 15px
padding-right: 15px
width: 300px
padding-right: 15px
border-right-width: 15px
margin-right: 15px
Then, the sum will be 390px
, so the remaining free space is 10px
.
Since the direction
is ltr
by default, the used value of the right margin will be 25px
instead of 15px
. That is, the remaining free space is added to the right margin in order to keep the block aligned to the left of the containing block.
Otherwise, the left margin would be modified to keep the block aligned to the right.
.container {
margin-bottom: 10px;
width: 400px;
border: 1px solid red;
}
.block {
margin: 0 15px;
border: 15px solid;
padding: 0 15px;
width: 300px;
direction: ltr;
}
.ltr { direction: ltr; }
.rtl { direction: rtl; }
Left-to-right container:
<div class="ltr container">
<div class="block">
Right margin becomes 25px instead of 15px
</div>
</div>
Right-to-left container:
<div class="rtl container">
<div class="block">
Left margin becomes 25px instead of 15px
</div>
</div>
In case the sum was greater than the containing block, the remaining free space would be negative. This is not problematic because margins can be negative.
Therefore, visually it's implemented correctly. However, note that under the hood, browsers might just just be distributing the remaining free space to the left or right of the block instead of modifying its margins.
This might explain why getComputedStyle
seems to return incorrect reults. According to CSSOM, it should return the resolved value, which in case of margins is
If the property applies to the element or pseudo-element and the resolved value of the 'display' property is not 'none', the resolved value is the used value. Otherwise the resolved value is the computed value.
Then, in this case it should be 25px
but seems to be 15px
on most browsers.
Upvotes: 4