零售电商 · 新资源

Sainsbury's 设计系统.

将 Sainsbury’s 的公开设计指南应用于完整的配送时段选择流程:使用真实的配色和尺寸参考、无障碍单选项、动态更新的摘要,以及如实说明的本地操作反馈。

OpenDesign 指南7 个章节38 条参考条目原始应用指南
01

Sainsbury's 设计系统 界面预览

更改日期和时间,查看示例费用,然后检查本地选择结果。

选择取件时段打开完整示例
根据 Sainsbury’s 公开指南制作的原创 HTML 版本。· 实现参考
02

Sainsbury's 设计系统 设计参考

Sainsbury’s 公开的颜色、字号令牌、排版和组件指南。对于公开发布的断点表中相互冲突的内容,会分别标注,而不会将其合并。

Sainsbury’s 调色板角色

来源
名称 / 规则值 / 配置用途
Primary brand base#F06C00 本示例中的品牌强调色和按钮填充色,搭配深色文字。
Primary hover#E55000 悬停填充色;不适合作为白色背景上的小字号文字颜色。
Primary pressed#C15100 按下状态。
Primary light#FEF5F0 选择项和摘要背景。
Secondary base#7F0442 少量使用的装饰性色彩。
Monochrome darker#262626 主要内容。
Monochrome dark#404040 辅助内容。
Monochrome light#D8D8D8 边界。
Monochrome lighter#F2F2F2 不可用选项的界面表面。
Success lighter#E6F4ED 本地审核反馈界面表面。
Success darker#246127 反馈文字。
Info darker#135CA3 应用焦点轮廓。

已发布的字号令牌

来源
名称 / 规则值 / 配置用途
xs2px公开字号令牌表中的间距值。
sm4px公开字号令牌表中的间距值。
md8px公开字号令牌表中的间距值。
lg16px公开字号令牌表中的间距值。
xl24px公开字号令牌表中的间距值。
2xl32px公开字号令牌表中的间距值。
3xl40px公开字号令牌表中的间距值。
4xl48px公开字号令牌表中的间距值。
width-sm1px边框令牌;宽度和圆角名称应彼此区分。
width-base2px边框令牌;宽度和圆角名称应彼此区分。
radius-base2px边框令牌;宽度和圆角名称应彼此区分。
radius-xl12px边框令牌;宽度和圆角名称应彼此区分。
min-width-sm576px令牌断点;与编辑版式页面中的断点不同。
min-width-md768px令牌断点;与编辑版式页面中的断点不同。
min-width-lg992px令牌断点;与编辑版式页面中的断点不同。
min-width-xl1200px令牌断点;与编辑版式页面中的断点不同。

Sainsbury’s 字号比例

来源
名称 / 规则值 / 配置用途
Body 11rem / 1.5 / Arial Regular正文。
Caption0.875rem / 1.571 / Arial Regular辅助说明。
Label 11rem / 1.5 / Arial Bold控件标签。
Display 11.25rem / 1.3官方指南中的品牌展示字体;此处使用后备字体。
Display 21.5rem / 1.333响应式替代方案为 Display 3。
Display 31.875rem / 1.333响应式替代方案为 Display 4。
Display 42.375rem / 1.316响应式替代方案为 Display 5。
Display 53rem / 1.292响应式替代方案为 Display 6。
Display 63.75rem / 1.267文档中规定的最大展示字号。
Responsive type thresholdlarger than 720px独立于 768px 的字号令牌断点。
03

Sainsbury's 设计系统 完整指南

实用指南,介绍如何为真实界面选择、应用和评审此系统。

DESIGN-sainsburys.md

完整指导、实现起点和源代码链接。

下载指南

Sainsbury's 设计系统 Sainsbury's 设计系统 多品牌系统与访问权限

选择一个品牌主题

Fable 通过共享组件结构和品牌专属值支持 Sainsbury’s、Argos、Nectar、Tu 和 Habitat。本指南仅使用 Sainsbury’s 调色板。在 Sainsbury’s 交互中混入 Nectar 紫色,或假定所有品牌使用相同字体,都会模糊系统中明确划定的边界。请将所选主题关联到应用入口。

摘自本 OpenDesign 指南

区分公开指南与私有软件包

公开的合作伙伴指南介绍了 React 组件、Fable Styles 和设计令牌包,但访问代码库需要凭据,需通过 Sainsbury’s 联系人申请。本示例无需任何凭据:它是基于已发布指南编写的完整原创 HTML。它不会假称自己运行了 Fable,也不会为无法访问的注册表编造安装命令。

Sainsbury's 设计系统 Sainsbury's 设计系统 配色与对比度

橙色应搭配适当的文字颜色

源文档说明,基础橙色和深橙色在白色背景上均不符合普通正文的对比度要求。本示例将橙色用作填充色,并搭配黑色按钮文字,而不是在白底上使用小号橙色文字,或在橙底上使用小号白色文字。文档中的品牌例外不应被悄然解读为所有颜色组合都符合无障碍要求。

确保反馈语义清晰

查看结果使用绿色成功背景和深绿色文字。不可用时段采用中性背景并附有文字标签,选中的时段则同时显示已选中的单选按钮和橙色描边。颜色只是辅助提示,不能取代时段、可用状态或选择状态的文字说明。

Sainsbury's 设计系统 Sainsbury's 设计系统 间距、圆角与断点

遵循已发布的尺寸比例

本示例在选项之间使用 8px 间距,每个时段内使用 16px 间距,主要内容组之间使用 24–32px 间距。控件采用 2px 圆角,摘要区则采用文档中规定的 12px 圆角。这些差异用于表达分组层级,而不是让所有区域都套用相同的圆角卡片样式。

注明文档中的差异

布局指南列出了 600px 和 900px 设备断点,而尺寸令牌表列出了 576px、768px 和 992px。排版指南还规定,显示文字的尺寸会在宽度超过 720px 时变化。这些断点并非同一比例的不同名称。本实现选择使用尺寸令牌中的 768px 断点来布局多列,并明确说明了这一选择。

Sainsbury's 设计系统 Sainsbury's 设计系统 排版与实用内容

遵守品牌字体的使用范围

Sainsbury’s 官方显示文字样式使用 Mary Ann Extra Bold,普通正文则使用 Arial。由于本示例未包含品牌字体文件,因此从头到尾都使用 Arial。示例保留了字号比例和行高关系,但不会声称这种备用字体的视觉效果完全一致。语义标题级别与显示字号彼此独立。

清楚呈现取货选择

Sainsbury's 设计系统 Sainsbury's 设计系统 单选选项与本地状态

在同一组中使用关联选项

日期控件会更改可选时段,每个时段都是同一命名组中的原生单选按钮。更改日期后,系统会选中该日期的第一个可用时段并更新摘要。不可用选项仍会显示,但无法选中。原生单选按钮提供熟悉的键盘操作方式,无需用可点击的 div 重新实现。

避免显示过时的预订信息

点击“查看”后会显示本地确认信息,并注明尚未预订任何时段。更改日期或时间后,该结果会隐藏。生产环境流程必须重新检查可用状态并等待服务器响应,之后才能确认已预订。本示例将交互约定单独呈现,避免将缺失的后端工作误认为预订流程已完成。

Sainsbury's 设计系统 Sainsbury's 设计系统 交互目标、焦点与响应式行为

为选项留出足够空间

公开的按钮指南建议触控目标高度为 48px。日期按钮和查看操作均达到这一高度,整个带标签的时段区域也都可以点击。蓝色焦点描边在橙色和浅色背景上始终清晰可见。装饰性购物篮图标对辅助技术隐藏。

允许较长内容换行

在窄屏布局中,摘要会排在选项列表后面,装饰性图标则会隐藏。时段标签和价格保留在正常文档流中,容器高度可灵活调整。翻译后的文字或较长的地点名称不应被固定高度的卡片裁切;本英文原型为后续本地化预留了足够空间。

Sainsbury's 设计系统 Sainsbury's 设计系统 实现与 AI Agent 评审

运行独立示例

保存完整的 HTML 示例并在本地运行。示例中的三个日期和每天三个时段均为编写的样例数据,所有更改都只保存在内存中。源码包含 CSS、单选按钮创建、摘要更新和过时反馈清除逻辑,因此预览背后不存在缺失的应用层。

  1. 将完整文件保存为 index.html。
  2. 选择星期二,并确认无法选中上午的不可用时段。
  3. 更改时段并检查摘要。
  4. 点击“查看”,然后更改日期,确认旧结果会清除。

仅在访问权限得到确认后再迁移到 Fable

对于经授权的内部集成,请先获取实际的软件包访问权限,并检查当前主题和组件 API。在用受支持的组件替换原始标记时,应保留本示例的行为。确认已安装的令牌比例与公开参考资料一致后,才能将截图视为实现依据。

  • 统一使用一种品牌主题。
  • 确认软件包访问权限和当前 API。
  • 分别检查文字对比度和品牌颜色还原度。

Sainsbury's 设计系统 Sainsbury's 设计系统组件示例

完整的取货时段流程

独立的 HTML/CSS/JavaScript,包含日期选择、单选时段、不可用状态和实时摘要。

html
<!doctype html>
<html lang="en">
  <meta charset="utf-8" /><meta
    name="viewport"
    content="width=device-width,initial-scale=1"
  /><title>Collection slot study</title
  ><style>
    * {
      box-sizing: border-box;
    }
    body {
      margin: 0;
      background: #fff;
      color: #262626;
      font:
        16px/1.5 Arial,
        sans-serif;
      padding: 32px;
    }
    header {
      border-top: 8px solid #f06c00;
      padding-top: 24px;
      display: flex;
      justify-content: space-between;
      gap: 24px;
    }
    h1 {
      font-size: 38px;
      line-height: 1.316;
      margin: 8px 0 16px;
    }
    h2 {
      font-size: 24px;
      line-height: 1.333;
      margin: 0 0 16px;
    }
    .eyebrow,
    small {
      font-size: 14px;
      color: #404040;
    }
    p {
      margin: 8px 0 24px;
    }
    .basket {
      font-size: 48px;
      line-height: 1;
      background: #fef5f0;
      border-radius: 50%;
      width: 96px;
      height: 96px;
      display: grid;
      place-items: center;
      color: #7f0442;
    }
    main {
      display: grid;
      grid-template-columns: 2fr 1fr;
      gap: 32px;
      margin-top: 24px;
    }
    fieldset {
      border: 0;
      padding: 0;
      margin: 0 0 24px;
    }
    legend {
      font-weight: bold;
      margin-bottom: 16px;
    }
    .dates {
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
    }
    button,
    select {
      font: inherit;
      min-height: 48px;
      padding: 12px 16px;
      border: 1px solid #737373;
      border-radius: 2px;
      background: white;
      color: #262626;
      cursor: pointer;
    }
    .dates button[aria-pressed="true"] {
      border: 2px solid #f06c00;
      background: #fef5f0;
      padding: 11px 15px;
    }
    .slots {
      display: grid;
      gap: 8px;
    }
    .slot {
      display: flex;
      gap: 12px;
      align-items: center;
      padding: 16px;
      border: 1px solid #d8d8d8;
      border-radius: 2px;
      cursor: pointer;
    }
    .slot:has(input:checked) {
      border: 2px solid #f06c00;
      padding: 15px;
      background: #fef5f0;
    }
    .slot:has(input:disabled) {
      background: #f2f2f2;
      cursor: default;
    }
    .slot input {
      accent-color: #c15100;
      width: 20px;
      height: 20px;
    }
    .slot strong {
      margin-left: auto;
    }
    .unavailable {
      color: #404040;
    }
    .primary {
      background: #f06c00;
      border: 2px solid #f06c00;
      font-weight: bold;
      color: #000;
    }
    .primary:hover {
      background: #e55000;
      border-color: #e55000;
    }
    .primary:active {
      background: #c15100;
      border-color: #c15100;
    }
    .summary {
      background: #fef5f0;
      border-radius: 12px;
      padding: 24px;
      align-self: start;
    }
    .summary dl {
      margin: 0;
    }
    .summary dt {
      font-size: 14px;
      margin-top: 16px;
    }
    .summary dd {
      margin: 4px 0;
      font-weight: bold;
    }
    #result {
      padding: 16px;
      background: #e6f4ed;
      color: #246127;
      margin-top: 24px;
    }
    button:focus-visible,
    input:focus-visible {
      outline: 3px solid #135ca3;
      outline-offset: 3px;
    }
    footer {
      border-top: 1px solid #d8d8d8;
      margin-top: 32px;
      padding-top: 16px;
      font-size: 14px;
      color: #404040;
    }
    [hidden] {
      display: none !important;
    }
    @media (max-width: 767px) {
      body {
        padding: 16px;
      }
      main {
        grid-template-columns: 1fr;
        gap: 24px;
      }
      h1 {
        font-size: 30px;
      }
      .basket {
        display: none;
      }
      .dates button {
        flex: 1;
      }
      .summary {
        padding: 16px;
      }
    }
  </style>
  <body>
    <header>
      <div>
        <span class="eyebrow">GROCERIES / ORIGINAL COLLECTION STUDY</span>
        <h1>Choose a collection slot</h1>
        <p>
          Select a sample day and time. No order or real availability is
          connected.
        </p>
      </div>
      <div class="basket" aria-hidden="true">▥</div>
    </header>
    <main>
      <section>
        <fieldset>
          <legend>Collection day</legend>
          <div class="dates" id="dates"></div>
        </fieldset>
        <fieldset>
          <legend id="slotLabel">Available times</legend>
          <div id="slots" class="slots"></div>
        </fieldset>
      </section>
      <aside class="summary">
        <h2>Collection details</h2>
        <dl>
          <dt>Sample location</dt>
          <dd>Riverside collection point</dd>
          <dt>Day and time</dt>
          <dd id="selection"></dd>
          <dt>Sample fee</dt>
          <dd id="fee"></dd>
        </dl>
        <p><small>All fees and slots are illustrative.</small></p>
        <button class="primary" id="review">Review collection</button>
        <div id="result" role="status" hidden></div>
      </aside>
    </main>
    <footer>
      Independent HTML interpretation of Sainsbury’s public guidance. Arial
      fallback; no private Fable runtime or brand font assets.
    </footer>
    <script>
      const days = [
        {
          label: "Monday",
          slots: [
            ["09:00–10:00", 1, true],
            ["12:00–13:00", 0, true],
            ["17:00–18:00", 2, false],
          ],
        },
        {
          label: "Tuesday",
          slots: [
            ["09:00–10:00", 0, false],
            ["12:00–13:00", 1, true],
            ["17:00–18:00", 1, true],
          ],
        },
        {
          label: "Wednesday",
          slots: [
            ["09:00–10:00", 0, true],
            ["12:00–13:00", 0, true],
            ["17:00–18:00", 2, true],
          ],
        },
      ];
      let day = 0,
        slot = 0;
      const $ = (id) => document.getElementById(id);
      function update() {
        const choice = days[day].slots[slot];
        $("selection").textContent = days[day].label + ", " + choice[0];
        $("fee").textContent =
          choice[1] === 0 ? "No collection fee" : "£" + choice[1].toFixed(2);
        $("result").hidden = true;
      }
      function render() {
        $("dates").replaceChildren(
          ...days.map((d, i) => {
            let b = document.createElement("button");
            b.textContent = d.label;
            b.setAttribute("aria-pressed", i === day);
            b.onclick = () => {
              day = i;
              slot = d.slots.findIndex((s) => s[2]);
              render();
            };
            return b;
          }),
        );
        $("slotLabel").textContent = days[day].label + " collection times";
        $("slots").replaceChildren(
          ...days[day].slots.map((s, i) => {
            let l = document.createElement("label");
            l.className = "slot";
            let input = document.createElement("input");
            input.type = "radio";
            input.name = "time";
            input.checked = i === slot;
            input.disabled = !s[2];
            input.onchange = () => {
              slot = i;
              update();
            };
            let text = document.createElement("span");
            text.textContent = s[0];
            let fee = document.createElement("strong");
            fee.textContent = s[2]
              ? s[1] === 0
                ? "No fee"
                : "£" + s[1].toFixed(2)
              : "Unavailable";
            l.append(input, text, fee);
            return l;
          }),
        );
        update();
      }
      $("review").onclick = () => {
        $("result").hidden = false;
        $("result").textContent =
          "Local selection ready: " +
          $("selection").textContent +
          ". No slot has been reserved.";
      };
      render();
    </script>
  </body>
</html>

代码参考

  • 无需私有软件包或凭据。
04

Sainsbury's 设计系统 AI Agent 设置

实现起点

Fable 软件包访问权限与这份公开且独立的示例无关。

sh
# Save the complete HTML example as index.html
python3 -m http.server 8080
# Open http://localhost:8080

适用于你项目的提示词

Agent 提示词
根据这份完整的 HTML 示例,构建一个遵循 Sainsbury’s 指南的取货时段选择器。使用单一品牌配色、橙色操作按钮上的黑色文字、带原生标签的单选按钮、48px 点击目标,以及明确采用的 768px 布局方案。每次选择变化时都清除审核反馈。使用虚构的可用时段,不要声称使用了 Fable 运行时或成功预订。
05

Sainsbury's 设计系统 来源与范围

对 Sainsbury’s 公开指南的 OpenDesign 应用研究。这是原创的 HTML,并非 Fable 私有运行时。使用 Arial 字体,而非重新分发的 Mary Ann 资源;取货时段和费用均为虚构。