在 12 月,我发布了 一篇介绍 Firefox 主题 API 的文章。虽然它允许你做很多事情,例如 动画主题、macOS 样式的过度滚动 或 交互式主题编辑器,但 API 有一些限制。与传统的 CSS 主题相比,动态主题 API 的一个问题是,它需要熟悉 JavaScript 和 WebExtension API 才能创建一个基本的动态主题。
为了解决这个问题,我尝试了一个简单的系统,它使用简单的主题“规则”来启用动态主题。“规则”由一个 JavaScript 条件字符串和一个主题名称组成。它在这里:https://github.com/nt1m/theming-rules
此样板代码处理了动态主题所需的所有繁重工作,例如设置 WebExtension 监听器,与其他 API 挂钩,以便让你专注于动态主题部分。
要开始使用,请在本地克隆上面的存储库。所有配置都位于样板代码的 config.js
文件中。打开此文件后,你应该会看到下面的代码
// The default theme: used when no rule is matched
const DEFAULT_THEME = "bright";
// The theming rules: priority is given to the bottom-most rule
const RULES = [
["privatebrowsing", "shady"],
["(hour >= 21) || (hour < 9)", "shady"]
];
在这种情况下,“shady”主题在晚上 9 点到早上 9 点以及私密标签页中使用。在所有其他情况下,使用“bright”默认主题。
让我们使用更复杂的示例编辑 config.js
文件
// The default theme: used when no rule is matched
const DEFAULT_THEME = "bright";
// The theming rules: priority is given to the bottom-most rule
const RULES = [
["privatebrowsing", "shady"],
["(hour >= 21) || (hour < 9)", "shady"],
["privatebrowsing && ((hour >= 21) || (hour < 9))", "bright"]
];
你能猜出这是做什么的吗?
这里有一个提示:规则具有“优先级”的概念,如果多个规则匹配,则使用最底部的规则。
在这种情况下,“bright”主题在白天和夜间私密窗口中使用。“shady”主题在夜间和白天私密窗口中使用。呼!
你可以使用多个属性,这是一个列表
- inactive_window(非活动窗口)
- privatebrowsing(隐私浏览)
- container(容器)
- domain(域名)
- protocol(协议)
- year(年份)
- month(月份)
- date(日期)
- day(星期几)
- hour(小时)
- minutes(分钟)
- seconds(秒)
稍后在本文中,我将展示如何定义自己的属性。
至于前面示例中使用的“bright”和“shady”主题,它们以标准的 WebExtension 主题格式定义,也在 config.js
文件中
const THEMES = {
bright: {
colors: {
frame: "#dedede",
tab_background_text: "#000",
toolbar_text: "#000",
toolbar: "#f8f8f8",
}
},
shady: {
colors: {
frame: "#000",
tab_background_text: "#ddd",
toolbar_text: "#ccc",
toolbar: "#3a3a3a"
}
}
};
用例:基于协议设置浏览器样式
现在你已经了解了这个系统,让我们构建一个有用的示例:让我们根据当前标签页是 HTTP 页面还是 HTTPS 页面来设置浏览器的样式。
首先,我们将定义 HTTP 和 HTTPS 主题的外观,我们将对 HTTP 站点使用红色,对 HTTPS 站点使用绿色
insecure: {
colors: {
frame: "red",
tab_background_text: "black",
toolbar: "pink",
toolbar_text: "black"
}
},
secure: {
colors: {
frame: "green",
tab_background_text: "white",
toolbar: "lightgreen",
toolbar_text: "black"
}
}
现在让我们定义规则
// The default theme: used when no rule is matched
const DEFAULT_THEME = "bright";
// The theming rules: priority is given to the bottom-most rule
const RULES = [
["protocol == 'http:'", "insecure"],
["protocol == 'https:'", "secure"]
];
…就是这样!请注意“bright”是如何作为默认主题保留的。这是因为存在其他协议(例如 file://
),在这种情况下,扩展程序会应用中性主题。
示例如下所示
添加更多属性
你可能已经注意到了特殊的 privatebrowsing
、hour
和 protocol
关键字。它们是内置属性,并以此方式定义
privatebrowsing: {
type: "boolean",
async get(tab) {
return tab.incognito;
}
},
protocol: {
type: "string",
async get(tab) {
return new URL(tab.url).protocol;
}
},
hour: {
type: "integer",
async get(tab) {
return (new Date(Date.now())).getHours();
}
}
每个属性定义都采用 WebExtension Tab
对象(你可以选择忽略它),并从中返回一个值。
所有内置属性定义都可以在 properties.js
文件 中找到。
如果你想添加自己的属性怎么办?添加属性就像添加属性定义一样简单。这是一个使用 cookies API 返回当前标签页域名的 Cookie 数量的示例
cookies: {
type: "integer",
async get(tab) {
let cookies = await browser.cookies.getAll({
domain: new URL(tab.url).hostname
});
return cookies.length;
}
}
它可以用来根据 Cookie 数量以不同的方式设置标签页的样式。
属性定义非常灵活,一些想法可能是拥有一个通过 XHR 返回当前天气的属性,或者页面上的跟踪器数量。唯一的限制是你的想象力 :)
试一试!
无论你需要一种非常简单的方法来创建不需要深入了解 WebExtension API 的动态主题,还是仅仅一种快速原型化上下文 UI 功能的方法,这都是适合你的工具!
使用此系统有很多可能性,看看你能想出什么将会很棒。
这是存储库:https://github.com/nt1m/theming-rules。
欢迎在下面的评论中或通过 Github 问题分享你的经验。
编辑(2019 年 7 月 21 日):更新了代码示例以删除 已弃用的主题属性
关于 Tim Nguyen
我从事 Web 浏览器的工作。
2 条评论