需要在操作系统中更改暗/亮模式以强制刷新外部 SVG 文件

Posted

技术标签:

【中文标题】需要在操作系统中更改暗/亮模式以强制刷新外部 SVG 文件【英文标题】:Need dark/light mode change in OS to force refresh of external SVG files 【发布时间】:2022-01-10 21:34:19 【问题描述】:

我的网站使用了许多外部 SVG 文件,它们在 SVG 文件本身中带有自己的 <style> 元素。我在主网站 CSS 中有暗模式媒体查询在 SVG 文件自己的样式中:@media (prefers-color-scheme:light)@media (prefers-color-scheme:dark)

在初始加载或硬刷新时,一切都按预期工作,网站 CSS 和 SVG CSS 都会根据系统操作系统设置为暗模式还是亮模式来加载适当的样式。

但是,如果我在操作系统中切换模式,只会更新网站 CSS,而不是外部 SVG 文件的 CSS。

所以,我需要硬重新加载缓存的 SVG 图像,或者只是刷新 SVG CSS。

我在 javascript 中设置了一个事件侦听器,可以正确检测操作系统模式更改,但我不知道如何在操作系统暗/亮模式更改时触发 SVG 刷新。我搜索了高低,但不知道如何做到这一点,希望以最简单、最优雅的方式。

window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => 
    // WHAT GOES HERE TO REFRESH SVGs TO CORRECTLY REFLECT OS MODE?
);

window.location.reload(true); 不会硬重新加载缓存文件。我不确定cache.delete 在这里是否合适,或者我将如何使用它来强制重新加载所有 SVG 图像 (<img src="whatever.svg"/>)。也许我忽略了另一种方法。

感谢您的帮助。

【问题讨论】:

Do any of these suggestions help? 是否可以选择将 SVG 作为背景图像?因为如果是这样,您可以使用@media (prefers-color-scheme:light) svgcontainer background-image: url(light.svg); @media (prefers-color-scheme:dark) background-image: url(dark.svg); @PaulLeBeau:我之前看到过,我想弄清楚如何使用 forEach 循环为多个图像实现它。一旦我这样做并测试它,我就会知道在这种情况下缓存破坏器是否有效。 @mrmonsieur:该网站非常庞大且复杂,将大量图标重建为背景图像将是一项艰巨的任务,而且许多图标是由管理员在 CMS 界面中的文本中手工编码的,并且html 需要对他们尽可能简单和用户友好。我需要一个通过 javascript 的解决方案。谢谢。 也许可以使用 Web 组件加载这些 SVG,以便全局 CSS 可以设置它们的样式:dev.to/dannyengelman/… 【参考方案1】:

这就是诀窍,几行 javascript。首先,在页面加载时,识别所有 SVG 图像并确定当前的prefers-color-scheme 主题。然后,检测该主题何时更改,并将动态缓存中断器附加到这些文件名,这会强制 SVG 重新加载。

// Dark mode changes needs cache refresh for external SVG file CSS.
allImg = document.querySelectorAll('img[src$=".svg"');
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) 
  thisMode = 'dark';
 else 
  thisMode = 'light';

window.matchMedia('(prefers-color-scheme: '+ thisMode + ')').addEventListener('change', e => 
  allImg.forEach(img => 
    imgTime = Date.now();
    newImgSrc = img.src + '?' + imgTime;
    img.src = newImgSrc;
  );
);

21 年 12 月 13 日更新了原始答案。现在,强制重新加载 SVG 的 cachebuster 仅在模式更改后调用,而不是在每次页面加载时调用。

21 年 12 月 19 日更新:此解决方案不适用于 Safari(a known bug,其中 Safari 不尊重 SVG 文件 CSS 中的 prefers-color-scheme 媒体查询)。对于 Safari,我编写了额外的 JS,用于在页面加载时检测 Safari,使用上面的 prefers-color-scheme 条件,如果操作系统是暗模式,则将所有 SVG 文件名从“image.svg”替换为“image-dark.svg” ,调用每个 SVG 的浅色或深色版本。当操作系统深色/浅色主题更改时,它还会在 Safari 中重新加载页面。如果 Apple 修复了这个错误,我可以使用上面更简单的解决方案。

【讨论】:

这种方法当然有一个缺点。每个 SVG 将在第一个页面加载时下载两次。如果您没有 @david 的约束,最好将查询字符串 ("?" + imgTime) 烘焙到原始 URL 中。 @PaulLeBeau:是的,由于这里的限制,将缓存破坏程序烘焙到原始 IMG SRC 中是不可行的。该站点依靠 HTML 知识有限的管理员将 SVG 手动插入 CMS 文本区域。幸运的是,SVG 为 1kb 或更小,任何给定页面上最多只有大约 10 个唯一的 SVG。

以上是关于需要在操作系统中更改暗/亮模式以强制刷新外部 SVG 文件的主要内容,如果未能解决你的问题,请参考以下文章

让用户在暗模式和亮模式之间进行选择(保存每个页面的设置,cookie?)

PKD为暗模式和亮模式绘制不同的结果

按钮在切换到暗/亮模式时更改 CSS 样式

检查 UIColor 是暗还是亮?

如何以编程方式快速切换到暗模式

如何在 swift UITests 中的 XCUIApplication 中设置暗模式?