Own markup: your HTML, CSS and JS in a Vizen shop
/docs/own-markupcurrentМашинный перевод с английского· проверено 2026-08-20
Статус: current · проверенный: 2026-08-20, live звонки + source измерения; §7.2 — 2026-09-12, против code (обработчики, валидаторы, витрины); layout Стили в The level-1 тень — 2026-09-13, против витрины магазина code + Безголовый Chrome работает владелец: гладиатр API документация · Служить: GET /docs/own-markup Машинный справочник: /docs/vz-keys.json (ключи, scope, уровень) • Та же таблица, что и проза: /docs/vz-keys мастерство: vizen-own-markup
1.Что вы можете сделать здесь
Пишите обыкновенные HTML, CSS и JavaScript, Положите его в page block, и иметь Замена платформы shop data на сервере. Ответом является plain HTML: тот text находится в page source, Поисковые системы видят это, и никаких иностранных JavaScript это необходимое для display data.
2. Решать first
| Если ты хочешь… | Возьми это path | Стоимость |
|---|---|---|
| а product row из любой section, на любой page, любой design | own разметка над products[] scope, тот section названный productsCategoryId | live цены - ≤ 48 items (или groups), base fields выбранный плюс attributes и group Плитка по запросу, один section за block |
| а отобранный вручную row в твоем order | own разметка productsIds (§2 ниже) | live data; до 48 ids, Один член семьи в обмороке mode |
| а product row с платформой look | платформа productListing (widgets.md) | props настроить standard look; layout CSS и объявленные крючки поддерживают преднамеренные переопределения (§5)) |
| а header Это, несомненно, ваше | own разметка в chrome комплект (chrome.md) | Вы восстанавливаете окно поиска и cart отсчет от vz- ключи; sticky Это уже не является затратой — это работает там (§ 5.7).) |
| а платформа block Это не должно look Как и платформа | keep тот widget, положите own class В своей группе — props.wrapperClass (§5) | CSS в layout папка или level-3 document (§5.4) |
| Одинаковая накладка на многие pages, с разными content каждый раз | а компонент — Та же папка плюс component.json и {{key}} (components.md, GET /docs/components) | Вы пишете a schema параметры, в обмен на один new Выпуск обновлений для каждой вставки |
| один-off приземление page | own накладная накладка на empty page со всеми тремя слоями hidden | Ничто из платформы не показывает через, что является точкой |
| Световой ящик, а product окно, а cart button, поиск — Готовое поведение без вашего own JavaScript | модуль из /docs/modules: скопировать его фрагмент в вашу разметку | тот look Это твой CSS, Поведение – это платформа's — Как и в его own blocks |
Где? data Вилка, которая имеет значение. The page scope перевозить shop, menu, crumbs, category, products и — на а product page — product.
products[] это live. Он построен на сервере из того же каталога. Платформа listing использует, так price и old_price уже прошли через тот promotion двигатель и preview уже является реципиентом path:
<article vz-for="p in products">
<img vz-src="p.preview" alt=""> <h3>{{ p.name }}</h3>
<span>{{ p.price_text }}</span>
<button vz-add-to-cart="{{ p.id }}">Buy</button>
</article>Feed Границы (явные) productsIds Выбор перевешивает section и его order):
- тот feed это ONE section — Тот, который BLOCK имена. По умолчанию: The section тот page Сама по себе она, как и посадка, является article, Домой page и а product page иметь none и
productsэто[]Назовите имя. section на block и Та же самая разметка работает в любом месте:props.html.productsCategoryIdна html widget,props.component.productsCategoryIdна вставке компонента. section из другой shop уступает empty feed, never Иностранные товары — это always сфера применения этого shop; - Заряжается только тогда, когда document спрашивать. Триггер - это text твоей document:
vz-for="… in products"или{{ products.… }}. А. document это never Упоминания о feed не платить за него; - 48 items за page, в section's own order если только
productsIdssets явно выраженный order. The page's own section pages с?page=N— параметр платформы listing использует, так канонический и "page Н." title И уже последуют за ним — иproducts_pageПеревозит навигацию:page,pages,total,per_page,prev_url,next_urlИ готовыйlinks[]row (number,url,current,gapдля "…"). А. block Назовите другое section получает first page Только один. section за block: два sections в одном row означает два blocks; - base fields:
id,name,sku,price,price_text,old_price,old_price_text,url,preview,preview_srcset,in_stock,promotion_name,discount_percent,discount_percent_text, плюс combo fields ниже. По просьбе block: избранный attributes (productsAttributes) и один плитка на product group с переключаемым members (productsMode: "collapse") — См. разделы «Атрибуты на плитке» и «Одна плитка на плитку» group» Ниже - галерея, variants внутри одного product и description есть не в feed; они live наproduct, которая существует в product page только.
рецепт — live products на посадку page. Посадка не является section, так block Скажите, какой из них показать:
{ "type": "text", "payload": { "v": 2, "kind": "html",
"props": { "html": { "html_document_id": 107, "level": 1,
"productsCategoryId": 625 } } } }<ul><li vz-for="p in products">{{ p.name }} — {{ p.price_text }}</li></ul>Два blocks на одном page может name два разных sections; корма с одинаковым section нормализованный профиль (mode, attributes, ids) Они распространяются; разные профили получают отдельные корма..
скидка percent. discount_percent Это сокращение в целом number и discount_percent_text готовый badge ("10%"); Оба они являются 0 и "" когда Нет никакого старого price или сокращение составляет менее одного процента. две цены, которые сервер уже вычислил, а не из второго дисконтного движка; Он округлен вниз — тот page never обещания more чем checkout брать. Та же пара сидит на product, Так что плитка и card Показать то же самое number.
Комбо в этом feed. p.combo Это set в котором THIS product самый дешевый: name, url, preview_url, item_price / item_regular_price (в-set price против обычного), combo_price и benefit, Каждый из них с _text Близнецы. отсутствие Когда нечего сказать честно — нет set, нет benefit, или в-set price Не ниже — так что vz-if="p.combo" Это целое condition. p.combos_count Сколько их sets тот product - Заходи. product это IS а set, p.combo_items[] несет в себе его состав (name, url, preview_url, quantity, price = тот price внутри set, regular_price = Обычный, оба с _text) и p.benefit_text Что это такое set экономия.
Над set Щелкните либо components_total_text или old_price_text: а set это ценовой по своему составу Везде, так что оба несут одно и то же. number на плитка и на set's own page. Одно отличие: old_price это empty Когда там Нечего бить (нет компонентов дешевле внутри). set), в то время как components_total это always Сумма — используйте ее для «N ⁇ отдельно»." line рядом тот benefit.
Обе половины являются одним extra пакетный запрос (GET /products/combo), Сделано один раз за page и Только когда ваша марка упоминает `.combo` или `combo_items` — а document Это не так, ничего не платит.: ids это повторяющийся параметр, а не список, разделенный запятой — GET /products/combo?company_id=19&ids=2606&ids=2607 (Ответы на запятую 400, название ids). Ответ - это редкий: а product Это в не set незамеченным Вместо того, чтобы вернуться empty, Так что соответствуй rows через product_id вместо того, чтобы position. Цифры приходят из одного и того же code это строит product card, Так что плитка и product's own page cannot несогласный. Не пересчитывайте их: в-set price Он был получен из BASE price, и а Второй расчет будет отклоняться от cart.
Рецепт — «дешевле в...» set" лента на листовой плитке:
<article vz-for="p in products">
<img vz-src="p.preview" alt="">
<span vz-if="p.discount_percent" class="badge">{{ p.discount_percent_text }}</span>
<a vz-if="p.combo" vz-href="p.combo.url" class="ribbon">
В КОМБО ВЫГОДНЕЕ {{ p.combo.item_price_text }}
<s>{{ p.combo.item_regular_price_text }}</s>
</a>
<h3>{{ p.name }}</h3><span>{{ p.price_text }}</span>
</article>Рецепт - а set плитка с ее составом (а section из kind=combo products):
<article vz-for="p in products">
<img vz-src="p.preview" alt=""><h3>{{ p.name }}</h3>
<p>{{ p.price_text }} <s>{{ p.components_total_text }}</s></p>
<div vz-for="c in p.combo_items" class="part">
<a vz-href="c.url"><img vz-src="c.preview_url" alt=""> {{ c.name }}</a>
<span>{{ c.price_text }} <s>{{ c.regular_price_text }}</s></span>
</div>
<a vz-href="p.url">Показать комбо</a>
</article>Атрибуты на плитке. The block Перечислите коды атрибутов, которые ему нужны, в order — productsAttributes рядом с productsCategoryId (props.html.… или props.component.…), до 32-х:
"props": { "component": { "ref": 89, "productsCategoryId": 625,
"productsAttributes": ["bed-size", "material"] } }Каждый item Затем он переносит p.attrs.<code> — {code, name, value, values, options}, где value Готов ли он text (единицы, опционные метки) — и p.attributes[] в это order. Один компонент может показать разные attributes в разных sections: Список принадлежит к block, Коды могут содержать дефисы:
<span vz-if="p.attrs.bed-size">{{ p.attrs.bed-size.value }}</span>
<dl><dt vz-for="a in p.attributes">{{ a.name }}: {{ a.value }}</dt></dl>Только attributes Покупатель может видеть в списках прибыть; hidden, empty и unknown Коды отсутствуют — охраняйте vz-if. Настройка доступа покупателя для selected attributes и group топоры before авторинг; дефолты, доступ PUT и его filter-панель side effect Канонический в /docs/catalogue §8.3. Неправильная форма code Упаковываются и сообщаются в render Вместо того, чтобы опустошить feed.
Одна плитка на group (size × Цвет на месте). productsMode: "collapse" поворот тот feed в одну плитку на product group (связанный products с топорами, /product-groups). Пейджинг и та total count идти groups, так page граница never Каждый из них состоит из трех частей (каждый из них имеет три части). field список в /docs/vz-keys.json → scope.products; это page Поясните, как их использовать):
p.members[]— Степной лист на одного члена с а full card (все в одном месте plain плитка имеет: own price, запас, картинка, url,combo,attrs);selectedзнаки член, который стоит как плитка. product вне любого group имеет один член - сам;m.variants[]— Чипы переключателей для этого члена. Изменение одной оси продолжается Комбинация, которой не существует, естьavailable: false— never а заменить SKU.has_comboНа чипе это означает, что какой-то член с этим value имеет прибыльный set (а size , который остается на другом цвете; set's own price только на члена, который в нем,m.combo;has_comboОн заселяется только тогда, когда document просьбы combo цитаты (упоминатьm.combo; Просто читатьhas_comboне load их —/docs/vz-keys.json→scope.products);p.group.all[]— каждый Член с а link, любой variant Можно открыть, Даже один неосевой чип не достигает.
Сервер отображает панель на члена; ключи vz-panes, vz-pane, vz-pick и vz-hidden Сделайте клик, чтобы показать участнику's Панель на месте — ничего не Пересчитанный в браузере. Чип - это реально link: без JavaScript, на Ctrl/Cmd-click, или для члена без панели, она открывает член's page.
<article class="card" vz-for="p in products" vz-panes>
<div vz-for="m in p.members" vz-pane="{{ m.id }}" vz-hidden="!m.selected">
<a vz-href="m.url"><img vz-src="m.preview" srcset="{{ m.preview_srcset }}" alt="{{ m.name }}" loading="lazy"></a>
<a vz-href="m.url">{{ m.name }}</a>
<b>{{ m.price_text }}</b>
<a vz-if="m.combo" vz-href="m.combo.url">В комбо {{ m.combo.item_price_text }}</a>
<div vz-for="ax in m.variants">
<span vz-for="o in ax.options">
<a vz-if="o.available" vz-href="o.url" vz-pick="{{ o.member_id }}" aria-current="{{ o.current }}">{{ o.label }}</a>
<span vz-if="!o.available" aria-disabled="true">{{ o.label }}</span>
</span>
</div>
<button vz-add-to-cart="{{ m.id }}">В корзину</button>
<button vz-fav="{{ m.id }}">♡</button>
</div>
<details vz-if="p.group">
<summary>Все варианты</summary>
<a vz-for="v in p.group.all" vz-href="v.url" vz-pick="{{ v.member_id }}">{{ v.label }}</a>
</details>
</article>Стиль selected чип a[aria-current="true"] (Правила санитарии: § 4. hidden стойка остается hidden над своим own display: (Платформа добавляет [vz-pane][hidden]{display:none!important}); для тебя own nodes с vz-hidden добавлять [hidden]{display:none}. Члены не подчиняются section's фильтры (семья может быть sections) — p.members Это семья, а не more Плитка. Полная cards: до 16 на человека group 200 на человека page; Член, выходящий за пределы не имеет подвески — чипсы и p.group.all[] Взносы, указывающие на то, что он несет has_pane: false и открыть его link. p.members существует только с productsMode: "collapse". Оба settings Ответ как покупатель для всех, owner включенный (catalogue.md §4.1).
Список избранных в вашем order — `productsIds`. До 48 product ids рядом с ref: тот feed Именно эти products в этом order Вместо того чтобы section (productsCategoryId это ignored, один page). С productsMode: "collapse" список один член на одного члена group — Он становится плиткой, и его панель является той, что показана. first, Так что список sets оба order семьи и их default variant; Все остальные члены семьи приходят как p.members. Тот же самый гарнитур выбирает sets для combo полоскать (p.combo_items). Проекты, hidden иностранный products есть просто отсутствует; недействительный ids Они были выброшены и зарегистрированы в render вопросы.
"props": { "component": { "ref": 42, "params": {},
"productsMode": "collapse", "productsAttributes": ["bed_size", "bed_color"],
"productsIds": [2503, 2509, 2498, 2501, 2515] } }Для level-1 CSS и разрешены attributes, См. § 4 ниже.
Только имена и цены, введённые буквально в наценку, являются snapshot. Изменить price в каталоге и что row Показать старый / The Old One до тех пор, пока document повторно загружается.
Скажи это owner before здание. Ан owner кто слышит цены на это «Посадка перестанет обновляться» решает иначе, чем тот, кто не.
Что остается live Независимо от того, что path: vz-add-to-cart, vz-cart-count, vz-fav, vz-variants.
`vz-panes` / `vz-pick` работать в level 1 Внутри корня тени, а также и в page DOM; Click Runtime использует составные event path. Это также было проверенный в owner’s TOPLOFT production приемка (2026-10-25)).
3. Объекты и где они находятся live
Разметка является file, не field: трехступенчатая загрузка → POST /html-documents → а block section kind: "html" ссылаясь на document id → тот block входить в page zone.
| Уровень | Что это значит | индексированный |
|---|---|---|
| 1 | статический, дезинфицированный; ключи расширяют сервер-side | yes |
| 2 | Скрипты внутри песочницы iframe | нет |
| 3 | Автор в реальном page DOM, Сценарий работает | yes |
4. Два словаря
Замены print data: {{ shop.name }}, {{ p.price_text }}. Ключи есть attributes Добавление поведения или структуры.
Список машин: GET /docs/vz-keys.json. Никогда не изобретай key — ан unknown vz- атрибут удаляется санитаром.
Проверенные поведения, которые легко ошибиться:
- гнездиться `vz-for` Видит внешний scope (Например,
pвнутриm in p.members) Работает на трех уровнях глубоко —m in menu→c in m.children→g in c.children. Расширенный на сервере; вот как мега menu построенный; - `vz-if` бегать before `vz-for` связывает свою переменную на одном и том же узле. condition используя это new переменная не видит value; Положите его на детский узел;
- `vz-toggle` без value sets
vz-state="open"На самом узле — это Единственный способ создать клик-дропдаун без JavaScript:.trigger[vz-state="open"] + .panel { … }; - `vz-toggle="#id"` sets Государство на a target Селектор — это модаль;
- `vz-gallery` читать `product.gallery` только Игнорировать
preview: ан empty Галерея ничего не рисует. Зум: добавьvz-lightboxВ одном корне (/docs/modules§4).
Условия — это пути, а не выражения.. vz-if="path" или vz-if="!path": Никаких сравнений, арифметических или булевых операторов. Чтобы показать ось с по крайней мере два options, использовать vz-if="ax.options.1". Чтобы отличить текстурированную ось от size Ось, когда таково shop's data моделируется, test vz-if="ax.options.0.image_url" (Недостающие текстуры нуждаются в text fallback).
<div vz-for="ax in m.variants">
<div vz-if="ax.options.1">
<span vz-if="ax.options.0.image_url">Текстуры</span>
<span vz-if="!ax.options.0.image_url">Размеры</span>
</div>
</div>Уровень 1 - дезинфицирующий. Все author data-* attributes Удалены: селектор [data-colour] cannot Классы использования и разрешенная доступность attributes (aria-current, aria-disabled, и т.д., а не произвольное aria-* Имя-пространство. Зарегистрированные ключи vz-pane и vz-pick выжить; selected Чипы используют [aria-current="true"]. <style> Выживает, а родственник <link rel="stylesheet" href="style.css"> Удаление. Включить CSS в <style> для самодостаточного level-1 освобождение. Это относится к HTML документы и компоненты, как; level 3 имеет другой договор (/docs/transfer).
4.0 Живой data Без тебя own script
А. header, Мини--cart или account menu твоей own потребности Нет опросов и нет Счетчики твои own — Платформа сохраняет эти nodes current, на всех page, охраняемые зоны, включающие:
| Положите это | Ты поняла |
|---|---|
<span vz-cart-count></span> | items в cart; empty при нулевом — прятаться [vz-cart-count]:empty{display:none} |
<span vz-fav-count></span> | items В любимом, то же самое rule |
<div vz-auth>…</div> | vz-state="in" или "out" когда сеанс известен (не атрибут) before — Нет "подпись") |
<span vz-user-initial></span> | зарегистрированный покупатель's начальный; empty для гостя |
<div vz-search>Search</div> | входной и то же самое live Предложения как платформа header (products с price и картинка, sections); Вход открывается results |
Ссылки на аккаунты платформы header: /wishlist (любимые), /orders (orders), /account (профиль, регистрация и выписка).
Когда вам нужно code (а badge анимация, ваша own menu), Слушай, не надо опрос — events на document:
vz:navigate{path}— тот page Изменился (и в дальнейшем) first load);vz:cart{count},vz:fav{count}— тот cart Изменились ли фавориты;vz:auth{signedIn, initial}— Сессия стала известной или изменилась.
Каждый пожар на переменах И однажды правильно after каждый `vz:navigate` с помощью current value, Поэтому отдельного "на" не существует. load" филиал:
document.addEventListener('vz:fav', e => badge.classList.toggle('on', e.detail.count > 0))Не создавайте URL-адреса ресиверов (/w/…) Или позвоните в каталог API от page для Вот что здесь написано — именно это и заменяют эти ключи..
Ссылки тоже не нужны. Все одинаковые-site <a href> Ваша разметка — header, footer, body, breadcrumbs — открывать без page перезаряжать, Как и любой другой link из site: тот header Оставаться на месте, page body Затем он меняется, vz:navigate пожары И ваши сценарии перезапускают (напишите их так, чтобы второй прогон был безвредным). тот standard Турбо, SvelteKit, Накст и next/link. Браузер продолжает загружаться тот page в full для: модификатор или средний клик, target, download, другой site, tel:/mailto:, files (/files/…, .pdf, .xml), На одной и той же якоре page, охраняемой территории и иных layout. Чтобы заставить а full load себя, наносить vz-reload на link или его container (как data-turbo="false"). Ссылки внутри vz-variants keep свиток position.
"You are here" Needs no" (не нужно) script. Серверы обозначают одинаково-site Ссылки на Ваш разметка: aria-current="page" на link к этому page, aria-current="true" на link в section выше него (/catalog/ на /catalog/beds). Стиль a[aria-current] в layout CSS — Изюминка находится прямо в first рама, когда script-set class моргнул бы after Каждая навигация.
4.1 Открыть product в окне (быстро) view)
Перенесённый в /docs/modules §3: открывающие фрагменты (vz-modal, href="modal:…", тот level 2 message). The modal: Параметры и окно's поведение в /docs/webcoding#14-3-modal-window-from-html-a-product-or-a-ready-design-group.
5.Самостоятель. wrapper, И два способа сделать block твой
Каждый block на page — платформа widget или ваш own Маркировка — нарисована внутри то же самое wrapper, и wrapper сконфигурирован одним и тем же section Объект как widget: Ключи сидят В корневой части `props` — рядом с widget's own гнездо (html, listing, card, …), never Внутри него и never рядом kind. А. wrapper key написанный на section Вместо этого хранится, возвращается на чтение и рисует ничего; POST /docs/validate Это называется ignored И назовите правильное место. делать block look В отличие от платформы, это не борьба с wrapper. Это один из двух Преднамеренные движения, и § 5.2 является вилкой между ними..
5.1 Анатомия: три nodes, И только один из них - клипс
div.vz-box.@container THE BAND — the outer div of every block. Background,
│ hairlines, padding, block radius; this is the node
│ that becomes sticky. It does NOT clip by default.
├─ div.vz-bglayer optional: present only when the band has a background
│ image or overlay — an absolute layer under content.
└─ div.vz-inner THE CONTENT BOX — the only other child. Caps the
│ content at the shop content width and centres it.
└─ div.vz-radius ONLY for kind:"html" at level 1 — the shadow host of
│ your document. ⚠️ THIS one clips, by default.
└─ #shadow-root your markup begins hereВ level 3 Нет ни тени, ни корня. .vz-radius: Хозяин является div.vz-authored, ничего не снимает, и ваша разметка реальна page DOM.
Что каждый узел делает с вами, в order кусается:
| Узел | Что он сделает с вашим layout |
|---|---|
.vz-box | отдавать block Площадка воздух и квадратная полоса, и позволяет все overflow Липкий, фон, линии волос и block radius все live здесь |
.vz-inner | Щепки твои width. А. design Что должно достичь края экрана, должно пройти через него: props.blockWidth: "full" снимает крышку, props.contentWidth возвращает его |
.vz-radius | Сократите выпадающие и модальные off в block край если только props.overflow: "visible" это set. Самый дорогой default в wrapper |
Переписать один из них с помощью class твоей own И вы преодолеете именно Альбом: The Air And The Band On .vz-box, тот width КОША и центрирование на .vz-inner, зажим на .vz-radius.
5.2 Решать first: Два способа быть уникальным
| Если ты хочешь… | Возьми это path | Сколько это стоит |
|---|---|---|
| а full переживать-layout — твой own сетка и точки останова | А.. `props.wrapperClass` — твой class В группе, потом твоя own CSS | Поделиться CSS в layout папка или level-3 document (§5.4) |
| переключаться Одно поведение off — Вырезка, вырезка width Для этого нужно: воздух, стеки — и keep остальное | Б. wrapper топоры — props.overflow, props.blockWidth, props.paddingSides, props.position, … | Ничего. Они не такие. plain props, и POST /docs/validate ответы applied / ignored before Ты пишешь |
| Повесить свой own CSS или script на одну конкретную block | `props.wrapperId` — один id на платформе, также используемой как #anchor | Уникальность во всем page Это твой к keep; Платформа не проверяет |
Для намеренного standard-template - стиль, использование заявленных крючков (§5.5)).
Предпочитаю B, где B может это сделать. Ось читается code который притягивает block, Он выдерживает каждое изменение на разметке; CSS rule И только в вашей стране, как стабильной как DOM Назовите.
Оба ключа работают на платформе. chrome слишком — siteHeader, siteMenu и siteFooter Они сами рисуют свою группу, но читают то же самое. wrapper props. Вот как ты keep работа header widget И до сих пор полностью переделывает.
5.3 Путь А, конец-конец
1.Дайте группе свою class. The key В корне сидит props, рядом с widget's own гнездо, а не внутри его writePath, И не на том section:
{ "type": "text", "payload": { "v": 2, "kind": "html",
"props": {
"wrapperClass": "promo-hero grid-2", // up to 3 names, separated by spaces
"wrapperId": "prices", // one name: #anchors and your scripts
"blockWidth": "full",
"html": { "html_document_id": 10, "level": 1 }
} } }2.Читать что такое page фактически выполненный. Ваши имена прибывают after тот платформы:
<div class="vz-box @container vz-edge promo-hero grid-2" id="prices">
<div class="vz-inner">…</div>
</div>3.Написать CSS против тебя own name. Order Внутри атрибута решает Ничего — специфика делает. class Связь с одним class, Против платформы rule При одинаковом весе использования .promo-hero.promo-hero или id:
.promo-hero { padding: 0; background: #0b0b12; }
.promo-hero > .vz-inner { max-width: none; display: grid;
grid-template-columns: 1fr 1fr; gap: 48px; }
@media (max-width: 700px) {
.promo-hero > .vz-inner { grid-template-columns: 1fr; gap: 24px; }
}.vz-inner появляется Как ребенок вашего own class, который limits этот перевес к избранному block. более широкий template Также доступна стилизация (§5.5)).
Правила о `props.wrapperClass` / `props.wrapperId`. Они проверяются API fields, Не имя rule Классы внутри вашего own HTML. Выберите свой own name (atelier, brand-shell, acme-card); Нет, не жидовка prefix это required. Каждый name В этих двух fields Проверяется целиком и сбрасывается целиком, поэтому Опечатка стоит того, что class и never сломанный page: максимум 3 класса, ровно один id, pattern ^[a-zA-Z_][a-zA-Z0-9_-]*$, 48 символов, и не name может Начнем с vz-. Это prefix принадлежит платформе — vz-edge В вашем списке Расширяя, block прошлое blockWidth и vz-vis-none Спрятал бы его прямо, Когда вы ищете причину в своем own CSS. А. value с указанием цитаты, а пространственно-тогда атрибут или угол скобки тоже не выживает: все, что не является целым действительным идентификатором never Достигает атрибута. Обо всем этом, с указанием file:line что обеспечивает его:
curl -s https://api.vizen.shop/docs/widgets \
| jq '.wrapper.axes[] | select(.path == "props.wrapperClass")'5.4 Где путь А's CSS должен live
CSS нацеливание на внешнюю wrapper должен live снаружи level-1 теневой корень. Используйте layout папка или level-3 document; местный level-1 селекционер cannot Пересеките эту границу. Уровень 3 требует owner/admin и соответствующие права на токены. Спроси before Ты пишешь: GET /v1/account/token ответы capabilities.html_level3_allowed — true означает, что key может создавать level-3 document, false средство POST /html-documents с level: 3 ответит HTML_SCRIPT_ROLE_REQUIRED. Это - а role в shop, не scope, нет другой паспорт field подразумевает — publish_allowed В частности, речь идет о dev contour И ничего не говорит об уровнях.. Отказ в доступе не решается путем молчаливого перехода на level 1. Единственный surface/cascade Матрица - §7.2.
5.5 Стабильные имена не изолируют ваши переопределения
/docs/vz-keys.json → markup_contract обещает стабильные имена и заявляет о своих Доступность в where; не гарантирует безопасность произвольного CSS. Используйте own корень или props.wrapperClass локальных изменений, например .promo-hero > .vz-inner. глобальный .vz-inner rule Дойти до каждого матча Колонка; Переопределение .vz-radius может переопределить radius выбранные в панели. Если site-широкий рестайлинг, проверьте все затронутые шаблоны и pages. Обычный author Классы не имеют required гладиатр prefix. Проверенный wrapper fields (§5.3) и время выполнения vz-* attributes имеют отдельные договоры. Сгенерированный список является авторитетным; не выводите стабильность из prefix.
5.6 Что такое wrapper sets через default — Читайте, не запоминайте
Каждый default обоих wrapper Divs публикуется Созданный из магазина code, Каждый из них с file:line это sets В ней, в wrapper section из GET /docs/widgets. Печать всего этого:
# the wrapper divs: node, property, value, when it applies, and the line that sets it
curl -s https://api.vizen.shop/docs/widgets | jq -r '
.wrapper.elements[] as $e | $e.defaults[]
| [$e.selector, .property, .value, (.when // "-"), .anchor.at] | @tsv'
# the axes that change them: key, type, default, and the line
curl -s https://api.vizen.shop/docs/widgets | jq -r '
.wrapper.axes[] | [.path, .type, (.default // "-"), .anchor.at] | @tsv'Нет. default value напечатано в этом document, специально. Этот столик восстановленный из code На каждой постройке и cannot Стать несвежим; стол, набранный в Проза может, и сделала, написанная от руки, которую она заменила обещанной. overflow: visible для одного html block когда теневой хозяин вырезал, 16px полоса radius У группы есть never Имел, и a key props.innerMax это Ничего не читала — настоящая props.contentWidth. Если вы держите стол из которого /docs/widgets-area §6, то есть рукописный один и три из его rows Все еще неправы: призыв выше побеждает его..
Три дефолта определяют большинство макетов, и все три удивляют людей.:
- тот группа never клипы. Тень, свечение или отрицательно-маржинальное перекрытие листьев тот block Полный; вырезка является опцией, через
props.overflow: "clip"; - тот Группа - квадрат. Округ, который вы видите внутри blocks принадлежит элементам *внутри* их (
.vz-radius), Не для группы; - тот Теневой хозяин одного html block клипы default. Для этого одного узла "key "отсутствует" не является
"visible"— a выпадающий или модальные потребностиprops.overflow: "visible"написанный явно.
Для kind: "html" Платформа также добавляет нет padding и нет radius его own: тот look принадлежит к author (.wrapper.ownDefaults В том же самом Справочник. Хотите воздух? props.paddingSides явно.
5.7 Липкий: где он работает и где он до сих пор не работает
props.position: "sticky" — с props.stickyTop в px, когда что-то выше уже sticky — делает группа Группа - единственный узел, у которого есть место для Путешествие: A position: sticky элемент внутри вашей разметки cannot move, Потому что его Родитель такой же высокий, как и block. Собственная разметка может требовать того же наносить vz-sticky на его корневой узле.
Оба были мертвы до 2026-08-19 годов — ветка жила в квартире. wrapper И не звонит когда-либо достигали его. source after фиксировать:
| поверхность | props.position: "sticky" | vz-sticky в document |
|---|---|---|
| любой block в page zone (top, презентации, bottom) | работа | работа |
| любой block в layout zone / chrome комплект — тот custom-header дело | работа | работа |
а block Вложенный внутри a columns widget | работа | Не спрашивали — использовать props.position на этом ребенке |
тот chrome widgets siteHeader, siteMenu, siteFooter | нет — тот wrapper never Бежит для таких | нет |
| тот editor холст в admin панель | нет — тот preview Не спрашивайте, live page делать |
В этой таблице есть третья ось, и она document's LEVEL. А. level-3 document выдается *без* Коробка платформы default — Это то, что точка level 3, ваш file В реальной page DOM — Без коробки не бывает Банда, чтобы остаться, нет wrapperClass, нет container, нет overflow. Наценка говорит так: <div class="vz-authored-block"> вместо того, чтобы <div class="vz-box …">. The props Они все еще хранятся и читаются, и ничто не отказывает им..
Попросите коробку обратно с `props.html.boxed: true`, и каждый row выше вновь применяется, в том числе в chrome slot, где custom header Хочет точно Это сочетание: level 3 для его own script, плюс sticky группа. Проверено. 2026-09-20 в витрине магазина source: а block в chrome slot проходит через то же самое section рендеринг как block в page body, И единственное, что решает Между двумя разметками находится level === 3 && !boxed. 1 и 2 уровня являются boxed В любом случае. chrome slot Предпочитает явное props.position: "sticky" ось над входной карточкой vz-sticky key — тот zone не always Создайте контекст тот key потребности.
Платформа header имеет свой own Переключай и это работает: props.sticky: true на siteHeader section (GET /docs/widgets → siteHeader).
⚠️ props.overflow: "clip" и sticky взаимоисключающие — вырезка Предок не является чем-то sticky Потомок может остаться. Выберите один на каждого. block.
Для header который сохраняет свое место в потоке, предпочитает sticky. Absolute/fixed позиционирование и overflow отделены друг от друга CSS Прежде чем обещать видоискатель-fixed элемент, использовать поверхностное матрицу и проверки браузера в §7.2.
6. Изображения
Написать plain <img src> Указывая на shop file. Сервер переписывает его на рециркулировать и добавлять srcset (640/1024/1600, Ты не строишь эти пути..
Сервер добавляет `loading="lazy"`. Все, что находится под слоем и Неправильно для одного image это *это* тот first Экран. Ваш. own value сохраняется, так писать loading="eager" fetchpriority="high" На героя image себя — Точно так же, как sizes, разумный default Что вы должны сознательно переопределить.
Настройка `sizes` себя. Только ты знаешь, slot width; Без него сервер предполагать full width браузер делает самый большой шаг — измеряется: 1600w для card Ширина 268px.Твой sizes это never переписанный; ваш own srcset Отключает переписывание полностью.
Feed адреса рециркуляции, такие как /w/… есть относительно shop ведущий. Тест на store.storefront_url, Не в том смысле API хозяин или местный file: page. Для small slots, чип options в m.variants[].options[] и selected атрибут options в p.attrs.<code>.options[] подвергать image_thumb + image_srcset; combo Композиция раскрывает p.combo_items[].preview_srcset рядом preview_url. Используйте те fields Вместо оригинала image_url:
<img vz-src="o.image_thumb" srcset="{{ o.image_srcset }}" sizes="40px" alt="">
<img vz-src="c.preview_url" srcset="{{ c.preview_srcset }}" sizes="44px" alt="">Эти sizes values Примеры: Соответствие фактическому CSS slot В каждой точке останова. Слишком большой намек делает ненужный шаг. slots и currentSrc в DPR 1/2/3, включая after переключатели; /docs/troubleshooting §2 имеет измерительный фрагмент. Доступ браузера к level-1 content: /docs/troubleshooting §2.
Сфера охвата image fields уже есть пути рециркуляции — product.preview_url и product.gallery[].url в card Шаг (1024), combo_items[] и in_combos[] предварительные просмотры в thumb2x (640), products[].preview В 640. До тех пор, пока 2026-08-20 они несли absolute хранение URL, и ан author Кто написал vz-src="product.preview_url" отправлено оригинальное: измерено 1 818 239 bytes 29 336 против 336 против /w/640/webp. Ворота: storefront/test/image-slicing.test.mjs ("подавать scope - Село , а, сырой,").
Готовы `srcset` для data-связанный images. А. value переплетаясь vz-src это заменяются на render время, after Сервер перезаписи запущен, поэтому он не получает srcset. The steps Приходите с data вместо: products[].preview_srcset (320/640/1024/1600) и product.gallery[].srcset (640/1024/1600/2560) с w описатели, gallery[].thumb_srcset (128/320/640) для миниатюрной полоски, плюс gallery[].zoom_url (2560) для а "look «Подойдите ближе» или «Платформа» Lightbox снимает большой кадр для вас (/docs/modules §2). А. srcset сделанный из одного {{ … }} это placeholder, не file: Проверка на освобождение не look За это напиши. <img vz-src="p.preview" srcset="{{ p.preview_srcset }}" sizes="…">. Ан empty value означает картинку cannot быть изменена (svg, Иностранный хозяин. не высококлассный: шаг выше оригинала возвращает оригинал.
⚠️ Сервер переписывает и `vz-` Ключи – это разные механизмы.. The Переписывание выше читается src из хранить document; vz-src Заполняется в render, after Переписывание уже началось, так что ничего не переписывается. Сегодня только потому, что scope fields Прибытие предварительно нарезанное — точка vz-src в URL из твой own Браузер получает именно то, что вы написали.
7. Сценарии
Уровень 3 показывает в ряд. Сценарии работают на прямом попадании и after в-site link щелкните — платформа оживит их, потому что разметка, вставленная маршрутизатором, будет В противном случае содержат инертность <script> nodes.
- never скрываться content за спиной script. Покажите это; пусть script декорация. приземление, cards Начало в
opacity: 0смотреть empty когда script делать не бегать; - Не полагайтесь на `DOMContentLoaded` — after в-site щелкните document это уже загруженный;
- Удалите глобальных обработчиков при выходе; платформа не очищается after ты.
Никогда в кабинете, cart или checkout: Эти границы соблюдаются, а не являются консультативными..
7.1 Принести готовый page как папка (HTML проект, level 3)
The full передача path — инвентаризация, dev key, layout папка, chrome groups, pages, шаблоны, data перезаключать контракт на время выполнения (совместно с каскадом) витрина магазина's Префайт, сценарий перезапуска after мягкая навигация, © Remap · drop стол — этоGET /docs/transfer(мастерствоvizen-transfer). Это section Это пер-widget механика.
The widget Это папка. А. page который уже существует как папка — index.html В корневой, styles.css, app.js, assets/… в подпапках — перемещается как и есть: нет path Переписывание, не врезаясь в blocks. Каждый родственник path снимается с корня папки; на site каждый file От него отправляется widget корень /_html/{doc}/{release}/… с одинаковым гнездом и site page не принимает участия в обращении. один wrapper — тот site's и нет другой mode: тот widget это block внутри site page (header, footer и другой blocks вокруг него), выполненный без платформенного ящика (props.html.boxed: true Вернуть коробку обратно).
Нормальный входной сигнал чистая разметка — нет <!doctype>, <html>, <head>, <body>: только твой sections плюс <link>/<style>/<script> (Формат 1). А. целое document (Формат 2) также принимается и преобразуется в publish: head связывание → <div class="vz-head vz-head-{doc}" hidden>, <title>/<meta>/<base> падение (title/description Иди к нему. page SEO Когда он fields есть empty), <body …> → <div class="vz-body vz-body-{doc} …">, и ваш body/html/:root CSS Селектор переписывается на .vz-body-{doc}. Чистый result заменять index.html в выпуске (оригинал не сохраняется) и Что? admin Показать и отредактировать: в редактировании admin это new Освобождение. widget = один html page (index.html); ан extra .html В выпуске есть а page.extra Предупреждение — это multi-page site несколько widgets на нескольких pages, или, сохраняя целостность и обособленность, site папка (/docs/file-storage).
Пути в разметке и CSS Переписывается в widget корень output. А. script который сам строит пути, читает корень из window.VZ_ASSET_BASE (тот Платформа Puts <script>window.VZ_ASSET_BASE="/_html/{doc}/{rid}/"</script> first в фрагменте): const base = window.VZ_ASSET_BASE || ''; img.src = base + 'assets/x.jpg'. Локально, из папки, base это empty. Струна path в file в .js без VZ_ASSET_BASE это js.assets Предупреждение — на site Он будет решаться из page URL и 404.
The document Это проект; а освобождение является непреложным snapshot его files Взято из относительных path (Ша256 выводится внутри shop; index.html это always загружен, потому что преобразователь изменяет его, и ровно один выпуск active. Обратный откат и активация move Только указатель. Полный рецепт с указанием Правила папок и органы запроса: /docs/webcoding §2а. Короткометражный form (scopes catalog:write + storage:write, плюс catalog:read Перечислить; role owner/admin в shop):
POST /html-documents {item:{name, level:3}}.POST /html-documents/{id}/releases {files:[{path,sha256,size}], base:"active"|"none"}— Сервер отвечает, что загружать (upload[]) и что у него уже есть (reused[],inherited[]). Или один запрос с ZIP:POST /html-documents/{id}/releases/zip?publish=1(многочленныйfile) — а Только выпуск: document Шаг 1 должен существовать, а шаг 5 по-прежнему ваш..PUT upload_urlДля каждого входа вupload[].POST /html-documents/{id}/releases/{rid}/publish— Окончательное загрузка, проверяет, преобразует, переключает указатель атомарно; ответыurl(для dev key тот page находится<slug>--dev.<zone>, Видимая под ним owner's сессия),path,embed_prefix(= тот widget корень),seo;422 RELEASE_INVALIDнесет отчет,409 FILES_PENDINGСписок того, что есть не загружается.- Гора: An html section
{html_document_id, level:3}на существующий page (type='page'; тот slug исходит изGET /categories); старый html blocks на этом page заменяются. - The files Прикреплен и обслуживается — Эта половина может быть проверена на API Одиноко, так что проверь:
GET /html-documents/{id}/releases/{rid}Список освобождение's files,GET …/releases/{rid}/file?path=<p>возвращает один, и page HTML должны ссылаться на/_html/{doc}/{rid}/. 200 с помощью правильно size Закрывается «No 404s» для всего, что вы отправили. - The script На самом деле, — Эта половина нуждается в браузере, и никакая конечная точка не может Ответ: Откройте
url, Снимите скриншот, прочитайте консоль, нет JS ошибки. Без браузера, скажите так прямо, а не подразумевая, что вы проверили - и напишите тот block Он по-прежнему имеет смысл без своего script (§7: never скрываться content за спиной script).
Читать назад: GET /html-documents/{id}/releases/{rid} Ответы на релиз с его file карте и GET /html-documents/{id}/releases/{rid}/file?path=style.css один source file — {path, mime, size, sha256, text}, text только типы и ≤ 2 MB (404 FILE_NOT_FOUND, 415 FILE_NOT_TEXT, 413 FILE_TOO_LARGE). Это то, что Читать половину правки на месте: читать → изменять → POST …/releases {base:"active", files:[…]} → publish.
Правила папки, которые валидатор применяет: index.html В корне, каждый path относительный и внутри папки; https:// только для external ресурсов; нет сервер-side Исполнительные: нет serviceWorker.register; ≤ 500 files, HTML ≤ 2 MB, любой file ≤ 50 MB.
Если у вас есть репозиторий платформы, все вышеперечисленное является одной командой.: node backend-3D/tools/html-transfer/transfer.mjs <folder> --page <slug> (Узел 18+, токен в VIZEN_TOKEN, --api Только с токеном и сигарой. тот API — Обычный случай — используйте два вызова выше.
7.2 Общее пространство CSS и JS live в LAYOUT, Не в том header
Стили оформления достигают внутри level-1 теневой корень. С 2026-09-13 гг. Стильные листы и шрифты layout, и его theme class, вводится в виде Тень каждого level-1 block и составной части, то есть level-1 Компонент наследуется тот site's design system Без дубликатов line, и main возражение против level 1 («Ничего из того, что site «В тени видна» — больше не держится. Детали и матрица поверхности находятся в конце этого процесса. section.
общий CSS принадлежит к layout Складка, столь необязывающая header не удалять таблица ниже указывает, какие поверхности принимают его. level-3 Стили также участвовать в page каскад; местный level-1 стиль остается в тени корня.
А. layout Это group-container из chrome.md §3.6 (group_type:"theme"), и У него есть папка с его own: Тот же механизм освобождения, что и § 7.1, адресованный тот layout Вместо того чтобы быть document id. index.html что-то значит else здесь — не content, но скелета из site:
| В папке | Куда он идет |
|---|---|
<head> из скелета | meta/link/style Стать настоящими метками в <head> из каждый page; script/noscript Путешествия как сырые HTML |
class на <body> | наклон page Корень, рядом с scope class |
тот content из <body> | тот code before </body> каждого page |
<title>, <base>, <meta http-equiv>, <link rel=manifest> | раздетый publish: тот title принадлежит к page, Остальное – на платформе |
любой *.css | голый html, body и :root Селекторы предназначены для .vz-theme-{doc} — тот class из page корень. Так body { font-family: … } и :root { --brand: … } Предполагаемый способ для style тот site. Селекторы соединений (body.dark, body[data-x]) Нарочно остаешься один: твои script Это ставит class На реальном <body> |
icon.png (или .jpg/.jpeg/.webp) | icon-32.png, icon-180.png, icon-192.png, icon-512.png и favicon.ico генерируется на publish; files Вы можете указать под этими именами never переписанный, icon.svg принимается как |
| все else | обслуживаемый /_html/{doc}/{rid}/…; Скрипты читают корень из window.VZ_THEME_BASE |
Скелет разбит Однажды, на publish, и хранимые в собранном виде в выпуске row — витрина магазина never парс HTML по запросу. SEO Не отнимается от него: один <title> для целого site Это будет прямая потеря поискового трафика..
Один design system через layout. связанный CSS достигать pages используя layout. банальный html/body/:root Переписывается на его scope class; обычный Селектор не является автоматически префиксированным. own корень name:
<head><link rel="stylesheet" href="site.css"></head>
<body class="atelier"></body>/* layout/site.css */
@font-face { font-family: Atelier; src: url("fonts/brand.woff2") format("woff2"); }
.atelier { --brand: #172520; font-family: Atelier, sans-serif; }
.atelier .campaign-card { background: var(--brand); color: white; }
/* Intentional override: wrapperClass="atelier-header" on the chosen header */
.atelier-header > .vz-inner { max-width: 72rem; }Классы тела приземляются на див: .atelier совпадает, body.atelier не. Предпочитаю свой own корень для независимого стиля; более широкие правила намеренно влияют на standard и шаблоны (§5.5). fixed таблица стилей order относительно платформа bundle Обещано: инспектировать precedence/layers, Специфика, ряд Стили и вычисленные стили. Внутри корня тени вводится theme стили предшествует локальной разметке; более поздние правила побеждают только при равном каскаде priority.
| поверхность | планировка CSS / границы |
|---|---|
| page, standard blocks, chrome, level-3 надписи | делиться page каскад; относительный fonts/images Решительность от layout освобождение |
| level-1 магазин | Ссылки и встраиваемые стили из layout head Они вводятся внутри тени, под ее scope/body классы; локальные селекторы cannot style внешний wrapper |
| level-2 iFrame | отдельный document; родитель CSS не входит; required Стили должны быть связаны явно |
| охраняемый system pages | layout CSS/classes и статическая разметка остается; author Сценарий и widget-Ссылки на относительные таблицы стилей удаляются |
| editor | level-3 preview получает layout head; level-1 preview иметь base Крючки, но не то же самое theme инъекция |
Для доступности крючка используйте сгенерированный markup_contract.where: page только — .vz-box, .vz-radius, data-vz-kind, data-vz-block, data-vz-kit, data-vz-idx; тени — .vz-pad, --vz-gutter; оба — .vz-inner, --vz-content-box. Это доступность, а не разрешение переопределить каждый Теневые помощники позволяют выровнять платформу Не изобретая ни required Схема именования для вашего own design.
Позиционирование и container запросы. Платформа заявляет, что query контейнеры. container-type Только одно не является доказательством fixed-position содержащий block: CSS Условный 5 удаляет его layout-сдерживание side effect. В локальном зонде Chrome 152, fixed Оставалось относительно inline-size, в явном виде contain:layout/paint или transform Прикрепил его к предку. Старые двигатели могут отличаться, а настоящие shop/layout Необходимо еще проверить в его target Это исследование не принимает pending dev-магазин test.
| поверхность | Платформа query container / последствия |
|---|---|
boxed block (level 1 или boxed) | .vz-box иметь container-type:inline-size; Проверить это и всех предков на предмет явного containment/transform |
| нескладной block в page zone, нет level-3 HTML бегство | main.vz-visibility-scope иметь container-type:inline-size |
| page с незаполненным level-3 HTML block | main.vz-has-authored переключаться на container-type:normal; не удаляет containers/transform на потомков |
| chrome slot | ChromeNav Сохраняет свои own .vz-visibility-scope query container; тот main Побег не меняется chrome |
| system-page body | тот standard system main не имеет visibility query container; Проверяйте любые вложенные обертки |
| level-2 iFrame | fixed iframe Viewport, а не родительский page видоискатель |
Побег был обнаружен из kind:html с props.html.level:3 и нет boxed; Один только компонент не вызывает его. Сбоку effect: range visibility правила Это зависело от того, main query container Незавершенный. query Контейнеры могут поставлять в range, и .vz-vis-none останки hidden. Проверить соседа blocks after adding/removing автор HTML; не отключать visibility глобально для фиксации позиционирования. 100vw/100dvh являются единицами контроля, а не container единицы. мера fixed getBoundingClientRect() before/after Прокрутить и проверить перекрытие.
Внутри layout использовать относительные пути, такие как fonts/brand.woff2. /_site/ Выберите shop's active layout, не page-Конкретный переопределение. для shared/external ссылки; file адресовать и CSS селектор scope отделены друг от друга.
Десять method/path операции, те же scopes и role как §7.1 (catalog:write + storage:write, catalog:read читать; owner/admin в shop). Пути не несут /v1:
| метод | Путь | Что он делает |
|---|---|---|
GET | /themes/{id}/site | состояние папки: {contour, theme_id, document_id, active_release_id, base, preview_base?, scope_class, files[], head_source, foot_source, head[], head_html, foot_html, body_class, icons[], icons_generated[], limits}. Пока нет папок → {document_id: 0, files: []} — а GET never Создать один |
POST | /themes/{id}/site/releases | draft освобождение от а manifest {base, files[{path,sha256,size}], delete[], note} → {release_id, upload[], reused[], inherited[]} |
POST | /themes/{id}/site/releases/zip | освобождение от а ZIP (?publish=1, ?base=) |
POST | /themes/{id}/site/releases/{rid}/publish | валидатор → очистка скелета на месте → фавиконы → скелет разобрали в выпуск row → указатель переключен. {release_id, kind:"theme", base, scope_class, icons_generated[], report}; нет url/path — а layout Не сидеть на одном page |
POST | /themes/{id}/site/releases/{rid}/validate | То же самое без публикации |
GET | /themes/{id}/site/releases, /themes/{id}/site/releases/{rid} | Отпуск с помощью active один/один выпуск с его file карта |
GET | /themes/{id}/site/releases/{rid}/file?path= | один source file этого освобождения: {path, mime, size, sha256, text}; text Только, ≤ 2 MB, else 415 FILE_NOT_TEXT / 413 FILE_TOO_LARGE |
POST | /themes/{id}/site/rollback | {release_id?} — Предыдущее опубликованное одним из default; только указатель (catalog:write) |
DELETE | /themes/{id}/site/releases/{rid} (и /html-documents/{id}/releases/{rid}) | Удалить старое version: {deleted, release_id, files_deleted}; тот version active на live site или в draft (in_use: true в списке) → 409 RELEASE_ACTIVE; а draft API key → 403 PAT_CONTOUR_MISMATCH (История - это откат material из live site). Файлы No Other version использования освобождаются от shop's квота на хранение (catalog:write + storage:write). Поворачивающий site Публикация вернёмся к a deleted version Сохраняет current Один из них и предостережения |
История выпуска - это разделяемый между собой draft и live site; только указатель на active Освобождение на contour. Публикация, опубликованная с X-Vizen-Contour: dev Поэтому в нем перечислены live Сессия тоже отмечена was_live: false, и активировать его там ответы 409 RELEASE_DRAFT_ONLY — publish тот draft (POST /v1/dev/publish) И это идет live через эту дверь. В одном draft Ничего не меняется. Версии являются never автоматически удаляется — Вся история остается для отката (включая перекатывание а) site публикация Версия: старые версии count к нему в сторону shop's Хранение до тех пор, пока вы не удалите их (DELETE …/releases/{rid}).
curl -X POST "$API/themes/118/site/releases/zip?publish=1" \
-H "Authorization: Bearer $VZ" -F file=@theme.zip
# → { "release_id": 42, "base": "/_html/77/42/", "scope_class": "vz-theme-77",
# "icons_generated": ["icon-32.png","icon-180.png","icon-192.png","icon-512.png","favicon.ico"], "report": {…} }
node backend-3D/tools/html-transfer/transfer.mjs ./theme --theme 118 # the one-command pathГраницы, и они очень жесткие:
- твой code не бегает в охраняемых зонах; —
/cart,/checkout,/account,/wishlist,/orders,/coupons,/deals,/dashboardи все, что вложено Под ними. layout'shead_html/foot_htmlиwindow.VZ_THEME_BASEне выпускается, и author-принадлежащий (level 3) header рендеринг без его сценариев. Стили, классы, разметка иhiddenСвойство Stay (data-*раздевается — style через class), так cart все еще Выглядит как ваш site — но never планировать script Ключи от §4.0 (счетчики,vz-auth,vz-search) keep Работать там, входить и выходить из дома. охраняемый zone это full перезарядить, так что layout script снова бегает; - Навигация внутри site После каждой навигации и after тот first load а
CustomEvent('vz:navigate', {detail:{path}})Отправляется наdocument— Инициировать его заново, а неDOMContentLoaded. Переезд в А page чей layout это различный Один из них - это full Перезагрузка, так что две макеты never смешивать; - limits § 7.1.'s (≤ 500 files, HTML ≤ 2 MB, любой file ≤ 50 MB, ZIP ≤ 60 MB); Скелет старше 64 лет KB предупреждать
theme.index_large— Он добавляется к каждому page; - Валидатор отбрасывает правила, которые не имеют смысла для wrapper (
head.stripped,page.noindex,img.nosize,file.unusedна иконах) и лечитьVZ_THEME_BASEкак корень активаVZ_ASSET_BASE. Скелет, который Не отменяется отсрочка:422 RELEASE_INVALID, codehtml.parse; - папка's обслуживание document не редактируется через
/html-documents/*(FailedPrecondition THEME_DOCUMENT_PROTECTED), отсутствует в document Список и не обслуживает/content. А.{id}Это не является layout твоей — иностранный, deleted или обыкновенный block — Один и тот же404 THEME_NOT_FOUND.
Теневая инъекция использует тот же парсинг layout head как page, не отдельный author-- сохранились таблицы стилей. CSS Путешествия: скрипты, иконки и Подсказки погрузчика - нет. shop без layout Стили не получают дополнительной тени wrapper. Посмотреть на стол выше.
Который layout а page Как связать одно с а section, и system pages (cart, checkout, account…) в chrome.md §3.6 Пошаговый рецепт это /docs/webcoding §2b.
8.Безмолвно ignored
| Что? | Что на самом деле происходит |
|---|---|
ан unknown vz- атрибут | Удаленный санитаром, нет error |
| level-1 attribute/CSS Крючки исчезают | соблюдать правила санитарии в § 4; использовать классы и разрешенную доступность; attributes |
vz-sticky или props.position на siteHeader / siteMenu / siteFooter | Эти виды рисуют свои own Группа и The Band block wrapper never Они бегают за ними, поэтому нет. sticky style Производится он вообще. header имеет свой own Переключатель, который работает: props.sticky: true (§5.7) |
vz-sticky на html block Вложенный внутри a columns widget | Колонка спрашивает ребенка's props и never тот document's key, так key Прочитано на page Но ничего не действует на него. props.position: "sticky" на этом ребенке section (§5.7) |
props.wrapperClass с а name который начинается с цифры, тире или vz- | тот name Все остальное в списке остается в силе — нет error, и class= не содержит его (§ 5.3)) |
| Замена одного из field Это не в scope | отпечатки empty |
ан href чей проект не указан в списке ниже | Вся эта href Удаление — это text Остаться и link мертвый |
The `href` схемы a level-1 document может использовать, И ничего else: https:// (и //host, то же самое external link), mailto:, tel:, то же самое-site path (/catalog), фрагмент (#anchor), form:<id> (Открывает лид form) и modal:product:<id> / modal:group:<id> с их документально оформленными query параметры (/docs/webcoding §14.3). http:// Выживает санитар, но высвобождение, которое В ней содержится отказ в publish (ref.http) — использовать https://. javascript: и data: Вы устранены, как и любая схема, которую вы Изобретать. level 3 разметка подается в письменном виде и этот список не применять.
9.Как это было проверено
2026-08-19, live витрина kiberpank.vizen.shop: DOM chain измеряется в реальном браузер; script Проверка дважды (прямая) URL и в-site щелкнуть); image steps Подсчитано по сетевым запросам; scope Корни, прочитанные vz-page-data на page.
2026-08-20, переоценка четырех претензий document привыкла ошибаться — через source и live Звонок, а не из памяти:
- `products[]` в scope.
storefront/src/widgets/html/scope.tsОбъявляет, что корень иproductsOf()берёт её live (listProducts, limit 48,previewчерезimgUrl);data.tsОн просит только тогда, когда document's text матчи/\bin\s+products\b|\{\{\s*products\b/. Живи:GET /docs/vz-keys.jsonсписокscope.productsОдиннадцать из них fields, и развернутый pages/cyberwear,/neon-gridнестиproductsкореньvz-page-data(empty Там нет ни page это section page). Ворота:scope-products.test.mjs(7 Сценарий, Зеленый); - тот `overflow` ось.
SectionHtmlInline.tsxиSectionHtml.tsxоба проходаclip={section.props?.overflow !== 'visible'}В тени хозяина.Врата:wrapper-sticky-clip.test.mjs, зеленый; - scope images. Все пять preview fields проходить
imgUrlвscope.ts. Ворота:image-slicing.test.mjs, зеленый; - `vz-sticky`. В момент этого прохода все еще был сломан — провод был Не было, не было, и было fixed В тот же день. wrapper волна ниже.
2026-08-19/20, тот wrapper волна — Что сейчас описывает §5. Измеряется на основании Собранная разметка, а не чтение source, Потому что предыдущие два прохода были Дважды обманутый, прочитав:
- Провод для sticky.
sectionSticky()вpackages/sections/src/SectionBox.tsxТеперь вопрос задает section список (PageSections.tsx) и вложенным blocks из тотcolumnswidget; витрина магазина'sstickyHtmlDocsОтвет, наконец, имеет Читатель. order ветви внутриwrapperFrameStyle()Изменился с ним: фон layer привыкший setposition: relativeпоследний и переписанныйsticky, группа с фоном never застрял; - тот chrome Исключение реально и остается.
SectionBoxвозвращает обратно widget нетронутым для chrome виды (CHROME_KINDS), нет wrapper style достигатьsiteHeader/siteMenu/siteFooter. Их группа была нарисованаChromeSectionBox, Что читатьwrapperClass/wrapperIdНо не принимаетsticky. Это why §5.7 - это таблица, а не предложение.; - own class и own id.
packages/sections/src/wrapperClass.tsэто Белый список, а не чистильщик: name должен соответствовать идентификатору pattern полностью или Проверено на отрисованной разметке —wrapperClass: 'a" onmouseover=…'производитьclass="vz-box @container"ни с одним изonmouseoverниalert(В любом месте output; - Дефолты больше не пишутся от руки.
wrapperDoc.tsТеперь он называет перевод code на empty props и вытаскивает остальное из якоря CSS линии, генератор превращает каждый якорь вfile:line— Неудачи в строительстве, когда тот line отсутствует, двусмысленна или не синхронизирована с editor's CSS зеркало. Ворота:storefront/test/wrapper-render.test.mjs(Реальные реалииPageSectionsчерезreact-dom/serverи сравнивает ссылку с разметкой) иstorefront/test/wrapper-sticky-clip.test.mjs. 86 тестов «зеленый»; - level 1 CSS cannot дотянуться до wrapper. The document внутри него выстроен
<template shadowrootmode="open">, Так что<style>Сквозь тень сквозит строительство;<style>Сама выживает в level-1 санитар (internal/api/catalog/html_sanitize.goЭто позволяет сделать это прямо. §5.4 предупреждение, и это свойство границы тени, а не баг.
10.Отрицания в этом document (rule §3.9)
"Не каждый"", "never", "empty", "не реализована в text выше перечислены Здесь с тем, что держит его true. Отрицание, не имеющее ни врат, ни line в этом Стол - это class приговор, который превратил пять заявлений об этом document вводить Зависает в одной неделе — три из них fixed В той самой волне, которая отгрузила эту функцию Они описали.
| Претензия | схваченный true через |
|---|---|
ан unknown vz- атрибут удаляется, нет error (§4, §8) | ворота internal/api/catalog/html_sanitize_test.go · TestHTMLLevel1PolicyStripsUnknownAndDataAttrs |
vz-if на петлевом узле работает before Его псевдоним связан (§ 4)) | packages/sections/src/widgets/html/render.ts, condition before клон scope |
vz-gallery игнорировать preview; ан empty Галерея ничего не рисует (§ 4)) | after-Прохождение волны — нет ворот |
products это [] до тех пор, пока document Спрашивают и [] на page Это не section Если только не block Названия один (§ 2)) | ворота storefront/test/scope-products.test.mjs |
productsCategoryId выбирай feed's section за block; иностранный section отдавать empty feed (§2) | ворота storefront/test/products-feed-category.test.mjs + component-params.test.mjs (тот key); Арендаторская половина - это сервер.'s company_id AND category_id — измеряется на копии production |
тот plain feed Не имеет галереи, description или variants внутри одного product; избранный attributes и group Плитка приходит только тогда, когда block sets productsAttributes / productsMode (§2) | ворота scope-products.test.mjs + vz-reference.json field Список; Профилированный feed — storefront/test/list-feed.test.mjs, feed-profile.test.mjs, опубликованный groups пример — scope-products-paging.test.mjs |
Теневой хост клипс когда props.overflow незавершенный (§5.1, §5.6)) | ворота storefront/test/wrapper-sticky-clip.test.mjs — предикат htmlHostClips() Это одна функция, называемая витриной магазина, холстом. AND ссылка, поэтому нет второй копии для дрейфа |
| Сама группа never скрепки, и является квадратом (§5.6)) | ворота storefront/test/wrapper-render.test.mjs · "aёртка до тройки: в нижнем краевом первенстве лэтье + cправочник дефолтный каскад на ка, на кустарнике — оба считывают визуализированную разметку, а не source |
kind: "html" не будет padding и нет radius (§5.6) | генерируемый: .wrapper.ownDefaults в /docs/widgets Он построен из widget's own manifest, так что cannot несогласие с рендером |
а name начиная с цифры, тире или vz- never достигать class= (§5.3, §8) | ворота storefront/test/wrapper-render.test.mjs · "стр. стр. «Самопомощь» + «Сынъэцъ» стр." |
level-1 CSS cannot смотреть .vz-box (§5.4) | собственности на теневой рубеж, а не на нашу code — тот document внутри него выстроен <template shadowrootmode>. Нечего ворот; он падает только если level 1 Прекратить использование Shadow DOM |
props.innerMax Не существует (§5.6)) | ворота storefront/test/wrapper-render.test.mjs · "s, , ⁇ , q, u, y, s , l, μ, π, σ, α, τ, ε, γ, ν, θ, φ, λ, β, δ, κ, Δ, χ, ω, ρ, − key Он был опубликован в течение нескольких недель и не читался никому. |
| нет default VALUE Указывается как current §5 (§5.6)) | тот rule Два числа действительно появляются в § 5.6, и оба приведены в качестве утверждений рукописной таблицы. section Заменить — то есть как вещи, которые были неправильно. Все, что было заявлено как current исходит из curl. А. number как заявлено в качестве current default Это регрессия |
твой sizes это never переписанный (§ 6)) | ворота internal/api/catalog/html_images_test.go · TestRewriteHTMLImagesKeepsAuthorSizes |
vz-src не переписывается сервером (§ 6)) | after-волновой проход — это следствие order Эти два механизма, и ничто не проверяет, что order |
sticky работать page зоны, layout зон и columns детей, и NOT На трех chrome в виде или в виде editor холст (§5.7, §8)) | ворота storefront/test/wrapper-render.test.mjs · "струйная струя. props "Сепарда", "Сево-А" и "Сепаратор-А" vz-sticky", "{{{item.group_date}} {[править править вики-текст]} style Атрибут отрисованной разметки. ⁇ ️ Старые ворота wrapper-sticky-clip.test.mjs Он оставался зеленым на протяжении всей жизни предыдущего дефекта, потому что он проверяет его. *форма* из source; Поверхности, где sticky До сих пор не спрашивают, удерживаются ли они только этим столом, поэтому переоцените их по поиску. |
| сценарий never Бежать по кабинету, cart или checkout (§7) | after-волновой проход — граница навязывается в витрине магазина, а не закрыта здесь |
| Замена одного из field снаружи scope отпечатки empty (§8) | after-Прохождение волны — нет ворот |
Как проходит пас. Пожалейте об этом file для never, not, no , empty, cannot, Проверить каждый удар по code — час на 600 человек Четыре строки, четыре вывода first Время было done.