Nuxt4编写WebTui主题小结
Outline

设计元素选取

本来我设想的设计元素是仿niriTUI。我希望采用卡片设计,平铺的一个个窗口本身就是一个个卡片。niri作为新兴的滚动式平铺布局有较高的热度,所以我选择了仿niri。 但之后在纸鹿大佬的文章中,提到用户有自己习惯的浏览方式,这种自作聪明的方式只会让用户感到不舒服,于是我放弃了仿niri

::share-card

content: 谈谈不受欢迎的博客技术特征 url: https://blog.zhilu.site/2025/unpopular-blog-tech author: 纸鹿本鹿 website: 纸鹿摸鱼处 img: https://www.zhilu.site/api/avatar.png


::

这是我写了一半的仿niri布局组件,由于不再需要它,暂时搁置了。

vue-candle
2026/2/19
 0 0 0
Mr.Lee
avatar
暂无描述
 0 0 0
2026/2/19

我早期是写era basic的, 作为一个写文字黄油的,所以你搞仿Gal交互是干啥的?纯粹吸引人眼球的吗? 我觉得TUI的设计元素更适合我博客的内容。 由于缺乏设计经验,我也不知道怎么设计TUI的风格,导致上个项目写的是个半吊子... 后来找到了WebTUI CSS这个开源项目,借鉴了它的设计,确保了我能够写出来TUI风格。感谢WebTui项目!

webtui
2026/2/20
 2.3k 0 41
WebTUI
avatar
暂无描述
 2.3k 0 41
2026/2/20

因此,我选择了完全拥抱TUI的设计元素,放弃了仿niri的设计元素。

框架选择

作为只会写 Vue 的开发者,Nuxt4是我唯一的选择了。 我之前经验不足对于Nuxt4的刻板印象是只能做ssr,我也没啥服务器做ssr...之后发现ssg也就是ssr渲染进行与渲染,二者没啥区别。 于是我开始了Nuxt4的探索之路。 ssr好香...原来找一个托管商就行了

Nuxt4不仅有高质量的文档,同时也有比较优秀的插件。本博客使用了以下插件。

  • color-mode:提供了高度自定义化的暗黑模式和亮色模式的切换功能。
  • content: 提供了强大的Markdown解析和内容管理功能,支持多种Markdown扩展语法。
  • mdc: 用于在没有Markdown文件的情况下渲染Markdown片段。
  • remark-reading-time: 这是nuxt content的一个插件,用于计算Markdown内容的阅读时间。

得益于这些丰富的插件,使我的开发效率得以提升。

样式编写

不要使用过于艳丽的图片

过于艳丽的图片

我的博客是基于TUI设计元素的,存在大量的文本/字符堆砌,高文字密度是不可避免的。 过于艳丽的图片本身也是一种高信息密度,会导致用户难以抓住重点,整体看上去非常乱。

避免使用高饱和度颜色

新人画画画白脸都喜欢给脸涂个接近#ffffff的颜色,然后没法画高光了。这里的饱和度也一样。 上来就用高饱和度,不仅无法凸显重点,还会上述的过于艳丽的图片一样,导致整体看上去非常乱。下图就是一个例子

高饱和度hsl调色

使用oklch调色

oklch是一种基于人类视觉感知的颜色空间,能够更准确地表示颜色的亮度、色相和饱和度。 传统的hsl调色只是相对于机器而言,在某些值的颜色,它根本没有一个定义,导致就算亮度设置为相同的值,也会导致有着亮度差异。

参照上方高饱和度hsl调色调色的图,可以看出绿色是明显比紫色要亮一些的。 使用oklch调色可以解决这个问题,确保不同颜色之间的亮度一致,从而提升整体的视觉体验。 但oklch也不是万能的,没有定义的颜色会回落到周围的颜色,导致颜色有偏差。 下面的网站是oklch的在线调色工具,可以用它来确认可用的区域范围,同时上面也有详细的oklch的使用方法。

::share-card

content: 'OKLCH 颜色选择器和转换器' url: 'https://oklch.net/zh-CN' author: '' website: 'OKLCH 颜色选择器' img: 'https://oklch.net/favicon.ico'


::

我们可以发现,上述的避免使用高饱和度颜色还有个好处,它的颜色定义范围更广。

WebTui的编写

如果没有特殊要求,建议直接使用WebTUI CSS这个开源项目的样式,毕竟它是专门为WebTUI设计的。 我设计早期,由于有透明背景的需要,它的Box标题是依靠填充背景颜色来实现的,不兼容透明背景,于是自己开始瞎折腾了。

绪论

WebTUI的官方主页对WebTui主题的样式设计有详细的说明和示例。

::share-card

content: 'TUIs vs GUIs' url: 'https://webtui.ironclad.sh/start/tuis-vs-guis/' author: 'webtui' website: 'WebTUI' img: 'https://webtui.ironclad.sh/logo.svg'


::

最主要的有两个地方:

  • 使用Monospace字体来保持文本的对齐和一致性。
  • 使用chlh基于字体大小的单位来设置元素的宽度和行高。

Tui是基于终端显示的,它最小单元就是一个字符。要想做到Tui的感觉,就不能使用px,mm等单位了。必须使用chlh等基于字体大小的单位来设置元素的宽度和行高。 终端由于排版需要,字体都是等宽的,但浏览器上并不是所有字体都是等宽的,我们需要使用Monospace字体,也就是等宽字体。 Monospace每个字符占用相同的水平空间,这样可以确保文本的对齐和一致性。

实用技巧

字体

字体推荐选择Nerd Font,我之前有介绍过,它是专门为终端设计的字体,包含了大量的图标和符号,不需要额外安装图标库里。

里世界
Mr.Lee
avatar在Web中使用NerdFont

突出重点

TUI中字体大小是固定的,无法通过字号来凸显重点。但我们还可以通过饱和度和颜色来进行区分。

方框绘制

善用::before::after伪元素+border来实现边框。尽管在真正的TUI中,是使用制表字符来实现边框的,但我们可以通过border手动绘制。 只要尺寸看着和一个一个字符组成,视觉效果就和制表字符差不多。

仿Vim选中高亮

点击本博客的任意标题,你可以看到第一个字被选中高亮的效果。这是通过::highlight来实现的。 ::highlight是一个可以通过代码选择自定义文字片段来施加额外样式的选择器。

::share-card

content: 'Highlight | Web API | MDN' url: 'https://developer.mozilla.org/zh-CN/docs/Web/API/Highlight' website: 'MDN' img: 'https://developer.mozilla.org/favicon.ico'


::

我的具体实现方式如下: 这也是从WebTUI CSS那里偷来的

TypeScript
onMounted(() => {
    watchEffect(applyVimCursorHighlight)
})

function getFirstTextNode(element: Node): Node | undefined {
    if (element.nodeType === Node.TEXT_NODE) return element
    if (!element.hasChildNodes()) return undefined
    for (const child of element.childNodes) {
        const textNode = getFirstTextNode(child)
        if (textNode?.textContent?.trim()) return textNode
    }
    return getFirstTextNode(element.firstChild!)
}

function applyVimCursorHighlight() {
    if (!selected.value) return

    if (!main.value) return

    const textNode = getFirstTextNode(main.value)

    if (!textNode?.textContent?.trim()) return

    const firstNonWhitespace = textNode.textContent.split('').findIndex((c) => !/\s/.test(c)) ?? 0

    const range = new Range()
    range.setStart(textNode, firstNonWhitespace)
    range.setEnd(textNode, firstNonWhitespace + 1)
    CSS.highlights.set('vim', new Highlight(range))
}
Sass
&.selected > *::highlight(vim)
    color: get-color-1()
    background-color: get-color-3-r()

仿Vim栏装饰

下边的这个栏是仿VIM的状态栏设计的,使用了::before伪元素 + clip-path来实现的。 通过clip-path来裁剪出一个斜边的效果,来达到和VIM状态栏差不多视觉效果。 这还是抄WebTUI CSS的

结语

当初编写博客时,找Tui风格的网站找了好久。现在写成了,分享下经验,希望能给其他想要写Tui风格博客的人一些启发。

这个博客前前后后折腾了快一个月的时间...中途多次更换框架,还被研究生抓走干活去了,导致开发进度缓慢。现在还有阅读次数,评论区等功能没有做,后续有机会再完善了。 大四真的好忙,放个假还有这么多事!(╥﹏╥)

本文章采用     CC BY-NC-SA 4.0 协议进行许可。如需转载,请注明出处。
2c6b20c
Post.vue
utf-8
TOP
1:1