---
title: 自定义 CSS/JavaScript 示例
description: 为页眉添加品牌标识和配色，并用 CSS 与 JavaScript 添加悬浮的 Ask AI 按钮，让这些自定义内容在 Jamdesk 更新后继续生效。
---

> **For AI agents:** the complete documentation index is at [llms.txt](https://jamdesk.com/docs/llms.txt). Append `.md` to any page URL for its markdown version.

本页以名为 Harbor 的演示站点为例。我们将为页眉添加 Harbor 的标识、配色和两个额外链接，并在右下角放置悬浮的 **Ask AI** 按钮。你可以直接复制这些文件，再换成自己的标识和配色。

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

<Frame>
  <img src="/images/custom-code/branded-header-ask-ai.webp" alt="文档站点的深蓝色页眉，下方有一条橙色横线，带有胶囊形的 Search 和 Ask AI 按钮，右下角有一个橙色 Ask AI 按钮" />
</Frame>

## 此页眉有哪些不同之处

默认情况下，Jam 页眉会与页面融为一体。在浅色模式下，页眉是透明的，可以看到后面的柔和渐变；在深色模式下，页眉则与其他内容一样呈近黑色。按钮的边角略微圆润。Harbor 版本做了四处改动：

- 浅色和深色模式下，页眉都呈深蓝色，因此更醒目。
- 页眉底边加了一条细橙线。
- 搜索框、**Ask AI** 和 **Book a demo** 按钮都采用完整的胶囊形圆角。
- 使用 Harbor 的白色标识替换默认标识。

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

此示例会在项目中使用以下文件：

```bash
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` 中：

```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` 颜色。请确保颜色足够深，让按钮上的白色文字仍然清晰易读。所有导航栏选项请参阅[导航链接](https://jamdesk.com/docs/cn/customization/branding#导航链接)。

<Note>
在将标识放在页眉中的主题（Jam、Nebula、Halo 和 Dusk）里，导航栏链接会在平板和桌面屏幕宽度下显示。Pulsar 会将标识放在侧边栏中，桌面端没有页眉栏，因此下方的页眉样式在 Pulsar 中不会显示。
</Note>

## 设置页眉样式

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

```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` 代码块会让深色模式下的深蓝色再暗一些：

<Frame>
  <img src="/images/custom-code/branded-header-dark.webp" alt="同一文档站点的深色模式视图，页眉的深蓝色稍暗，角落里有橙色 Ask AI 按钮" />
</Frame>

## 添加悬浮的 Ask AI 按钮

脚本会向页面添加一个普通的 `<button>`。点击按钮会发送 <kbd>Ctrl</kbd>+<kbd>I</kbd>，这是打开和关闭聊天面板的键盘快捷键，因此效果与页眉中的 **Ask AI** 按钮相同。

```javascript 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`：

```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。聊天面板打开后会覆盖大部分屏幕，按钮会隐藏，直到面板关闭：

<Frame>
  <img src="/images/custom-code/ask-ai-button-mobile.webp" alt="手机屏幕宽度下的文档站点视图，带有深蓝色页眉，右下角有橙色 Ask AI 按钮" style={{ maxWidth: '375px' }} />
</Frame>

此按钮需要启用 AI 聊天。如果 `docs.json` 中的 `chat.enabled` 为 `false`，点击按钮不会有任何效果，因此请勿添加此按钮。

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

## 每次页面更改后运行代码

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

如果代码需要读取或修改页面内容，就需要检测页面何时发生变化。以下代码段会监听主栏，并检查 URL 是否已更改。将它放在同一个 `script.js` 文件中，接在按钮代码下方：

```javascript 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，可能会在任何一次发布中发生变化。按钮标签也可能改变，因为多语言站点会翻译这些标签。请改用以下选择器：

| Selector | 匹配对象 |
|----------|---------|
| `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"]` | 首个页面加载完成后设置 |

<Warning>
不要将 Jamdesk 自带的元素移到其他容器中，也不要用脚本隐藏它们。访客浏览页面时，Jamdesk 会重新绘制部分页面内容，因此移动元素可能导致它跳回原位或破坏导航。请像 Ask AI 按钮那样，将自己的元素添加在 Jamdesk 元素旁边。
</Warning>

## 测试更改

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

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

## 接下来做什么？

<Columns cols={2}>
  <Card title="自定义 CSS" icon="paintbrush" href="/cn/customization/custom-css">
    CSS 文件的存放位置及加载方式
  </Card>
  <Card title="自定义 JavaScript" icon="code" href="/cn/customization/custom-javascript">
    脚本加载、文件顺序和限制
  </Card>
</Columns>
