网页主题自动适配:网页跟随系统自动切换主题

主题切换是网站设计中一个非常有趣的功能,它允许用户在多种预先设计的样式之间轻松切换,以改变网站的视觉表现。最常见的就是白天和黑夜主题的切换,用户可以根据自己的喜好进行设置。
除了让用户手动去切换主题外,如果能够让用户第一次访问时,网站就设置为用户系统的主题样式,这无疑是一种更好的体验。

主题切换

CSS主题切换有多种方式实现,这里就简单描述下,不是本文重点

方式1:通过自定义标签属性来实现主题切换

/* 默认主题样式 */
body {background-color: white;color: black;
}/* 深色主题样式 */
body[data-theme="dark"] {background-color: black;color: white;
}
:root {--body-background: rgb(248, 244, 212);--text-color: #000;
}
html[data-theme="dark"] {--body-background: rgb(58, 70, 90);--text-color: #eee;
}

方式2:运行时动态地修改CSS变量的值,从而实现主题切换的效果

:root {--primary-color: #007bff;--secondary-color: #6c757d;--background-color: white;--text-color: black;
}
​
body {background-color: var(--background-color);color: var(--text-color);
}
document.documentElement.style.setProperty('--background-color', 'black');
document.documentElement.style.setProperty('--text-color', 'white');

方式3:使用类名切换,通过对顶层节点设置不同的类名,然后定义不同类名的CSS样式,切换主题时修改类名即可

.theme-light {background-color: white;color: black;
}
​
.theme-dark {background-color: black;color: white;
}
function switchTheme() {const bodyElement = document.body;if (bodyElement.classList.contains('theme-light')) {bodyElement.classList.remove('theme-light');bodyElement.classList.add('theme-dark');} else {bodyElement.classList.remove('theme-dark');bodyElement.classList.add('theme-light');}
}


方式4:link标签动态引入

function switchTheme(theme) {const linkElement = document.createElement('link');linkElement.rel = 'stylesheet';if (theme === 'light') {linkElement.href = 'theme-light.css'; // 切换为浅色主题} else {linkElement.href = 'theme-dark.css'; // 切换为深色主题}
​document.head.appendChild(linkElement);
}

扫码加入前端交流群,期待你的加入!
描述文字

CSS媒体查询

CSS媒体查询是实现响应式网页设计的重要工具,它允许根据设备的特定特性来应用不同的样式规则。

使用 @media 规则可以实现这一功能,通过这个规则可以定义一个或多个条件,当这些条件满足时,相应的样式代码块将会被应用到文档上。例如,在屏幕宽度小于或等于768像素时,背景颜色可以设置为浅蓝色

/* 基础样式 */
body {background-color: lightblue;color: white;font-size: 16px;padding: 20px;
}/* 当屏幕宽度小于或等于768像素时,应用以下样式 */
@media (max-width: 768px) {body {background-color: red;color: black;font-size: 14px;padding: 10px;}
}

CSS媒体查询还可以检测用户是否有将系统的主题色设置为两色或者暗色

  • light:表示用户已告知系统选择使用浅色主题界面
  • dark:表示用户已告知系统选择使用暗色主题界面
.day {background: #eee;color: black;
}
.night {background: #333;color: white;
}@media (prefers-color-scheme: dark) {.day.dark-scheme {background: #333;color: white;}.night.dark-scheme {background: black;color: #ddd;}
}@media (prefers-color-scheme: light) {.day.light-scheme {background: white;color: #555;}.night.light-scheme {background: #eee;color: black;}
}

这种方式的确可以实现主题跟随系统的变换而变换,但是存在以下缺点:

  • 增加工作量:开发者需要编写更多的CSS代码,这可能会导致工作效率降低

  • 加载时间延长:随着CSS代码量的增加,页面的加载时间可能会变长,尤其是对于那些包含大量媒体查询的复杂样式表

  • 用户无法自定义:样式固定,用户无法自定义设置主题样式

JS媒体查询

JS同样拥有媒体查询的方法 matchMedia()。传入一个被用于媒体查询解析的字符串,返回一个用来媒体查询新的 MediaQueryList 对象,其中的 matchs 属性值就是匹配结果。

// 如果视口的宽度小于或等于600像素,则输出为true
const mql = window.matchMedia('(max-width: 600px)');
console.log(mql.matchs)

同样的也可以用来查询系统是否使用了暗色主题

const osThemeIsDark = matchMedia("(prefers-color-scheme: dark)").matches;

接下来就采用上面方式1的主题切换方案,结合JS媒体查询来实现跟随系统主题切换的功能。

:root {--body-background: rgb(248, 244, 212);--text-color: #000;
}
html[data-theme="dark"] {--body-background: rgb(58, 70, 90);--text-color: #eee;
}
body {padding-top: 200px;height: 100vh;width: 100vw;margin: 0;background: var(--body-background);text-align: center;color: var(--text-color);
}
<body><div><select><option value="light">白天模式</option><option value="dark">黑夜模式</option><option value="os">跟随系统</option></select></div><h1>公众号:前端筱园</h1><p>www.dengzhanyong.com</p>
</body>
const select = document.querySelector('select');
const html = document.querySelector("html");
// 获取用户设置的主题,默认是跟随系统
const localTheme = localStorage.getItem('theme') || 'os';
settingTheme(localTheme);
// 设置select选中的值
select.value = localTheme;
​
select.onchange = (e) => {
const theme = e.target.value;settingTheme(theme);localStorage.setItem('theme', theme)
}function settingTheme(theme) {// 如果是跟随系统,就获取系统的主题
if (theme === 'os') {
const osThemeIsDark = matchMedia("(prefers-color-scheme: dark)").matches;html.dataset.theme = osThemeIsDark ? 'dark' : 'light';} else {html.dataset.theme = theme;}
}

监听媒体变化

现在还有一个问题,如果页面已经打开的情况下,再去修改系统主题,是否能检测到系统主题的变化,使得网页在不刷新的情况下自动切换。

答案是可以的,可以通过监听 MediaQueryListchange 事件,当 matches 的值发生变化时会触发。

matchMedia("(prefers-color-scheme: dark)").addEventListener("change", event => {html.dataset.theme = event.matches ? 'dark' : 'light';
})

利用媒体查询还可以检测很多内容,比如:浏览器可视区域尺寸、设备尺寸、设备目前处于横向还是纵向、检测设备宽高比、设备颜色位数等

写在最后

欢迎访问我的个人网站:www.dengzhanyong.com

前端筱园交流群】已经正式开通啦!在这里,你可以与一群志同道合的小伙伴们交流、分享、学习、共同成长,扫码加入,期待你的加入!
描述文字
关注我的公众号【前端筱园】,不错过每一篇推送

描述文字

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/323094.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TypeScript学习日志-第十九天(namespace命名空间)

namespace命名空间 一、基本用法 namespace 所有的变量以及方法必须要导出才能访问&#xff0c;如图&#xff1a; 二、 嵌套 namespace 可以进行嵌套使用&#xff0c;如图&#xff1a; 它也必须需要导出才能访问 三、合并 当我们出现两个同名的 namespace 它就会合并这两…

docker Harbor私有仓库部署管理

搭建本地私有仓库&#xff0c;但是本地私有仓库的管理和使用比较麻烦&#xff0c;这个原生的私有仓库并不好用&#xff0c;所以我们采用harbor私有仓库&#xff0c;也叫私服&#xff0c;更加人性化。 一、什么是Harbor Harbor是VWware 公司开源的企业级Docker Registry项…

【SpringBoot记录】自动配置原理(1):依赖管理

前言 我们都知道SpringBoot能快速创建Spring应用&#xff0c;其核心优势就在于自动配置功能&#xff0c;它通过一系列的约定和内置的配置来减少开发者手动配置的工作。下面通过最简单的案例分析SpringBoot的功能特性&#xff0c;了解自动配置原理。 SpringBoot简单案例 根据S…

百面算法工程师 | 支持向量机面试相关问题——SVM

本文给大家带来的百面算法工程师是深度学习支持向量机的面试总结&#xff0c;文章内总结了常见的提问问题&#xff0c;旨在为广大学子模拟出更贴合实际的面试问答场景。在这篇文章中&#xff0c;我们还将介绍一些常见的深度学习算法工程师面试问题&#xff0c;并提供参考的回答…

python代码无法点击进入,如何破???

python代码无法点击进入&#xff0c;如何破&#xff1f;&#xff1f;&#xff1f; 举个栗子&#xff1a; model.chat是无法进入的&#xff0c;这时可以使用如下的命令进行操作&#xff1a; ?model.chat

Jmeter用jdbc实现对数据库的操作

我们在用Jmeter进行数据库的操作时需要用到配置组件“JDBC Connection Configuration”&#xff0c;通过配置相应的驱动能够让我们通过Jmeter实现对数据库的增删改查&#xff0c;这里我用的mysql数据库一起来看下是怎么实现的吧。 1.驱动包安装 在安装驱动之前我们要先查看当前…

【LAMMPS学习】八、基础知识(5.9)LAMMPS 近场动力学

8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语,以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各种模拟。 …

这 7 道 Redis 基础问题,很常见!!

后端项目如果用到分布式缓存的话&#xff0c;一般用的都是 Redis。不过&#xff0c;Redis 不仅仅能做缓存&#xff0c;还能用作分布式锁、延时队列、限流等等。 什么是 Redis&#xff1f; Redis[1] &#xff08;REmote DIctionary Server&#xff09;是一个基于 C 语言开发的…

基于Springboot+Vue+Java的校园资料分享平台

&#x1f49e; 文末获取源码联系 &#x1f649; &#x1f447;&#x1f3fb; 精选专栏推荐收藏订阅 &#x1f447;&#x1f3fb; &#x1f380;《Java 精选实战项目-计算机毕业设计题目推荐-期末大作业》&#x1f618; 更多实战项目~ https://www.yuque.com/liuyixin-rotwn/ei3…

springboot3项目练习详细步骤(第一部分:用户业务模块)

目录 环境准备 用户模块 注册 注册接口文档 ​编辑 实现结构 Spring Validation 登录 登录的接口文档 实现登录逻辑 JWT令牌 完善登录认证 拦截器 获取用户详细信息 接口文档 Usercontroller类中编写方法接口 忽略属性返回 优化代码ThreadLocal 更新用户基本信…

点击短信链接唤起Android App实战

一.概述 在很多业务场景中,需要点击短信链接跳转到App的指定页面。在Android系统中,想要实现这个功能,可以通过DeepLink或AppLink实现。二.方案 2.1 DeepLink 2.1.1 方案效果 DeepLink是Android系统最基础、最普遍、最广泛的外部唤起App的方式,不受系统版本限制。当用户…

YOLOv8+PyQt5蔬菜识别检测(26种不同蔬菜类型,yolov8模型,从图像、视频和摄像头三种路径识别检测)

1.基于最新的YOLOv8训练的蔬菜检测模型&#xff0c;和基于PyQt5制作的可视蔬菜检测系统&#xff0c;该系统可自动检测和识别图片或视频当中出现的26种蔬菜&#xff1a;鸡蛋, 姜, 菜椒, 南瓜, 山药, 辣椒, 霉豆, 蘑菇, 香菜, 茼蒿, 油菜, 黄瓜, 角瓜, 莲藕, 西兰花, 菜花, 土豆,…

Linux的基础IO:文件描述符 重定向本质

目录 前言 文件操作的系统调用接口 open函数 close函数 write函数 read函数 注意事项 文件描述符-fd 小补充 重定向 文件描述符的分配原则 系统调用接口-dup2 缓冲区 缓冲区的刷新策略 对于“2”的理解 小补充 前言 在Linux中一切皆文件&#xff0c;打开文件…

libcity笔记:参数设置与参数优先级

1 参数优先级 高优先级的参数会覆盖低优先级的同名参数 Libcity中的优先级顺序维&#xff1a; 命令行参数&#xff08;命令行python run_model.py时导入的&#xff09; > 用户定义配置文件&#xff08;命令行python run_model.py时由config_file导入的&#xff09; >…

Windows下,基于Gradle用Docker发布自己的程序

方案1&#xff1a; windows下打包程序&#xff0c;然后&#xff0c;上传到linux下&#xff0c;生成docker镜像&#xff0c;然后执行。 首先&#xff1a; 由于是采用Gradle管理的项目&#xff0c;打包的时候需要执行build任务。执行完成后&#xff0c;再build\libs目录下应该…

机器学习:基于TF-IDF算法、决策树,使用NLTK库对亚马逊美食评论进行情绪分析

前言 系列专栏&#xff1a;机器学习&#xff1a;高级应用与实践【项目实战100】【2024】✨︎ 在本专栏中不仅包含一些适合初学者的最新机器学习项目&#xff0c;每个项目都处理一组不同的问题&#xff0c;包括监督和无监督学习、分类、回归和聚类&#xff0c;而且涉及创建深度学…

js原生手写一个拖拽小功能

先上效果图 附上代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewport" content"widthd…

【强训笔记】day16

NO.1 代码实现&#xff1a; class StringFormat { public:string formatString(string A, int n, vector<char> arg, int m) {string ret;int j0;for(int i0;i<n;i){if(A[i]%){if(i1<n&&A[i1]s){retarg[j];i;}else {retA[i];}}else {retA[i];}}while(j&l…

PyQt5中重要的概念:信号与槽

PyQt中信号与槽概念定义如下&#xff08;网络上引用的&#xff09;&#xff1a; 信号&#xff08;signal&#xff09;和槽&#xff08;slot&#xff09;是Qt的核心机制&#xff0c;也是在PyQt编程中对象之间进行通信的机制。在创建事件循环之后&#xff0c;通过建立信号和槽的…

我们的小程序每天早上都白屏,真相是。。。

大家好&#xff0c;我是程序员鱼皮。最近我们在内测一款面试刷题小程序&#xff0c;没错&#xff0c;就是之前倒下的 “面试鸭”&#xff01; 在我们的内测交流群中&#xff0c;每天早上都会有同学反馈&#xff1a;打开小程序空白&#xff0c;没任何内容且登录不上。 然后过了…