对以键盘操作为优先的用户来说,一旦学会了如何退出 Vim,可能不消多久,便想在肉眼可见之处使用 Vim 的这套模态编辑。多年来,不少软件都内置了 Vim 风格的按键绑定,来迎合这类用户的肌肉记忆。其中,更有一些开发者,决心将 Vim 的这套风格应用至网页浏览器——qutebrowser 便是其中典型。
对应 Vim 这样的模态文本编辑器 (modal text editor),我姑且将 qutebrowser 称作为模态网页浏览器。在聊 qutebrowser 之前,先向从未接触过 Vim 的读者介绍下模态文本编辑器。
A modal text editor can be, as its name implies, in different modes. Depending on the current mode, keys have different effects: in insert mode most keys insert their character in the buffer, as in non-modal editors, but in normal (default) mode, keys have a different effect.
A modal text editor makes all these operations much more accessible, and easier to express. But they are not only about having convenient shortcuts.
—— Why Kakoune
如上所述,在 Vim 这样的模态编辑器中,不同模式下,同一个按键有着不同的行为与意义。即使你从未使用过 Vim,模态亦随处可见:当你切换大写锁定时,或是切换输入法时,你使用的就是一种模态界面。具体到 Vim,在普通模式 (Normal Mode) 下,当你按下 G,其实是执行了一个将光标移到文件末行的命令;而在插入模式 (Insert Mode) 下,你就只是输入了一个 G 罢了。下表是 qutebrowser 与 Vim 在普通模式下一些操作的对比:
| 按键 | Vim | qutebrowser |
| gg | 跳转到文件首行 | 跳转到网页顶部 |
| G | 跳转到文件末行 | 跳转到网页底部 |
| h/j/k/l | 充当方向键使光标在文件内移动 | 作为方向键来滚动网页 |
| Ctrl-f/Ctrl-b | 向下/向上翻一整页内容 | 向下/向上翻一整页内容 |
| d | d 表示 delete,按下 dd 以删除光标所在行的文本 | 按下 d 会关闭当前浏览的标签页 |
| y | y 表示 yank,按下 yy 以复制光标所在行的文本 | 按下 yy 以复制当前网页的链接 |
| . | 重复上一次操作,如再次删除当前行 | 重复上一次操作,如再次关闭页面 |
| u | u 表示 undo,可撤销刚才的操作,如恢复删除的那一行 | 撤销上一次操作,如重新打开之前关闭的标签页 |
| / | 在当前文本文件内进行搜索 | 在当前网页中搜索 |
| :wq | 保存当前文件并退出 Vim | 退出 qutebrowser,下次进入时将重新打开退出前的所有标签页 |


可见,qutebrowser 将网页视作 Vim 中的文本缓冲区 (text buffer),同样的按键在行为上也与 Vim 相贴近。而这样的设计,qutebrowser 并非首创。在介绍 qutebrowser 中的其他模式前,先简要回顾下这类「模态浏览器」的历史。
模态网页浏览器大致可以分为两类:
Vimperator 作为先行者,早已实现了模态浏览器所需的诸多核心功能。但由于宿主浏览器迭代带来的 API 变动,插件的兼容性问题层出不穷。随着 Firefox 从 XUL 转向 WebExtensions,插件所能行使的权限与能力被大幅收紧,导致其在体验上慢慢落后给那些基于 Web 引擎重新开发的模态浏览器。另一方面,如 dwb,luakit 等浏览器大多基于 Webkit 引擎,常常受累于其频发的性能与安全问题。2013 年底,Florian Bruhin 眼见 dwb 渐渐停止维护,便萌生了开发一款与之相似的浏览器的想法。这便是 qutebrowser 项目的开端。
第一次打开 qutebrowser,你面对的可能会是这样的界面。

委婉地讲,模样比较复古。可假使你有 emacs 的使用经验,简陋的默认界面反倒给你自由客制化的信心。请忍耐片刻,在开始配置前,有必要先熟悉下 qutebrowser 中的几个重要模式。(美观起见,之后的截图均采用配置后的样式)

普通模式,即 qutebrowser 的默认模式,也是平时使用最多的一个模式。除了让用户能以尽可能少的按键来浏览网页外,普通模式也充当入口,通过特定的几个按键来切换至其他模式。

普通模式下,除上文提及的用以滚动、关闭页面的一些快捷键外,常用的操作还有:
o后,用户输入网址,网址将在当前页面打开。按键o其实是对 qutebrowser 内建命令 open的绑定。许多命令都支持额外的参数,如 O(大写)被默认绑定至open -t,意为将网址在新标签页中打开。H / L在当前页面进行回退或前进。使用 r (reload)K / J切换至上一个或下一个标签页。
qutebrowser 中,默认标签页的格式为 favicon + index + pagetitle。我们可以使用 Alt + 数字来切换至对应 index 的标签页,也可用数字 + d 来关闭对应的标签页。
在普通模式下,当按下 :,我们便进入了命令模式。其中,最重要的命令是help,用以查询其他命令或配置项的文档。另一个重要的命令是spawn,用以唤起外部程序配合 qutebrowser 使用,比如使用 mpv 来播放页面中的视频。

大多数重要的命令都有其默认绑定。我会在之后介绍修改按键绑定的方法。
默认设置下,当你点击网页中的某个输入框时,你便进入了插入模式。你也可以在普通模式下按下i主动进入该模式。与传统浏览器中的输入体验不同,qutebrowser 允许你在插入模式下调用外部的编辑器进行文本操作。当你保存并退出编辑器后,编辑过的文本会直接回填至网页的输入框内。这意味着你可以在输入过程中使用你编辑器里的纠错、补全、甚至 AI 相关的功能。
浏览网页时,最常见的一种操作便是用鼠标点击打开网页上的某个链接。提示模式则让你仅通过键盘来完成此操作。

如上图所示,在普通模式下按 f 进入提示模式,接着按下页面上提示的字母,便可访问其对应的链接。
一些网页(特别是 PWA 应用)本身会提供一些快捷键,无疑会与 qutebrowser 不同模式下的快捷键相冲突。在普通模式下,按下 Ctrl+v 进入 qutebrowser 的直通模式。该模式下,浏览器将被还原到一种无模式的状态,从而规避这类 Modal Error 的问题。
配置 qutebrowser 一般可采取两种方式:
通过访问 qute://settings进入内建的设置界面进行定制,改动后的值会存入你配置目录下的autoconfig.yml文件中。(访问qute://version来查看自己配置目录的具体位置)

或是直接编辑配置目录下的config.py文件。在 qutebrowser 内,可通过config-edit命令打开该文件。第一次配置时,可用config-write-py --default命令写入默认配置后再进行修改。修改完后,使用config-source命令重载配置文件。
为了方便管理,你可以将配置拆分为多份文件,再在 config.py中使用config.source来导入。
config.load_autoconfig(True)
config.source("conf.d/theme.py")
config.source("conf.d/options.py")
…编辑配置时,使用 config.set或全局对象 c来设置选项:
config.set("tabs.position", "left")
# 等同于
c.tabs.position = "left"使用 config.bind进行按键绑定:
# 在普通模式下将按键组合<Ctrl-h>绑定为命令history
config.bind("<Ctrl-h>", "history")
# 要在其他模式下添加绑定,需指定mode参数。
config.bind("<Ctrl-n>", "completion-item-focus next", mode="command")配置过程中,请多用 :help来查看各命令/选项的文档,用:set和 :bind来查看某选项/某按键绑定在当前设置中的值。你也可以在我这份样例配置的基础上进行修改。

我一度将 qutebrowser 作为主力浏览器使用,但最终还是放弃了它。主要原因如下:
如上所述,QtWebEngine 基于 Chromium,但其目前尚不支持 Web Extensions,这意味着 qutebrowser 用户无法享受 Chrome 的插件生态。
虽然 qutebrowser 允许你编写 userscripts 对浏览器进行扩展,但一来 userscripts 提供的扩展能力有限,实现的效果往往无法与 Chrome 下的同类插件相比(如 qutebrowser 虽内建有广告屏蔽器,但无法做到如 AdGuard 那样的页面元素级的隐藏);二来自行开发维护所需的插件,也要耗费用户不少精力。
我使用 qutebrowser,源自一次 degoogle 的尝试。qutebrowser 不要求你与任何账户绑定,虽然它没有用户系统,但由于其设置、书签和 userscripts 都是纯文本文件,你可以使用如 git 这样的工具在不同设备间同步它们。遗憾的是,qutebrowser 的缺陷不在于它缺乏必要的功能,而是这些必要的功能实现得太过基础,甚至简陋。
qutebrowser 的书签分为 quickmark 和 bookmark 两种,在功能上两者却并没有本质的差别。新用户常为此困惑,作者也认为应该将两者合并(参见此 Issue),但目前该合并仍未完成。除开不必要的两种书签的问题,qutebrowser 还缺乏对书签文件夹、标签的支持,而这些功能在主流浏览器中都不成问题。
如果说 qutebrowser 的书签功能尚可以通过一些第三方软件(如 linkding 这样的自架服务)来补足的话,管理 qutebrowser 的浏览历史记录则比较灾难了。

如图所示,qutebrowser 的历史页面仅仅显示过往记录,你无法进行勾选,或按浏览时间来批量地删除。qutebrowser 内建的命令history-clear只能删除全部的历史记录,这对任何使用过主流浏览器的用户来说都是难以接受的。
qutebrowser 没有提供页面来显示之前的下载记录,且下载过程中无法暂停。
qutebrowser 不支持标签页分组。它的垂直标签实现也非常基础,没有折叠、树状分页的功能。
对厌倦了种种AI噱头的浏览器用户来讲,qutebrowser 的全键盘交互令人耳目一新。在其核心卖点「模态浏览」上,qutebrowser 的实现相当成熟。但在浏览器应有的基础功能方面,它又显得比较粗糙敷衍。这些缺憾不能归咎给 qutebrowser 的作者,在调校 qutebrowser 期间,我越发感受到现代网页浏览器的庞杂繁复,以至于个人想要驱动这样的项目几乎成了一个无法完成的任务。无奈放弃后,最终我还是选择了一个 Ungoogled Chromium,回过头想,我也许不是那么地讨厌使用鼠标。

> 简单、好用、专注的写作软件,少数派为你呈现 🚀
> 守护孩子的天马行空,从零开始美术教育启蒙 🎨