Exercise 3: Reproducing the Crash and Explaining Why Padding/Border Never Trigger It — Possible Solution ==================================================================== THE TEST ------------------------------ centered = block({'width': '100px', 'margin': '0 auto'}) calculate_block_width_naive(centered, root_cb) RESULT ------------------------------ ValueError: unsupported length: 'auto' THE EXACT CALL RESPONSIBLE ------------------------------ def calculate_block_width_naive(layout_box, containing_block): style = box_style(layout_box) padding = expand_shorthand(style.get('padding', '0')) border = expand_shorthand(style.get('border-width', '0')) margin = expand_shorthand(style.get('margin', '0')) # <- this call ... The line `margin = expand_shorthand(style.get('margin', '0'))` is responsible. expand_shorthand (Chapter 2's original) splits the value string into tokens and calls parse_length() on every single one, unconditionally: lengths = [parse_length(p) for p in value_str.split()] For '0 auto', value_str.split() gives ['0', 'auto']. parse_length('0') succeeds (0.0). parse_length('auto') reaches its own final line, `raise ValueError(f"unsupported length: {s!r}")`, because 'auto' is neither the literal string '0' nor a string ending in 'px' -- the only two cases parse_length knows how to handle. The list comprehension propagates that exception immediately, before expand_shorthand ever gets to its own branching logic for 1/2/3/4 values. WHY padding AND border-width NEVER HIT THIS SAME CRASH ------------------------------ The code path is structurally identical for all three properties -- padding = expand_shorthand(...), border = expand_shorthand(...), and margin = expand_shorthand(...) all call the exact same function. The difference isn't in the CODE at all; it's in what VALUES ever actually appear in a real stylesheet for each property. CSS itself simply never defines an 'auto' keyword as valid for padding or border-width -- there is no such thing as `padding: auto` or `border-width: auto` anywhere in the CSS specification, so no real stylesheet (and no test in this course, before this chapter) was ever going to hand expand_shorthand() the string 'auto' for those two properties. margin is the one property, among these three, where CSS itself explicitly defines 'auto' as a meaningful value with real, specified behavior (this chapter's whole subject) -- so it's the only one of the three where reusing expand_shorthand() was ever going to be tested against an input that exposes the gap. WHY THIS WORKS AS AN ANSWER ------------------------------ This is the same kind of bug this course has surfaced before (Chapter 2's own bare-unitless-zero crash, Chapter 1's own dropped-text-nodes bug): code that was completely correct for every input it was ever tested against, right up until a later chapter tried to use it for a genuinely different purpose than it was originally designed for. expand_shorthand() isn't "buggy" in any general sense -- it correctly implements CSS's own real 1/2/3/4-value shorthand rules for any property that only ever takes real lengths. The mistake was applying it unmodified to a THIRD property (margin) that happens to have one more legal value (auto) than the two properties it was originally built for.