網站需要一個漂亮的介面來將資訊帶給用戶,開發這個介面除了要使用
HTML Tag 外,亦需要使用
Cascading Style Sheets (CSS) 去令這個介面更美觀。有人說: 你只要複製一次程式碼其實亦是複製了一個
Bug,所以我們在設計程式時也盡量不要將相同的程式碼複製到不同地方,在
Java 可以將一些程式碼包裝成
Object 以便不同地方也使用同一組程式碼,但在
CSS 又怎麼辦? 使用外部的
CSS 檔案其實已經很大程度地減少重複的外觀設置程式碼,但這仍然不足夠。
今次介紹的工具能夠在
CSS 設置一些常用參數,外觀設置程式碼的組合,簡單的算法和使用
Javascript 功能等等。這款工具就是
LESS 了。
以下例子可以對比普通
CSS 和
LESS CSS 的不同。
參數:
普通
CSS:
.header{
background-color: #777;
color: #f5f5f5;
}
a{
color: #777;
}
p.desc{
border: solid 1px #777;
color: #777;
}
以上的
CSS 出現了好幾次
#777 這個顏色設置,如果網頁樣式改變了,需要將灰色設置為淺一點的灰色,只好一個一個
#777 找出來加以修改。
使用
LESS 可以:
@gray: #777;
@smoke-white: #f5f5f5;
.header{
background-color: @gray;
color: @smoke-white;
}
a{
color: @gray;
}
p.desc{
border: solid 1px @gray;
color: @gray;
}
這樣只需將 @gray 參數改變就可以一次轉換所有灰色了。
除了參數還可以組合外觀設置程式碼:
普通
CSS:
.header{
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
}
ul.stack li{
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
}
LESS CSS:
.border-radius (@radius 5px) {
border-radius: @radius;
-moz-border-radius: @radius;
-webkit-border-radius: @radius;
}
.header{
.border-radius;
}
ul.stack li{
.border-radius(3px);
}
因為不同的瀏覽器設置圓角的程式碼也不同,如果以後又有一款新瀏覽器提供圓角的樣式,就可以加一句到 .border-radius 就完成所有設置,方便得多。
LESS 的組合外觀設置程式碼提供了傳入參數和默認參數。
LESS 可以令
CSS 程式碼更直觀:
普通
CSS:
.header p{
background-color: #777;
}
.header p span{
font-size: 18px;
}
.header p span.brand a{
color: #ccc;
}
.header p span.brand a:hover{
color: #f5f5f5;
}
LESS CSS:
.header{
p{
background-color: #777;
span{
font-size: 18px;
&.brand{
a{
color: #ccc;
&:hover{
color: #f5f5f5;
}
}
}
}
}
}
這樣可以更加清楚知道
.header 內的所有風格。
如要使用
LESS 有
2 種方法:
- 使用 less.js 在瀏覽器將 LESS CSS 轉換為普通 CSS
- 下載 Node.js 然後使用 npm 去下載 LESS 並使用 Command 將 LESS CSS 轉換為普通 CSS
第一個方法在開發環境使用還好,在真實環境建議使用第 2 種方法。
我弄了一個
Node.js 的
script 以方便大量轉換
CSS,有興趣可拿去用:
#!/usr/bin/env node
var sys = require('util')
var fs = require('fs');
var less = require('less');
var targetDir = 'public';
var currentDir = 'source';
convertResource(currentDir);
function convertResource(dirName){
fs.readdir(dirName, function(err, files){
if (err){
console.log(err);
return;
}
for (var i = 0; i < files.length; i++){
(function(){
var sourceFile = dirName + "/" + files[i];
var targetFile = sourceFile.replace(currentDir, targetDir);
fs.lstat(sourceFile, function(e, stats){
if (stats.isDirectory()){
if (!isFileExist(targetFile)){
fs.mkdirSync(targetFile);
}
convertResource(sourceFile);
}else{
if (sourceFile.match(/^(.*)(\.css|\.less)$/i)){
complieCss(sourceFile, targetFile.replace(/^(.*)(\.css|\.less)$/i, "$1.css"));
}else{
var is = fs.createReadStream(sourceFile)
var os = fs.createWriteStream(targetFile);
sys.pump(is, os);
}
}
});
})();
}
});
}
function complieCss(sourceFile, targetFile){
fs.readFile(sourceFile, "utf-8", function(e, data){
new(less.Parser)({
paths: [".", sourceFile.substring(0, sourceFile.lastIndexOf('/'))],
filename: sourceFile
}).parse(data, function (err, tree) {
if (err) {
console.log(err);
} else {
try {
css = tree.toCSS({
yuicompress: true
});
if (targetFile) {
if (isFileExist(targetFile)){
fs.unlinkSync(targetFile);
}
var fd = fs.openSync(targetFile, "w");
fs.writeSync(fd, css, 0, "utf8");
}else{
sys.print(css);
}
} catch (e) {
console.log("CSS file complie error. Ignore file: " + sourceFile);
}
}
});
});
}
function isFileExist (path) {
try {
fs.statSync(path);
return true;
} catch (e) {
return false;
}
}
更多的用法可在
LESS 官網找到:
官網:
http://lesscss.org/