前情

最近在做需求开发,要求根据后台传来的配置对网页换肤,按以往的换肤思路应该是写好几套样式做切换达到换肤效果,但是现在想做到能根据后台配置动态修改。

原理

通过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

换肤实战

  1. 通过颜色配置表生成一个包含所有css变量的style插入到head中
  2. 所有css中需要进行颜色替换的都通过css变量来设置
  3. 动态更换主题的话只要替换上面生成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实现网页换肤的更多相关文章

  1. js网页换肤

    使网页背景颜色可选黄/粉 <html> <head> <meta charset="utf-8"> <meta name="ge ...

  2. JS实现网页换肤功能效果

    网页换肤的基本原理 使用 JS 切换对应的 CSS 样式表.例如hao123首页的右上方就有网页换肤功能.除了切换 CSS 样式表文件之外,通常的网页换肤还需要通过 Cookie 来记录用户之前更换过 ...

  3. JavaScript网页换肤

    使网页背景颜色可选黄/粉 <!doctype html> <html> <head><title>网页换肤</title></head ...

  4. 【转】Javascript+css 实现网页换肤功能

    来源:http://www.php100.com/html/webkaifa/DIV_CSS/2008/1014/2326.html Html代码部分: 1.要有一个带id的样式表链接,我们要通过操作 ...

  5. 基于js的网页换肤(不需要刷新整个页面,只需替换css文件)

    1. [代码][JS]代码    <HTML><HEAD><link ID="skin" rel="stylesheet" typ ...

  6. 网页换肤,模块换肤,jQuery的Cookie插件使用(转)

    具体效果如下: 第一次加载如下图: 然后点击天蓝色按钮换成天蓝色皮肤如下图: 然后关闭网页重新打开或者在打开另一个网页如下图: 因为皮肤用Cookie保存了下来,所以不会重置 具体的实现代码如下: & ...

  7. jquery网页换肤+jquery的cookie+动态调用css样式文件,可以的

    比较具有参考性,代码全贴(当然,还需要一张图片需要的留个邮箱,看到就发) 贴在这儿吧,修改一下css的引用位置应该可以用 <%@ page language="java" c ...

  8. css, js 项目练习之网页换肤

    首先,该练习参考自:https://www.jianshu.com/p/2961d9c317a3 我就直接上代码了(颜色可以自己调). HTML: <nav> <li>< ...

  9. 网上找到的一个jquery版网页换肤特效

    这个跟我之前在锋利的JQuery那本书里看到的那个一模一样. <!DOCTYPE html> <html> <head> <meta name="& ...

  10. 网页换肤:原生js与jq

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. JVM(JAVA Virtual Machine)Java虚拟机

    JVM的跨平台性 一次编写,到处运行 JVM将字节码文件编译成对应操作系统的机器码 JVM的语言无关性 JVM的内存区域 虚拟机栈:在JVM运行过程中存储当前线程运行方法所需的数据,指令.返回地址 本 ...

  2. SuperMap iManager for K8S 删除旧环境修改NFS地址流程

    一.完整删除SuperMap iManager 找到SuperMap iManager安装目录,执行: ./shutdown.sh -v 二.修改NFS存储路径 有两种办法,一种是直接修改/etc/e ...

  3. Hive 2.3.2安装

    一.安装mysql 安装MySQL服务器端和MySQL客户端: •安装: – yum install mysql – yum install mysql-server •启动: – /etc/init ...

  4. Android libusb

    一.环境:配置NDK环境 1.下载libusb源码: https://github.com/libusb/libusb/releases,如下图所示 2.删除一些和Android平台无关的文件,删除后 ...

  5. iOS中UIlabel多行文本展示使用小结

    最近在项目开发中遇到了一个新的需求,就是菜单标题最多两行展示,一行展示的标签顶部和两行展示的标签顶部对齐.看到要求后,第一反应是这是什么奇葩的设计,但是没办法谁让别人是产品经理呢.细细思索后,代码如下 ...

  6. Vue3 的emit3 属性和 props 属性?

    使用场景:使用父子组件通信的时候 : 作用: 用来声明组件有哪些自定义事件,不在emtis里面都会当成原生事件,绑定给组件的根标 签. 好处: 不在像 vue2 使用  .native 修饰符 在 v ...

  7. 012 Python约定俗称的常量

    #!/usr/bin/env python # -*- coding:utf-8 -*- # Datatime:2022/7/18 21:13 # Filename:011 Python约定俗称的常量 ...

  8. 16 Transformer 的编码器(Encodes)——我在做更优秀的词向量

    博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 配套 github 链接:https:// ...

  9. jmeter使用beanshell完成签名计算,附与python代码对比

    签名计算过程: 1.ticket计算:时间戳加+随机数字拼接后md5加密 2.组装公共参数+ticket+时间戳+业务参数 beanshell代码实现: import java.util.*;impo ...

  10. KubeSphere 最佳实战:Kubernetes 部署集群模式 Nacos 实战指南

    Nacos 是 Dynamic Naming and Configuration Service 的首字母简称,一个更易于构建云原生应用的动态服务发现.配置管理和服务管理平台. Nacos 是构建以服 ...