auto
An Adventure in LayoutStyle computation is per element, depth-first traversal of all dirty elements.
End result: exactly one value per property per element.
{1} DOM Element → {0,1,2} CSS Boxes
# Boxes | display
|
---|---|
0 | none , contents
|
1 | all other values |
2 | table , list-item
|
End result: zero or more boxes per element.
{1} CSS Box → 1+ Box Fragments
Fragmentation = line breaking, page breaking, column breaking, region breaking, etc.
We're not going to talk about fragmentation.
The goal of layout is to fill in the correct values
for x
, y
, width
, and height
for all boxes in the tree.
Origin coords are relative to parent origin.
~10K lines of code, i.e. we're simplifying this next slide a lot.
VeryBasicLayoutBox::Reflow() { CalculateMyWidth(); positionOfNextChild = 0; for each child in childList { “Yo, I'm this wide. What size do you wanna be?” — me “I wanna be this big.” — child “Okay, I'm gonna put you here.” — me positionOfNextChild += child.size; } CalculateMyHeight(); }
VeryBasicLayoutBox::Reflow() { CalculateMyWidth(); positionOfNextChild = 0; for each child in childList { “Yo, I'm this wide. What size do you wanna be?” — me “I wanna be this big.” — child “Okay, I'm gonna put you here.” — me positionOfNextChild += child.size; } CalculateMyHeight(); }
VeryBasicLayoutBox::Reflow() { CalculateMyWidth(); positionOfNextChild = 0; for each child in childList { “Yo, I'm this wide. What size do you wanna be?” — me “I wanna be this big.” — child “Okay, I'm gonna put you here.” — me positionOfNextChild += child.size; } CalculateMyHeight(); }
VeryBasicLayoutBox::Reflow() { CalculateMyWidth(); positionOfNextChild = 0; for each child in childList { “Yo, I'm this wide. What size do you wanna be?” — me “I wanna be this big.” — child “Okay, I'm gonna put you here.” — me positionOfNextChild += child.size; } CalculateMyHeight(); }
VeryBasicLayoutBox::Reflow() { CalculateMyWidth(); positionOfNextChild = 0; for each child in childList { “Yo, I'm this wide. What size do you wanna be?” — me “I wanna be this big.” — child “Okay, I'm gonna put you here.” — me positionOfNextChild += child.size; } CalculateMyHeight(); }
VeryBasicLayoutBox::Reflow() { CalculateMyWidth(); positionOfNextChild = 0 for each child in childList { “Yo, I'm this wide. What size do you wanna be?” — me “I wanna be this big.” — child “Okay, I'm gonna put you here.” — me positionOfNextChild += child.size; } CalculateMyHeight(); }
VeryBasicLayoutBox::CalculateMyWidth() { if mStyleContext.width == auto { mRect.width = mParent.width - border - padding - margin; } else { // fixed size mRect.width = mStyleContext.width; } }
VeryBasicLayoutBox::CalculateMyHeight() { if mStyleContext.height == auto { mRect.height = positionOfNextChild; } else { // fixed size mRect.height = mStyleContext.height; } }
Works great... until we start to put things side-by-side.
“CSS [spec] editing: expect 80% of the time to be spent defining what 'auto' does and does not do and you'll do fine.” — Sylvain Galineau
auto
: Sizing Primitivespx
, pt
, pc
, in
, cm
, mm
em
, ch
, rem
, vw
, vh
, vmin
, vmax
%
) sizing
containingBlock.width×percentage − (borders + padding + margins)
min-content
max-content
auto
: Compound Sizingfit-content
aka shrink-to-fit
flex
fit-content
aka shrink-to-fit
max(
min(max-content
, /* Be as wide as the content but no wider */
fill-available
), /* But avoid overflowing the containing block */
min-content
) /* And definitely don't let any content overflow */
)
flex
basis + flex ratio × (fill-available − ∑basis)
auto
: Sizing Constraintsmin/max-width/height
auto
: What is auto
?fill
min-size
, flex-basis
+ flex
×free space)
auto
: Why is it auto
?auto
: Flexboxflex-basis: auto;
flex-grow: 0;
flex-shrink: 1;
min-width: auto;
With great power comes great responsibility.
order
or positioningWhat is your sizing based on?
em
or rem
.
em
or ch
.
auto
or min-content
/max-content
.
flex
, min-width
, max-width
, etc.
Absolute units are usually the wrong answer.
WARNING: Requires Critical Thinking
Set media query breakpoints in em
or ch
, not always in px
.
Use shorthands. Protect yourself against invading rules!
.lowSpecificity { background: linear-gradient(red, maroon); } /* … more stuff … */ #highSpecificity { background-color: green; }
Unless you're intentionally wanting a longhand to cascade in from somewhere else, use the shorthand to give you a blank slate.
background: url(…) top left, url(…) bottom right, url(…) center; background-repeat: no-repeat
em
s.
direction
or unicode-bidi
.
dir
attribute, because it's content, not style (and you can then use :dir()
selectors).