从功能强大的扩展程序,如 Stratiform 或 FT Deep Dark,到简单的 轻量级主题,主题在 Firefox 中一直很受欢迎。现在 Firefox Quantum (57) 已经发布,它带来了许多性能改进和闪亮的全新界面,我们希望通过一个新的主题 API 来弥合差距,该 API 允许你超越基本的轻量级主题。
演示者 John Gruen
你能主题化什么?
在 Quantum 发布之前,轻量级主题有一组有限的属性可以主题化:你只能添加一个标题图片并设置框架文本颜色和背景颜色。新的主题 API 引入了一些新属性。完整的列表可以在 MDN 上找到。一个基本的 Theme
对象如下所示
{
"images": {
"theme_frame": ""
},
"colors": {
"frame": "tomato",
"tab_background_text": "white",
"toolbar": "#444",
"toolbar_text": "lightgray",
"toolbar_field": "black",
"toolbar_field_text": "white"
}
}
以下是上面主题的显示方式
注意 images.theme_frame
属性是如何被设置为一个空字符串的。这是因为它属于三个强制属性之一:images.theme_frame
、colors.frame
和 colors.tab_background_text
。(编辑:这些属性在最近的版本中已变为可选)
最后,轻量级主题的另一个改进是支持使用 images.additional_backgrounds
字段的多张标题图片,该字段接受一个图像路径数组。这些图像的对齐方式和平铺方式是通过 properties.additional_backgrounds_alignment
和 properties.additional_backgrounds_tiling
实现的,它们分别接受一个 background-position
和 background-repeat
值数组。你可以查看 MDN 页面以获取示例。可以使用多个背景,以便在浏览器 UI 两侧显示窗帘,或者作为在 UI 中添加多个主题指示器(体育/天气/私人浏览)的一种方式。
动态主题
假设你想要在主题中引入夜间模式。动态主题允许你做到这一点。它们拥有普通浏览器扩展程序的全部功能。要使用动态主题,你需要在你的清单中添加 theme
权限。
<a href="https://mdn.org.cn/en-US/docs/Mozilla/Add-ons/WebExtensions/API/theme/update">browser.theme.update()</a>
方法是这种主题的核心。它接受一个 Theme
对象作为参数。该方法可以在你的后台脚本中的任何位置调用。
对于这个例子,让我们创建一个扩展程序,根据是白天还是黑夜来切换主题。第一步是在你的后台脚本中创建一个函数,将你的主题切换到白天主题或黑夜主题
var currentTheme = '';
const themes = {
'day': {
images: {
theme_frame: 'sun.jpg',
},
colors: {
frame: '#CF723F',
tab_background_text: '#111',
}
},
'night': {
images: {
theme_frame: 'moon.jpg',
},
colors: {
frame: '#000',
tab_background_text: '#fff',
}
}
};
function setTheme(theme) {
if (currentTheme === theme) {
// No point in changing the theme if it has already been set.
return;
}
currentTheme = theme;
browser.theme.update(themes[theme]);
}
上面的代码定义了两个主题:白天主题和黑夜主题,setTheme
函数然后使用 browser.theme.update()
来设置主题。
下一步是使用这个 setTheme
函数,并定期检查扩展程序是否应该切换主题。你可以使用闹钟 API 来实现。下面的代码定期检查并相应地设置主题
function checkTime() {
let date = new Date();
let hours = date.getHours();
// Will set the sun theme between 8am and 8pm.
if (hours > 8 && hours < 20) {
setTheme('day');
} else {
setTheme('night');
}
}
// On start up, check the time to see what theme to show.
checkTime();
// Set up an alarm to check this regularly.
browser.alarms.onAlarm.addListener(checkTime);
browser.alarms.create('checkTime', {periodInMinutes: 5});
这就是这个例子!完整的示例可以在webextension-examples github 仓库中找到。
另一个例子中没有涵盖的方法是 <a href="https://mdn.org.cn/en-US/Add-ons/WebExtensions/API/theme/reset">browser.theme.reset()</a>
。这个方法只是将主题重置为默认的浏览器主题。
每个窗口的主题
动态主题 API 非常强大,但是如果你需要为私人窗口或非活动窗口应用不同的主题怎么办?从 Firefox 57 开始,就可以为 <a href="https://mdn.org.cn/en-US/Add-ons/WebExtensions/API/theme/update">browser.theme.update()</a>
和 <a href="https://mdn.org.cn/en-US/Add-ons/WebExtensions/API/theme/reset">browser.theme.reset()</a>
指定一个 windowId
参数。windowId
是由windows API 返回的相同 ID。
让我们做一个简单的例子,将一个深色主题添加到私人窗口,并将其他窗口设置为默认主题
我们首先定义 themeWindow
函数
function themeWindow(window) {
// Check if the window is in private browsing
if (window.incognito) {
browser.theme.update(window.id, {
colors: {
frame: "black",
tab_background_text: "white",
toolbar: "#333",
toolbar_text: "white"
}
});
}
// Reset to the default theme otherwise
else {
browser.theme.reset(window.id);
}
}
完成之后,我们可以使用 windows API 将其连接起来
browser.windows.onCreated.addListener(themeWindow);
// Theme all currently open windows
browser.windows.getAll().then(wins => wins.forEach(themeWindow));
非常直观吧?完整的示例可以在这里找到。以下是该示例的外观
另一个使用这些功能的附加组件是 Jonathan Kingston 的 Containers 主题,它将每个窗口的主题设置为其所选标签的容器。该附加组件的源代码可以在这里找到。
VivaldiFox 附加组件 也使用此功能在不同的窗口中显示不同的网站主题
获取有关当前主题的信息
从 Firefox 58 开始,你现在可以获取有关当前主题的信息并监视主题更新。以下是这为什么重要的原因
这允许附加组件将它们的界面与用户当前安装的主题无缝集成。一个例子是将你的侧边栏标签颜色与你当前主题的颜色相匹配。
为此,Firefox 58 提供了两个新的 API:<a href="https://mdn.org.cn/en-US/Add-ons/WebExtensions/API/theme/getCurrent">browser.theme.getCurrent()</a>
和 <a href="https://mdn.org.cn/en-US/Add-ons/WebExtensions/API/theme/onUpdated">browser.theme.onUpdated</a>
。
以下是一个简单的示例,将一些当前主题属性应用于sidebar_action 的样式
function setSidebarStyle(theme) {
const myElement = document.getElementById("myElement");
// colors.frame and colors.accentcolor are aliases
if (theme.colors && (theme.colors.accentcolor || theme.colors.frame)) {
document.body.style.backgroundColor =
theme.colors.accentcolor || theme.colors.frame;
} else {
document.body.style.backgroundColor = "white";
}
if (theme.colors && theme.colors.toolbar) {
myElement.style.backgroundColor = theme.colors.toolbar;
} else {
myElement.style.backgroundColor = "#ebebeb";
}
if (theme.colors && theme.colors.toolbar_text) {
myElement.style.color = theme.colors.toolbar_text;
} else {
myElement.style.color = "black";
}
}
// Set the element style when the extension page loads
browser.theme.getCurrent().then(setSidebarStyle);
// Watch for theme updates
browser.theme.onUpdated.addListener(async ({ theme, windowId }) => {
const sidebarWindow = await browser.windows.getCurrent();
/*
Only update theme if it applies to the window the sidebar is in.
If a windowId is passed during an update, it means that the theme is applied to that specific window.
Otherwise, the theme is applied globally to all windows.
*/
if (!windowId || windowId == sidebarWindow.id) {
setSidebarStyle(theme);
}
});
完整的示例可以在Github 上找到。正如你在下面的截图中看到的那样,侧边栏使用了当前应用的浏览器主题的颜色
另一个例子是Tree Style Tab 附加组件,它使用了这些 API 来将它的界面与当前使用的主题集成。以下是一个演示该附加组件与 VivaldiFox 一起工作的视频
下一步是什么?
这个 API 还有更多功能!我们计划扩展支持的属性集,并完善主题应用方式周围的一些粗糙边缘。API 的跟踪错误可以在 Bugzilla 上找到。
同时,我们迫不及待地想看看你能用新的主题 API 做些什么。请告诉我们你希望看到哪些改进。
编辑(2019 年 7 月 21 日):更新的代码示例删除了已弃用的主题属性
关于 Tim Nguyen
我在 Web 浏览器方面工作。
17 条评论