Drawably: 手绘风格 UI 控件

Hacker News Top 工具

摘要

Drawably 是一个 JavaScript 库,为网页开发提供带有动画笔刷效果的手绘风格 UI 控件。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/09/14 14:49

Danilaa1/drawably

源码:https://github.com/Danilaa1/drawably

drawably

手绘风格的 UI 控件。每次挂载都会根据种子随机性生成全新的笔触草图,笔画会像动画涂鸦般动态沸腾。零依赖,压缩后约 9 KB JavaScript(React 封装包增加不到 1 KB),外加 3 KB 样式表。可选的手绘字体单独提供(31 KB)。

按钮、复选框、单选按钮和开关均采用沸腾笔触绘制。

安装

npm i drawably

快速开始

import { drawablyButton } from "drawably";  
import "drawably/style.css";  
drawablyButton(document.querySelector("#done"), { variant: "solid" });  

React 版本:

import { DrawablyButton } from "drawably/react";  
import "drawably/style.css";  
<DrawablyButton>Done</DrawablyButton>  

每次调用 attach 都会返回一个草图句柄:

const sketch = drawablyButton(el);  
sketch.resketch(); // 使用新种子重新绘制  
sketch.resketch(42); // 使用特定种子重新绘制  
sketch.destroy(); // 移除 SVG 及所有事件监听器  

按钮

三种变体:outline(默认)、solidscribble。按钮还内置状态机用于异步操作:
按钮的四种状态:idle、loading、error、success

const button = drawablyButton(el);  
button.setState("loading"); // 按钮变暗,沸腾加速  
button.setState("error"); // 用红色重绘  
button.setState("success"); // 用绿色重绘  
button.setState("idle");  

在 React 中,通过 state 属性传递状态;草图保持不变,仅状态更新:

<DrawablyButton state="success">Save</DrawablyButton>  

可通过 --drawably-error--drawably-success 自定义状态颜色。对于次要或危险操作,可设置 tone: "neutral"(暖灰色)或 tone: "danger"(红色)。

控件列表

函数期望的元素
drawablyButton(el, opts)一个 <button>
drawablyCheckbox(el, opts)包含 <input type="checkbox"> 的包裹容器
drawablyRadio(el, opts)包含 <input type="radio"> 的包裹容器
drawablyToggle(el, opts)包含 <input type="checkbox"> 的包裹容器
drawablyInput(el, opts)包含 <input> 的包裹容器
drawablyTextarea(el, opts)包含 <textarea> 的包裹容器
drawablySelect(el, opts)包含 <select> 的包裹容器
drawablyDivider(el, opts)<hr> 或 div 元素
drawablyCard(el, opts)任何块级元素
drawablyBadge(el, opts)任何内联元素
drawablyList(el, opts)<ul><ol>;每个 <li> 都会生成草图标记

徽章支持 variant: "outline" | "scribble";列表支持 marker: "dash" | "check"

选择框会保留最宽选项的宽度,确保选择时不会改变布局;在 Chromium 中,选项列表会获得草图边框和笔触勾选标记(使用 appearance: base-select),Safari 和 Firefox 保持系统原生弹窗。实际输入元素保留在 DOM 中,因此键盘操作、表单、标签和屏幕阅读器照常工作。草图是位于底层的 aria-hidden SVG。

所有控件在 drawably/react 中都有对应的 React 版本:
DrawablyButtonDrawablyCheckboxDrawablyRadioDrawablyToggleDrawablyInputDrawablyTextareaDrawablySelectDrawablyDividerDrawablyCardDrawablyBadgeDrawablyList

文本装饰

像用笔一样为文本添加注释。每个装饰都应用于内联元素,不影响布局;适用于单词或短语。

函数绘制内容
drawablyUnderline(el, opts)文本下方粗糙线条,悬停时重新绘制
drawablyHighlight(el, opts)文本背后的记号笔涂抹效果
drawablyCircle(el, opts)围绕文本的手绘椭圆
drawablyArrow(from, to, opts)从一个元素指向另一个元素的箭头
import { DrawablyUnderline, DrawablyHighlight, DrawablyCircle, DrawablyArrow } from "drawably/react";  
<p>  
  <DrawablyUnderline>手绘</DrawablyUnderline> UI,  
  <DrawablyHighlight>全新草图</DrawablyHighlight>  
  <DrawablyCircle>每次挂载</DrawablyCircle>。  
</p>  
<DrawablyArrow from={noteRef} to={buttonRef} />  

跨越多行的装饰会每行绘制一次。箭头的 SVG 以文档坐标追加到 <body>,并在窗口调整大小时重绘。滚动容器内的锚点会随滚动偏移。

组合组件

由上述控件组合而成的部件。统一的 seed 可重现组合中的所有笔画;destroy() 会销毁所有部件。

函数标记结构绘制内容
drawablyChip(el, opts)<label><span><input type="checkbox"></span> 文本</label>围绕芯片的徽章,输入包裹容器的草图方框
drawablyTabs(el, opts)子元素为各标签页活动标签页的下划线;active 索引或 aria-selected="true"setActive(i)
drawablyTooltip(tip, target, opts)两个元素围绕提示的卡片,指向目标的箭头
drawablyAlert(el, opts)可选的 [data-tag] 子元素围绕警告的卡片,标签上的徽章
drawablySteps(el, opts)<ol>带勾选标记的列表
drawablyKbd(el, opts)<kbd>更稳健的徽章
drawablyQuote(el, opts)第一个子元素,可选 <footer>引文线上的高亮,页脚的分隔线
drawablyPager(el, opts)<button> 元素轮廓页码,实心当前页;active 索引或 aria-currentsetPage(i)
import { DrawablyChip, DrawablyTabs, DrawablyTooltip, DrawablyAlert, DrawablySteps, DrawablyKbd, DrawablyQuote, DrawablyPager } from "drawably/react";  
<DrawablyChip defaultChecked>pen</DrawablyChip>  
<DrawablyTabs active={tab}><span>a</span><span>b</span></DrawablyTabs>  
<DrawablyTooltip to={buttonRef}>undo</DrawablyTooltip>  
<DrawablyAlert><span data-tag>new</span> Import from Attio lands Friday</DrawablyAlert>  
<DrawablySteps><li>record</li><li>label</li></DrawablySteps>  
<DrawablyKbd>⌘K</DrawablyKbd>  
<DrawablyQuote><span>less, but better</span><footer>Rams</footer></DrawablyQuote>  
<DrawablyPager active={page}><button>‹</button><button>1</button><button>›</button></DrawablyPager>  

配置选项

所有控件接受相同的基础选项:

选项默认值功能说明
seed随机省略则每次挂载生成唯一草图,传入数字则生成可重现的草图
roughness1基础草图的抖动幅度
boil0.3帧间像素闪烁量;设为 0 则渲染静态路径
strokefillpaper笔触蓝/白色颜色值,通过 --drawably-* 自定义属性设置
width2笔触宽度(像素)

颜色使用标准 CSS 自定义属性,主题可统一设置:

:root {  
  --drawably-stroke: #1a1a1a;  
  --drawably-fill: #1a1a1a;  
}  

字体优先使用页面加载的 Inter,回退至 system-ui。除非主动加载可选字体,否则库不会引入任何字体。

动效

笔触柔和沸腾:基于同一草图生成三帧,在共享基础上微抖动,通过纯 CSS 以 1200ms 周期循环。悬停或按压时会重绘按钮、复选框、单选按钮、开关、下划线和圆圈;按钮悬停时会浮起,按压时会下沉。
prefers-reduced-motion 会将所有元素冻结为静态草图(包括上方演示图片)。

字体(可选)

Drawably Pen 字体采用与笔触相同的笔迹:包含 a–z、A–Z、数字和标点,由库自身的笔触代码(font/)构建为 31 KB TrueType 字体。它不会通过 style.css 加载;库本身不依赖该字体。若希望标签与界面风格一致:

import "drawably/font.css";  
.drawably-button {  
  font-family: "Drawably Pen", Inter, sans-serif;  
}  

构建自定义形状

粗糙渲染器已导出。每个函数返回 SVG 路径字符串,variants 函数生成沸腾帧序列:

import { roughRoundedRect, roughLine, roughCircle, variants } from "drawably";  
const frames = variants(  
  (o) => roughRoundedRect(0, 0, 200, 100, 12, o),  
  { seed: 7, roughness: 1, boil: 0.3 },  
); // 三个路径字符串——渲染它们并循环透明度  

同时导出:roughEllipseroughArrowroughCheckmarkscribbleFill,以及带种子的 PRNG mulberry32randomSeed

许可证

MIT。

相似文章

Drawsy

Product Hunt

Drawsy 是一个集成画布与代码的 AI 工作空间,用于创意和开发任务。

DayuanJiang/next-ai-draw-io

GitHub Trending (daily)

Next AI Draw.io 是一个开源的 Next.js 网页应用,它集成了 AI 能力与 draw.io,通过自然语言命令来创建和修改图表。该应用支持多个大型语言模型提供商,并提供在线演示。

Canvas 中的 HTML 演示

Hacker News Top

来自 Chrome DevRel 团队的 CSS 和 Web UI 演示合集,包括 Canvas 中的 HTML 演示。