{"id":"l-css-2-1","courseId":"css-mastery","lang":"en","kind":"lesson","summary":"Predict how flexbox sizes items from flex-basis, grow and shrink, fix the min-width auto overflow trap, and build rows that wrap without media queries.","html":"<p>The session row on Waypoint’s schedule is three things in a line: a time, a title and a save button. It looks fine until the content team schedules “Shipping Accessible Design Systems Across Twelve Product Teams Without Losing Your Mind”, and the save button slides off the edge of the card. Nothing in the CSS mentions widths, so where did the overflow come from?</p>\n<p>From flexbox doing exactly what its algorithm says. Once you know the algorithm, this bug takes thirty seconds to fix.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">How flexbox decides sizes</h2>\n<p>Flexbox sizes items along the main axis in two passes:</p>\n<ol>\n<li><strong>Hypothetical size.</strong> Each item starts at its <code dir=\"ltr\">flex-basis</code>. With the default <code dir=\"ltr\">auto</code>, that’s its <code dir=\"ltr\">width</code> if set, otherwise its content width.</li>\n<li><strong>Distribute the difference.</strong> The container compares the sum of the bases (plus gaps) with its own size. If there’s space left, items with <code dir=\"ltr\">flex-grow</code> share it in proportion to their grow factors. If there’s too little, items with <code dir=\"ltr\">flex-shrink</code> give some back, weighted by shrink factor times basis, so big items shrink more.</li>\n</ol>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 680 230\" role=\"img\" aria-labelledby=\"l-css-2-1-t1\"><defs><marker id=\"arrow-l-css-2-1-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-css-2-1-t1\">Top row: three items at their flex-basis with free space left over in a 600 pixel container. Bottom row: the free space has been divided between the title, which has flex-grow 1, while the time and button keep their basis.</title>\n  <text class=\"d-label-muted\" x=\"20\" y=\"24\">1. Start at flex-basis</text>\n  <rect class=\"d-box\" x=\"20\" y=\"36\" width=\"600\" height=\"56\" rx=\"8\"/>\n  <rect class=\"d-box-accent\" x=\"28\" y=\"44\" width=\"80\" height=\"40\" rx=\"6\"/>\n  <text class=\"d-code\" x=\"44\" y=\"70\">time</text>\n  <rect class=\"d-box-primary\" x=\"116\" y=\"44\" width=\"180\" height=\"40\" rx=\"6\"/>\n  <text class=\"d-code\" x=\"132\" y=\"70\">title</text>\n  <rect class=\"d-box-success\" x=\"304\" y=\"44\" width=\"70\" height=\"40\" rx=\"6\"/>\n  <text class=\"d-code\" x=\"314\" y=\"70\">save</text>\n  <rect class=\"d-box-warn d-dashed\" x=\"382\" y=\"44\" width=\"230\" height=\"40\" rx=\"6\"/>\n  <text class=\"d-label-muted\" x=\"412\" y=\"70\">free space</text>\n  <text class=\"d-label-muted\" x=\"20\" y=\"134\">2. Title has flex-grow: 1, so it takes the free space</text>\n  <rect class=\"d-box\" x=\"20\" y=\"146\" width=\"600\" height=\"56\" rx=\"8\"/>\n  <rect class=\"d-box-accent\" x=\"28\" y=\"154\" width=\"80\" height=\"40\" rx=\"6\"/>\n  <text class=\"d-code\" x=\"44\" y=\"180\">time</text>\n  <rect class=\"d-box-primary\" x=\"116\" y=\"154\" width=\"418\" height=\"40\" rx=\"6\"/>\n  <text class=\"d-code\" x=\"132\" y=\"180\">title</text>\n  <rect class=\"d-box-success\" x=\"542\" y=\"154\" width=\"70\" height=\"40\" rx=\"6\"/>\n  <text class=\"d-code\" x=\"552\" y=\"180\">save</text>\n</svg><figcaption>Flex items start at their basis; leftover space is shared by grow factor</figcaption></figure>\n<p>The <code dir=\"ltr\">flex</code> shorthand sets all three values, and its keywords are worth memorising because they behave very differently:</p>\n<div class=\"table-wrap\" role=\"region\" aria-label=\"Scrollable table\" tabindex=\"0\"><table><thead>\n<tr>\n<th>Shorthand</th>\n<th>Expands to</th>\n<th>Use it for</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code dir=\"ltr\">flex: 1</code></td>\n<td><code dir=\"ltr\">1 1 0%</code></td>\n<td>Equal columns, whatever the content</td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">flex: auto</code></td>\n<td><code dir=\"ltr\">1 1 auto</code></td>\n<td>Keep content size, share only the extra</td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">flex: none</code></td>\n<td><code dir=\"ltr\">0 0 auto</code></td>\n<td>Never grow or shrink (icons, buttons)</td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">flex: 0 0 5rem</code></td>\n<td>fixed basis</td>\n<td>A column of exact width</td>\n</tr>\n</tbody>\n</table></div><h2 id=\"sec-2\" tabindex=\"-1\">The <code dir=\"ltr\">min-width: auto</code> trap</h2>\n<p>Back to the runaway title. It has <code dir=\"ltr\">white-space: nowrap</code>, so its content width is the whole sentence, maybe 700px. The row is 400px. Shrinking should solve it, so why doesn’t it?</p>\n<p>Because flex items have <code dir=\"ltr\">min-width: auto</code> by default, and for a flex item that means “no smaller than my min-content size”. Shrinking stops at that floor. The unbreakable title can’t shrink below its full width, so it overflows and drags the button with it.</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">session-row.css</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-row</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  display</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">flex</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  align-items</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">center</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  gap</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">12</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-row</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> .time</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">flex</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 5</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-row</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> .title</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  flex</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  min-width</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;            </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* allow shrinking below content size */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  overflow</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">hidden</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  text-overflow</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">ellipsis</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  white-space</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">nowrap</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-row</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> .save</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">flex</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">none</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span></code></pre></div>\n<p><code dir=\"ltr\">min-width: 0</code> removes the floor, and the three overflow properties turn the clipped text into a tidy ellipsis. The same trap appears with long URLs, code blocks and nested flex or grid containers, so this is a fix you’ll write many times.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">Common mistake</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Blaming the parent’s width</span></p>\n<p>When a flex child overflows, people add <code dir=\"ltr\">overflow: hidden</code> or <code dir=\"ltr\">max-width: 100%</code> to the <em>container</em>. The container is fine; the item’s automatic minimum is the problem. Put <code dir=\"ltr\">min-width: 0</code> on the item that refuses to shrink (in a column-direction container, it’s <code dir=\"ltr\">min-height: 0</code>).</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">Push with auto margins</h2>\n<p>Waypoint’s header holds the logo, the day switcher and a “Get tickets” link that belongs at the far end. <code dir=\"ltr\">justify-content: space-between</code> would spread all three apart. An auto margin is more precise:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.site-header</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">display</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">flex</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">align-items</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">center</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">gap</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.site-header</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> .tickets</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">margin-inline-start</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">auto</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span></code></pre></div>\n<p>Auto margins on flex items absorb all free space on their side, so the link moves to the end and everything before it stays packed together. It’s the flexbox equivalent of “and then a spring”.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">Wrapping without media queries</h2>\n<p>The filter bar holds four track filters. On a wide screen they fit on one line; on a phone they shouldn’t be squeezed to unreadable slivers. Wrapping plus a basis gives you that with no breakpoint:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.filters</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  display</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">flex</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  flex-wrap</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">wrap</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  gap</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0.5</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.filters</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> ></span><span style=\"color:#116329;--shiki-dark:#7EE787\"> *</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  flex</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 1</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 10</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>Each filter wants 10rem. The browser fits as many 10rem items as it can on a line, wraps the rest, then lets each line’s items grow to fill it. At 25rem wide you get two per line; at 45rem, all four. The breakpoint is implied by the content.</p>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">Tip</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Use <code dir=\"ltr\">gap</code>, not margins</span></p>\n<p><code dir=\"ltr\">gap</code> puts space only <em>between</em> items, so you never need <code dir=\"ltr\">:last-child { margin: 0 }</code> or negative margins on the container. It works in flexbox in every current browser.</p>\n</aside>\n<h2 id=\"sec-5\" tabindex=\"-1\">Your turn</h2>\n<p>The exercise gives you a 400px session row with a very long title. Make the time a fixed 5rem column, let the title fill the remaining space and truncate with an ellipsis, and keep the save button at the end. When rows of cards need to line up in two dimensions, flexbox runs out of road; that’s where grid takes over in the next lesson.</p>\n","toc":[{"id":"sec-1","text":"How flexbox decides sizes","level":2},{"id":"sec-2","text":"The min-width: auto trap","level":2},{"id":"sec-3","text":"Push with auto margins","level":2},{"id":"sec-4","text":"Wrapping without media queries","level":2},{"id":"sec-5","text":"Your turn","level":2}],"takeaways":["Flexbox sizes items in two passes: each item starts at its <code dir=\"ltr\">flex-basis</code>, then leftover space is shared by <code dir=\"ltr\">flex-grow</code> or a shortfall is taken back by <code dir=\"ltr\">flex-shrink</code>.","<code dir=\"ltr\">flex: 1</code> means <code dir=\"ltr\">1 1 0%</code>, so items get equal shares regardless of content; <code dir=\"ltr\">flex: auto</code> means <code dir=\"ltr\">1 1 auto</code>, so content size is kept and only the extra is shared.","Flex items default to <code dir=\"ltr\">min-width: auto</code>, which stops them shrinking below their content; set <code dir=\"ltr\">min-width: 0</code> to let text truncate instead of overflowing.","An auto margin on a flex item absorbs all free space on that side, which is the cleanest way to push one item to the far end."],"further":[{"title":"Controlling ratios of flex items along the main axis (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Flexible_box_layout/Controlling_flex_item_ratios"},{"title":"flex (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/flex"},{"title":"Flexbox (web.dev Learn CSS)","url":"https://web.dev/learn/css/flexbox"}],"quiz":[{"q":"<p>Three items with different text lengths sit in a 600px flex container. You want three equal 200px columns. Which declaration on the items does it?</p>","options":[{"text":"<code dir=\"ltr\">flex: auto</code>","why":"<code dir=\"ltr\">auto</code> means a basis of <code dir=\"ltr\">auto</code> (the content size), so longer text starts wider and stays wider after the extra space is shared."},{"text":"<code dir=\"ltr\">flex-grow: 1</code>","why":"This keeps the default <code dir=\"ltr\">flex-basis: auto</code>, so items still start from their content width; only the leftover space is split evenly."},{"text":"<code dir=\"ltr\">flex: 1</code>","why":"Correct. <code dir=\"ltr\">flex: 1</code> sets the basis to 0%, so all 600px is free space, shared equally by three items with grow 1."}],"answer":2},{"q":"<p>A session title in a flex row is a long unbroken string with <code dir=\"ltr\">white-space: nowrap</code>. It pushes the save button out of the card even though the title has <code dir=\"ltr\">flex: 1</code>. What fixes it?</p>","options":[{"text":"Add <code dir=\"ltr\">min-width: 0</code> (plus <code dir=\"ltr\">overflow: hidden</code>) to the title.","why":"Correct. Flex items default to <code dir=\"ltr\">min-width: auto</code>, which means “never smaller than my content”. Zero removes that floor, so the title can shrink and truncate."},{"text":"Add <code dir=\"ltr\">flex-shrink: 10</code> to the title.","why":"Shrink factors can’t take an item below its minimum size, and <code dir=\"ltr\">min-width: auto</code> sets that minimum at the content width."},{"text":"Add <code dir=\"ltr\">flex-wrap: wrap</code> to the row.","why":"Wrapping moves items onto new lines, but the title alone is still wider than the row, so it would still overflow."}],"answer":0},{"q":"<p>In a header that is a flex row, how do you push the “Get tickets” link to the far right while the logo and nav stay left?</p>","options":[{"text":"<code dir=\"ltr\">justify-content: space-between</code> on the header.","why":"That spreads every item apart, so the nav would float to the middle instead of staying next to the logo."},{"text":"<code dir=\"ltr\">margin-inline-start: auto</code> on the link.","why":"Correct. An auto margin swallows all free space on that side, so the link moves to the end and the others stay packed at the start."},{"text":"<code dir=\"ltr\">float: right</code> on the link.","why":"Floats have no effect on flex items; the flex container ignores <code dir=\"ltr\">float</code>."},{"text":"<code dir=\"ltr\">justify-self: end</code> on the link.","why":"<code dir=\"ltr\">justify-self</code> does nothing in flexbox, because the main axis is shared by all items, not split into cells."}],"answer":1},{"q":"<p><code dir=\"ltr\">.filters &gt; * { flex: 1 1 10rem; }</code> in a wrapping flex container 25rem wide with four filters. What happens?</p>","options":[{"text":"All four squeeze onto one line at 6.25rem each.","why":"Wrapping happens before shrinking. Four 10rem bases don’t fit in 25rem, so the line breaks instead."},{"text":"Each filter is exactly 10rem wide, leaving a gap at the end of each line.","why":"With grow 1 the items share the leftover space on their line, so they stretch to fill it."},{"text":"Two per line, each growing to fill half of its line.","why":"Correct. Two 10rem bases fit, three don’t, so each line holds two items that then grow to share the remaining space."}],"answer":2}],"exercise":{"kind":"web","mode":"dom","starter":{"html":"<div class=\"session-row\">\n  <span class=\"time\">09:30</span>\n  <span class=\"title\">Shipping Accessible Design Systems Across Twelve Product Teams Without Losing Your Mind</span>\n  <button class=\"save\" type=\"button\">Save</button>\n</div>","css":"/* The row is fixed at 400px for this exercise */\n.session-row {\n  width: 400px;\n  display: flex;\n  align-items: center;\n  gap: 12px;\n  border: 1px solid #e5e7eb;\n  border-radius: 10px;\n}\n.time {\n  width: 5rem;\n  font-variant-numeric: tabular-nums;\n  color: #6b7280;\n}\n.title {\n  white-space: nowrap;\n  font-weight: 600;\n}\n.save {\n  padding: 0.3em 0.8em;\n}\n"},"solution":{"html":"<div class=\"session-row\">\n  <span class=\"time\">09:30</span>\n  <span class=\"title\">Shipping Accessible Design Systems Across Twelve Product Teams Without Losing Your Mind</span>\n  <button class=\"save\" type=\"button\">Save</button>\n</div>","css":"/* The row is fixed at 400px for this exercise */\n.session-row {\n  width: 400px;\n  display: flex;\n  align-items: center;\n  gap: 12px;\n  border: 1px solid #e5e7eb;\n  border-radius: 10px;\n}\n.time {\n  flex: 0 0 5rem;\n  font-variant-numeric: tabular-nums;\n  color: #6b7280;\n}\n.title {\n  flex: 1;\n  min-width: 0;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  font-weight: 600;\n}\n.save {\n  flex: none;\n  padding: 0.3em 0.8em;\n}\n"},"checks":[{"id":"time-fixed","test":"const box = (s) => $(s).getBoundingClientRect(); return Math.abs(box('.time').width - 80) < 1;"},{"id":"no-overflow","test":"const row = $('.session-row'); return row.scrollWidth <= row.clientWidth + 1;"},{"id":"save-at-end","test":"const box = (s) => $(s).getBoundingClientRect(); const row = $('.session-row'); const inner = box('.session-row').right - parseFloat(style(row, 'border-right-width')) - parseFloat(style(row, 'padding-right')); return Math.abs(box('.save').right - inner) < 1.5;"},{"id":"title-fills","test":"const box = (s) => $(s).getBoundingClientRect(); const gap = parseFloat(style('.session-row', 'column-gap')) || 0; return Math.abs(box('.title').right + gap - box('.save').left) < 1.5;"},{"id":"ellipsis","test":"return style('.title', 'text-overflow') === 'ellipsis' && style('.title', 'overflow-x') === 'hidden';"},{"id":"short-title-still-fills","test":"const box = (s) => $(s).getBoundingClientRect(); const t = $('.title'); const old = t.textContent; t.textContent = 'Keynote'; await tick(16); const row = $('.session-row'); const inner = box('.session-row').right - parseFloat(style(row, 'border-right-width')) - parseFloat(style(row, 'padding-right')); const ok = Math.abs(box('.save').right - inner) < 1.5 && Math.abs(box('.time').width - 80) < 1; t.textContent = old; return ok;"}],"title":"Tame the runaway session title","prompt":"<p>The row is 400px wide, and the long title pushes the <strong>Save</strong> button out of it. Using flexbox properties on the items:</p>\n<ul>\n<li>make <code dir=\"ltr\">.time</code> a fixed <strong>5rem</strong> column that never grows or shrinks,</li>\n<li>let <code dir=\"ltr\">.title</code> take all remaining space and truncate with an <strong>ellipsis</strong> instead of overflowing,</li>\n<li>keep <code dir=\"ltr\">.save</code> at its natural size at the end of the row.</li>\n</ul>\n<p>The row must not overflow, and the layout should still hold when the title is short.</p>\n","hints":["Something stops the title from shrinking below its text width. Which property sets that floor on flex items?","<code dir=\"ltr\">flex: 0 0 5rem</code> gives a fixed column. <code dir=\"ltr\">flex: 1</code> plus <code dir=\"ltr\">min-width: 0</code> lets the title fill and shrink.","On <code dir=\"ltr\">.title</code>: <code dir=\"ltr\">flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;</code>. On <code dir=\"ltr\">.save</code>: <code dir=\"ltr\">flex: none;</code>."],"explanation":"<p>Flex items have <code dir=\"ltr\">min-width: auto</code>, which keeps them at least as wide as their content; with <code dir=\"ltr\">white-space: nowrap</code> that is the whole sentence. <code dir=\"ltr\">min-width: 0</code> removes the floor so the title can shrink, and <code dir=\"ltr\">overflow: hidden</code> with <code dir=\"ltr\">text-overflow: ellipsis</code> turns the clipped text into <code dir=\"ltr\">…</code>. <code dir=\"ltr\">flex: 0 0 5rem</code> fixes the time column (a plain <code dir=\"ltr\">width: 5rem</code> would still shrink), <code dir=\"ltr\">flex: 1</code> makes the title absorb leftover space even when it’s short, and <code dir=\"ltr\">flex: none</code> stops the button from being squeezed.</p>\n","checkLabels":{"time-fixed":"The time column is exactly 5rem wide","no-overflow":"Nothing overflows the row","save-at-end":"The Save button sits at the end of the row","title-fills":"The title fills the space up to the button","ellipsis":"The title truncates with an ellipsis","short-title-still-fills":"With a short title, the layout still holds"}},"words":687,"readMinutes":3}