VitePress 组件、样式自定义方法
替换内部组件
使用 Vite 的 aliases 别名来自定义组件替换默认主题的组件。具体参考 Vite 官方文档。
这里以替换主页的 Features 组件部分为例。要做到这一点,需要两步。
- 在配置文件
./vitepress/config.mts
中声明 - 读取
.md
文档数据并编写自定义组件
声明替换组件
find
字段通过正则匹配内置组件名,要找到想要替换的组件名,可以用开发工具查看。
replace
字段中要填写自定义组件的路径.。
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 页面数据并渲染。
<script setup lang="ts">
import { useData } from "vitepress"
// 读取 vitepress md 页面数据
const { page, frontmatter } = useData()
</script>
除此以外要注意很多 Vue 函数和钩子需要自己导入,不能直接使用。
覆盖CSS属性
新建docs\.vitepress\theme\custom.css
,在其中键入对应规则和属性即可。
TIP
需要注意的是,构建过程会为每个样式生成对应的哈希后缀,所以要给每个规则后加上一个!important
,否则无法覆盖原本存在的规则。
以下是一个示例。
/* .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()
实现的。
@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
来代替就可以解决这个问题。
以下是具体实现。
/* .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;
}
}