目录
以下转自:https://www.cnblogs.com/leiting/p/11203383.html
文章1:
以下转自:https://segmentfault.com/a/1190000018865621
某一天,一个头条的大佬问我,听说你之前在项目里面弄过主题切换,你当时是怎么实现的可以详说一下吗?
如果已经对less了如指掌,直接从这里开始。
从less说起
使用
Node.js 环境中使用 Less :
npm install -g less
> lessc styles.less styles.css
在浏览器环境中使用 Less :
<link rel="stylesheet/less" type="text/css" href="styles.less" />
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/3.8.1/less.min.js" ></script>
不过比较推荐的还是通过webpack或者gulp等工具先将less编译成css,然后再引入使用。
变量
@nice-blue: #5B83AD;
@light-blue: @nice-blue + #111;
#header {
color: @light-blue;
}
混合
-
常用
.bordered { border-top: dotted 1px black; &:hover { border: 1px solid red; } // 同样可以包含选择器混用 } .post a { color: red; .bordered !important; // 可以在属性后面都加上!important }
-
编译后不输出至css文件
.my-other-mixin() { background: white; }
-
作用域混合
#outer { .inner() { color: red; } } #outer1 { .inner() { color: blue; } } .c { #outer > .inner; }
输出
.c { color: red; }
-
拥有前置条件的作用域混合,更多详情
@mode: little; #outer when (@mode=huge) { .inner { color: red; } } #outer when (@mode=little) { .inner { color: blue; } } .c { #outer > .inner; }
输出(可以看到没有通过前置条件的样式被过滤了)
#outer .inner { color: blue; } .c { color: blue; }
-
带参数混合,可以指定默认值,可以带多个参数,使用时可以通过名称赋值
.mixin(@color: black; @margin: 10px; @padding: 20px) { color: @color; margin: @margin; padding: @padding; } .class1 { .mixin(@margin: 20px; @color: #33acfe); } .class2 { .mixin(#efca44; @padding: 40px); }
-
使用
@arguments
.mixin(@a; @b) { margin: @arguments; right:extract(@arguments,2); top:@b; } p {.mixin(1px; 2px);}
输出
p { margin: 1px 2px; right: 2px; top: 2px; }
-
使用
@rest
参数// 方式1 .mixin(@listofvariables...) { border: @listofvariables; } p { .mixin(1px; solid; red); } // 方式2 .mixin(@a; ...) { color: @a;} .mixin(@a) { background-color: contrast(@a); width:100%;} .mixin(@a; @b;) { background-color: contrast(@a); width:@b;} p { .mixin(red); } p.small { .mixin(red,50%); }
输出
/*方式1*/ p { border: 1px solid red; } /*方式2*/ p { color: red; background-color: #ffffff; width: 100%; } p.small { color: red; background-color: #ffffff; width: 50%; }
-
模式匹配混合
.mixin(dark; @color) { color: darken(@color, 10%); } .mixin(light; @color) { color: lighten(@color, 10%); } .mixin(@_; @color) { display: block; } @switch: light; .class { .mixin(@switch; #888); }
输出
.class { color: #a2a2a2; display: block; }
-
规则集混合
// declare detached ruleset @detached-ruleset: { background: red; }; // use detached ruleset .top { @detached-ruleset(); }
函数
类似于先函数运算计算出变量的值,再通过变量的值设置属性。
.mixin() {
@width: 100%;
@height: 200px;
}
.caller {
.mixin();
width: @width;
height: @height;
}
输出
.caller {
width: 100%;
height: 200px;
}
继承
继承另外一个选择器的属性,更多详情
nav ul {
&:extend(.inline);
background: blue;
} // &是父类型选择器,指代的是nav ul
.inline {
color: red;
}
输出
nav ul {
background: blue;
}
.inline,
nav ul {
color: red;
}
嵌套
#header {
color: black;
.navigation {
font-size: 12px;
}
.logo {
width: 300px;
}
}
引入
@import "foo"; // foo.less is imported
@import "foo.less"; // foo.less is imported
@import "foo.php"; // foo.php imported as a less file
@import "foo.css"; // statement left in place, as-is
参数
@import (keyword) "filename";
reference
: use a Less file but do not output itinline
: include the source file in the output but do not process itless
: treat the file as a Less file, no matter what the file extensioncss
: treat the file as a CSS file, no matter what the file extensiononce
: only include the file once (this is default behavior)multiple
: include the file multiple timesoptional
: continue compiling when file is not found
循环
.generate-columns(4);
.generate-columns(@n, @i: 1) when (@i =< @n) {
.column-@{i} {
width: (@i * 100% / @n);
}
.generate-columns(@n, (@i + 1));
}
输出
.column-1 {
width: 25%;
}
.column-2 {
width: 50%;
}
.column-3 {
width: 75%;
}
.column-4 {
width: 100%;
}
合并
-
逗号合并
.mixin() { box-shadow+: inset 0 0 10px #555; } .myclass { .mixin(); box-shadow+: 0 0 20px black; }
输出
.myclass { box-shadow: inset 0 0 10px #555, 0 0 20px black; }
-
空格合并
.mixin() { transform+_: scale(2); } .myclass { .mixin(); transform+_: rotate(15deg); }
输出
.myclass { transform: scale(2) rotate(15deg); }
切换主题样式
方案1
当几种主题布局类似,几乎只是颜色不同时,可以使用这种。
通过对less的了解(可以进行许多额外的骚操作哦),我们这里最简单地编写出如下less文件。
- 基础样式模版
style.less
,里面主要通过变量设置各个样式 - 爱国红样式
patriotic-red.less
,设置变量的值 - 天空蓝样式
sky-blue.less
,设置不同的变量值 - ...
style.less
里样式类似这样
a,
.link {
color: @link-color;
}
a:hover {
color: @link-color-hover;
}
.widget {
color: #fff;
background: @link-color;
}
patriotic-red.less
里样式类似这样
@import "style";
@link-color: #f03818;
@link-color-hover: darken(@link-color, 10%);
sky-blue.less
里样式类似这样
@import "test";
@link-color: #428bca;
@link-color-hover: darken(@link-color, 10%);
利用相关工具(或原始人手动lessc)提前编译成patriotic-red.css
和sky-blue.css
文件。
这里简单的假设页面header中只引入了默认爱国红——
<link rel="stylesheet" href="./patriotic-red.css" />
同时存在一个按钮,用户点击时切换主题。首先我们给按钮绑定点击事件,当用户点击时删除当前导入的样式,然后再引入另外一个样式。具体操作如下:
function toggleThemeClick() {
let a = document.getElementsByTagName("link");
let aHref = a[0].getAttribute("href").slice(2, -4);
a[0].parentElement.removeChild(a[0]);
let b = document.createElement("link");
b.setAttribute("rel", "stylesheet");
if ("patriotic-red" === aHref) {
b.setAttribute("href", "./sky-blue.css");
} else {
b.setAttribute("href", "./patriotic-red.css");
}
document.getElementsByTagName("head")[0].appendChild(b);
}
这样我们就可以自由的切换主题啦。
方案2
我们还可以通过给body添加类标签来进行主题的切换。
新建一个style-mixin.less
,里面内容如下——
.patriotic-red {
@import "patriotic-red";
}
.sky-blue {
@import "sky-blue";
}
这里需要注意的是,在sky-blue.less
或者patriotic-red.less
中引入style.less
时,需要使用(multiple)
参数,否则会只编译出一份样式。编译出来的样式会自动加上.patriotic-red
和sky-blue
前缀。
这个时候只需要引入一份style-mixin.css
就行了,要切换样式的时候修改body的类标签。
document,getElementsByTagName('body')[0].className='xxx'
题外话
头条大佬似乎并不是很认可方案1,他认为方案1会导致之前引入的样式和后来的冲突?我没有明白具体是什么意思,由于时间关系他也没有解释得很清楚,希望知道问题出在哪里的同学告诉我一下哦。
文章2:
以下转自:https://www.cnblogs.com/leiting/p/11203383.html
使用 css/less 动态更换主题色(换肤功能)
前言#
说起换肤功能,前端肯定不陌生,其实就是颜色值的更换,实现方式有很多,也各有优缺点
一、看需求是什么#
一般来说换肤的需求分为两种:
1. 一种是几种可供选择的颜色/主题样式,进行选择切换,这种可供选择的主题切换不会很多
2. 另一种是需要自定义色值,或者通过取色板取色,可供选择的范围就很大了
二、如何实现#
1. 对于可供选择的颜色/主题样式换肤的实现#
-
一个全局class控制样式切换#
切换的时候js控制样式的切换
-
JS改变href属性值切换样式表,例如:#
<link id="skincolor" href="skin-default.css" rel="stylesheet" type="text/css">
document.getElementById('#skincolor').href = 'skin-red.css';
这种方式需要维护几个主题样式表,js点击切换的时候通过改变css样式表链接来实现。 例如这个 demo
这种实现对于,颜色和主题多了的时候,维护起来就很麻烦,需要同时维护 n 个样式文件,并且使用JS改变href属性会带来加载延迟,样式切换不流畅,体验也不好。
但如果是有包含不同复杂背景图片切换的时候,这种方式可以实现,但其他如下面要说的css变量 less modifyVars 就无法实现了
-
HTML 的 rel 属性下的 alternate 实现: MDN Alternative style sheets#
示例:
<link href="reset.css" rel="stylesheet" type="text/css">
<link href="default.css" rel="stylesheet" type="text/css" title="Default Style">
<link href="fancy.css" rel="alternate stylesheet" type="text/css" title="Fancy">
<link href="basic.css" rel="alternate stylesheet" type="text/css" title="Basic">
所有样式表都可分为3类:
- 没有title属性,rel属性值仅仅是stylesheet的
<link>
无论如何都会加载并渲染,如reset.css; - 有title属性,rel属性值仅仅是stylesheet的
<link>
作为默认样式CSS文件加载并渲染,如default.css; - 有title属性,rel属性值同时包含alternate stylesheet的
<link>
作为备选样式CSS文件加载,默认不渲染,如red.css和green.css;
alternate意味备用,相当于是 css 预加载进来备用,所以不会有上面那种切换延时
但怎么用呢?禁用掉?
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link
link 的 disabled 属性
使用JavaScript代码修改<link>
元素DOM对象的disabled
值为false
,可以让默认不渲染的CSS开始渲染。实现 demo
2. 对于制定动态色值换肤的实现#
如果是要实现动态换肤,自定义色值,那上面的几种方式就不适合了。
先看下已有的实现有哪些方法
Element-UI 有换肤功能 示例预览
实现原理: 官方解释
- 先把默认主题文件中涉及到颜色的 CSS 值替换成关键词:https://github.com/ElementUI/theme-preview/blob/master/src/app.vue#L250-L274
- 根据用户选择的主题色生成一系列对应的颜色值:https://github.com/ElementUI/theme-preview/blob/master/src/utils/formula.json
- 把关键词再换回刚刚生成的相应的颜色值:https://github.com/ElementUI/theme-preview/blob/master/src/utils/color.js
- 直接在页面上加
style
标签,把生成的样式填进去:https://github.com/ElementUI/theme-preview/blob/master/src/app.vue#L198-L211
看这个实现,还是比较麻烦的,想看看还有没有更优雅的方法来实现
Ant Design 的更换主题色功能是用 less 提供的 modifyVars 的方式进行覆盖变量来实现。
less的 modifyVars方法
modifyVars方法是是基于 less
在浏览器中的编译来实现。所以在引入less文件的时候需要通过link方式引入,然后基于less.js中的方法来进行修改变量
less.modifyVars({
'@themeColor': 'blue'
});
link方式引入主题色文件
<link rel="stylesheet/less" type="text/css" href="./src/less/public.less" />
更改主题色事件
// color 传入颜色值
handleColorChange (color) {
less.modifyVars({ // 调用 `less.modifyVars` 方法来改变变量值'
@themeColor':color
})
.then(() => {
console.log('修改成功');
});
};
如果发现项目运行报错如下:
.bezierEasingMixin();
^
Inline JavaScript is not enabled. Is it set in your options?
那可能是没有开启 javascriptEnabled:true
在webpack配置里开启
{
test: /\.less$/,
loader: 'less-loader',
options: {
javascriptEnabled: true
}
},
less方法仅限于用less的项目才能使用,查了下sass是没有类似 less.modifyVars 这种方法的。
那有没有通用一点的方法呢?于是就有了
css 变量方法
如果项目里用的不是less, 那么还是用css的方法,通用且容易操作,使用css变量来进行主题色的修改,替换主题色变量,然后用setProperty来进行动态修改
用法就是给变量加--前缀,涉及到主题色的都改成var(--themeColor)这种方式
用之前看下兼容性
https://caniuse.com/#search=CSS%20Variables
大部分主流浏览器还是支持的,而且主要是操作起来够简便。
用法举例:
body{
--themeColor:#000;
}
使用:
.main{
color: var(--themeColor);
}
要修改主题色的话:
document.body.style.setProperty('--themeColor', '#ff0000');
总结#
至此,总结了一些换肤的实现方案,大家如果有更好的方案,欢迎补充哦~
文章3:
以下转自:https://blog.csdn.net/bocongbo/article/details/104773028/
1、实现原理
给内容最外层标签添加不同的主题class,用以区分不同的主题
2、less写法
.module-theme(@theme, @tag) {
.m-title-box {
background: @theme;
}
.m-head .m-info .m-name {
color: @theme;
}
// 其他样式也如此
}
.theme-orange {
@theme: #f9a51b;
@tag: #fecc4e;
.module-theme(@theme, @tag);
}
.theme-sky-blue {
@theme: #6fa4d7;
@tag: #93bde5;
.module-theme(@theme, @tag);
}
3、scss写法
$themes: (
theme-orange: (
theme: #f9a51b,
tag: #fecc4e
),
theme-sky-blue: (
theme: #6fa4d7,
tag: #93bde5
)
);
@each $theme, $config in $themes {
.#{$theme} {
.m-title-box {
background: map-get($config, 'theme');
}
.m-head .m-info .m-name {
color: map-get($config, 'theme');
}
// 其他样式也是如此
}
}
4、使用,传入主题名,给最外层标签使用对应的主题class
document.getElementById("theme").setAttribute("class", "theme-" + theme);