某一天,一個頭條的大佬問我,聽說你之前在專案裡面弄過主題切換,你當時是怎麼實現的可以詳說一下嗎?
如果已經對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會導致之前引入的樣式和後來的衝突?我沒有明白具體是什麼意思,由於時間關係他也沒有解釋得很清楚,希望知道問題出在哪裡的同學告訴我一下哦。
ps,有沒有更好的切換主題的方案呢,求大佬指點~