ЁЯПл The SchoolтА║ЁЯУМ UIтА║ЁЯОи рдзрдбрд╛ 03 тАФ CSS layout: рдПрдХрдЪ рдлрд▓рдХ, рдкреНрд░рддреНрдпреЗрдХ screen
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯОи рдзрдбрд╛ 03 тАФ CSS layout: рдПрдХрдЪ рдлрд▓рдХ, рдкреНрд░рддреНрдпреЗрдХ screen

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 03 ┬╖ рдорд╛рдЧреЗ: lesson-02-html-structure ┬╖ рдкреБрдвреЗ: lesson-04-javascript-events


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ02, рдЖрдгрд┐ рдлрд▓рдХ рдХрд╕рд╛ рдорд╛рдВрдбрд▓рд╛ рдЖрд╣реЗ: box model, рдЧреЛрд╖реНрдЯреАрдВрдЪреНрдпрд╛ рдПрдХрд╛ рдУрд│реАрд╕рд╛рдареА flexbox, рднрд╛рдЧрд╛рдВрдиреА рдмрдирд▓реЗрд▓реНрдпрд╛ рдкрд╛рдирд╛рд╕рд╛рдареА grid, рдЖрдгрд┐ рдПрдХрдЪ рдлрд▓рдХ phone рд╡рд░ рдЖрдгрд┐ рднрд┐рдВрддреАрд╡рд░ рдЪрд╛рд▓рд╡рдгрд╛рд▒реНрдпрд╛ рдХрд╛рд╣реА рдореЛрдЬрдХреНрдпрд╛ рд╕рд╡рдпреА.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдлрд▓рдХрд╛рд╡рд░рдЪрд╛ рдкреНрд░рддреНрдпреЗрдХ element рдПрдХ box ЁЯУж рдЖрд╣реЗ, рдЖрдгрд┐ box рд▓рд╛ рдЖрддреВрди рдмрд╛рд╣реЗрд░ рдЪрд╛рд░ рдерд░ рдЕрд╕рддрд╛рдд: content, padding (рдЪреМрдХрдЯреАрдЪреНрдпрд╛ рдЖрддрд▓реА рдЬрд╛рдЧрд╛), border (рдЪреМрдХрдЯ), рдЖрдгрд┐ margin (рддрд┐рдЪреНрдпрд╛ рдмрд╛рд╣реЗрд░рдЪреА рдЬрд╛рдЧрд╛). рд╕реБрд░реБрд╡рд╛рддреАрд▓рд╛рдЪ рдПрдХрджрд╛ box-sizing: border-box рд▓рд╛рд╡рд╛, рдореНрд╣рдгрдЬреЗ box рдЪреА рд╕рд╛рдВрдЧрд┐рддрд▓реЗрд▓реА width рд╣реАрдЪ рддреНрдпрд╛рдЪреА рдмрд╛рд╣реЗрд░рдЪреА width рдард░рддреЗ тАФ рд╕рдЧрд│реЗ рд▓реЛрдХ рдкреНрд░рддреНрдпрдХреНрд╖рд╛рдд рдЕрд╕рд╛рдЪ рд╡рд┐рдЪрд╛рд░ рдХрд░рддрд╛рдд.

рдордЧ boxes рдорд╛рдВрдбрдгреНрдпрд╛рдЪреЗ рджреЛрди рдорд╛рд░реНрдЧ рдЖрд╣реЗрдд:

рдЖрдгрд┐ рдлрд▓рдХ рд╕рдЧрд│реАрдХрдбреЗ рдЪрд╛рд▓рд╡рдгрд╛рд░рд╛ рдирд┐рдпрдо: рдЖрдзреА phone рдЪрд╛ layout рд▓рд┐рд╣рд╛, рдордЧ media query рдиреЗ рдореЛрдареНрдпрд╛ screens рд╕рд╛рдареА columns рдЬреЛрдбрд╛. рд╕рд╛рдкреЗрдХреНрд╖ units (rem, %, fr) рддрд╛рдгрд▓реНрдпрд╛ рдЬрд╛рддрд╛рдд; рдард░рд╛рд╡реАрдХ pixel widths рддрд╛рдгрд▓реНрдпрд╛ рдЬрд╛рдд рдирд╛рд╣реАрдд.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart TB
    box["ЁЯУж box model: content тЖТ padding тЖТ border тЖТ margin<br/>box-sizing: border-box, always"]
    flex["тЖФя╕П flexbox тАФ a row of things<br/>display:flex ┬╖ gap ┬╖ align-items ┬╖ margin-left:auto"]
    grid["тЦж grid тАФ areas<br/>grid-template-columns: 2fr 1fr ┬╖ auto-fill minmax(200px,1fr)"]
    resp["ЁЯУ▒тЖТЁЯЦея╕П mobile first<br/>one column; @media (min-width:720px) тЖТ two"]
    box --> flex --> grid --> resp

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг "рдорд╛рдЭреНрдпрд╛ laptop рд╡рд░ рдЪрд╛рд▓рддреЗ" рд╣реЗ рд╡рд╛рдХреНрдп layout рдордзреНрдпреЗрдЪ рдорд░рддреЗ. Flex, grid рдЖрдгрд┐ рд╕рд╛рдкреЗрдХреНрд╖ units рд╡рд╛рдкрд░реВрди mobile-first рдмрд╛рдВрдзрд▓реЗрд▓рд╛ рдлрд▓рдХ рджреБрд╕рд▒реНрдпрд╛ codebase рд╢рд┐рд╡рд╛рдп рдХреЛрдгрддреНрдпрд╛рд╣реА screen рд▓рд╛ рдЬреБрд│рд╡реВрди рдШреЗрддреЛ; рдард░рд╛рд╡реАрдХ widths рдЖрдгрд┐ absolute positioning рдиреЗ рдмрд╛рдВрдзрд▓реЗрд▓рд╛ рдлрд▓рдХ рдкреНрд░рддреНрдпреЗрдХ рдирд╡реАрди device рд╕рд╛рдареА рдкреБрдиреНрд╣рд╛ рд▓рд┐рд╣рд╛рд╡рд╛ рд▓рд╛рдЧрддреЛ.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

ui/styles.css рд╕реБрдорд╛рд░реЗ рдкрдиреНрдирд╛рд╕ рдУрд│реАрдВрдЪреЗ рдЕрд╕реВрди рддреАрди рднрд╛рдЧрд╛рдВрдд рдЖрд╣реЗ: tokens (lesson 08), layout (рд╣рд╛ рдзрдбрд╛ тАФ body, .board-head flex, main grid, .cards auto-fill grid), рдордЧ components. min-width: 720px рд╡рд░рдЪреА рдПрдХрдореЗрд╡ media query рд╣реЗрдЪ рд╕рдВрдкреВрд░реНрдг "desktop" design рдЖрд╣реЗ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 ui/mock_api.py     # http://127.0.0.1:8000/
# 1) shrink the browser to ~380px wide (or DevTools тЖТ device toolbar): one column, nothing clipped
# 2) delete the @media block in styles.css and reload at desktop width тАФ one column everywhere
# 3) change .cards to grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)) тАФ watch cards reflow
# 4) set body { max-width: none } and read a paragraph at 1600px тАФ that is why max-width exists
# 5) find the winner: DevTools тЖТ Elements тЖТ Styles on a .card, see which rules applied and which were struck through

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

Phone width рд╡рд░ рдлрд▓рдХ рдПрдХрд╛рдЪ column рдордзреНрдпреЗ рдЕрд╕рддреЛ рдЖрдгрд┐ рдЖрдбрд╡рд╛ scrollbar рдирд╕рддреЛ; тЙе720px рд╡рд░ students рдЖрдгрд┐ enrol рд╢реЗрдЬрд╛рд░реА рд╢реЗрдЬрд╛рд░реА рдмрд╕рддрд╛рдд. Media query рдирд╕реЗрд▓ рддрд░ desktop рд╡рд░рд╣реА рдПрдХрдЪ column рдЕрд╕рддреЛ (mobile-first рдореНрд╣рдгрдЬреЗ рдкрд╛рдпрд╛ mobile рдЕрд╕рддреЛ). рддреБрдореНрд╣реА рдЖрдХрд╛рд░ рдмрджрд▓рддрд╛ рддрд╕реЗ card grid рд╕реНрд╡рддрдГрд╣реВрди columns рдЪреА рд╕рдВрдЦреНрдпрд╛ рдмрджрд▓рддреЗ.

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

рджреЛрди layout рдкрджреНрдзрддреА рдЖрдгрд┐ рдПрдХрд╛ media query рдиреЗ рдкреНрд░рддреНрдпреЗрдХ screen рд╕рд╛рдареА рд╕рдВрдкреВрд░реНрдг рдлрд▓рдХ рдорд╛рдВрдбрд▓рд╛, рдЖрдгрд┐ рдХреЛрдгрддрд╛ рдирд┐рдпрдо рдЬрд┐рдВрдХрд▓рд╛ рддреЗ DevTools рдиреЗ рддреБрдореНрд╣рд╛рд▓рд╛ рдиреЗрдордХреЗ рджрд╛рдЦрд╡рд▓реЗ.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рдЦрд▒реНрдпрд╛ traffic рдкреИрдХреА рдЕрд░реНрдзреНрдпрд╛рд╣реВрди рдЬрд╛рд╕реНрдд phones рд╡рд░реВрди рдпреЗрддреЗ. рдпрд╛ рдзрдбреНрдпрд╛рддрд▓реНрдпрд╛ рджреЛрди рд╕рд╡рдпреА тАФ mobile-first рдЖрдгрд┐ рд╕рд╛рдкреЗрдХреНрд╖ units тАФ рдореНрд╣рдгрдЬреЗ рдПрдХ stylesheet рдЖрдгрд┐ рдлрд▓рдХрд╛рд╡рд░рдЪрд╛ рдХрд╛рдпрдордЪрд╛ "mobile bug" column рдпрд╛рдВрдЪреНрдпрд╛рддрд▓рд╛ рдлрд░рдХ.

тПня╕П рдкреБрдвреЗ

рдлрд▓рдХ рдмрд░реЛрдмрд░ рджрд┐рд╕рддреЛ; рдЖрддрд╛ рддреЛ рдХрд╛рд╣реАрддрд░реА рдХрд░реЗрд▓ рдЕрд╕реЗ рдХрд░рд╛: JavaScript рдЖрдгрд┐ events тАФ clicks, forms, рдЖрдгрд┐ рдХрд╛рдЙрдВрдЯрд░рдХрдбреВрди fetch рдХрд░рдгреЗ.

git checkout lesson-04-javascript-events

ЁЯОи Lesson 03 тАФ CSS layout: one board, every screen

ЁЯУН You are here: Lesson 03 of 12 ┬╖ Previous: lesson-02-html-structure ┬╖ Next: lesson-04-javascript-events


ЁЯУж What's in this branch

Lessons 01тАУ02, plus how the board is arranged: the box model, flexbox for a row of things, grid for a page of areas, and the handful of habits that make one board work on a phone and on a wall.

ЁЯзТ Explain like I'm 5

Every element on the board is a box ЁЯУж, and a box has four layers from the inside out: the content, the padding (space inside the frame), the border (the frame), and the margin (space outside it). Set box-sizing: border-box once at the top and a box's declared width is its outer width тАФ the way everyone actually thinks.

Then there are two ways to arrange boxes:

And the rule that makes the board work everywhere: write the phone layout first, then add columns for bigger screens with a media query. Relative units (rem, %, fr) stretch; fixed pixel widths do not.

ЁЯЧ║я╕П Diagram

flowchart TB
    box["ЁЯУж box model: content тЖТ padding тЖТ border тЖТ margin<br/>box-sizing: border-box, always"]
    flex["тЖФя╕П flexbox тАФ a row of things<br/>display:flex ┬╖ gap ┬╖ align-items ┬╖ margin-left:auto"]
    grid["тЦж grid тАФ areas<br/>grid-template-columns: 2fr 1fr ┬╖ auto-fill minmax(200px,1fr)"]
    resp["ЁЯУ▒тЖТЁЯЦея╕П mobile first<br/>one column; @media (min-width:720px) тЖТ two"]
    box --> flex --> grid --> resp

тЭУ What

ЁЯдФ Why

Because layout is where "it works on my laptop" goes to die. A board built mobile-first with flex, grid and relative units bends to any screen without a second codebase; one built with fixed widths and absolute positioning needs a rewrite for every new device.

ЁЯФз How (in this repo)

ui/styles.css is about fifty lines in three parts: tokens (lesson 08), layout (this lesson тАФ body, .board-head flex, main grid, .cards auto-fill grid), then components. The single media query at min-width: 720px is the whole "desktop" design.

ЁЯзк Try it

python3 ui/mock_api.py     # http://127.0.0.1:8000/
# 1) shrink the browser to ~380px wide (or DevTools тЖТ device toolbar): one column, nothing clipped
# 2) delete the @media block in styles.css and reload at desktop width тАФ one column everywhere
# 3) change .cards to grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)) тАФ watch cards reflow
# 4) set body { max-width: none } and read a paragraph at 1600px тАФ that is why max-width exists
# 5) find the winner: DevTools тЖТ Elements тЖТ Styles on a .card, see which rules applied and which were struck through

тЬЕ Verify тАФ what you should see

At phone width the board is one column with no horizontal scrollbar; at тЙе720px students and enrol sit side by side. Without the media query, the desktop is a single column (mobile-first means the base is mobile). The card grid changes column count by itself as you resize.

ЁЯПБ What you just proved

Two layout systems and one media query arranged the whole board for every screen, and DevTools showed you exactly which rule won.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: over half of real traffic is phones. The two habits in this lesson тАФ mobile-first and relative units тАФ are the difference between one stylesheet and a permanent "mobile bug" column on the board.

тПня╕П Next

The board looks right; now make it do things: JavaScript and events тАФ clicks, forms, and fetching from the counter.

git checkout lesson-04-javascript-events
тЖР Previoushtml structureNext тЖТjavascript events

This page is the lesson's README from the lesson-03-css-layout branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.