Компонент · рівень 2

Група фільтра

Один розділ рейки каталогу: заголовок, який згортає, і те, що під ним. Найгустіший компонент продукту за кількістю - 140 груп і 350 опцій на семи екранах каталогу. І всередині нього файл малював смугу ціни, а потім сам її стирав.

рівень 2design/system/components/filter-group.css99 рядків18 селекторів27 оголошень13 екранів140 груп
Анатомія

Розмітка звідси - та сама, що будує wireframes/_nav.js для десктопної рейки і для мобільного аркуша: одне джерело на два місця, тому телефон ніколи не розходиться з десктопом.

Наявність ▾
Ціна, ₴ ▾
8001500
Бренд ▾
1Шапка .fh - 14/700, стрілка .ar приглушена. Уся шапка це контрол: role="button" і aria-expanded дає design/_nav.js з кроку 7.34, до того панель була недосяжна з клавіатури
2Опція .fopt - рядок з прапорцем. Сам прапорець тут не оголошений: квадрат, галочка, ховер, натиск і кільце живуть у checkbox.css з кроку 7.38. Цей файл каже тільки ритм - 12 між опціями
3Лічильник .ct - margin-left: auto притискає цифру до правого краю. Це розкладка рядка, а не властивість лічильника, тому вона тут, а не в counter.css
4Ціна - справжній повзунок із двома ручками. Він не з цього файлу: design/_nav.js будує його, price-slider.css одягає. Спробуйте потягнути
5Ще .fmore - 12/вторинний. Не приглушений: приглушений відтінок у цій системі носить вимкнений контрол, а цей живий

Це рейка експерта. Тренер знає, що йому потрібно, і йому треба звузити 84 товари до восьми за три дотики - тому групи розгорнуті одразу, а не приховані за акордеоном. Аудиторія primary вирішує.

Смуга, яку файл малював і сам же стирав
.frange { height: 4px; border-radius: 4px; margin: 16px 2px 8px; position: relative } .frange::before, .frange::after { content: ''; width: 12px; height: 12px; ... } .frange::before { left: 18% } .frange::after { right: 26% } .frange { background: var(--bg-track) } .frange::before, .frange::after { background: var(--bg-action) } .frange.uiv-slider::before, .frange.uiv-slider::after { content: none; display: none } .frange.uiv-slider { background: none; border-radius: 0 }

Сім правил, і останні два існували тільки щоб скасувати перші п'ять. Сірий прототип малює повзунок картинкою: смужка і дві крапки, прибиті на 18% і 26%, нічого не тягнеться. У кольорі повзунок справжній, тож файл дописав рядки, які гасять картинку - замість того щоб її не малювати.

Заміряно в браузері до видаленняЗначення
.frange у кольоровому продукті14 - по дві на кожен із 7 екранів каталогу
скільки з них лишились .frange0. Усі 14 несуть uiv-slider
обидві рейки будуютьсяна завантаженні, тож апгрейд застає обидві
::before / ::aftercontent: none · display: none
border-radius · фон0px · rgba(0, 0, 0, 0)
висота, поля, positionвиграє price-slider.css .uiv-slider
оголошень, що не доходять до пікселя22

Пішли обидві половини - і малюнок, і гумка. Сірий прототип свою копію зберігає в wireframes/_wf.css, бо там картинка і є контрол.

Правило

Компонент або малює річ, або віддає її іншому - третього немає. Рядок, що гасить власний рядок кількома лініями нижче, це не налаштування, це слід від переїзду, який не довели до кінця.
Що з цього файлу вже поїхало
КрокЩоКуди і чому
7.28колір волосиничитав --bg-skeleton - фон замість лінії. Обидва це --warm-200, тож нуль пікселів; одне ім'я перестало брехати
7.34кільце фокусаз'явилось уперше: до того обидва контроли панелі були недосяжні, і питання, який тут вигляд у фокуса, просто не виникало
7.38прапорецьу checkbox.css. Файл переписував атом на ім'я класу (.fopt .cb), через що кожне оголошення самого атома було мертвим - і тут лежала друга мертва редакція поверх
7.75смуга ціниу price-slider.css, де вона й була. Розібрано вище

Файл почав із 80 рядків і чотирьох чужих компонентів усередині. Лишились три речі, які справді його: межа групи, ритм опцій і розкриття.

Кільце йде на рядок, а не на квадрат
Ціль ▾
натисніть Tab: спершу шапка, далі кожна опція. Кільце обводить увесь рядок

Контрол це увесь ярлик: він бере крок табуляції, він відповідає на пробіл, у нього влучає палець. Кільце навколо самого квадрата сказало б, що ціль це квадрат, а слова поруч - оздоблення, і це протилежне до правди. Радіус --radius-4 повторює квадрат, навколо якого рядок побудований. :focus-visible, а не :focus, щоб миша не запалювала кільце - той самий рядок тримають чип, кнопка, поле, радіо і посилання.

Стани
СтанЩо робитьЧому так
спокійгрупи розділені волосиною, всі розгорнутірейка експерта: фільтри видно одразу, а не за акордеоном
остання група:last-child знімає нижню лініюлінія в кінці відрізала б рейку від краю панелі
наведення на шапкутекст і стрілка беруть акцентний колірнатискається вся шапка, тож підсвічується вся шапка
згорнуто.collapsed: стрілка на 180°, вміст схованоселектор > *:not(.fh) - ховається все, крім шапки, і групі не треба знати, що саме всередині
фокус на шапцікільце --ring-focus-control:focus-visible, розібрано вище
цінадві ручки, помаранчева заливка між нимине цього файлу: price-slider.css
Правило і антиправило

Правило

Кожна опція називає, скільки за нею стоїть. «В наявності 71» - це не оздоблення, це те, що дає натиснути впевнено: видно, скільки лишиться. Тренер відсіює 84 до восьми, не гадаючи.

Антиправило

Не ховай групи за акордеон, щоб рейка виглядала коротшою. Згортання тут - вибір людини, а не стан за замовчуванням. Коротка рейка, у якій нічого не видно, економить піксель і коштує дотику.
Згорнута група

.fgroup.collapsed ховає все, крім голови, і повертає стрілку. Це стан, який дописує classList у мить натиску, але показати його можна в спокої: він нічого не робить із часом, він лише інша форма тієї самої групи.

Холостий контроль

Сторінка звіряє себе з файлом: 6 власних класів і 4 стани оголошено в filter-group.css.

Рух

Робота: ВІДПОВІДЬ. Рухається: колір рядка фасета і поворот шеврона групи. Тривалість --dur-fast (150ms), крива --ease-standard. Значення читаються через var(): підміна токена в браузері веде за собою кожне з них, тобто числа у файлі немає. При prefers-reduced-motion рух зникає, а стан лишається.

.2s шеврона згорнулось у швидку: шеврон це ВІДПОВІДЬ пальцю, а не поява панелі.

Токени

Прочитані з filter-group.css: 6 семантичних ролей і 7 примітивів.

Семантичні ролі (6)Примітиви (7)
--line-hair --ring-focus-control --text-action --text-body --text-muted --text-secondary--fs-12 --fs-14 --fw-bold --radius-4 --space-8 --space-12 --space-16
–--dur-fast --ease-standard

Повз шкалу лишилось одне число - 1px волосини. До 7.75 їх було сім: 4px висоти, -4px зсуву, двічі 12px на крапку, 18% і 26% їхніх позицій - шість чисел, і всі шість належали смузі, якої тут більше немає.

A/B

Три проходи по 40 екранах на чотирьох ширинах: HEAD, HEAD ще раз і робоче дерево. Нульовий прохід 0, різниця 0, 215 452 елементи з кожного боку.

Перепис не заміряє content псевдоелемента, тож нуль тут нічого не довів би сам по собі. Заміряно окремо, на обох серверах: .frange на трьох екранах - геометрія, поля, радіус, фон і обидва псевдоелементи однакові до і після.

Немає в коді -> етап 09

Чого бракує

  • Стан «нічого не знайдено за фільтром» - є listing-empty.html, але рейка на ньому виглядає так само, і жоден фільтр не позначений як той, що обнулив видачу
  • Скидання фільтрів - у рейці немає «Очистити». Опції вмикаються, і жодного одного дотику, щоб вимкнути всі
  • Пошук бренду - .fmore обіцяє «+ ще 11 · пошук бренду», і поля пошуку в коді немає
  • Числа біля опцій статичні: 71, 13, 12, 9 не перераховуються, коли ввімкнено інший фільтр

Не домальовано наперед і не замовчано: етап 09 стартує з цього списку, зведеного в design/kit/docs/architecture.md.