Jamdesk Documentation logo

自定义 CSS/JavaScript 示例

使用 CSS 和 JavaScript 自定义页眉与品牌,并添加悬浮式 Ask AI 按钮,确保 Jamdesk 更新后仍能正常运行。

本页将在名为 Harbor 的演示站点上构建一个示例:为页眉添加 Harbor 的徽标、品牌色和两个额外链接,并在右下角放置一个悬浮的 Ask AI 按钮。你可以直接复制这些文件,再换成自己的徽标和颜色。

屏幕截图显示的是英文界面。

文档站点的深蓝色页眉,下方有一条橙色线,配有胶囊形的 Search 和 Ask AI 按钮,右下角有一个橙色 Ask AI 按钮

此页眉有哪些不同之处

默认情况下,Jam 页眉会融入页面背景。浅色模式下,页眉是透明的,可以看到后方柔和的渐变;深色模式下,页眉则与页面其他部分一样,呈近黑色。按钮的圆角略微圆润。Harbor 版本做了四处调整:

  • 浅色和深色模式下都使用深蓝色背景,让页眉从页面中凸显出来。
  • 底边添加了一条细橙线。
  • 搜索框、Ask AI 和 Book a demo 都改为全圆角胶囊形。
  • 使用 Harbor 的白色徽标替换默认徽标。

这些更改只涉及 CSS 和一个徽标文件,不会修改 Jamdesk 的页眉本身,因此搜索、Ask AI、主题切换器和移动端菜单仍会照常工作。

示例会用到项目中的这些文件:

harbor-docs/
├── docs.json              ← logo, header links and brand colors
├── style.css              ← header and button styles
├── script.js              ← creates the Ask AI button
└── images/
    └── harbor-logo.svg    ← white logo for the navy header

从 docs.json 开始

第一步不需要编写代码。徽标、颜色、页眉链接和 Book a demo 按钮都在 docs.json 中设置:

docs.json
{
  "logo": {
    "light": "/images/harbor-logo.svg",
    "dark": "/images/harbor-logo.svg"
  },
  "colors": {
    "primary": "#C2410C",
    "light": "#D9480F",
    "dark": "#9A3412"
  },
  "navbar": {
    "links": [
      { "label": "Blog", "href": "https://example.com/blog" },
      { "label": "Status", "href": "https://example.com/status" }
    ],
    "primary": {
      "type": "button",
      "label": "Book a demo",
      "href": "https://example.com/demo"
    }
  }
}

徽标是白色的。由于浅色和深色模式下的页眉都是深蓝色,同一个文件可以用于两种模式。

Jamdesk 会将你的 primary 颜色用于 Book a demo 按钮、当前选中的侧边栏项目和链接,因此橙色会贯穿整个站点。深色模式则使用 light 颜色。请确保颜色足够深,让按钮上的白色文字仍然清晰易读。所有导航栏选项请参阅导航链接。

在将徽标放在页眉中的主题(Jam、Nebula、Halo 和 Dusk)里,导航栏链接会在平板和桌面屏幕宽度下显示在页眉中。在手机上,这些链接会移入菜单,因此下方的页眉样式不会作用于它们。Pulsar 会将徽标放在侧边栏中,桌面端没有页眉栏,因此下方的页眉样式在该主题中不会显示。

设置页眉样式

页眉的文字、边框、搜索框和圆角都由 CSS 变量控制。在页眉内部设置这些变量,就只会更改页眉:

style.css
/* header[data-has-tabs] matches the site header only.
   A plain `header` selector would also match the title
   block at the top of every page. */
header[data-has-tabs] {
  --header-top: #0f1d3a;
  --header-bottom: #1b2f5b;
  --header-stripe: #f97316;
  --color-text-primary: #ffffff;
  --color-text-secondary: #cbd5e1;
  --color-text-tertiary: #cbd5e1;
  --color-text-muted: #94a3b8;
  --color-bg-primary: #0f1d3a;
  --color-bg-secondary: rgba(255, 255, 255, 0.08);
  --color-bg-hover: rgba(255, 255, 255, 0.16);
  --color-border: rgba(255, 255, 255, 0.16);
  /* Rounds the search box, Ask AI and buttons into pills */
  --radius-md: 999px;
  --radius-lg: 999px;
}

html.dark header[data-has-tabs] {
  --header-top: #0a1328;
  --header-bottom: #13234a;
  --color-bg-primary: #0a1328;
}

/* Some themes keep the header background transparent on
   purpose, so paint the color on a layer behind it. */
header[data-has-tabs]::before {
  content: "";
  position: absolute;
  inset: 0 -24px; /* reach past the 16-24px page gutter */
  z-index: -1;
  background: linear-gradient(
    90deg, var(--header-top), var(--header-bottom)
  );
  border-bottom: 3px solid var(--header-stripe);
}

/* The sparkle icon uses the accent color, which is hard to
   see on navy, so give it the stripe color instead */
header[data-has-tabs] .fa-sparkles {
  color: #fdba74;
}

深蓝色背景设置在 ::before 伪元素层上,因为 Jam 主题使用 !important 将页眉的 background 设为 none。在页眉上设置普通的 background 规则会被覆盖。这个伪元素层位于页眉内容后方,可用于所有主题。

将 --radius-md 和 --radius-lg 设为 999px,即可将页眉中的按钮变成胶囊形。由于更改仅作用于 header[data-has-tabs],页面上的卡片和代码块仍保留原有圆角。

页眉中的 Ask AI 图标使用强调色,在深蓝色背景上不够显眼。最后一条规则会将它改为浅橙色。

深色模式下,Jamdesk 会为 <html> 添加 dark 类,因此 html.dark 代码块会让深色模式下的深蓝色稍微暗一些:

同一个文档站点的深色模式界面,页眉为稍暗的深蓝色,角落里有橙色 Ask AI 按钮

添加悬浮的 Ask AI 按钮

脚本会向页面添加一个普通的 <button>。点击按钮时,它会发送 Ctrl+I,也就是打开或关闭聊天面板的键盘快捷键,因此效果与页眉中的 Ask AI 按钮相同。

script.js
(function () {
  if (document.getElementById('ask-ai-fab')) return;

  var button = document.createElement('button');
  button.id = 'ask-ai-fab';
  button.type = 'button';

  // Jamdesk loads Font Awesome, so its icons are available here
  var icon = document.createElement('i');
  icon.className = 'fa-solid fa-sparkles';
  icon.setAttribute('aria-hidden', 'true');
  button.append(icon, ' Ask AI');

  button.addEventListener('click', function () {
    // Same as pressing Ctrl+I / Cmd+I: toggles the chat panel
    var shortcut = { key: 'i', ctrlKey: true, bubbles: true };
    document.dispatchEvent(new KeyboardEvent('keydown', shortcut));
  });

  document.body.appendChild(button);
})();

接着,将按钮样式添加到 style.css:

style.css
#ask-ai-fab {
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: 40; /* below the header, search and mobile menu */
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: #c2410c;
  color: #fff;
  font: inherit;
  font-weight: 600;
  box-shadow: 0 6px 20px rgba(15, 29, 58, 0.25);
  cursor: pointer;
}

#ask-ai-fab:hover {
  background: #9a3412;
}

#ask-ai-fab:focus-visible {
  outline: 2px solid #f97316;
  outline-offset: 2px;
}

/* Hide the button while the chat panel is open. On mobile
   the closed panel stays in the page with data-open="false",
   so exclude that case. */
body:has([data-chat-panel]:not([data-open="false"])) #ask-ai-fab {
  display: none;
}

@media (max-width: 767px) {
  #ask-ai-fab {
    right: 16px;
    bottom: 16px;
  }
}

在手机上,按钮距离屏幕边缘 16px。聊天面板打开时会覆盖屏幕的大部分区域,按钮也会隐藏,直到面板关闭:

手机屏幕宽度下的文档站点界面,页眉为深蓝色,右下角有橙色 Ask AI 按钮

要使用此按钮,必须启用 AI 聊天。如果 docs.json 中的 chat.enabled 为 false,点击按钮不会有任何反应,因此请勿在这种情况下添加按钮。

如果你还使用 Crisp 或 Intercom 等客服小组件,它们可能也位于右下角。为避免重叠,可以在 #ask-ai-fab 中使用 left: 24px 替代 right,也可以增大 bottom 的值,让按钮显示在小组件上方。

每次页面更改后运行代码

访客首次打开站点时,脚本会运行一次。之后,点击文档中的链接会切换页面内容,但不会重新加载页面,因此脚本不会再次运行。Ask AI 按钮不受影响,因为它挂载在 <body> 上,而 <body> 会一直保留。

如果代码需要读取或更改页面内容,就需要知道页面何时发生变化。下面的代码片段会监视主栏,并检查 URL 是否发生变化。将它放在同一个 script.js 文件中,置于按钮代码之后:

script.js
(function () {
  var lastPath = location.pathname;
  var main = document.getElementById('main-content') || document.body;

  function onPageChange() {
    // Your per-page code goes here
    console.log('Now on', location.pathname);
  }

  new MutationObserver(function () {
    if (location.pathname === lastPath) return;
    lastPath = location.pathname;
    onPageChange();
  }).observe(main, { childList: true, subtree: true });
})();

每进入一个新页面,onPageChange 就会运行一次,无论访客是点击侧边栏链接、使用搜索,还是按下浏览器的后退按钮。

可用的选择器

Jamdesk 的类名来自 Tailwind,可能会在任何版本中发生变化。按钮标签也会变化,因为多语言站点会翻译这些标签。请改用以下选择器:

SelectorMatches
html.dark深色模式开启时的页面
body[data-theme="jam"]当前使用的主题,按名称区分(jam、nebula、pulsar、halo、dusk)
header[data-has-tabs]站点页眉
#main-content主栏,包括页面和目录
#content-scroll-container页面内容栏
article .prose当前页面的正文
[data-chat-panel]AI 聊天面板
[data-theme-toggle]浅色/深色/系统模式切换器
body[data-jd-ready="true"]首个页面加载完成后设置

不要将 Jamdesk 自带的元素移到其他容器中,也不要用脚本隐藏这些元素。访客浏览页面时,Jamdesk 会重新绘制页面的部分内容,因此移动后的元素可能会跳回原位或导致导航异常。请像 Ask AI 按钮那样,将自定义元素添加到 Jamdesk 元素旁边。

测试更改

jamdesk dev 会显示你的 CSS,但不会运行自定义 JavaScript;AI 聊天也只有在发布后的站点上才能使用。要在本地测试脚本,请将它粘贴到预览页面的浏览器控制台中。按钮会显示出来,但发布站点之前无法打开聊天面板。

请在手机屏幕尺寸(宽 375px)和深色模式下检查效果,不要只在桌面端测试。页眉颜色和固定定位的按钮通常会在这些情况下出现问题。

接下来做什么?

自定义 CSS

CSS 文件的存放位置及其加载方式

自定义 JavaScript

脚本加载方式、文件顺序和限制