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

Скелетон

Сірі фігури на місці контенту, поки він вантажиться. Функційна підказка, а не декорація: форма скелетона це обіцянка того, що приїде.

рівень 1design/system/components/skeleton.css355 рядків18 імен15 екранів
Анатомія

Розмітка та сама, що в продукті. До кроку 7.28 тут стояло <div class="skcardbox"><div class="skcard">… - коробка всередині коробки, чого в продукті немає жодного разу, тому демо малювало подвійну рамку. Сітка була придушена інлайновим style="display:grid;grid-template-columns:repeat(3,1fr);gap:14px", тобто показувала не .skgrid, а інлайн поверх нього. І пульсації в демо не було зовсім, хоча анатомія її називала.

1Форма .skcard - повторює форму майбутньої картки: той самий квадратний знімок, той самий падінг, ті самі три рядки. Якщо форма не збігається, завантаження виглядає як перебудова. І саме це тут і було до 7.68: цей рядок обіцяв 10/11 - і картка малювала 10/11 від 620 угору, а під 620 вона квадратна. На 390 скелет виходив 171 × 188.09 над карткою 171 × 171: стрибок на 17px саме на телефоні. Обіцянка, написана на цьому стенді, не виконувалась там, де її найбільше видно
2Смуга .skline - 10px, радіус 4, ґрунт --bg-sunken. Три ширини l m s, щоб стос смуг не читався таблицею
3Пульсація .skpulse - на контейнері, не на смузі. Каже «триває», а не «зламалось»
Смуга: шість редакцій в чотирьох файлах

Браузер обійшов 40 кольорових екранів на 1280 і 390: 140 елементів скелетона, 22 підписи класів, 5 екранів завантаження. Найчастіша частина - смуга - була написана шість разів.

Ім'яФайл до 7.28ШтВисотаsml
.sklineskeleton.css7810px50%72%90%
.co-skel .slcheckout-form.css311px46%72%-
.auth-skel .slauth-dialog.css211px-70%-
.acc-subskaccount-shell.css112px---
.acc-h1skaccount-shell.css124px---
.skcardbox .sklineskeleton.css-10pxвласний ґрунт, який перекривався

Висоти ні за чим не йдуть. Це перевірено, а не припущено: кожен екран завантажено двічі - як скелетон і як контент.

СмугаСтоїть на місціТекстВідношення
.skline 10px.pcard .nm16 / 20.80.63
.acc-h1sk 24px.acc-h130 / 480.80
.acc-subsk 12px.acc-sub14 / 22.40.86

Ні драбини, ні коефіцієнта - просто чотири числа. Скелетонна смуга це не висота тексту, це знак, який каже «тут буде рядок»; знак, що каже те саме, має казати це одним розміром. Тому рядок скрізь 10 - як уже було в 78 смугах з 84 - і власне число лишає тільки та смуга, що стоїть на місці заголовка: інше речення, а не промах.

Три видимі зміни
ЩоБулоСталоСкільки
висота смуги .sl і .acc-subsk11px · 12px10px6 смуг
.co-skel .sl.s46%50%1
.auth-skel .sl.m70%72%1

Два файли, що розійшлись на два відсотки щодо одного сірого прямокутника, - це не рішення, яке хтось ухвалював. Ширші за них два вузькі стовпчики (чекаут і діалог входу) стали на 2px нижчі, бо в кожному по дві смуги, - це наслідок, а не окрема зміна.

Пульсація - це модифікатор, а не деталь

Найважливіше, чого не було на попередній редакції сторінки: .skpulse вішають на контейнер, і контейнер здебільшого це справжній компонент. Вісім з 22 підписів перепису - це живий компонент, вбраний в один клас.

НосійЩо це
.bb.skpulseблок покупки на PDP
.gmain.skpulse .gthumb.skpulseгалерея товару, велике фото і 4 мініатюри
.acc-nav.skpulse .acc-cardgrid.skpulseнавігація і сітка кабінету
.skgrid.skpulseсітка карток каталогу

Прозорість на батькові, тому нічому всередині не треба знати, що воно вантажиться. Саме тому це голий клас, а не щось, прив'язане до фігур цього файлу.

І тепер вона зупиняється. На кроці 7.28 додано @media (prefers-reduced-motion: reduce): підказка про завантаження не має права бути тим, від чого людині зле. Форма лишається, дихання зупиняється, прозорість фіксується на 0.78 - посередині циклу, щоб стан читався так само.

Скелетон вбирається в той компонент, який обіцяє - крок 8.38

Перепис угорі цього файлу рахував смугу «шість разів у чотирьох файлах». Його знімали по 40 кольорових екранах на 7.28, а тренерський потік увійшов у колір на 7.95. Перерахунок по п'ятьох тренерських екранах завантаження дав дев'ять редакцій, і три нові не згодні ні з шістьма, ні між собою.

СмугаВисотаРадіусҐрунтДе
.sk-line13px6px--bg-sunkencoach-client-loading
.skln12px6px--bg-rulecoach-order-loading, coach-orders-loading
.qa-skel .sk12px6px--bg-rulecoach-session-loading
.skline10px4px--bg-sunkenцей файл, і 78 смуг із 84

--bg-rule - це --warm-200, тобто --line-hair. Три тренерські екрани фарбували скелетонну смугу кольором волосини, поки решта продукту фарбувала --warm-100. Зміряно: rgb(233,231,226) проти rgb(242,240,237).

А рядки навколо смуг були тим самим компонентом, передрукованим руками. Не схожість - ті самі оголошення поруч: .sk-row = .oc-item (40 / 1fr, gap 11, волосина), .sk-ph = .oc-ph (40 квадрат, радіус 7), .qa-skel = .qa-row (44 / 1fr, gap 11, padding 9/0), .skhd = .ccard-hd, .skav = .ccard-av, .skclist = .clist, .skgrp = .od-grp.

Тому правило не «перенести їх у компонент», а правило 7.68, дочитане до кінця: скелетон - це обіцянка про коробку, яка його замінить, і єдина обіцянка, що не може розійтися, - сама коробка. Розмітка тих п'ятьох екранів тепер носить .ocard, .oc-item, .oc-ph, .ccard, .clist, .od-grp, .qa-row - справжнє, порожнє, зі .skline всередині. 20 приватних правил пішли в нуль, і жодне оголошення їх не замінило.

Додалось рівно двоє: заглушка кнопки, яку писали двічі (.sk-btn 38 × 120 і .skacts i 38 із flex: 1) - обидві на 2px нижчі за btn--s, чий min-height = --size-40; і речення під скелетоном.

Завантажуємо список клієнтів…

Це доводить 8.24 до кінця, а не скасовує його. Той крок зняв coach-clients-loading з третього імені скелетонної картки і поставив на .skcard; те саме читання на крок далі каже, що це взагалі не скелетонна картка, а картка клієнта, що стоїть порожня. .skcard лишається каталогу й кабінету, де коробка-замінник це .pcard; назвати їх - питання етапу 09, а не рух, який цей крок зміряв.

Токен, що ніколи не фарбував скелетон

Був --bg-skeleton = #E9E7E2. Його називали три оголошення - .acc-h1sk, .acc-subsk, .skcardbox .skline - і всі три перекривались одним пізнішим рядком у account-shell.css, який повертав їх на --bg-sunken. Тому всі 140 виміряних елементів дали #F2F0ED, і жоден - #E9E7E2.

Те, що він справді фарбував: дві штрихові підкладки (.auth-visual, .wfh-mega .ms-ph) і одна волосина (.fgroup). Жодне з трьох не скелетон.

Перейменовано на слово власника, крок 7.28. Штриховка лишила значення й отримала ім'я того, що малює - --bg-hatch, 4 вживання (два елементи по дві зупинки градієнта). Волосина пішла на --line-hair, і це той самий --warm-200: примітив у себе в нотатці так і зветься - «plate pixel - the hairline». Нуль пікселів змінилось, одне ім'я перестало брехати. Ґрунт скелетонної смуги - --bg-sunken, і тепер він сказаний один раз у skeleton.css.

І остання умова пішла разом із сіткою, яку скелет обіцяє - раунд 3

Раунд 1 звів тут три числа до двох підлог із перемиканням на 620. Раунд 3 показав розгорткою, що саме це перемикання робить у product-grid.css: ряд карток губив колонку на 620, бо підлога стрибала зі 150 на 200. Сітка перейшла на пандус, а скелет, що лишився б із перемикачем, почав би брехати рівно на тій ширині - тобто повернув би дефект, який раунд 1 тут і полагодив. Тепер обидва читають --grid-col-fluid і --grid-gap-fluid, одним оголошенням без жодної умови. І 959 пішло: воно стояло в парі з 960 у account-shell.css, тому раунд 1 і лишив його винним - обидва склались на --bp-shell-wide разом.

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

Від якого порогу: --bp-grid-2col (620), і більше жодного. Було три фіксовані кількості колонок на двох умовах - 1fr 1fr, потім три на 620, потім чотири на 1040, - і 1040 немає в реєстрі. Що саме міняється: сітка тепер auto-fill з тими самими двома підлогами, що й product-grid.css (--grid-col-min-narrow 150px і --grid-col-min 200px), і з тим самим проміжком. І це виправило дефект, якого ніхто не бачив: на 1280 справжня сітка товарів дає три колонки по 248px, а скелет малював чотири по 185 - обіцяв розкладку, якої сторінка не приносила. Тепер обидві дають 248 x 3, піксель у піксель.
Коли вживати

На кожному екрані, де дані приходять мережею: каталог, PDP, кабінет, чекаут, діалог входу. Принцип 2 - «ніколи порожній погляд». У продукті таких екранів 11 - зміряно tools/inventory.mjs по 88 кольорових екранах, за якорями цього файлу, - і на кожному скелетон повторює форму саме того, що там буде. На 7.28 їх було 5: тренерський потік увійшов у колір на 7.95, а на 8.38 його п'ять екранів завантаження перестали малювати власні скелетони.

Правило і антиправило

Правило

Форма скелетона = форма контенту. Тоді завантаження виглядає як проявлення, а не як перебудова. Тому .skcard має те саме співвідношення знімка, що й картка товару.

Антиправило

Не став спінер замість нього на списках. Спінер каже «чекай», скелетон каже «ось що буде». Для однієї дії (надсилання форми) спінер доречний - див. Форма чекауту. І не малюй смугу власної висоти «бо тут заголовок» - для заголовка є .acc-h1sk.
Марки, які розмір мав, а імені не мав 12.2

Шістнадцять марок на трьох екранах завантаження стояли інлайновими висотами: смуга, чий РОЗМІР казав, за що вона стоїть, а ім'я не казало нічого. Тепер у кожної своя робота, і два екрани, що малювали ту саму марку двома числами, зійшлись в одну: рядок наявності в блоці покупки (30 x 40%) і провідна цифра картки акаунта (28 x 40%) - це одне, і зветься воно .skline--fig.

Цифри поза сходинками притягуються до найближчої, а нічия йде вгору - це власне правило файла про відступи, прочитане на розмір. Там, де сходинки поруч немає, літерал лишається і несе [?]: .skline--trust це 120, і воно стоїть за цілий блок довіри.

Логотип бренда - не фотографія 12, партія 2

.skimg це aspect-ratio: 1, бо кожна фотографія цього продукту квадратна. Коробка логотипа не квадратна і не фотографія - вона широка й низька, тож brands-loading обіцяв не ту коробку правильним компонентом. Марка бере ту висоту, яку коробка справді має.

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

Сторінка звіряє себе з файлом: 18 власних класів і 1 стан оголошено в skeleton.css. Нижче - ті, яких на цій сторінці немає ні в демо, ні в розмітці.

Рух

Робота: СТАТУС. Рухається: opacity, рівний цикл. Тривалість цикл 1.1s, поза реєстром, крива ease-in-out. Значення читаються через var() з tokens.css: підміна токена в браузері веде за собою кожне з них, тобто числа у файлі немає. При prefers-reduced-motion рух зникає, а стан лишається.

Цикл, а не перехід: skpulse 1.1s ease-in-out infinite. Токена в нього поки немає - жоден із трьох щаблів циклу не виражає, і четвертий заводиться лише окремим рішенням власника. При prefers-reduced-motion цикл ЗАМІНЮЄТЬСЯ статикою (animation: none, рівний тон), а не прискорюється: пульс на 1ms це миготіння, тобто гірше.

Крок 4: цикл став токеном. 1.1s ease-in-out був одним із трьох останніх літералів продукту. Тривалість пішла в --dur-cycle і зберегла число цього файлу: за КІЛЬКІСТЮ ЕКЗЕМПЛЯРІВ пульс - це той цикл, який продукт реально показує (22 сірих і 39 кольорових проти трьох обертунів), тож токен узяв 1100, а обертуни віддали 200мс. Крива - linear, і платить за це саме цей файл: обертання іншої не терпить, а тристопкова рампа під linear має ріг на повороті. М'якість переїхала в кейфрейми, де формі циклу й місце - сім стопок, що наближають косинус. Кінцеві значення ті самі, 1 і .55.

Токени

Прочитані з skeleton.css, не переписані руками. Колір іде лише через роль, геометрія - напряму з примітива. Два числа без токена: 10px смуги і 240/320px двох іменованих смуг кабінету - вони названі рішеннями в самому файлі.

Семантичні ролі (4)Примітиви (19)
--bg-sunken --elevation-1 --line-hair --text-muted--dur-cycle --ease-cycle --fs-12 --grid-col-fluid --grid-gap-fluid --radius-12 --radius-4 --radius-8 --size-24 --size-30 --size-40 --size-46 --size-52 --size-64 --space-12 --space-16 --space-2 --space-24 --space-8
Розмітка
<div class="skgrid skpulse"> <div class="skcard"><div class="skimg"></div><div class="skb"><div class="skline l"></div><div class="skline m"></div><div class="skline s"></div></div></div> </div>

Окрема коробка без знімка - .skcardbox, і вона ніколи не стоїть усередині .skcard: це два різні візерунки, сітка кабінету і сітка каталогу. .skcardbox.span2 розтягує її на всю ширину сітки.

<div class="skcardbox"><div class="skline l"></div><div class="skline s"></div></div> <div class="skcardbox span2">…</div>
Де вживається

Якорі: .skline .skgrid .skcard .skcardbox .skpulse .sl

5 екранів у design/: account-loading.html, auth-loading.html, checkout-loading.html, listing-loading.html, product-loading.html. Плюс .skpulse на живих компонентах тих самих екранів.