Vizen Shop

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, любой designown разметка над products[] scope, тот section названный productsCategoryIdlive цены - ≤ 48 items (или groups), base fields выбранный плюс attributes и group Плитка по запросу, один section за block
а отобранный вручную row в твоем orderown разметка 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 приземление pageown накладная накладка на 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 если только productsIds sets явно выраженный 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статический, дезинфицированный; ключи расширяют сервер-sideyes
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):

  1. POST /html-documents {item:{name, level:3}}.
  2. 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 по-прежнему ваш..
  3. PUT upload_url Для каждого входа в upload[].
  4. 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 Список того, что есть не загружается.
  5. Гора: An html section {html_document_id, level:3} на существующий page (type='page'; тот slug исходит из GET /categories); старый html blocks на этом page заменяются.
  6. 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» для всего, что вы отправили.
  7. 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 pageslayout CSS/classes и статическая разметка остается; author Сценарий и widget-Ссылки на относительные таблицы стилей удаляются
editorlevel-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 blockmain.vz-has-authored переключаться на container-type:normal; не удаляет containers/transform на потомков
chrome slotChromeNav Сохраняет свои own .vz-visibility-scope query container; тот main Побег не меняется chrome
system-page bodyтот standard system main не имеет visibility query container; Проверяйте любые вложенные обертки
level-2 iFramefixed 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/releasesdraft освобождение от а 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's head_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, code html.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 из тот columns widget; витрина магазина's stickyHtmlDocs Ответ, наконец, имеет Читатель. order ветви внутри wrapperFrameStyle() Изменился с ним: фон layer привыкший set position: 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.

Исходник: https://api.vizen.shop/docs/own-markup?full=1

Работает в демо-режиме