Content Width Determination with the Box Model
I was working on a this design that contains a few badges aligned like this on a corner. The content of those badges is not fixed, so I do not know the exact width of each of them. However, the design requires that they have flexible widths.
I did my basic CSS and they turned out to look like this:
They actually look pretty neat to me, but the designer insists that they each set their own widths š
https://codepen.io/wgao19/pen/VRzLvm
Intuition from the specs
Once again I decided to look for answers in the specs. Luckily since Iāve already read many sections of the specs, I roughly knew where to look ā check how CSS determines content width.
There are ten cases here in non-human language š kill me please.
- inline, non-replaced elements
- inline, replaced elements
- block-level, non-replaced elements in normal flow
- block-level, replaced elements in normal flow
- floating, non-replaced elements
- floating, replaced elements
- absolutely positioned, non-replaced elements
- absolutely positioned, replaced elements
- 'inline-block', non-replaced elements in normal flow
- 'inline-block', replaced elements in normal flow
If youāre like me, registering āthesaurusā while reading CSS specs, letās exchange dictionary: I think of ābrowsersā whenever I see āuser agentsā. Your turn now..
Anyway, it seems to me that those 10 cases are alternating between ānon-replacedā and āreplacedā elements. My thesaurus for āreplacedā elements is āimgā. And Iām not concerned about images now, this cuts my target in half. My elements are not āinlineā, nor āfloatingā, not āabsolutely-positionedā, and not āinline-blockā. Then I found my case!
10.3.3 Block-level, non-replaced elements in normal flow
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
Now, this equation seems like a tautology at first sight. But whatās really holding the checks here is this: sometimes thereād be conflicting (CSSās term: over-constrained) values, some other times there are not enough values. This section describes how those cases should be handled such that this equation is satisfied:
If 'width' is not 'auto' and 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' (plus any of 'margin-left' or 'margin-right' that are not 'auto') is larger than the width of the containing block, then any 'auto' values for 'margin-left' or 'margin-right' are, for the following rules, treated as zero.
This is saying that if the width
is not auto
and the total space needed is larger than the space there is, then any auto
goes to 0.
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 is saying that if all of those values are specified, then one of those specified value will give up its constraint and just take up the remaining space. Depending whether you are reading left-to-right or right-to-left, whichever side that comes later has the margin
on that side become this candidate.
If there is exactly one value specified as 'auto', its used value follows from the equality.
Makes total sense, right?
If 'width' is set to 'auto', any other 'auto' values become '0' and 'width' follows from the resulting equality.
I understand this line as follows: width
has an auto
of higher precedence over other auto
values, i.e., if everyone is auto
, then width
takes the entire remaining space and everyone else becomes 0. Again, it makes sense because I actually donāt want those paddings and margins to appear unless I specify them.
It follows that width
will adjust itself if there are specified values around it, while still taking higher priority over other auto
values, taking up the entire remaining space.
Here's the CodePen link to those two illustrations.
https://codepen.io/wgao19/pen/WmOYve
And finally,
If both 'margin-left' and 'margin-right' are 'auto', their used values are equal. This horizontally centers the element with respect to the edges of the containing block.
Hereās the margin: 0 auto
trick everyoneās using š
Many of the remaining 9 sections either share the similar spirit, or follows a logic that serves its context quite sensibly.
A few solutions to the problem
display: inline
on children sets the widths free, but it also makes them appear on the same line.
Floating the elements
float: right
also sets the widths free for those children nodes, but I need to set a specific width for the parent.
The parent width needs to be such that it forces each element to wrap.
Otherwise the children nodes will still appear on the same line, which does not yield the desired design.
Nevertheless, this does not feel like a neat implementation and so I'm not happy with it.
https://codepen.io/wgao19/pen/pYwQVR
One another solution is to wrap each of them in an extra block
div, then put the clip inside that has float: right
or display: inline
that gives them free widths. But Iām not a fan of that, neither.
Flexbox to create rows of flexible widths
I eventually went with flex-box
, CodePen.
Reading the flexbox specs had been more freshening than I thought.
So I'll follow up a post dedicated for it :]
https://codepen.io/wgao19/pen/XGNOXe
ććććć¾ćć š¤