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

ЁЯУМ рдзрдбрд╛ 01 тАФ UI рдХрд╛: рд╕реВрдЪрдирд╛ рдлрд▓рдХ

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


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

рдЗрддрд░ рдкреНрд░рддреНрдпреЗрдХ рд╢рд╛рд│рд╛ рдЬреНрдпрд╛ рдЧреЛрд╖реНрдЯреАрдЪреНрдпрд╛ рджрд┐рд╢реЗрдиреЗ рдмрд╛рдВрдзрддреЗ рддреА рдЧреЛрд╖реНрдЯ тАФ рдЖрдгрд┐ рддреА рдмрдирд╡рдгрд╛рд▒реНрдпрд╛ рддреАрди files. рдЦрд▒реНрдпрд╛ files, рдЬреНрдпрд╛ рддреБрдореНрд╣реА рд╕рдВрдкреВрд░реНрдг рдХреЛрд░реНрд╕рднрд░ рд╡рд╛рдкрд░рд╛рд▓:

ЁЯОТ рд╕реБрд░реВ рдХрд░рдгреНрдпрд╛рдЖрдзреА: рддреБрдореНрд╣рд╛рд▓рд╛ рдПрдХ browser рдЖрдгрд┐ Python 3 рд▓рд╛рдЧреЗрд▓ (рдлрдХреНрдд рдлрд▓рдХ рдЖрдгрд┐ рддреНрдпрд╛рдЪрд╛ рдЫреЛрдЯрд╛ рдХрд╛рдЙрдВрдЯрд░ serve рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА). Node рдирд╛рд╣реА, npm рдирд╛рд╣реА, framework рдирд╛рд╣реА, build step рдирд╛рд╣реА. рдЪрд╛рдВрдЧрд▓реЗ рд╢реЗрдЬрд╛рд░реА: API рд╢рд╛рд│рд╛ (рд╣рд╛ рдлрд▓рдХ рдЬреНрдпрд╛ рдХрд╛рдЙрдВрдЯрд░рд╕рд╛рдареА slips рднрд░рддреЛ рддреЛ) рдЖрдгрд┐ CI/CD рд╢рд╛рд│рд╛ (рдлрд▓рдХ рдХрд╕рд╛ рд▓рд╛рд╡рд▓рд╛ рдЬрд╛рддреЛ). рд╣рд╛ рдХреЛрд░реНрд╕ рдХрд╛рдп рдирд╛рд╣реА: React рдХреЛрд░реНрд╕ рдирд╛рд╣реА тАФ рддреБрдореНрд╣реА рд╣рд╛рддрд╛рдиреЗ рдХрд░реВрди рдкрд╛рд╣рд┐рд▓реНрдпрд╛рдирдВрддрд░ frameworks рдХрд╛рдп automate рдХрд░рддрд╛рдд рддреЗ lesson 07 рджрд╛рдЦрд╡рддреЛ.

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

рд╢рд╛рд│реЗрдХрдбреЗ рдПрдХ рд╕реБрдВрджрд░ рдиреЛрдВрджреА рдареЗрд╡рдгреНрдпрд╛рдЪреА рдЦреЛрд▓реА ЁЯЧДя╕П (Database рд╢рд╛рд│рд╛) рдЖрдгрд┐ рдПрдХ рдирдореНрд░ рд╕рдореЛрд░рдЪреЗ рдХрд╛рд░реНрдпрд╛рд▓рдп ЁЯПв (API рд╢рд╛рд│рд╛) рдЖрд╣реЗ. рдПрдХ рдкрд╛рд▓рдХ рдЖрдд рдпреЗрддрд╛рддтАж рдЖрдгрд┐ рддреНрдпрд╛рдВрдирд╛ рдХрд╛рд╣реАрдЪ рджрд┐рд╕рдд рдирд╛рд╣реА. рддрд┐рдереЗ рд╕реВрдЪрдирд╛ рдлрд▓рдХ рдирд╛рд╣реА.

рдореНрд╣рдгреВрди рд╢рд╛рд│рд╛ рдПрдХ рдлрд▓рдХ рд▓рд╛рд╡рддреЗ ЁЯУМ. рддреНрдпрд╛рд╡рд░: рд╡рд░реНрдЧрд╛рдЪреА рдпрд╛рджреА, рдирд╡реАрди рд╡рд┐рджреНрдпрд╛рд░реНрдереНрдпрд╛рдЪреЗ рдирд╛рд╡ рдиреЛрдВрджрд╡рдгреНрдпрд╛рд╕рд╛рдареА рдПрдХ form, рдЖрдгрд┐ рд╣рд╛ рдлрд▓рдХ рдХрд╛рдп рдЖрд╣реЗ рдпрд╛рдмрджреНрджрд▓ рдПрдХ рдЯреАрдк. рдлрд▓рдХ рддреАрди рдЧреЛрд╖реНрдЯреАрдВрдиреА рдмрдирд▓реЗрд▓рд╛ рдЖрд╣реЗ, рдЖрдгрд┐ рдкрд╣рд┐рд▓реНрдпрд╛рдЪ рджрд┐рд╡рд╢реА рддреНрдпрд╛ рдбреЛрдХреНрдпрд╛рдд рд╡реЗрдЧрд╡реЗрдЧрд│реНрдпрд╛ рдареЗрд╡рдгреЗ рдлрд╛рдпрджреНрдпрд╛рдЪреЗ рдЖрд╣реЗ:

  1. HTML тАФ рдХрд╛рдп рд▓рд╛рд╡рд▓реЗ рдЖрд╣реЗ. рдпрд╛рджреА, form, headings. рд░рдЪрдирд╛ рдЖрдгрд┐ рдЕрд░реНрде: рд╣реЗ heading рдЖрд╣реЗ, рддреЗ button рдЖрд╣реЗ, рд╣реА рдкрд╛рдЪ рд╡рд┐рджреНрдпрд╛рд░реНрдереНрдпрд╛рдВрдЪреА рдпрд╛рджреА рдЖрд╣реЗ.
  2. CSS тАФ рддреЗ рдХрд╕реЗ рджрд┐рд╕рддреЗ. рд░рдВрдЧ, рдЕрдВрддрд░, рд░реБрдВрдж рднрд┐рдВрддреАрд╡рд░ рджреЛрди рд╕реНрддрдВрдн рдЖрдгрд┐ phone рд╡рд░ рдПрдХ. рдЕрд░реНрдерд╛рдмрджреНрджрд▓ рдХрд╛рд╣реАрдЪ рдирд╛рд╣реА; рд╕рдЧрд│реЗ рдХрд╛рд╣реА рд╕рд╛рджрд░реАрдХрд░рдгрд╛рдмрджреНрджрд▓.
  3. JavaScript тАФ рдХреЛрдгреА рд╕реНрдкрд░реНрд╢ рдХреЗрд▓реНрдпрд╛рд╡рд░ рдХрд╛рдп рд╣реЛрддреЗ. рдпрд╛рджреА filter рдХрд░рдгреЗ, form рдкрд╛рдард╡рдгреЗ, рдХрд╛рдЙрдВрдЯрд░рдХрдбреВрди рддрд╛рдЬреА рдирд╛рд╡реЗ fetch рдХрд░рдгреЗ.

Browser HTML рд╡рд╛рдЪрддреЛ рдЖрдгрд┐ objects рдЪреЗ рдЭрд╛рдб тАФ DOM тАФ рдмрд╛рдВрдзрддреЛ, рдордЧ рддреЗ рд░рдВрдЧрд╡рддреЛ. CSS рддреНрдпрд╛ рдЭрд╛рдбрд╛рд▓рд╛ рд╕рдЬрд╡рддреЗ; JavaScript рддреЗ рдмрджрд▓рддреЗ. рдпрд╛ рдХреЛрд░реНрд╕рдордзрд▓реА рдкреНрд░рддреНрдпреЗрдХ рдЧреЛрд╖реНрдЯ рдпрд╛ рддрд┐рдШрд╛рдВрдкреИрдХреА рдПрдХ рдЖрд╣реЗ, рдХрд┐рдВрд╡рд╛ рддреЗ рдПрдЦрд╛рджреНрдпрд╛ рдорд╛рдгрд╕рд╛рдкрд░реНрдпрдВрдд рдХрд╕реЗ рдкреЛрд╣реЛрдЪрддрд╛рдд рддреЗ рдЖрд╣реЗ.

рдЖрдгрд┐ рдлрд▓рдХ рджрд┐рд╕рддреЛ рддреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдорд╣рддреНрддреНрд╡рд╛рдЪрд╛ рдХрд╛ рдЖрд╣реЗ: рд▓реЛрдХрд╛рдВрдирд╛ рдЬреЗ рджрд┐рд╕рддреЗ рддреЗрдЪ product рдЖрд╣реЗ. рдиреЛрдВрджреАрдВрдЪреА рдЦреЛрд▓реА рдкрд░рд┐рдкреВрд░реНрдг рдЕрд╕реВ рд╢рдХрддреЗ рдЖрдгрд┐ рдХрд╛рдЙрдВрдЯрд░ рдЬрд▓рдж, рдкрдг рдЬрд░ рдлрд▓рдХ рдЧреЛрдВрдзрд│рд╛рдЪрд╛ рдЕрд╕реЗрд▓, keyboard рдиреЗ рд╡рд╛рдкрд░рддрд╛ рдпреЗрдд рдирд╕реЗрд▓, рдХрд┐рдВрд╡рд╛ phone рд╡рд░ рдордВрдж рдЕрд╕реЗрд▓, рддрд░ рдЬреНрдпрд╛ рд▓реЛрдХрд╛рдВрд╕рд╛рдареА рд╢рд╛рд│рд╛ рдЕрд╕реНрддрд┐рддреНрд╡рд╛рдд рдЖрд╣реЗ рддреНрдпрд╛рдВрдЪреНрдпрд╛рд╕рд╛рдареАрдЪ рддреА рдореЛрдбрд▓реЗрд▓реА рдЖрд╣реЗ.

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

flowchart LR
    subgraph back["ЁЯЧДя╕ПЁЯУи the back office"]
        db["Database school<br/>the record room"]
        api["API school<br/>the counter"]
        db --- api
    end
    subgraph board["ЁЯУМ the notice board тАФ this course"]
        h["ЁЯз▒ HTML тАФ what is pinned (structure + meaning)"]
        c["ЁЯОи CSS тАФ how it looks"]
        j["тЪб JavaScript тАФ what happens when touched"]
        h --> c --> j
    end
    api -->|"fetch /api/students"| board
    board -->|"the browser builds the DOM and paints"| person["ЁЯСА a person"]

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

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг UI рдордзреНрдпреЗрдЪ рдмрд░реЛрдмрд░рдкрдгрд╛ рдЙрдкрдпреЛрдЧреА рдард░рддреЛ. рдпрд╛ рдорд╛рд▓рд┐рдХреЗрддрд▓реА рдЗрддрд░ рдкреНрд░рддреНрдпреЗрдХ рд╢рд╛рд│рд╛ рдХрд╛рд╣реАрддрд░реА рдЦрд░реЗ рдмрдирд╡рддреЗ; рд╣реА рд╢рд╛рд│рд╛ рддреЗ рджрд┐рд╕рдгрд╛рд░реЗ, рд╕рдордЬрдгрд╛рд░реЗ рдЖрдгрд┐ рд╡рд╛рдкрд░рддрд╛ рдпреЗрдгрд╛рд░реЗ рдмрдирд╡рддреЗ тАФ keyboard, screen reader, рдХрд┐рдВрд╡рд╛ рдордВрдж рд░реЗрд▓реНрд╡реЗрдд рдкрд╛рдЪ рд╡рд░реНрд╖реЗ рдЬреБрдирд╛ phone рд╡рд╛рдкрд░рдгрд╛рд▒реНрдпрд╛рдВрд╕рд╛рдареАрд╕реБрджреНрдзрд╛.

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

ui/mock_api.py рддрд┐рдиреНрд╣реА files рдЖрдгрд┐ рдПрдХ рдЫреЛрдЯрд╛ /api/students рдХрд╛рдЙрдВрдЯрд░ serve рдХрд░рддреЛ, рдореНрд╣рдгрдЬреЗ рдлрд▓рдХ рддреБрдордЪреНрдпрд╛ laptop рд╡рд░рд╕реБрджреНрдзрд╛ production рдордзреНрдпреЗ рд╡рд╛рдЧреЗрд▓ рдЕрдЧрджреА рддрд╕рд╛рдЪ рд╡рд╛рдЧрддреЛ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛ (60 рд╕реЗрдХрдВрдж тАФ рд╕рдВрдкреВрд░реНрдг рдХреЛрд░реНрд╕, live)

python3 ui/mock_api.py          # terminal 1 тЖТ http://127.0.0.1:8000/
python3 ui/smoke_test.py        # terminal 2 тЖТ ten checks

рдордЧ browser рдордзреНрдпреЗ: рдПрдЦрд╛рджрд╛ рд╡рд░реНрдЧ filter рдХрд░рд╛, рдПрдХрд╛ рд╡рд┐рджреНрдпрд╛рд░реНрдереНрдпрд╛рдЪреЗ рдирд╛рд╡ рдиреЛрдВрджрд╡рд╛, ЁЯМЩ Dark рд╡рд░ click рдХрд░рд╛, рдЕрдЧрджреА рд╡рд░реВрди Tab рджрд╛рдмрд╛ (рдПрдХ рд▓рдкрд▓реЗрд▓реА "Skip to content" link рд╕рд░реНрд╡рд╛рдд рдЖрдзреА рджрд┐рд╕рддреЗ), рдЖрдгрд┐ filter рдХрд░рддрд╛рдирд╛ DOM рдХрд╕рд╛ рдмрджрд▓рддреЛ рддреЗ рдкрд╛рд╣рдгреНрдпрд╛рд╕рд╛рдареА DevTools тЖТ Elements рдЙрдШрдбрд╛.

Smoke test рдордзреВрди рддреБрдореНрд╣рд╛рд▓рд╛ рд╣реЗ рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ:

тЬЕ lang attribute on <html>      тЬЕ one <h1>          тЬЕ every input has a label
тЬЕ images have alt               тЬЕ skip link + live region
тЬЕ design tokens defined         тЬЕ dark theme via tokens    тЬЕ focus is visible
тЬЕ API returns students          тЬЕ API rejects a bad form (400)
ЁЯОЙ the board stands

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

рдлрд▓рдХрд╛рд╡рд░ рдкрд╛рдЪ рд╡рд┐рджреНрдпрд╛рд░реНрдереНрдпрд╛рдВрдЪреА рдпрд╛рджреА рджрд┐рд╕рддреЗ; рд╡рд░реНрдЧ filter рдкрд╛рди reload рди рдХрд░рддрд╛ рдпрд╛рджреА рд▓рд╣рд╛рди рдХрд░рддреЛ; рдирд╛рд╡ рдиреЛрдВрджрд╡рд▓реНрдпрд╛рд╡рд░ рдПрдХ card рдЬреЛрдбрд▓реЗ рдЬрд╛рддреЗ рдЖрдгрд┐ "тАж is on the board." рдЫрд╛рдкрд▓реЗ рдЬрд╛рддреЗ; smoke test ЁЯОЙ the board stands рдиреЗ рд╕рдВрдкрддреЛ. DevTools тЖТ Network рдордзреНрдпреЗ load рд╣реЛрддрд╛рдирд╛ рдлрд▓рдХ рдХрд░рдд рдЕрд╕рд▓реЗрд▓реА рдПрдХрдореЗрд╡ GET /api/students request рддреБрдореНрд╣реА рдкрд╛рд╣реВ рд╢рдХрддрд╛.

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

рдПрдХ рдЦрд░рд╛, interactive, accessible web app рдореНрд╣рдгрдЬреЗ рддреАрди text files рдЖрдгрд┐ рдПрдХ browser тАФ рдЖрдгрд┐ рддрд┐рдиреНрд╣реА рднрд╛рдЧ рдПрдХрддреНрд░ рдХрд╛рдо рдХрд░рддрд╛рдирд╛ рддреБрдореНрд╣реА рдЖрдзреАрдЪ рдкрд╛рд╣реВ рд╢рдХрддрд╛.

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

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: users рдирд╛ рдЦрд░реЛрдЦрд░ рдЬрд╛рдгрд╡рдгрд╛рд░реА рдкреНрд░рддреНрдпреЗрдХ incident рдЗрдереЗрдЪ рдШрдбрддреЗ: phone рд╡рд░реВрди рдкрд╛рдард╡рддрд╛ рди рдпреЗрдгрд╛рд░рд╛ form, screen reader рд▓рд╛ рди рд╕рд╛рдкрдбрдгрд╛рд░реЗ button, 3G рд╡рд░ рдЖрда рд╕реЗрдХрдВрдж рдШреЗрдгрд╛рд░реЗ рдкрд╛рди. рдорд╛рдЧрдЪреЗ рдХрд╛рд░реНрдпрд╛рд▓рдп рдЕрджреГрд╢реНрдп рдЕрд╕рддреЗ; рдлрд▓рдХ рд╣реЗрдЪ product рдЖрд╣реЗ.

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

рдиреЗрдордХреЗ рдХрд╛рдп рд▓рд╛рд╡рд╛рдпрдЪреЗ, рдЖрдгрд┐ рдХреЛрдгрддреНрдпрд╛ рдЖрдХрд╛рд░рд╛рдд? HTML рд░рдЪрдирд╛ тАФ semantic elements, forms, labels рдЖрдгрд┐ alt text.

git checkout lesson-02-html-structure

ЁЯУМ Lesson 01 тАФ Why UI: the notice board

ЁЯУН You are here: Lesson 01 of 12 ┬╖ Next: lesson-02-html-structure


ЁЯУж What's in this branch

The thing every other school builds towards тАФ and the three files that make it. Real files you will use all the way through:

ЁЯОТ Before you start: you need a browser and Python 3 (only to serve the board and its little counter). No Node, no npm, no framework, no build step. Good neighbours: the API school (the counter this board fills slips for) and the CI/CD school (how a board gets pinned up). What this is not: a React course тАФ lesson 07 shows what frameworks automate after you have done it by hand.

ЁЯзТ Explain like I'm 5

The school has a beautiful record room ЁЯЧДя╕П (the Database school) and a polite front office ЁЯПв (the API school). A parent walks inтАж and sees nothing. There is no notice board.

So the school pins one up ЁЯУМ. On it: the class list, a form to enrol a new student, a note about what the board is. The board is made of three things, and it is worth separating them in your head on day one:

  1. HTML тАФ what is pinned up. The list, the form, the headings. Structure and meaning: this is a heading, that is a button, this is a list of five students.
  2. CSS тАФ how it looks. Colours, spacing, two columns on a wide wall and one on a phone. Nothing about meaning; everything about presentation.
  3. JavaScript тАФ what happens when someone touches it. Filter the list, submit the form, fetch fresh names from the counter.

The browser reads the HTML and builds a tree of objects тАФ the DOM тАФ then paints it. CSS decorates the tree; JavaScript changes it. Everything in this course is one of those three, or how they travel to a person.

And the reason the board matters more than it looks: what people see IS the product. The record room could be perfect and the counter fast, and if the board is confusing, unusable with a keyboard, or slow on a phone, the school is broken for the only people it exists for.

ЁЯЧ║я╕П Diagram

flowchart LR
    subgraph back["ЁЯЧДя╕ПЁЯУи the back office"]
        db["Database school<br/>the record room"]
        api["API school<br/>the counter"]
        db --- api
    end
    subgraph board["ЁЯУМ the notice board тАФ this course"]
        h["ЁЯз▒ HTML тАФ what is pinned (structure + meaning)"]
        c["ЁЯОи CSS тАФ how it looks"]
        j["тЪб JavaScript тАФ what happens when touched"]
        h --> c --> j
    end
    api -->|"fetch /api/students"| board
    board -->|"the browser builds the DOM and paints"| person["ЁЯСА a person"]

тЭУ What

ЁЯдФ Why

Because the UI is where correctness becomes usefulness. Every other school in this series makes something true; this one makes it seen, understood and operable тАФ including by people using a keyboard, a screen reader, or a five-year-old phone on a slow train.

ЁЯФз How (in this repo)

ui/mock_api.py serves the three files and a tiny /api/students counter, so the board behaves exactly as it would in production, on your laptop.

ЁЯзк Try it (60 seconds тАФ the whole course, live)

python3 ui/mock_api.py          # terminal 1 тЖТ http://127.0.0.1:8000/
python3 ui/smoke_test.py        # terminal 2 тЖТ ten checks

Then, in the browser: filter a class, enrol a student, click ЁЯМЩ Dark, press Tab from the very top (a hidden "Skip to content" link appears first), and open DevTools тЖТ Elements to watch the DOM change as you filter.

You should see, from the smoke test:

тЬЕ lang attribute on <html>      тЬЕ one <h1>          тЬЕ every input has a label
тЬЕ images have alt               тЬЕ skip link + live region
тЬЕ design tokens defined         тЬЕ dark theme via tokens    тЬЕ focus is visible
тЬЕ API returns students          тЬЕ API rejects a bad form (400)
ЁЯОЙ the board stands

тЬЕ Verify тАФ what you should see

The board lists five students; the class filter narrows it without a page reload; enrolling adds a card and prints "тАж is on the board."; the smoke test ends with ЁЯОЙ the board stands. In DevTools тЖТ Network you can see the single GET /api/students the board makes on load.

ЁЯПБ What you just proved

A real, interactive, accessible web app is three text files and a browser тАФ and you can already see all three parts working together.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: every incident that users actually notice happens here: a form that cannot be submitted on a phone, a button a screen reader cannot find, a page that takes eight seconds on 3G. The back office is invisible; the board is the product.

тПня╕П Next

What exactly should be pinned, and in what shape? HTML structure тАФ semantic elements, forms, labels and alt text.

git checkout lesson-02-html-structure
тЖР Course homeall lessonsNext тЖТhtml structure

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