Skip to content

VitePress 组件、样式自定义方法

替换内部组件

使用 Vite 的 aliases 别名来自定义组件替换默认主题的组件。具体参考 Vite 官方文档

这里以替换主页的 Features 组件部分为例。要做到这一点,需要两步。

  • 在配置文件 ./vitepress/config.mts 中声明
  • 读取 .md 文档数据并编写自定义组件

声明替换组件

find 字段通过正则匹配内置组件名,要找到想要替换的组件名,可以用开发工具查看。

replace 字段中要填写自定义组件的路径.。

ts
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vitepress'

export default defineConfig({
  vite: {
    resolve: {
      alias: [
        {
          find: /^.*\/VPHomeFeatures\.vue$/,
          replacement: fileURLToPath(
            new URL('./components/CustomNavBar.vue', import.meta.url)
          )
        }
      ]
    }
  }
})

编写自定义组件

编写自定义组件需要导入 markdown 页面数据并渲染。

vue
<script setup lang="ts">
import { useData } from "vitepress"
// 读取 vitepress md 页面数据
const { page, frontmatter } = useData()
</script>

除此以外要注意很多 Vue 函数和钩子需要自己导入,不能直接使用。

覆盖CSS属性

新建docs\.vitepress\theme\custom.css,在其中键入对应规则和属性即可。

TIP

需要注意的是,构建过程会为每个样式生成对应的哈希后缀,所以要给每个规则后加上一个!important,否则无法覆盖原本存在的规则。

以下是一个示例。

css
/* .vitepress/theme/custom.css */
/* 自定义的 主题样式,用于扩展默认主题 */

:root {
  --vp-c-brand-1: rgb(91, 193, 234);
  --vp-c-brand-2: pink;
  --vp-c-brand-3: rgb(91, 193, 234);

  /* 第一行字体 */
  --vp-home-hero-name-color: transparent;
  --vp-home-hero-name-background: -webkit-linear-gradient(
    120deg,
    #12c2e9 0%,
    #c471ed 50%,
    #f64f59 100%
  );
}

修复滚动条导致的页面横向布局闪烁

参考:

滚动条的宽度就会挤压容器的内容区域宽度

盒子模型中,当由于overflow: scroll;或者overflow: auto;产生右侧的滚动条时,这个盒子的内容区域宽度会被挤压而减小。从而导致这个盒子中的元素整体往左移一小段距离。

在 VitePress 开发的页面中,当通过侧边栏在无滚动条有滚动条的两个页面之间切换时,侧边栏和顶部导航栏就会产生非常明显的左右闪烁现象!

分析

在开发者工具中找到侧边栏元素组件。可以看到其实现响应式布局的方式是通过百分比单位和calc()实现的。

css
@media (min-width: 1440px) {
    .VPSidebar[data-v-c847dbc6] {
        padding-left: max(32px, calc((100% -(var(--vp-layout-max-width) - 64px)) / 2));
        width: calc((100% -(var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px);
    }
}

而问题就在这个100%上,这会获取其父元素内容区域的宽度,层层往上,最终获得的是body元素上的宽度,而这个宽度又和滚动条有关:当滚动条出现时,body元素的内容宽度会减小。

所以,这最终导致100%代表的数值减小,引起左右闪烁现象。

解决

在 VitePress 中,这个100%最终追溯到了body元素上,所以我们需要的值其实应该是整个视口的宽度。所以,在所有通过百分比单位计算宽度和边距的组件中直接用100vw来代替就可以解决这个问题。

以下是具体实现。

css
/* .vitepress/theme/custom.css */
@media (min-width: 768px) {
  .VPContent {
    width: 100vw !important;
  }
  .VPFooter {
    width: 100vw !important;
  }
  .VPLocalNav {
    width: 100vw !important;
  }
  .VPNav {
    width: 100vw !important;
  }
}

@media (min-width: 1440px) {
  .VPSidebar {
    padding-left: max(
      32px,
      calc((100vw - (var(--vp-layout-max-width) - 64px)) / 2)
    ) !important;
    width: calc(
      (100vw - (var(--vp-layout-max-width) - 64px)) / 2 +
        var(--vp-sidebar-width) - 32px
    ) !important;
  }
}

Released under the GNU General Public License v3.0.