news 2026/9/13 16:10:07

Figma Effect Styles 实战指南:用 Plugin API 构建可复用的阴影与模糊 Token 系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Figma Effect Styles 实战指南:用 Plugin API 构建可复用的阴影与模糊 Token 系统

Figma Effect Styles 实战指南:用 Plugin API 构建可复用的阴影与模糊 Token 系统

【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills

Effect Style(效果样式)是 Figma 中把投影、内阴影、模糊等视觉效果封装为具名、可复用定义的机制,也是设计系统中"阴影/高度(elevation)Token"在 Figma 侧最贴近的等价物。本文以本仓库figma-useSkill 的 wwds-effect-styles.md 为核心骨架,结合 plugin-api-standalone.d.ts 的类型定义与 effect-style-patterns.md 的可运行代码模式,系统讲解 EffectStyle 的数据模型、四种 Effect 类型、变量绑定机制以及创建/枚举/应用的全流程,帮助你通过use_figmaSkill 用 Plugin API 把设计系统里的阴影规范变成真实的 Figma 文件内容。

Effect Style 是什么:阴影与模糊的"命名 Token"

在 Figma 的设计系统语境中,Effect Style 是一个或多个视觉效果的具名、可复用定义——这些视觉效果包括投影(drop shadow)、内阴影(inner shadow)和模糊(blur)。从设计系统的角度看,它最接近代码侧的 shadow / elevation token:团队可以预先定义Elevation/100Elevation/200这样的效果样式,然后在任意节点上一键复用,保证全文件阴影规范一致。

需要特别区分的是:Effect Style 与 Variables(变量)是两套不同的机制。Figma 中没有单独一种变量类型能够直接表示一个阴影。但反过来,效果内部的单个数值属性与颜色属性(如colorradiusspreadoffsetXoffsetY)是可以绑定到变量上的。这意味着阴影既可以作为整体被样式复用,其构成参数又能接入 Token 体系参与明暗主题切换,两条路径互补而不冲突。相关设计系统总体理念可参考 wwds.md。

EffectStyle 数据模型:一个核心可写属性 + 继承字段

在 plugin-api-standalone.d.ts 中,EffectStyle接口的定义如下:

interface EffectStyle extends BaseStyleMixin { type: 'EFFECT' effects: ReadonlyArray<Effect> readonly boundVariables?: { readonly [field in VariableBindableEffectStyleField]?: VariableAlias[] } }

除继承自BaseStyleMixin的字段外,EffectStyle只有一组核心可写属性,归纳如下:

属性类型说明
namestring样式名称,用/分隔以形成分组,例如"Elevation/200"
effectsReadonlyArray<Effect>只读数组—— 必须克隆、修改后再整体重新赋值
descriptionstringBaseStyleMixin继承的描述字段
type'EFFECT'类型判别字面量,读取其他属性前应始终先检查type
boundVariablesReadonly该效果样式上各字段绑定的变量别名(只读)

BaseStyleMixin(见 plugin-api-standalone.d.ts)还提供id(只读)、namegetStyleConsumersAsync()(查询样式消费者)和remove()(删除本地样式)等能力,其中id正是后续把样式应用(assign)到节点时要用到的关键值。

Effect 类型详解:判别联合下的四种常用形态

Effect是一个判别联合(discriminated union)。在 plugin-api-standalone.d.ts 中,完整的联合成员包括DropShadowEffect | InnerShadowEffect | BlurEffect | NoiseEffect | TextureEffect | GlassEffect。其中最常见的四种类型及关键属性如下:

type关键属性备注
DROP_SHADOWcolor: RGBAoffset: Vectorradius: numberspread: numbervisible: booleanblendMode外投影,可额外设置showShadowBehindNode
INNER_SHADOWDROP_SHADOW相同内阴影,spread为正时向内收缩
LAYER_BLURradius: numbervisible: boolean图层模糊
BACKGROUND_BLURradius: numbervisible: boolean背景模糊(毛玻璃效果)

对照类型定义(plugin-api-standalone.d.ts)可以确认几个实现细节:

  • 阴影的colorRGBA(即{ r, g, b, a }四个 0–1 之间的数值),offsetVector(即{ x, y });
  • radius必须>= 0,数值越小阴影越锐利;
  • spread为可选字段,默认值为 0;正 spread 让外投影大于节点、内阴影向内收缩,负值则相反。且 spread 只在矩形、椭圆,以及带有可见填充且开启clipsContent的 Frame/Component/Instance 上生效;
  • 模糊类型(LAYER_BLUR/BACKGROUND_BLUR)只关心radiusvisible两个属性。

务必牢记的颜色规范:所有效果颜色均为 0–1 区间的RGBA分量,不是0–255,也不是十六进制。例如半透明黑色应写作{ r: 0, g: 0, b: 0, a: 0.15 }。这是use_figmaSkill 的强制性规则之一(见 SKILL.md 的 Critical Rules 第 6 条),颜色通道大于 1 是运行时报错的高频原因。

变量绑定:让阴影参数参与 Token 系统

尽管效果样式本身不能整体绑定变量,但单个属性可以通过setBoundVariableForEffect(effect, field, variable)绑定到变量上(可在节点上调用,也可在构造时内联绑定)。可绑定的字段(VariableBindableEffectField,见 plugin-api-standalone.d.ts):

'color' | 'radius' | 'spread' | 'offsetX' | 'offsetY'

其中color绑定 COLOR 类型变量,radius/spread/offsetX/offsetY绑定 FLOAT 类型变量;模糊效果则只有radius(FLOAT)可以绑定。api-reference.md中给出的绑定模式如下(见 api-reference.md):

// Binding variables to effects (COLOR/FLOAT variables) const newEffect = figma.variables.setBoundVariableForEffect(effectCopy, field, variable) // field for shadows: "color" (COLOR), "radius" | "spread" | "offsetX" | "offsetY" (FLOAT) // field for blurs: "radius" (FLOAT) // ⚠️ Returns a NEW effect — must capture return value! node.effects = [newEffect]

根据 plugin-api-standalone.d.ts 的类型签名,setBoundVariableForEffect返回一个绑定后的新 Effect 对象副本;如果传入variable = null,则会解除该字段的绑定。因此使用时的铁律是:

  1. 把调用返回值捕获下来;
  2. 再整体重新赋值给effects数组(注意node.effects同样是一个只读数组,禁止原地修改)。

这正是效果参与明暗双主题切换的机制:把阴影颜色和偏移绑定到主题变量后,切换模式即可全局联动。

实战:枚举、创建与应用 Effect Style

本仓库的 effect-style-patterns.md 提供了三个可直接运行的核心模式。注意:在use_figmaSkill 环境中,代码应使用顶层awaitreturn返回数据,不要包裹 async IIFE、不要调用figma.closePlugin()(见 SKILL.md);以下代码保留了原文在标准 Plugin 环境下的写法,便于对照。

1. 枚举本地所有 Effect Style

/** * Lists all local effect styles. * * @returns {Promise<Array<{id: string, name: string, key: string, effectCount: number}>>} */ async function listEffectStyles() { const styles = await figma.getLocalEffectStylesAsync(); return styles.map(s => ({ id: s.id, name: s.name, key: s.key, effectCount: s.effects.length })); }

在标准 Plugin 环境下的完整运行脚本:

(async () => { try { const results = await listEffectStyles(); figma.closePlugin(JSON.stringify(results)); } catch(e) { figma.closePluginWithFailure(e.toString()); } })()

API 演进提醒getLocalEffectStyles()(同步版本)已被标记为@deprecated(见 plugin-api-standalone.d.ts),当插件 manifest 声明了"documentAccess": "dynamic-page"时它会直接抛异常;请始终使用getLocalEffectStylesAsync()

2. 创建投影 Effect Style

创建的核心是figma.createEffectStyle()(见 plugin-api-standalone.d.ts)。以下函数演示了如何构造一个标准投影样式,包含颜色(RGBA 0–1)、偏移、模糊半径与 spread:

/** * Creates a drop shadow effect style. * * @param {string} name - e.g. "Elevation/200" * @param {{ r: number, g: number, b: number, a: number }} color - RGBA, 0-1 range * @param {{ x: number, y: number }} offset * @param {number} radius - blur radius * @param {number} [spread=0] * @returns {EffectStyle} */ function createDropShadowStyle(name, color, offset, radius, spread) { const style = figma.createEffectStyle(); style.name = name; style.effects = [{ type: "DROP_SHADOW", color, offset, radius, spread: spread || 0, visible: true, blendMode: "NORMAL" }]; return style; }

完整运行脚本(创建"Elevation/200"样式:黑色 15% 透明度、向下偏移 4、模糊 12、无 spread):

(async () => { try { const style = createDropShadowStyle( "Elevation/200", { r: 0, g: 0, b: 0, a: 0.15 }, { x: 0, y: 4 }, 12, 0 ); figma.closePlugin(JSON.stringify({ id: style.id, name: style.name })); } catch(e) { figma.closePluginWithFailure(e.toString()); } })()

命名建议使用斜杠分隔以形成层级分组(如"Elevation/200"),这与设计系统中 token 的层级命名规范一一对应。

3. 把 Effect Style 应用到节点

应用的本质是把样式的id赋给节点的effectStyleId属性——赋值后节点的effects属性会自动反映该样式的值。注意effectStyleId并不是所有节点都具备的属性,因此应用前要做能力探测:

/** * Applies an effect style to all nodes on the current page that match a given name pattern. * * @param {string} styleId - The ID of an EffectStyle. * @param {string} nodeNamePattern - Substring match against node names. * @returns {number} - Number of nodes the style was applied to. */ function applyEffectStyleToMatchingNodes(styleId, nodeNamePattern) { const nodes = figma.currentPage.findAll(n => n.name.includes(nodeNamePattern)); let applied = 0; for (const node of nodes) { if ('effectStyleId' in node) { node.effectStyleId = styleId; applied++; } } return applied; }

完整运行脚本(把名为'STYLE_ID'的样式应用到所有名称包含'Card'的节点):

(async () => { try { const applied = applyEffectStyleToMatchingNodes('STYLE_ID', 'Card'); figma.closePlugin(JSON.stringify({ applied })); } catch(e) { figma.closePluginWithFailure(e.toString()); } })()

dynamic-page 模式的补充:根据 plugin-api-standalone.d.ts 的说明,如果插件 manifest 包含"documentAccess": "dynamic-page"effectStyleId属性变为只读,此时应改用setEffectStyleIdAsync(styleId)异步方法来更新样式引用。

常见陷阱(Common Gotchas)

把上面所有内容浓缩成五条最容易踩坑的规则:

  • effects是只读数组:不能原地 push/mutate。必须克隆、修改、再整体重新赋值,例如style.effects = [...style.effects, newEffect];对节点的node.effects同样如此。
  • 效果按数组顺序堆叠:数组中的效果顺序直接影响视觉结果——投影按从底部到顶部的顺序渲染,多阴影叠加时顺序不同观感完全不同(多层投影的典型写法见 plugin-api-patterns.md)。
  • 颜色一律是 RGBA 0–1{ r: 0, g: 0, b: 0, a: 0.15 }这样的写法,而不是 hex、不是 0–255。若某次运行报"Property value out of range",先检查是否误用了 0–255 的色值。
  • getLocalEffectStyles()已废弃:始终使用异步的getLocalEffectStylesAsync()
  • 样式不会自动生效:创建EffectStyle不会对任何节点产生影响,只有把它的id赋给节点的effectStyleId后才会真正应用。

在 use_figma 环境中执行的额外注意事项

通过本仓库的figma-useSkill 调用use_figmaMCP 执行上述代码时,还需遵守 Skill 的运行环境约束(详见 SKILL.md):

  • 代码自动包裹在 async 上下文中,用顶层awaitreturn返回结果,不要使用figma.closePlugin()(async () => { ... })()包装;
  • return值是唯一的输出通道,console.log()不会被回传;所有新建/修改的节点或样式 ID 必须结构化返回(如return { createdStyleIds: [...] }),供后续调用引用与校验;
  • 每次调用会重置页面上下文,多步工作流建议"创建样式 → 校验 → 应用"分步执行,每步用get_metadata验证结构;
  • 脚本失败是原子的——出错时整个脚本不会执行,文件保持原状,先仔细阅读错误信息再修正重试,不要盲目立即重试。

小结与延伸阅读

Effect Style 是设计系统 Token 链路中"高度/阴影"语义的落点:用命名样式统一视觉规范,用变量绑定接通主题切换,再用effectStyleId让任意节点一键套用。掌握了createEffectStyle()getLocalEffectStylesAsync()setBoundVariableForEffect()effectStyleId这四件套,你就能用 Plugin API 完整落地阴影 Token 体系的创建、查询、绑定与应用。

  • 完整可运行代码:阅读 effect-style-patterns.md;
  • 精确类型签名:在 plugin-api-standalone.d.ts 中 grepEffectStyleDropShadowEffectsetBoundVariableForEffectVariableBindableEffectField等符号;
  • 其他效果写法的直接示例(投影、内阴影、背景模糊、图层模糊、多阴影叠加):plugin-api-patterns.md;
  • 变量绑定的完整 API 对照表:api-reference.md;
  • 设计系统工作总纲与其余范式(Components / Variables / Text Styles):wwds.md。

【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 16:10:05

Linux内核IPv6地址管理源码解析:addrconf.c核心机制

去年底我给自己定了一个任务&#xff1a;把 Linux 6.19 的 net/ipv6/addrconf.c 完整读一遍。说实话这个文件我早就想啃&#xff0c;但一直没下定决心&#xff0c;因为地址配置这块涉及的状态机、定时器、netlink 回调纠缠在一起&#xff0c;光看代码很容易绕晕。后来我借助 De…

作者头像 李华
网站建设 2026/9/13 16:02:19

LunaTranslator 实战手册:4 步配置让日系视觉小说变成实时中文

LunaTranslator 实战手册&#xff1a;4 步配置让日系视觉小说变成实时中文 【免费下载链接】LunaTranslator 视觉小说翻译器 / Visual Novel Translator 项目地址: https://gitcode.com/GitHub_Trending/lu/LunaTranslator 剧情关键抉择处&#xff0c;对话框突然冒出日文…

作者头像 李华
网站建设 2026/9/13 16:00:48

嵌入式面试高频问题实战解析:从volatile到设备树匹配

1. 这不是“八股文合集”&#xff0c;而是一份嵌入式工程师面试现场还原手册我带过37个校招新人&#xff0c;筛过214份嵌入式岗位简历&#xff0c;也作为主面官参与过华为海思、地平线、大疆、蔚来智驾、全志科技等12家一线企业的技术终面。过去三年&#xff0c;我亲手把68位应…

作者头像 李华
网站建设 2026/9/13 15:58:42

安防镜头一体化驱动芯片:GC6208硬件协同设计解析

1. 项目概述&#xff1a;一颗芯片如何重构安防镜头的驱动逻辑GC6208这个名字乍一听像一串编号&#xff0c;但在我拆解过二十多款安防模组、亲手调过上百颗镜头驱动芯片的十年里&#xff0c;它代表的是一个分水岭——不是技术参数堆砌出来的“又一颗国产替代”&#xff0c;而是真…

作者头像 李华