前情

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

原理

通过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. C++ const常量指针

    const常量指针 const是C++关键字,译为常量,const指针即为常量指针. 分为三类 指向const的指针 const指针 指向const的const指针 指向const的指针 表示指向区域 ...

  2. QT硬件通讯基础

    QT硬件通讯基础 使用AI技术辅助生成 1 QT与硬件通讯概述 1.1 QT硬件通讯的基本概念 1.1.1 QT硬件通讯的基本概念 QT硬件通讯的基本概念 QT硬件通讯的基本概念 QT作为一种跨平台的 ...

  3. ChatGPT转发工具-springboot

    背景 国内服务器无法访问openAI接口,我想过有两种实现方式 代理工具类似 tinyproxy.nginx 开发一个转发客户端(java.python都可以实现),提供一个api接口 源码 gith ...

  4. 【赵渝强老师】Kafka的体系架构

    一.什么是Kafka? 数据工程中最具挑战性的部分之一是如何从不同点收集和传输大量数据到分布式系统进行处理和分析.需要通过消息队列正确地分离大量数据,因为如果一部分数据无法传送,则可以在系统恢复时传输 ...

  5. 组件传参v-model语法糖只能写一次的解决办法

    v-model 的使用 解决只能使用一次v-model的问题:使用 sync 修饰符

  6. 70.http拦截能做些什么(问的是axios的封装)

    请求拦截器统一添加 token ,也可以手动的判断token是否过期  : 响应拦截器判断返回数据的逻辑处理,被动的判断token过期并处理 :

  7. 如何集成化管理API_方便企业内外部调用?

    API 已成为企业数字战略中不可或缺的一部分.它们使不同软件系统.应用程序和服务之间能够高效.灵活地相互沟通.API不仅能提升企业内部各部门之间的协作效率,还能加强与外部合作伙伴及客户之间的互动. A ...

  8. 神经网络之卷积篇:详解残差网络(ResNets)(Residual Networks (ResNets))

    详解残差网络 ResNets是由残差块(Residual block)构建的,首先解释一下什么是残差块. 这是一个两层神经网络,在\(L\)层进行激活,得到\(a^{\left\lbrack l + ...

  9. WebStorm 和 Rider 现在对非商业用途免费

    JetBrains 在程序员节这一天在官方博客上发布了一篇文章:<WebStorm 和 Rider 现在对非商业用途免费>宣布了JetBrains将WebStorm和Rider IDE对非 ...

  10. Linux下的网络抓包tcpdump

    tcpdump [ -AdDefIJKlLnNOpqRStuUvxX ] [ -B buffer_size ] [ -c count ] [ -C file_size ] [ -G rotate_se ...