Меню вибору
Одне значення зі списку. Крок 7.2. До нього продукт мав два способи вибрати одне зі списку, і жоден не був цілим: сортування - список, зібраний руками, який відповідав лише миші, а на телефоні не відкривався взагалі; вибір клієнта - нативний <select>, у якого все це є безкоштовно, але розкритий список малює операційна система. Тепер обидва - один атом.
<select>: меню будується з нього і пише назад у нього, тому форма різниці не бачить, а сторінка без JS працює. Замінено закритий тригер і розкритий список, а не сенс контрола. Дія - не значення: «+ Новий клієнт…» виходить зі списку значень і стає кнопкою під роздільником. Саме через це пікер не міг лишитись нативним селектом: вибір такої опції означав би «значення = Новий клієнт», що неправда.Усе, що нативний <select> давав задарма і що тепер винні ми. У списку, зібраному руками до кроку 7.2, не було жодного рядка з цієї таблиці.
| Клавіша | На тригері | У списку |
|---|---|---|
↓ / ↑ | відкриває - на обраному рядку, або на останньому для ↑ | рухає на рядок |
Enter / Space | відкриває | обирає й закриває |
Home / End | - | перший / останній |
| літери | - | стрибок на рядок, що з них починається (вікно 700 мс) |
Esc | - | закриває, фокус повертається на тригер |
Tab | далі по сторінці | закриває і йде далі |
Ролі: тригер несе aria-haspopup="listbox" і aria-expanded, список - role="listbox", рядок - role="option" і aria-selected. Дія стоїть поза списком і тому не має ні ролі опції, ні галочки.
Нижче 480 список, прив'язаний до тригера, або тікає за екран, або лягає під палець. У продукті вже є нижня шторка для фільтрів, тож меню бере ту саму форму, а не вигадує другу: смужка-хват, рядки 52, ґрунт під усім екраном.
І шторка залишає свій тригер. .mtoolbar - липкий блок із z-index: 20, тобто власний контекст накладання: всередині нього жоден наш z-index не підніметься над нижньою панеллю (z 50), і шторка відкривалась під нею. Тому нижче 480 menu.js переносить список і ґрунт у <body>, поки меню відкрите, і повертає назад, коли закрите. Через це стан відкритості висить на самому списку (.menu-pop.open), а не на .menu.open .menu-pop.
ПОВЕДІНКА НА ШИРИНІ - етап 10, крок 4
Від якого порогу:--bp-grid-2col (620), було 479. Що саме міняється: відкрита випадайка стає повноекранним шитом зі скримом. Це поведінка, а не розмір, тож вона лишається точкою, а не стає плинною; питання було лише в тому, якою з двох, і продукт має дві. Нижче 620 списку немає де бути випадайкою - з тієї ж причини, з якої там ряд карток перестає бути однією колонкою. Наслідок вголос: між 480 і 619 меню тепер бере форму шита, яку раніше брало лише нижче 480. На 360 не зрушило нічого.Правило
Меню обирає значення, кнопка робить дію. Список - цеlistbox зі значень; усе, що не є значенням, стоїть під роздільником окремою кнопкою. Обраний рядок несе акцент і галочку: колір сам по собі не працює для того, хто його не бачить.Одне меню за раз. Відкриття закриває будь-яке інше: два розкриті списки - це дві відповіді на одне питання.
Антиправило
Не роби меню з того, що веде. Мова, кабінет, мега-меню - це навігація: там вибір нічого не обирає, а переносить. Їхній список неlistbox, і галочки в ньому бути не може.Не лишай нативний select там, де в списку є дія. Це єдина причина, з якої пікер клієнта перестав бути селектом - не вигляд.
Робота: ВІДПОВІДЬ. Рухається: шеврон тригера (transform), фон і колір рядка списку. Тривалість --dur-fast (150ms), крива --ease-standard. Значення читаються через var() з tokens.css: підміна токена в браузері веде за собою кожне з них, тобто числа у файлі немає. При prefers-reduced-motion рух зникає, а стан лишається.
Живе меню з міткою будує menu.js вище на цій сторінці: тут навмисно стоїть сам тригер, бо мітку тригера пише продукт, а не розмітка стенда.
Крок 4, дві поверхні. Поповер проявляється і не подорожує - він стоїть проти контрола, який його відкрив. Галочка обраного рядка - найменша поверхня продукту й єдина чиста ВІДПОВІДЬ серед двадцяти: --dur-fast, крива рядка, і приходить у ту саму мить, що й зміна кольору двома правилами вище. Без руху: галочка, яка їде, десь була, а вона не була.
Прочитані з menu.css, не переписані руками. Одинадцять ролей на шістнадцять примітивів, і в цьому наборі є одна пара, якої немає більше ніде: дві висоти тіні в одному компоненті.
| Семантичні ролі (11) | Примітиви (16) |
|---|---|
--bg-page --bg-sunken --bg-rule | --fs-14 --fs-16 |
--elevation-3 --elevation-4 | --fw-medium --fw-semibold --lh-snug |
--scrim-overlay | --radius-8 --radius-12 --radius-16 --radius-pill |
--line-strong --ring-focus-control | --size-20 --size-44 --size-52 |
--text-action --text-body --text-muted | --space-4 --space-8 --space-12 --space-24 |
| – | --dur-base --dur-fast --ease-enter --ease-exit --ease-standard |
--elevation-3 на десктопі і --elevation-4 на телефоні - це не непослідовність, це та сама відстань до різного тла. Спадне меню лягає на сторінку і мусить читатись відірваним від неї на один крок. Шторка на телефоні лягає на --scrim-overlay, тобто на затемнену сторінку, і крок від затемненого тла коштує дорожче - інакше вона читалась би приклеєною до скрима.
Чотири радіуси в одному файлі - 8 для рядка, 12 для коробки, 16 для шторки, pill для ручки, - і всі чотири це щаблі драбини. Жодного літерала геометрії у файлі немає взагалі, що для компонента з двома в'юпортними формами трапляється нечасто.