代码块是怎么高亮的

技术Astro

代码高亮是在构建时完成的。Astro 内置了 Shiki,你写 ```js 这样的围栏,构建后拿到的就是一段已经上好色的 HTML——浏览器不需要下载任何高亮库,也就不存在闪烁和延迟。

双主题

因为站点支持深浅色切换,代码块也配了两套配色:

// astro.config.mjs
markdown: {
  shikiConfig: {
    themes: { light: 'github-light', dark: 'github-dark-default' },
    defaultColor: false,
    wrap: true,
  },
},

defaultColor: false 会让 Shiki 输出 --shiki-light--shiki-dark 两组 CSS 变量,而不是直接写死颜色。然后在样式表里根据 data-mode 挑一组用:

.astro-code,
.astro-code span {
  color: var(--shiki-light);
  background-color: var(--shiki-light-bg);
}

:root[data-mode='dark'] .astro-code,
:root[data-mode='dark'] .astro-code span {
  color: var(--shiki-dark);
  background-color: var(--shiki-dark-bg);
}

切主题时颜色立刻跟着变,不需要重新渲染代码。

复制按钮

Shiki 不负责复制按钮,那是几行原生 JavaScript 的事:

document.querySelectorAll('pre.astro-code').forEach((pre) => {
  const btn = document.createElement('button');
  btn.className = 'copy-btn';
  btn.textContent = '复制';
  btn.addEventListener('click', async () => {
    await navigator.clipboard.writeText(pre.innerText);
    btn.textContent = '已复制';
  });
  pre.appendChild(btn);
});

pre.innerText 拿到的是渲染后的纯文本,不会带上标签。

各种语言都试试

Python:

from dataclasses import dataclass

@dataclass
class Post:
    title: str
    tags: list[str]

    def is_tagged(self) -> bool:
        return len(self.tags) > 0

Bash:

npm run build
npx wrangler pages deploy dist --project-name=my-home

JSON:

{
  "nickname": "林一",
  "headline": "写字、放歌、换壁纸"
}

行内代码也一样,比如 npm run dev 或者 src/data/profile.json

小提示:Shiki 支持的语言列表很长,写错语言名不会报错,只是不会高亮而已。

0:00 / 0:00