css var实现网页换肤
前情
最近在做需求开发,要求根据后台传来的配置对网页换肤,按以往的换肤思路应该是写好几套样式做切换达到换肤效果,但是现在想做到能根据后台配置动态修改。
原理
通过css3新增变量特性,把颜色定义为变量再全局使用,在想更改颜色的时候,我们只要修改对应变量对应的颜色就能全局换肤,主要原理演示代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style type="text/css">
:root {
--main-bg-color: red;
}
.test{
width: 500px;
height: 100px;
background-color: green;
background-color: var(--main-bg-color);
}
</style>
</head>
<body>
<div class="test"></div>
</body>
</html>
演示地址:https://jsbin.com/lozizajuva/edit?html,output
换肤实战
- 通过颜色配置表生成一个包含所有css变量的style插入到head中
- 所有css中需要进行颜色替换的都通过css变量来设置
- 动态更换主题的话只要替换上面生成style里的内容即可
演示代码
html结构
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
body{
--test-var: 'green';
}
.test{
width: 500px;
height: 100px;
/* 低版本不兼容的浏览器也有个默认颜色 */
background-color: blue;
background-color: var(--main-color)
}
.test_in{
width: 100px;
height: 50px;
line-height: 50px;
font-size: 14px;
background-color: #dddddd;
/* 低版本不兼容的浏览器也有个默认颜色 */
color: blue;
color: var(--main-color);
}
</style>
</head>
<body>
<div class="test">
<div class="test_in">css var换肤</div>
</div>
<select id="themeSelect">
<option value ="deault">默认</option>
<option value ="red">红色</option>
<option value="green">绿色</option>
</select>
</body>
</html>
javascript
// 颜色配置表,测试数据,正常是从服务端过来的
const THEME_CONFIG = {
"default": {
"--main-color": "blue"
},
"red": {
"--main-color": "red"
},
"green": {
"--main-color": "green"
}
}
// 存储当前用的是什么色系
let currentConfig = THEME_CONFIG['default'];
// 备份styles
let stylesBackups = null;
/**
* 生成主题代码段
* @param {Object} config
* @returns
*/
function createThemeStyle(config) {
let result = `
:root {
--main-color: ${config['--main-color']};
}`
return result;
}
/**
* 插入主题style段
* @param {String} styleString
*/
function insertThemeStyle(styleString) {
let styleTag = document.querySelector('#themeStyleTag');
if (!styleTag) {
styleTag = document.createElement('style');
styleTag.id = 'themeStyleTag';
styleTag.setAttribute('type', 'text/css');
document.getElementsByTagName('head')[0].insertBefore(styleTag, document.getElementsByTagName('style')[0]);
}
styleTag.innerHTML = styleString;
}
/**
* 判断css变量是否被支持
*/
function cssVarIsSupport() {
var testVar = getComputedStyle(document.body).getPropertyValue("--test-var");
return testVar ? true : false;
}
/**
* 解决兼容,根据主题配置生成正则
* @returns string
*/
function createStyleRegex() {
let regexStr = '';
let varList = Object.keys(currentConfig);
for(let i=0,len=varList.length; i<len; i++) {
regexStr += `var\\(${varList[i]}\\)${i<len-1 ? '|' : ''}`;
};
return regexStr;
}
/**
* css变量兼容处理-第一次
*/
function compatibleProcessingCssVar() {
let styles = document.getElementsByTagName('head')[0].getElementsByTagName('style');
stylesBackups = {};
// 生成正则匹配规则字符串
let regexStr = createStyleRegex();
// 遍历所有style标签替换
for(let i=1,len=styles.length; i<len; i++) {
let item = styles[i];
let replaceReg = new RegExp(regexStr, 'g');
let styleStr = item.innerHTML;
if (!replaceReg.test(styleStr)) {
continue;
}
if (!stylesBackups['theme'+i]) {
item.setAttribute('id', 'theme'+i);
stylesBackups['theme'+i] = styleStr;
}
styleStr = styleStr.replace(replaceReg, function(mactchStr) {
return currentConfig[mactchStr.split(/\(|\)/)[1]];
});
item.innerHTML = styleStr;
}
}
/**
* 解决兼容浏览器的动态换肤问题
* css变量兼容处理-后面不需再去获取所有style,通过从内存中拿缓存的style来做字符串替换
*/
function compatibleProcessingCssVarFromCache() {
// 生成正则匹配规则字符串
let regexStr = createStyleRegex();
let styleKeys = Object.keys(stylesBackups);
// 遍历所有style标签替换
for(let i=1,len=styleKeys.length; i<len; i++) {
let key = styleKeys[i];
let styleStr = stylesBackups[key];
let replaceReg = new RegExp(regexStr, 'g');
styleStr = styleStr.replace(replaceReg, function(mactchStr) {
return currentConfig[mactchStr.split(/\(|\)/)[1]];
});
document.getElementById(key).innerHTML = styleStr;
}
}
/**
* 适配主题
* @param {string} theme
*/
function adaptationTheme(theme) {
// 获取颜色列表
currentConfig = THEME_CONFIG[theme];
// 对于兼容css var的浏览器
if (cssVarIsSupport()) {
// 生成style
let styleString = createThemeStyle(currentConfig);
// 插入style中
insertThemeStyle(styleString)
} else {
// 对于不兼容css var的浏览器(chrome49、ie15以下)
if (stylesBackups) {
compatibleProcessingCssVarFromCache();
return;
}
compatibleProcessingCssVar();
}
}
window.onload = function(){
adaptationTheme('default');
// 动态更换主题
document.querySelector('#themeSelect').addEventListener('change', function() {
adaptationTheme(this.value)
}, false)
}
注意事项:
如果想兼容低版本浏览器则需要所有样式通过style写入,因为在做兼容处理的时候,是通过js代码替换掉style标签里的css变量来做兼容处理的,上面代码有做低版本兼容,对于不需要兼容低版本浏览器的,上面代码可以删减掉兼容代码。
演示地址:https://jsbin.com/tetuguxifi/1/edit?html,js,output
css var实现网页换肤的更多相关文章
- js网页换肤
使网页背景颜色可选黄/粉 <html> <head> <meta charset="utf-8"> <meta name="ge ...
- JS实现网页换肤功能效果
网页换肤的基本原理 使用 JS 切换对应的 CSS 样式表.例如hao123首页的右上方就有网页换肤功能.除了切换 CSS 样式表文件之外,通常的网页换肤还需要通过 Cookie 来记录用户之前更换过 ...
- JavaScript网页换肤
使网页背景颜色可选黄/粉 <!doctype html> <html> <head><title>网页换肤</title></head ...
- 【转】Javascript+css 实现网页换肤功能
来源:http://www.php100.com/html/webkaifa/DIV_CSS/2008/1014/2326.html Html代码部分: 1.要有一个带id的样式表链接,我们要通过操作 ...
- 基于js的网页换肤(不需要刷新整个页面,只需替换css文件)
1. [代码][JS]代码 <HTML><HEAD><link ID="skin" rel="stylesheet" typ ...
- 网页换肤,模块换肤,jQuery的Cookie插件使用(转)
具体效果如下: 第一次加载如下图: 然后点击天蓝色按钮换成天蓝色皮肤如下图: 然后关闭网页重新打开或者在打开另一个网页如下图: 因为皮肤用Cookie保存了下来,所以不会重置 具体的实现代码如下: & ...
- jquery网页换肤+jquery的cookie+动态调用css样式文件,可以的
比较具有参考性,代码全贴(当然,还需要一张图片需要的留个邮箱,看到就发) 贴在这儿吧,修改一下css的引用位置应该可以用 <%@ page language="java" c ...
- css, js 项目练习之网页换肤
首先,该练习参考自:https://www.jianshu.com/p/2961d9c317a3 我就直接上代码了(颜色可以自己调). HTML: <nav> <li>< ...
- 网上找到的一个jquery版网页换肤特效
这个跟我之前在锋利的JQuery那本书里看到的那个一模一样. <!DOCTYPE html> <html> <head> <meta name="& ...
- 网页换肤:原生js与jq
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
随机推荐
- AJAX——简介
AJAX 同步与异步 AJAX 快速入门
- USB和CAN都是用差分信号来传输数据,为什么CAN的传输距离能比USB远那么多?
USB和CAN的区别 今天在看USB项目设计实例的时候,突然想到一个问题,从而引发了一些思考.经过思考加上查阅资料,写出了这一篇文章作为记录. 问题 USB和CAN都是用两条线作为差分线以差分信号 ...
- `std::string_view`(c++17) 和 `std::stringstream` 使用区别·
std::string_view 和 std::stringstream 都是 C++ 中处理字符串的工具,但它们的设计目标和使用场景非常不同.我们可以通过几方面进行对比. 1. 设计目的和核心功能 ...
- USB协议详解第1讲(核心概念通俗理解)
0.概括 USB协议学习中最重要几个概念如下,没有提及的就是对USB协议学习中不重要的或者编程不需要用到的.大家也不用着急,概念必须要学会,否则都不知道下面这些东西是什么还学什么通用串行总线协议,大家 ...
- Cookie、sessionStorage、localStorage的区别 ?
共同点:都是保存在浏览器端的. 区别: 1.cookie数据始终携带在同源的http请求中,即cookie在浏览器和服务器间来回传递,而sessionStorage和Localstorage不会自动把 ...
- apisix~helm方式的部署到k8s
什么是apisix Apache APISIX 是一个高性能.轻量级的开源 API 网关,基于 Nginx 和 OpenResty 构建.APISIX 提供了丰富的功能和灵活的配置,适用于构建现代的微 ...
- kotlin协程——>通道
通道:延期的值提供了⼀种便捷的⽅法使单个值在多个协程之间进⾏相互传输.通道提供了⼀种在流中传输 值的⽅法. 通道基础: ⼀个 Channel 是⼀个和 BlockingQueue ⾮常相似的概念.其中 ...
- SQL语法-列的新增、删除
MySQL的语法: 新增列 ALTER TABLE `xxdb`.`xxtable` ADD COLUMN `xx_flag` varchar(1) NULL; 删除列 ALTER TABLE `xx ...
- 云原生周刊:2024 年 K8s 基准报告 | 2024.4.8
开源项目推荐 Argo CD Image Updater Argo CD Image Updater 是一个自动更新 Argo CD 管理的 Kubernetes 工作负载容器镜像的工具.简而言之,它 ...
- MISC 高手进阶区 1-5
1.reverseME 题目描述 无 附件 一个 .jpg 的图片 是一个flag字符串的图片镜像. reverse V-T If you reverse the order of a set of ...