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

Тост

Смужка внизу екрана, яка каже, що дія вдалась. Єдиний компонент системи, якого в стані спокою не існує - і саме тому це виявилась єдина область продукту, куди жоден прохід ніколи не дійшов.

рівень 2design/system/components/toast.css76 рядків9 селекторів46 оголошень35 екранівJS
Анатомія

Натисніть - тости справжні, їх будує та сама wfToast(), що й у крамниці, і зникають вони так само через 4.2 секунди.

«Зникання» показує стан .out одразу: у крамниці він настає сам через 4.2 секунди, і чекати його на стенді - не показувати його
1Стос .wf-toasts - position: fixed, знизу 22, по центру, 92% ширини й не ширше 380. z-index: 70 - вище за все, крім модалок
2Смужка .wf-toast - --bg-inverse з --elevation-4, найважча тінь системи. Це єдина поверхня, яка лягає поверх усього, тож вона мусить читатись відірваною від сторінки
3Значок .tt-ic - біле коло 20 з чорним знаком. Знак набраний шрифтом, і це відкрите питання нижче
4Текст .tt-m - flex: 1, забирає все, що лишилось. Один рядок або два, обмеження немає
5Закрити .tt-x - aria-label="Закрити", і з 7.78 знак малюється з набору, як усі інші хрестики магазину

Стос має aria-live="polite". Тому тост чують, а не тільки бачать: читач з екрана отримує текст тоді ж, коли він з'являється, і не мусить його шукати. Це єдине місце продукту, де оголошення робиться саме так.

Область, куди не дійшов жоден прохід

marks.js існує заради одного правила: знак малює набір, а не шрифт машини. Проходи запускає uivChrome() останнім рядком - «щоб вони побачили кнопки, які всі проходи вище закінчили будувати». Тост будується не тоді. Він будується тоді, коли хтось зберіг адресу.

Заміряно на cart.htmlЧим намальовано
хрестик шухляди кошика .xнабір, .uiv-ic svg
хрестик діалогу .cd-xнабір, .uiv-ic svg
хрестик тоста .tt-xшрифт, символ ✕

Доказом, що нічого не бракувало, крім виклику, став ручний запуск: uivMarks() по контейнеру тоста перетворив символ на знак із набору одразу. Тож 7.78 не додав нового проходу - він обгорнув будівника, як uivPatchMenus() уже обгортає три будівники каталожного оверлея з тієї самої причини.

Заміряно на чотирьох ширинах, обидва сервериДоПісля
чим намальовано .tt-xсимвол ✕набір
коробка .tt-x11 x 2215 x 22
коробка .tt-m272 x 22268 x 22
сам тост, фон, межа, радіус, тінь, значокоднаково

Правило

Прохід, який діє один раз при завантаженні, не покриває те, що з'являється пізніше. Двічі за цей етап: спершу каталожний оверлей, тепер тост. Обидва полагоджені однаково - обгортанням будівника, а не другим проходом.
Два оголошення, які не робили нічого, і по-різному
.wf-toast.error .tt-ic { background: var(--bg-page); color: var(--text-primary) } .wf-toast.info .tt-ic { font-style: normal }

Перше було побайтно тим самим, що правило на рядок вище. Запущено всі три типи й прочитано обчислений стиль з кожного: коло біле rgb(255,255,255) на чорному rgb(28,28,28) в ok, в error і в info однаково. Значок помилки ніколи не виглядав інакше за значок успіху.

Друге повторювало початкове значення - і воно потрапило сюди звичкою. font-style: normal у системі є ще чотири рази: .tbanners .tbx i, .addr-method .am-tx i, .oh-thumbs i. У кожному з них елемент це <i>, який браузер нахиляє за замовчуванням. А .tt-ic це <span>. Звичка переїхала, тег - ні.

Після видалення в файлі не лишилось жодного правила для .info. Це чесно: інформаційний тост і є базовий тост, і тепер це видно з коду.

Помилка й успіх - це та сама коробка
ТипФонМежаЗначокВисота
okrgb(28,28,28)0біле коло, ✓46
errorrgb(28,28,28)1px білогобіле коло, !48
inforgb(28,28,28)0біле коло, i46

Уся різниця між «збережено» і «заповніть виділені поля» - це волосина 1px білого на майже чорному і інший набраний символ. У системі є ціла родина небезпеки - --bg-danger-soft, --line-danger-soft, --text-danger, - якою вже малюються .errbox, поле з помилкою і .btn--danger. Тост не бере з неї нічого.

Не змінено цим кроком, і це рішення власника

«Як має виглядати помилка на інверсній поверхні» - питання вигляду, а не заміру. Тепла червона заливка на чорному не працює, а червоне коло значка працює, але це вибір, а не виправлення. Записано в architecture.md з цим замірoм.
Знак статусу лишився набраним, і чому

✓, ! та i немає в UIV_SIGN_ONLY - карті, яка перетворює символ на знак. Додати їх не однорядкова зміна: у наборі є check і alert, а знака info немає взагалі. Два з трьох лишили б інформаційний тост єдиним досі набраним, що гірше за три з трьох.

marks.js сам пише це правило про свої карти: «поза нею нічого не чіпається, і жодна з двох карт не має права рости здогадкою». Тож знак статусу - записаний, а не заметений.

Стани
СтанЩо робитьЧому так
поява@keyframes tt-in: 220ms, знизу вгору на 10pxрух знизу каже, звідки річ прийшла; це не спалах уваги, а поява
спокійчорна смужка з тінню, до 4.2 секундидостатньо, щоб прочитати два рядки, і замало, щоб заважати
.outпрозорість 0 і вниз на 8px, 250msзникає туди ж, звідки прийшов
.errorдодає межу 1px --line-oninkєдина відмінність від успіху, розібрано вище
.infoнічогопісля 7.78 у файлі немає жодного правила для цього класу
кілька одразустос колонкою, крок 8wfToast дописує в кінець, старі не витісняються
наведеннянемає, і таймер не спиняєтьсязаписано нижче: тост, що зник під курсором, - це втрачене повідомлення
Правило і антиправило

Правило

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

Антиправило

Не клади сюди те, що не можна пропустити. 4.2 секунди й aria-live="polite" означають, що повідомлення можна не побачити й не почути. Помилка, яка блокує оформлення, мусить стояти на самому полі, а не пролітати внизу екрана.
Холостий контроль

Сторінка звіряє себе з файлом: 7 власних класів і 2 стани оголошено в toast.css.

ПОВЕДІНКА НА ШИРИНІ - етап 10, крок 4

Від якого порогу: жодного. Тост плинний: ширина обмежена своїм контейнером, текст переноситься. Раунд молекул його не чіпав.
Рух

Робота: ЗВ'ЯЗОК. Рухається: прихід і відхід: opacity і transform на --move-md. Тривалість --dur-slow (330ms), крива --ease-enter / --ease-exit. Значення читаються через var(): підміна токена в браузері веде за собою кожне з них, тобто числа у файлі немає. При prefers-reduced-motion рух зникає, а стан лишається.

Єдина молекула з роботою ЗВ'ЯЗОК, тому єдина, що бере --dur-slow. Прихід іде на --ease-enter, відхід на --ease-exit - тост іде туди ж, звідки прийшов. Тут же помер єдиний у продукті transition: all: він анімував усе, що змінилось, і перепис показав, що одне оголошення дістає 32 елементи. Тепер названі рівно дві властивості, які справді йдуть. Відстань 8px згорнулась у --move-md, тобто в те саме число, з якого тост приходить.

Крок 4, і тут знайшлись дві речі. Перша: вихід перейшов на --dur-base, і причина лежить у файлі, якого цей етап чіпати не може - wireframes/_nav.js знімає вузол через 250мс після класу .out, а крок 3 поставив вихід на 330. Тост зникав посеред власного згасання. Сірий корпус заморожений, тож рухається число: 220 вміщається в 250. Друга: тост помилки тепер рухається інакше за тост успіху - --dur-base і --move-sm замість --dur-slow і --move-md. До цього wfToast('error', ...) приходив тим самим розмахом, що й «Адресу збережено»: один рух під двома протилежними реченнями. Механізм - локальний псевдонім --tt-travel, а не перевизначений токен.

Токени

Прочитані з toast.css: 6 семантичних ролей і 9 примітивів.

Семантичні ролі (6)Примітиви (9)
--bg-inverse --bg-page --elevation-4 --line-onink --text-oninverse --text-primary--fs-12 --fs-14 --fw-black --radius-8 --radius-circle --size-20 --space-8 --space-12 --space-16
–--dur-base --dur-slow --ease-enter --ease-exit --move-md --move-sm

Повз шкалу п'ять чисел, і всі п'ять про розміщення й рух: 22px знизу, 92% і 380px ширини, 10px появи й 8px зникання. Жодне з них не про вигляд самої смужки - фон, радіус, тінь, кегль і кроки всередині взяті з системи повністю.

У цього файлу немає блока кольору взагалі - усі 43 оголошення в секції структури. І це правда, а не пропуск: тост від початку намальований інверсною поверхнею й ролями --bg-inverse / --text-oninverse, тож кольоровому продукту нема чого тут перебивати.

A/B

Перепис цей компонент не бачить. Він обходить 40 екранів у спокої, а тоста в спокої не існує - у переписі 7.75 кожне оголошення цього файлу впало в графу «не збігається з жодним елементом», усі до одного.

Тому A/B цього кроку інший: ті самі три тости на обох серверах, на чотирьох ширинах, і чотирнадцять обчислених значень з кожного - коробка, фон, межа, радіус, відступ, тінь, значок, текст, хрестик і ярлик. Різниця рівно там, де її замовляли: спосіб малювання хрестика і його коробка. Решта - однаково.

Плюс звичайні три проходи по 40 екранах: нульовий прохід 0, різниця 0 - бо в спокої обгортка wfToast нічого не робить, і це саме те, що треба було довести.

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

Чого бракує

  • Помилка невідрізненна від успіху - волосина 1px і набраний символ. Родина небезпеки в системі є й не використана
  • Знака info немає в наборі - тому знак статусу лишається набраним шрифтом у всіх трьох типах
  • Ціль «закрити» 15 x 22 при мінімумі 44, і це єдиний спосіб прибрати тост раніше
  • Таймер не спиняється ні на наведенні, ні на фокусі: повідомлення може зникнути з-під курсора того, хто його читає
  • 4.2 секунди - число, написане в wireframes/_nav.js і ніде не пояснене
  • Скільки тостів одночасно - обмеження немає, десять дій дадуть десять смужок

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