Swagger UI 很好用,但默认配色在深夜的屏幕前总显得有点刺眼;而当接口列表变得很长时,滚动回到页面顶端也会变成一种“重复劳动”。
返回顶部按钮带平滑滚动,并对滚动事件做了节流,避免性能抖动。
本文示例基于你现有的三个文件:
-
swagger-ui/SwaggerModule.cs:在 Swagger UI 中注入 CSS 与 JS -
swagger-ui/custom.css:Dracula 深色主题(颜色覆盖)+ 两个按钮样式 -
swagger-ui/theme-toggle.js:主题切换 + 返回顶部(含节流与无障碍属性)
JS 只做两件事:
- 设置
data-theme(并持久化) -
第一步:在 Swagger UI 中注入你的 CSS 与 JS你在
SwaggerModule.cs里做的事情非常直接:在UseSwaggerUI配置中注入静态资源。关键代码如下(保持原样即可):
app.UseSwaggerUI(c =>
{
// ... SwaggerEndpoint 等配置
c.RoutePrefix = "swagger";
// 设置 Swagger UI 支持深色模式
c.InjectStylesheet("/swagger-ui/custom.css");
// 注入主题切换脚本
c.InjectJavascript("/swagger-ui/theme-toggle.js");
});如果你不是用默认的
wwwroot,也可以通过自定义StaticFileOptions将该目录映射到/swagger-ui/。全局背景与文字
-
opblock(并对 GET/POST/PUT/DELETE/PATCH 做了对应的 Dracula 方法色)
-
code block、markdown、modal 等
宗旨:只覆盖颜色,不触碰布局、间距、尺寸,以确保与原始 swagger-ui.css 完美兼容。
这会带来两个直接收益:
- 「升级 swagger-ui 的成本更低」 :DOM 微调时,只要类名还在,颜色就继续生效。
- 「减少视觉抖动与错位」 :布局不动,用户就不会遇到“某些按钮突然飘走”的惊吓。
第三步:JS 让主题“记得你”,也让页面“照顾你”
你的 theme-toggle.js 做得相当完整,核心点有三个:
- 「localStorage 记忆」 (键名为
swagger-ui-theme) - 「系统主题兜底」 (
prefers-color-scheme: dark) - 「按钮注入与无障碍」 (
aria-label/title)
主题切换的关键:给 上 data-theme
function setTheme(theme) {
const html = document.documentElement;
if (theme === "dark") {
html.setAttribute("data-theme", "dark");
} else {
html.removeAttribute("data-theme");
}
localStorage.setItem(THEME_KEY, theme);
updateThemeButtonText(theme);
}
这里的优点是:CSS 只需要关心 [data-theme="dark"],而不用把逻辑散落到各处。
滚动监听为什么要节流?
滚动事件触发频率很高,如果每一帧都执行 DOM 更新,某些机器上容易出现掉帧。
你用一个简单的 throttle 把频率限制在每 100ms 一次:
window.addEventListener("scroll", throttle(handleScroll, 100));
这属于“看不见的性能优化”,但用户会用脚投票。
常见坑位清单(建议收藏)
- 「按钮注入时机」 :Swagger UI 的
.topbar可能不是立刻存在。
- 你通过
querySelector(".topbar") + setTimeout 重试处理了这个问题。
题外话:官方暗黑模式正在路上
值得期待的是:「新版 Swagger UI 已经在上游官方合并了暗黑模式相关的 PR」。等 Swashbuckle.AspNetCore 在后续版本跟进更新 Swagger UI 依赖后,很多项目可能就能“开箱即用”地获得官方暗黑模式支持。
在那之前,这篇文章的方案依然很实用:它侵入性低、可控性强,也便于你按团队审美做微调。
如果你愿意再精致一点,下一步可以考虑:
-
为代码块引入更细腻的语法高亮(在不破坏 swagger-ui 自身样式的前提下)
