企业产品设计 · 新资源

Porsche 设计系统.

通过流动式间距、CSS 配色方案、Porsche Next 字体和双选项配置器,探索 Porsche Design System v4。参考内容包含真实的令牌表达式,以及完整的 Vite 入口文件,并采用当前的分段控件事件。

OpenDesign 指南8 个章节45 个参考条目原始应用指南
01

Porsche 设计系统 界面预览

选择饰面和轮毂样式,查看会话摘要,并切换界面的明暗模式。

原创饰面与轮毂方案打开完整示例
对 v4 令牌角色和分段选项行为的原创离线 HTML/CSS 演绎。没有使用原生 PDS 运行时、远程字体、官方车型图片或真实车辆数据。 · 实现参考
02

Porsche 设计系统参考

Porsche Design System v4 文档;令牌页面显示 v4.8.0。这是限定版本范围的参考,不代表最新版本。原创饰面色样属于应用数据,并非保时捷官方车漆代码。

静态间距

来源
名称 / 规则值 / 配置用途
spacingStatic2Xs1px固定间距令牌。
spacingStaticXs4px固定间距令牌。
spacingStaticSm8px固定间距令牌。
spacingStaticMd16px固定间距令牌。
spacingStaticLg32px固定间距令牌。
spacingStaticXl48px固定间距令牌。
spacingStatic2Xl80px固定间距令牌。

流动间距

来源
名称 / 规则值 / 配置用途
spacingFluidXsclamp(4px, 0.25vw + 3px, 8px)较小的自适应间隔。
spacingFluidSmclamp(8px, 0.5vw + 6px, 16px)紧凑型自适应间隔。
spacingFluidMdclamp(16px, 1.25vw + 12px, 36px)页面内边距示例。
spacingFluidLgclamp(32px, 2.75vw + 23px, 76px)区块间距。
spacingFluidXlclamp(48px, 3vw + 38px, 96px)大间距。
spacingFluid2Xlclamp(80px, 7.5vw + 56px, 200px)用于主要布局的间距。

颜色角色

来源
名称 / 规则值 / 配置用途
colorCanvaslight-dark(#fff,hsl(225 66.7% 1.2%))页面画布。
colorSurfacelight-dark(hsl(240 10% 95%),hsl(240 2% 10%))次级界面表面。
colorPrimarylight-dark(hsl(225 66.7% 1.2%),hsl(225 100% 99%))主文本。
colorFocuslight-dark(#1A44EA,#1A44EA)键盘焦点。
colorContrastLow / colorContrastLowerDecorative only不符合无障碍要求的文本角色。

字体表达式

来源
名称 / 规则值 / 配置用途
fontPorscheNext'Porsche Next','Arial Narrow',Arial,'Heiti SC',SimHei,sans-serif官方字体系列及回退字体。
typescale2Xs.75rem列出的最小字号。
typescaleXs.875rem小号元数据。
typescaleSm1rem正文基准字号。
typescaleMdclamp(1.13rem, 0.21vw + 1.08rem, 1.33rem)流动字号。
typescale2Xlclamp(1.6rem, 1.56vw + 1.29rem, 3.16rem)流动大标题。
leadingNormalcalc(6px + 2.125ex)行高随字体而异。
fontWeightNormal / Semibold / Bold400 / 600 / 700可用字重。

形状

来源
名称 / 规则值 / 配置用途
radiusXs / Sm / Md2px / 4px / 6px小尺寸形状。
radiusLg8px紧凑型交互控件。
radiusXl12px标准交互控件。
radius2Xl16px通知。
radius3Xl24px卡片和类似对话框的容器。
radius4Xl32px最大的固定圆角。
radiusFullcalc(infinity * 1px)独立的胶囊形指示器。

断点

来源
名称 / 规则值 / 配置用途
breakpointXs480与 px 配合使用的数值令牌。
breakpointSm760与 px 配合使用的数值令牌。
breakpointMd1000与 px 配合使用的数值令牌。
breakpointLg1300与 px 配合使用的数值令牌。
breakpointXl1760与 px 配合使用的数值令牌。
breakpoint2Xl1920与 px 配合使用的数值令牌。

分段选项约定

来源
名称 / 规则值 / 配置用途
valuestring | number选中项的值。
change eventdetail: { value: string | number }更新应用状态。
columnsauto or 1–25; responsive values supported控制项目网格。
noWrapfalse by default设为 true 时,显示可滚动的单行内容。
statenone / error / success验证样式。
disabledExcludes value from form submission不同于普通的未选中项。
03

Porsche 设计系统 完整指南

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

DESIGN-porsche.md

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

下载指南

Porsche 设计系统 完整使用 v4 基础体系

现在必须使用全局变量

v4 基于全局 CSS 变量构建组件样式。因此,导入全局样式表是架构上的必要要求,而非装饰性重置。同一次导入还包含规范化样式和 Porsche Next 的 @font-face 定义。

摘自本 OpenDesign 指南

本参考将 v4 组件与令牌约定整合在一起。旧示例中使用的文本字段包装器或按组件设置主题的属性,不应在未参考迁移指南的情况下直接沿用。文档本身有版本,因此本页面会明确标出适用范围,而不会声称内容永不过时:API。

阅读配套规范

Porsche 设计系统 配色方案会选择完整的角色配对

将界面角色与饰面样本分开

画布、界面表面和主要前景色令牌包含 light-dark() 配对。CSS color-scheme 属性用于选择对应分支。根据应用是固定模式还是遵循用户偏好,设置为 light、dark 或 light dark。

本示例中的饰面颜色是彼此独立的原创色样。切换界面暗色模式只会改变周围的背景层和文本,不会改变所选饰面。对比度较低的颜色角色仅用于装饰;若将其用于重要选项标签,就超出了令牌的预期用途。

阅读配套规范

Porsche 设计系统 流动节奏与固定控件间距可以并存

在空间应随尺寸增长时使用 clamp 表达式

保时捷提供静态和流动两种间距比例。原生条目使用中号流动表达式作为页面内边距,而选项区域内则使用 16px 和 32px 的固定间距,保持稳定的布局关系。流动间距设有最大值,避免宽屏上出现无止境扩大的留白。

示例在宽屏上采用视觉内容与控件并列的布局,宽度低于 760px 时则改为分区堆叠;760px 是文档列出的断点值之一。是否改为堆叠属于应用布局决策;断点值本身则是设计系统参考。

阅读配套规范

Porsche 设计系统 字体排版依赖所提供的字体

行高表达式不是通用比例

Porsche Next 有文档规定的回退字体栈,以及由固定小字号和流动大字号组成的字体比例。leadingNormal 使用 ex 单位,随字体的 x 高度变化,并加上固定的像素值。若将其替换成任意的 1.5 比例,就会改变预期的排版节奏。

离线演绎使用本地回退字体和易读的行高,不会假装已打包授权字体。原生条目中的全局样式表会定义实际字体。v4 设计语言中的标题使用常规字重;建立层级不需要加粗大字号。

阅读配套规范

Porsche 设计系统 控件和容器使用不同的圆角

12 像素和 24 像素构成主要层级

标准交互圆角为 12px;卡片和对话框系列使用 24px。紧凑型控件改用 8px,通知则使用 16px。若所有元素都采用最大圆角,这些层级关系就会消失。

原创预览将车辆设计置于宽大的 24px 界面表面上,并使用 12px 控件。车辆轮廓是原创的 CSS 插画,并非保时捷车型渲染图或产品照片。同样的布局也可用于材质选择器,但不应因此暗示用户可以实际配置车辆。

阅读配套规范

Porsche 设计系统 分段控件用于选项选择,不是标签栏

使用稳定的值,并由单一状态源管理

每个 p-segmented-control-item 都会提供一个值。变更事件会在 event.detail 中返回该值,示例会先将其存入状态,再重新绘制摘要。分组控件会显示可见标签,以便区分饰面选项和轮毂选项。

v4 API 支持自适应列数,也可选择启用不换行的滚动容器。简短选项可以同时显示;较长的本地化标签应换行,或使用有意设计的滚动容器,而不是将内容截断。禁用的控件不会包含在表单数据中;将此示例扩展为真实表单时,这一点尤为重要。

  1. 在应用状态中一次性初始化 finish 和 wheel 的值。
  2. 从分组的 change 事件中读取 detail.value。
  3. 同时更新可见的方案和文字选项。
  4. 编辑后清除之前保留的摘要。

阅读配套规范

Porsche 设计系统 本地选择不等于已完成的交易

明确指定按钮类型

p-button 默认类型为 submit。示例将 type="button" 设为按钮类型,因为保留组合和切换配色方案都属于本地交互。导航应使用 Link 组件,而不是使用按钮并虚构目标地址。

主要操作会准确说明实际发生的事情:本次页面会话中保留了一组组合。它不会声称数据在重新加载后仍然保留、已存入账户或已下单。这种有限的行为是刻意设计的,对于界面示例来说也已足够完整。

  • 主要操作会保留当前本地组合。
  • 次要操作会切换界面的配色方案。
  • 两个操作都保留可见标签。
  • 没有待处理操作时,不显示加载动画。

阅读配套规范

Porsche 设计系统 加载组件并保护其首次渲染

加载器、样式表和编译器协同工作

Vite 配置会将官方加载器片段注入文档的 body。主入口会导入全局样式表并渲染真正的自定义元素。作用域内的 :not(:defined) 规则可防止所选组件标签在注册前闪现。

文档所述的 Vite 设置会排除 Lightning CSS 的 LightDark 转换,因为该 polyfill 被标记为存在缺陷。保留此排除项很重要:错误地编译掉令牌函数可能会破坏主题,即使组件标记本身正确无误。之后可通过文档所述的字体、图标和组件片段添加建议的预加载项。

阅读配套规范

Porsche 设计系统组件示例

完整的独立交互示例

将完整文档保存为 index.html 并在浏览器中打开。这是对 v4 令牌角色和分段选项行为的原创离线 HTML/CSS 解读。不包含原生 PDS 运行时、远程字体、官方车型图片或真实车辆数据。

html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>Original finish study</title><style>:root{color-scheme:light;--canvas:#fff;--surface:hsl(240 10% 95%);--ink:hsl(225 66.7% 1.2%);--line:#c8c8cd;--paint:#b9b6ae}*{box-sizing:border-box}body{margin:0;background:var(--canvas);color:var(--ink);font:16px/1.5 'Arial Narrow',Arial,sans-serif}body.dark{color-scheme:dark;--canvas:hsl(225 66.7% 1.2%);--surface:hsl(240 2% 10%);--ink:#fcfcff;--line:#515156}button{font:inherit;cursor:pointer}button:focus-visible,input:focus-visible+span{outline:3px solid #1a44ea;outline-offset:4px}header{display:flex;justify-content:space-between;gap:16px;align-items:center;padding:24px 32px;border-bottom:1px solid var(--line)}header b{letter-spacing:3px;font-weight:400}header button{border:1px solid var(--line);color:var(--ink);background:var(--canvas);border-radius:12px;padding:8px 16px}main{max-width:1200px;padding:clamp(16px,1.25vw + 12px,36px);margin:auto}h1{font-size:clamp(1.6rem,1.56vw + 1.29rem,3.16rem);font-weight:400;line-height:1.2;margin:16px 0}.intro{color:var(--ink);opacity:.8;max-width:650px}.layout{display:grid;grid-template-columns:1.4fr 1fr;gap:32px;margin-top:32px}.stage{background:var(--surface);border-radius:24px;display:flex;flex-direction:column;justify-content:center;min-height:360px;overflow:hidden;padding:32px;position:relative}.scene{height:210px;position:relative;width:100%;max-width:520px;margin:auto}.car{height:80px;width:94%;position:absolute;bottom:28px;left:3%;background:var(--paint);border-radius:60% 35% 18% 22% / 75% 65% 25% 35%;box-shadow:inset 0 5px 10px #ffffff70,inset 0 -10px 12px #0003}.roof{position:absolute;bottom:80px;left:25%;width:46%;height:70px;background:var(--paint);border-radius:65% 55% 0 0;transform:skewX(-9deg)}.window{position:absolute;inset:9px 13px 4px;background:linear-gradient(135deg,#202d37,#67737b);border-radius:70% 52% 0 0;border-right:7px solid var(--paint)}.window:after{content:'';position:absolute;left:46%;top:0;height:100%;width:6px;background:var(--paint)}.wheel{position:absolute;bottom:12px;width:69px;height:69px;background:repeating-conic-gradient(#d2d5d8 0deg 13deg,#42464b 13deg 60deg);border:11px solid #191a1d;border-radius:50%;box-shadow:0 0 0 4px #08090a}.wheel.a{left:16%}.wheel.b{right:12%}.aero .wheel{background:radial-gradient(circle,#505860 0 18%,#c6c9cc 20% 65%,#464a4d 68%)}.headlight{position:absolute;right:0;top:18px;width:34px;height:12px;background:#fff9d8;border:2px solid #ffffff80;border-radius:80%;transform:rotate(15deg)}.shadow{height:10px;background:#0002;position:absolute;bottom:7px;width:90%;left:5%;border-radius:50%;filter:blur(5px)}.stage small{font-size:12px;opacity:.7}.panel{padding:8px 0}fieldset{border:0;padding:0;margin:0 0 32px;min-width:0}legend{font-size:18px;margin-bottom:16px}.segments{display:flex;background:var(--surface);padding:4px;border-radius:16px;gap:4px}.segments label{flex:1;min-width:0;position:relative;text-align:center;cursor:pointer}.segments input{position:absolute;opacity:0;width:1px;height:1px}.segments span{display:block;padding:12px 8px;border:1px solid transparent;border-radius:12px}.segments input:checked+span{background:var(--canvas);border-color:var(--ink);box-shadow:0 1px 4px #0002}.swatch{display:inline-block;width:12px;height:12px;border-radius:50%;margin-right:6px;border:1px solid #777}.summary{border-top:1px solid var(--line);padding-top:24px;margin:0 0 24px}.summary small{display:block;opacity:.65;margin-bottom:4px}.summary strong{font-weight:400;font-size:20px}.primary{border:0;border-radius:12px;min-height:52px;background:var(--ink);color:var(--canvas);padding:12px 24px;width:100%}.saved{border-left:3px solid var(--ink);padding-left:16px;margin-top:24px}.saved:empty{display:none}footer{font-size:12px;opacity:.7;padding-top:32px}@media(max-width:759px){header{padding:16px}header b{font-size:13px;letter-spacing:1px}.layout{grid-template-columns:1fr;gap:24px}.stage{min-height:270px;padding:16px}.scene{height:210px}.wheel{width:53px;height:53px;border-width:8px;bottom:21px}.car{bottom:38px}.roof{bottom:91px;height:60px}.segments span{padding:12px 5px;font-size:14px}fieldset{margin-bottom:24px}}
</style><header><b>DESIGN STUDY / 01</b><button id="theme" type="button">Dark interface</button></header><main><h1>A different point of view.</h1><p class="intro">Explore two small choices in an original vehicle study. See how a restrained interface keeps the object at the center.</p><div class="layout"><div class="stage"><div class="scene" id="scene" role="img" aria-label="Original vehicle illustration in Chalk with Classic wheels"><div class="shadow"></div><div class="roof"><div class="window"></div></div><div class="car"><div class="headlight"></div></div><div class="wheel a"></div><div class="wheel b"></div></div><small>Original illustration · Not a Porsche model render</small></div><section class="panel" aria-label="Study options"><fieldset><legend>Finish</legend><div class="segments"><label><input type="radio" name="paint" value="chalk" checked><span><i class="swatch" style="background:#b9b6ae"></i>Chalk</span></label><label><input type="radio" name="paint" value="blue"><span><i class="swatch" style="background:#456171"></i>Coastal blue</span></label><label><input type="radio" name="paint" value="red"><span><i class="swatch" style="background:#9f2937"></i>Garnet</span></label></div></fieldset><fieldset><legend>Wheel study</legend><div class="segments"><label><input type="radio" name="wheel" value="Classic" checked><span>Classic</span></label><label><input type="radio" name="wheel" value="Aero"><span>Aero</span></label></div></fieldset><p class="summary" aria-live="polite"><small>YOUR COMBINATION</small><strong id="summary">Chalk · Classic</strong></p><button class="primary" id="save" type="button">Keep this combination</button><p class="saved" id="saved" role="status"></p></section></div><footer>Independent PDS v4 interpretation. Original finish names and illustration; no pricing, vehicle specification, live configuration or order. Choices last only for this page session.</footer></main><script>const colors={chalk:'#b9b6ae',blue:'#456171',red:'#9f2937'},names={chalk:'Chalk',blue:'Coastal blue',red:'Garnet'};function values(){return[document.querySelector('[name=paint]:checked').value,document.querySelector('[name=wheel]:checked').value]}function update(){const[p,w]=values();document.documentElement.style.setProperty('--paint',colors[p]);document.querySelector('#scene').classList.toggle('aero',w==='Aero');document.querySelector('#scene').setAttribute('aria-label',`Original vehicle illustration in ${names[p]} with ${w} wheels`);document.querySelector('#summary').textContent=`${names[p]} · ${w}`;document.querySelector('#saved').textContent=''}document.querySelectorAll('input').forEach(x=>x.addEventListener('change',update));document.querySelector('#save').onclick=()=>{const[p,w]=values();document.querySelector('#saved').textContent=`Kept for this page session: ${names[p]}, ${w}. No order submitted.`};document.querySelector('#theme').onclick=e=>{const dark=document.body.classList.toggle('dark');e.currentTarget.textContent=dark?'Light interface':'Dark interface'};</script></html>

代码参考

  • 车漆和轮毂选项会更新原创的配置器插画。它们不是保时捷产品规格;原生分段控件事件见另一个 v4 示例。

两个受控选项与仅在会话内保留的摘要

原生 p-segmented-control 元素会发出包含 detail.value 的 change 事件;p-button 使用 click 事件,并显式指定 type。

TypeScript
import './style.css';
const paints={chalk:'#b9b6ae',blue:'#456171',red:'#9f2937'};
const names={chalk:'Chalk',blue:'Coastal blue',red:'Garnet'};
type Paint=keyof typeof paints;
let paint:Paint='chalk',wheel='Classic';
document.querySelector<HTMLDivElement>('#app')!.innerHTML=`
<main><h1>Explore an original color study</h1>
<p>This specimen is not a real vehicle configurator or order.</p>
<div class="options">
<p-segmented-control id="paint" label="Finish" value="chalk">
 <p-segmented-control-item value="chalk">Chalk</p-segmented-control-item>
 <p-segmented-control-item value="blue">Coastal blue</p-segmented-control-item>
 <p-segmented-control-item value="red">Garnet</p-segmented-control-item>
</p-segmented-control>
<p-segmented-control id="wheel" label="Wheel study" value="Classic">
 <p-segmented-control-item value="Classic">Classic</p-segmented-control-item>
 <p-segmented-control-item value="Aero">Aero</p-segmented-control-item>
</p-segmented-control>
</div><div class="preview"><div id="swatch" style="height:120px;border-radius:12px"></div>
<p id="summary" aria-live="polite"></p></div>
<div class="actions"><p-button id="save" type="button">Keep this combination</p-button>
<p-button id="scheme" type="button" variant="secondary">Switch color scheme</p-button></div>
<p id="saved" role="status"></p></main>`;
function render(){document.querySelector<HTMLElement>('#swatch')!.style.background=paints[paint];document.querySelector('#summary')!.textContent=`${names[paint]} · ${wheel} wheel study`;document.querySelector('#saved')!.textContent='';}
document.querySelector('#paint')!.addEventListener('change',e=>{const v=(e as CustomEvent<{value:string}>).detail.value;if(v in paints){paint=v as Paint;render();}});
document.querySelector('#wheel')!.addEventListener('change',e=>{wheel=String((e as CustomEvent<{value:string}>).detail.value);render();});
document.querySelector('#save')!.addEventListener('click',()=>{document.querySelector('#saved')!.textContent=`Kept for this page session: ${names[paint]}, ${wheel}. No order submitted.`;});
document.querySelector('#scheme')!.addEventListener('click',()=>{const root=document.documentElement;root.style.colorScheme=root.style.colorScheme==='dark'?'light':'dark';});
render();

代码参考

  • 更改任一选项都会清除之前保留的组合。
  • color-scheme 属性控制系统主题;车漆色样属于原创应用数据。
  • 此示例不会收集联系信息、预订车辆或提交订单。
04

Porsche 设计系统 Agent 设置

实现起点

采用文档所述的全局样式表和加载器片段,设置 v4 原生 Web Component。离线预览不含远程字体或包运行时;此处未验证原生包编译。

文本
# In a new Vite vanilla-ts project:
npm create vite@latest pds-specimen -- --template vanilla-ts
cd pds-specimen
npm install
npm install @porsche-design-system/components-js@4
npm install --save-dev lightningcss

// vite.config.ts
import {defineConfig} from 'vite';
import {Features} from 'lightningcss';
import {getLoaderScript} from '@porsche-design-system/components-js/partials';
export default defineConfig({
 plugins:[{name:'pds-loader',transformIndexHtml(html){
  return html.replace('</body>',getLoaderScript()+'</body>');
 }}],
 css:{transformer:'lightningcss',lightningcss:{exclude:Features.LightDark}}
});

/* src/style.css */
@import '@porsche-design-system/components-js';
html { color-scheme: light; }
:is(p-button,p-segmented-control,p-segmented-control-item):not(:defined){visibility:hidden}
main{max-width:60rem;margin:auto;padding:clamp(16px,1.25vw + 12px,36px)}
.options{display:grid;gap:32px}
.preview{padding:32px;border-radius:24px;margin-block:32px;border:1px solid currentColor}
.actions{display:flex;gap:16px;flex-wrap:wrap}

# Replace src/main.ts with the example below, then:
npm run dev

适用于你项目的提示词

Agent 提示词
构建 v4 PDS 组合,使用必需的全局样式、加载器片段、color-scheme、实际流式间距,以及 12px 控件圆角和 24px 容器圆角。为两个原创示例选项使用 segmented-control 的 change detail.value,并为本地操作显式设置 type=button。不要混用旧版包装器 API,也不要将示例描述为真实车辆配置。
05

Porsche 设计系统 来源与范围

独立的 OpenDesign 参考示例,范围限定为 PDS v4。原创插画和车漆名称并非保时捷车辆规格、漆面代码或可选配置。此示例不会执行任何交易。