8788 / blog Goto Github PK
View Code? Open in Web Editor NEW博客迁移到GitHub,采用issues方式发布
博客迁移到GitHub,采用issues方式发布
历史文章,发布于2014年,现迁移到issues
css预处理器已经算不上一个新鲜的词了,当前比较有代表性的css预处理器有sass、less、stylus。关于三者选择问题一直都是比较受争议的话题,这里就不在讨论了,适合的就是最好的。这篇文章主要会介绍一些sass的常见用法,当然很多理论都是相通的。
在介绍sass前,我们先得明确几点:
sass是基于ruby的产物,因此在安装sass前需要先安装ruby。(ps: 本机系统环境,win7 64位)
下载对应系统的版本,一路next即可。安装完成后,在命令行输入ruby -v
可查看ruby版本。
$ ruby -v
ruby 2.0.0p451 (2014-02-24) [x64-mingw32]
安装完ruby后,在命令行输入gem install sass
即可安装sass,安装完后可通过sass -v
来查看sass版本。
$ sass -v
Sass 3.3.5 (Maptastic Maple)
sass有两种可选的文件后缀.sass
和.scss
,两者的主要区别就是在书写格式上。
.sass
文件是缩进式的写法,对格式要求比较严谨,末尾不能有分号
.test
margin: 5px 10px
font-size: 14px
color: #333
.scss
文件的写法和css一致
.test {
margin: 5px 10px;
font-size: 14px;
color: #333;
}
可以根据个人的书写习惯来选择这两种风格,只要同一个文件中不混用即可。(ps: 文章后面用到的代码采用的是第二种风格)
sass test.scss test.css
也可以设置输出css文件的风格
sass --style compressed test.scss test.css
输出样式的风格可以有四种选择,默认为nested
sass --watch test.scss:test.css
sass --watch src:dest
sass的一个重要特性就是引入了变量。我们可以把反复用到的属性值或者经常修改的值定义成变量,方便调用和修改。
$base-gap: 10px;
$base-color: #333;
.test {
margin-top: $base-gap;
color: $base-color;
}
如果在字符串中引用变量,则需要将变量名写在#{}
中。如:
$img-dir: "public/images/";
.test {
background-image: url(#{$img-dir}icon.png);
}
默认变量用来提供sass的默认值。它的含义是:如果这个变量被声明赋值了,那就用它声明的值,否则就用默认值。这在书写sass库文件时非常有用。设置默认变量的方法也非常简单,只需在变量值后加上!default
即可。
$color: #ccc;
$color: #000 !default;
p {
color: $color;
}
多值变量类似js中的数组,声明时只需用空格将多个值隔开即可。如:
$colors: #fff #ccc #999 #666 #333;
我们可以通过length($colors)
来获取多值变量的值的个数,通过nth($colors, index)
来获取第index
个位置的值。ps: index
的取值范围为1到length($colors)
。
$colors: #fff #ccc #999 #666 #333;
p::after {
content: "#{length($colors)}"; // 5
color: nth($colors, 1); // #fff
}
嵌套是一个比较实用的功能,它不仅可以省去书写大量重复选择器的时间,还能够让代码显得更有条理、更易维护。
.list {
margin-top: 10;
}
.list li {
padding-left: 15px;
}
.list a {
color: #333;
}
.list a:hover {
text-decoration: none;
}
用嵌套改写
.list {
margin-top: 10px;
li {
padding-left: 15px;
}
a {
color: #333;
&:hover {
text-decoration: none;
}
}
}
嵌套代码中的&
表示父元素选择器。嵌套虽然很方便,但不建议嵌套层次太深,以免生成的css选择器过长。除了选择器可以嵌套外,css属性也可以嵌套(用的相对较少),如:
.test {
border: {
width: 2px;
style: solid;
color: #000;
}
}
css有一个不太常用的特性,即@import
导入功能,它允许在一个css文件中导入其他css文件。然而,结果是只有执行到@import
规则时,浏览器才会去下载其他css文件,这会导致页面样式加载特别慢,从而容易出现页面闪的问题。
sass也有@import
导入规则,与css不同的是,sass中的@import
规则会在生成css文件时,把相关的文件导入合并成一个文件,而无需浏览器去下载其他的文件。另外在被导入文件中定义的变量等也可以在导入文件中正常使用。
在使用@import
导入sass文件时,可以省略sass文件的后缀名.sass
或.scss
,例如:
- a.scss
body {
background-color: #f00;
}
- style.scss
@import "a";
div {
color: #333;
}
编译后的style.css
文件内容如下:
body {
background-color: #f00;
}
div {
color: #333;
}
如果你是编译整个sass目录的话,会发现一个问题,在生成style.css
的同时也生成了一个a.css
,这个结果并不是我们想要的,a.scss
作为一个中间文件,一般情况下是不需要在生成css的。sass开发者也考虑到了这点,我们只需要在文件名前加上下划线_
,sass编译的时候就会忽略这个文件,@import
引用的时候可以加下划线引用,也可以不加。还是上面的例子,我们可以进行修改:
- _a.scss
body {
background-color: #f00;
}
- style.scss
@import "a";
div {
color: #333;
}
这样一来就只会生成style.css
文件,不会再生成多余的a.css
了。
当然,如果你需要像原生css那样去导入其他的css文件,也是可以的,如果符合以下三条中的任意一种情况,sass就会认为你想用css原生的@import
:
.css
结尾@import url(...)
方式去导入文件sass支持原生css的注释格式/* 注释内容 */
,同时也支持类似js中的单行注释// 注释内容
。对于单行注释,sass会在生成的css文件中删除单行注释,只保留css原生的注释内容,例如:
.test {
margin: 10px; // 这块注释不会出现在生成的css文件中
color: #333; /* 这块注释会出现在生成的css文件中 */
}
当然,如果你把多行注释写在原生css不允许的地方时,在编译生成css文件时,sass会将这些注释抹掉。例如:
.test {
padding /* 这块注释不会出现在生成的css文件中 */: 10px
margin: 5px /* 这块注释也不会出现在生成的css文件中 */ 10px;
}
sass中的混合器一般用来解决大段代码重复的问题。比如我们经常使用的单行文本溢出显示省略号,可以使用@mixin
来定义一个简单的混合器:
@mixin ellipsis {
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
然后在需要用到的地方我们可以通过@include
来使用这个混合器:
.text {
@include ellipsis;
}
输出的css为:
.text {
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
混合器不仅可以实现代码的重复利用,还可以传递参数,根据需要生成不同的css。这在跨浏览器的css3
兼容方面尤为好用。例如:
@mixin radius($value) {
-moz-border-radius: $value;
-webkit-border-radius: $value;
border-radius: $value;
}
使用时,我们只需传入相应的参数值即可。
.test {
@include radius(3px);
}
生成的css为:
.test {
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
}
另外我们还可以给参数提供默认值,如:
@mixin link-colors($normal: #333, $hover: $normal, $visited: $normal) {
color: $normal;
&:hover {
color: $hover;
}
&:visited {
color: $visited;
}
}
调用时,可以传参,也可以不传:
.text {
@include link-colors;
}
.error {
@include link-colors(red);
}
a {
@include link-colors(blue, green, yellow);
}
生成的css为:
// 鉴于篇幅问题,已将生成的代码改成单行
.text { color: #333;}
.text:hover { color: #333;}
.text:visited { color: #333;}
.error { color: red;}
.error:hover { color: red;}
.error:visited { color: red;}
a { color: blue;}
a:hover { color: green;}
a:visited {color: yellow;}
使用sass时,继承是一个很不错的减少css重复代码的功能。继承可以让一个选择器继承另一个选择器的所有样式,并联合声明。可以使用@extend
语法来实现继承。
.text {
color: #333;
font-size: 14px;
margin: 10px 0;
}
.error {
@extend .text;
color: #f00;
}
上面代码中,.error
继承了.text
中的所有样式,并且.error
和.text
中的公共样式会进行联合声明。生成的css为:
.text, .error {
color: #333;
font-size: 14px;
margin: 10px 0;
}
.error {
color: #f00;
}
这种继承虽然方便,但是也有一定的弊端。比如我们仅仅想继承.text
类中的样式,而实际并不需要.text
的这个类。换句话说就是我们的html中并没有class="text"
这样的代码,这样的话生成的css中的.text
其实就是多余的。
对于这种情况,sass
3.2.0及以后的版本也给我们提供了解决方案:占位选择器%。
占位选择器的优势在于:声明之后,如果不调用,则不会产生类似.text
的多余css代码。占位选择器通过%
标识来定义,也是通过@extend
来调用。
%text {
color: #333;
font-size: 14px;
margin: 10px 0;
}
.warn {
@extend %text;
color: #fdd;
}
.error {
@extend %text;
color: #f00;
}
生成的css为:
.warn, .error {
color: #333;
font-size: 14px;
margin: 10px 0;
}
.warn {
color: #fdd;
}
.error {
color: #f00;
}
这样就不会再额外生成多余的样式了。
sass中的@if
语句和js中的if
很相似。可以单独使用,也可以配合@else
使用。
$lte7: true; // 是否支持ie7以下版本
$theme: yellow;
.clearfix {
@if $lte7 {
zoom: 1;
}
&:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
}
body {
@if $theme == red {
background: rgba(255, 0, 0, 0.5);
} @else if $theme == yellow {
background: rgba(255, 255, 0, 0.5);
} @else if $theme == black {
background: rgba(0, 0, 0, 0.5);
}
}
生成css为:
.clearfix {
zoom: 1;
}
.clearfix:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
body {
background: rgba(255, 255, 0, 0.5);
}
三目运算符的语法为:@if($condition, $condition_true, $condition_false)
,例如:
$fontBold: true;
.title {
font-weight: if($fontBold, bold, normal);
}
生成的css为
.title {
font-weight: bold;
}
历史文章,发布于2014年,现迁移到issues
用wordpress很长一段时间了,尽管wp很成熟,插件也比较多,功能也应有尽有。但是每次写东西的时候,都要经历一个繁琐的过程,很是让人不爽。之前的流程是这样:
markdown编写内容 --> 插件导出html --> 粘贴到wp后台 --> 发布
当想修改文章的时候,又得重新来一遍。终于还是受不了了,于是抽出了几天时间了解了 hexo,觉得挺好用的,而且可以直接托管在github,连虚拟主机的费用都省了。而且hexo从写到发布流程也比较简单,只需两条命令就可以完成发布流程:
hexo g --> hexo d
迁到hexo的同时,也更换了新的域名,旧的文章后期会选择性的迁过来一些。
对于第一次接触hexo的用户来说,还是需要花点时间来了解下的,我是参考了下面的两篇文章,介绍的非常详细,所以对这里就不赘述了。
hexo主题是这次迁移博客花的时间最多的地方,https://github.com/tommy351/hexo/wiki/Themes,官方虽然也列出来了不少主题,大致看了一遍都不是太喜欢。于是就在hexo-theme-strict的基础上进行了修改,也就是现在用的这个主题,等以后对hexo熟悉之后再考虑自己开发一个主题。
这次主要对strict
主题进行了以下修改:
首页风格如下图:
修改后的主题源码也放到了github上,喜欢的可以下载下来使用,具体使用方法可参考说明
我们知道要想在博客的根目录添加资源(图片、html等),只需将对应的文件放在source
目录下即可。但是经过测试发现,当把.html文件放在source
目录下时,hexo也会把它当成.md文件去渲染。官方给出的方案是在html文件头部加上:
layout: false
---
很显然,如果页面过多的话,会比较坑。目前还没发现比较好的方案,于是尝试修改hexo的源码。在node安装目录\node_modules\hexo\lib\plugins\generator
下有个page.js
文件(ps: 测试的系统是win7 64位,hexo版本2.5.2
),找到以下代码:
if (!layout || layout === 'false'){
route.set(item.path, function(fn){
fn(null, item.content);
});
} else {
render(item.path, [layout, 'page', 'post', 'index'], item);
}
将其修改为:
var notRender = ['test1', 'test2']; // 设置不被render的目录
var dir = path.substring(0, path.indexOf('/'));
if (!layout || layout === 'false' || notRender.indexOf(dir) > -1){
route.set(item.path, function(fn){
fn(null, item.content);
});
} else {
render(item.path, [layout, 'page', 'post', 'index'], item);
}
notRender中的test1
, test2
目录即为不需要被render的目录,保存后,重新执行hexo g
命令就会发现source
中的test1
和test2
目录下的html文件没有被render。
另外感谢@xzper 和 @熙和 补充的通过hexo-processor-copyassets
插件来解决的方案,详情请参考:
历史文章,发布于2014年,现迁移到issues
一些javascript技巧被资深的程序员广泛使用。然而对于初学者来说,有的技巧的含义并不是那么的显而易见。这些技巧往往使用的并不是语言的直接含义,而是利用一些特性或者副作用来达到目的。下面我会对一些常用的技巧做出解释。
你应该明白,这些技巧中的很多都属于hack,不应该在日常开发中使用。这篇文章的目的是解释这些hack是如何工作的,并不是推荐去使用它们。
!!
将值转换为布尔型在javascript中,所有的东西都能被转换成“真”或“假”。也就是说,当你把一个对象放进if
语句的条件中,执行时,要么走条件为真的分支,要么就走条件为假的分支。
0
, false
, ""
, null
, undefined
, NaN
为假,其他对象都为真。有时候想将一个对象转换成布尔值,你可以使用!!
。
另外,如果不是if (x == "test")
这种形式,你可以简单的写成if (x)
,当x
为false时,程序将直接运行其它块。
+str
将字符串转换成数字在javascript中,当+
作为一元运算符使用时会返回一个数值或NaN
。有时当你想知道一个变量是否是数值(number
)时,你可以这样来写代码x === +x
(见underscorejs
源码)。
这种方法意图并不明显,通常,你应该使用parseFloat
或者parseInt(x, 10)
来将一个变量转换成数值型(number
)。
||
来提供默认值在javascript中,||
是一个短路求值的例子,也常用在其他语言当中。||
操作符会首页判断左边表达式的值,如果为false
,则继续判断右边。在任何情况下它都会返回第一个值不为false
的结果,参考下面例子:
function setAge(age) {
this.age = age || 10;
}
setAge();
我们没有传入age的值,因此age || 10
会返回10
,这是给变量设置默认值的非常好的一个方式。事实上这段代码等价于:
var x;
if (age) {
this.age = age;
} else {
this.age = 10;
}
很明显,前者代码更简洁,这就是为什么到处都在使用它的原因。
就我自己而言,我经常使用这种方式,因为足够的简洁明了。需要注意的是,这种方式你没法设置age
为0
,因为0
是false
,因此下面的方法应该是一个更好的方案(但是代码稍微有些冗长):
this.age = (typeof age !== "undefined") ? age : 10;
void 0
来替代undefined
关键字void
后跟着一个参数,并总会返回undefined
。为什么不直接使用undefined
?因为在一些浏览器中,undefined
仅仅被视作一个变量,并且可以被重新赋值,而前者可以给我们更高的信赖。虽然你可以看到这种写法在很多代码或库中被使用,但是我并不建议经常使用它,因为所有遵循EC5
的浏览器已经禁止重写undefined
了。
(function() {...})()
当你想要封装代码时,你可以用一个匿名函数包裹代码,然后立刻执行这个匿名函数。在javascript中,有两种作用域:全局作用域和局部(函数)作用域。你写的代码包括变量和函数声明,不论在任何位置,都会进入全局作用域。通常,你可以将代码封装在匿名函数的内部,而只向全局作用域暴露调用接口的方法名。这个模式使用起来也非常方便,请看以下代码:
(function() {
function div(a, b) {
return a / b;
}
function divBy5(x) {
return div(x, 5);
}
window.divBy5 = divBy5;
})()
div // => undefined
divBy5(10); // => 2
本文中列出的这些hack中,这条确实是无害的,你应该在代码中使用它以防止代码的内部逻辑暴露在全局作用域中。
总之,我想提醒的是,你写的任何代码都应该本着让其他人读起来简单易懂为原则。
一些文章中列出的问题,在ES6
标准中已经通过优雅的方式进行了解决。例如,在未来你不需要使用age = age || 10
这种模式了,ES6
提供的一种更好的方式来设置默认值:
function(age = 10) {
...
}
另一个例子是(function() {...})()
这种模式,当现代浏览器支持ES6 modules之后,你可以使用模块化来代替。
历史文章,发布于2012年,现迁移到issues
layout是windows IE的一个私有概念,它决定了元素如何对其内容定位和尺寸计算,以及与其他元素的关系和相互作用。当一个元素“拥有布局”时,它会负责本身及其子元素的尺寸和定位。而如果一个元素“没有拥有布局”,那么它的尺寸和位置由最近的拥有布局的祖先元素控制。
必须说明的是,IE8及以上浏览器使用了全新的显示引擎,已经不在使用haslayout属性,因此文中提到的haslayout属性只针对IE6和IE7。
理论上说,每个元素都应该控制自己的尺寸和定位,即每个元素都应该“拥有布局”,当然这只是理想状态。而对于早期的IE显示引擎来说,如果所有元素都“拥有布局”的话,会导致很大的性能问题。因此IE开发团队决定使用布局概念来减少浏览器的性能开销,即只将布局应用于实际需要的那些元素,所以便出现了“拥有布局”和“没有拥有布局”两种情况。
下面,先来看下哪些元素在默认情况下就“拥有布局”。
html, body
table
tr, td
img
hr
input, select, textarea, button
iframe, embed, object, applet
marquee
haslayout是windows IE私有的,而且它不是css属性,我们无法通过css显式的设置元素的haslayout。但我们可以通过javascript来查看一个元素是否拥有布局:
<div id="div1">这是一个div</div>;
var oDiv = document.getElementById('div1');
alert(oDiv.currentStyle.hasLayout); //弹出false
如果元素拥有布局,obj.currentStyle.hasLayout就会返回true,否则返回false。hasLayout是一个只读属性,所以也无法通过javascript进行设置。
在实际开发过程中,很多IE下(IE6、IE7)的显示问题,都可以通过触发元素的haslayout来解决,下面列出一些常见的可以触发元素haslayout的属性和方法:
float: left或right
display: inline-block
position: absolute
width: 除auto外任何值
height: 除auto外任何值
zoom: 处normal外任何值
writing-mode: tb-rl
在IE7中,以下属性也可以触发元素的haslayout
min-height: 任意值
min-width: 任意值
max-height: 除none 外任意值
max-width: 除none 外任意值
overflow: 除visible外任意值,仅用于块级元素
overflow-x: 除visible 外任意值,仅用于块级元素
overflow-y: 除visible 外任意值,仅用于块级元素
position: fixed
当然可能还有一些我们没有发现的bug,一般情况下我们会使用zoom: 1;来触发haslayout从而来解决这些bug,因为zoom: 1不会影响到元素的现有表现,虽然zoom: 1无法在IE5.0中触发haslayout,但是IE5.0已经不在我们的测试范围内了,所以可以放心的使用zoom: 1。另外在IE6及较早版本的浏览器中还可以使用height: 1%来触发,IE7中可以使用min-height: 0来触发。
参考文章:
历史文章,发布于2014年,现迁移到issues
sublime作为一款小而美的编辑器相信很多FE都在使用,然而美中不足的就是sublime没有自带浏览器预览功能,wbond上也没有发现比较好用的预览插件。也有网友提供了一些解决方案,但是大部分都只实现了快捷键调用默认浏览器中预览的功能,但是作为前端,需要在多个浏览器下测试兼容性,频繁的手动打开浏览器势必会降低工作效率。这里介绍一种利用SideBarEnhancements
插件来实现多浏览器下预览的功能。ps: sublime text2/3测试都可以用。
SideBarEnhancements
插件ctrl + shift + p
--> Install Package
--> 找到SideBarEnhancements
Preferences
--> Key Bindings - User
将以下代码复制到数组中。
// chrome
{
"keys": ["f2"], "command": "side_bar_files_open_with",
"args": {
"paths": [],
"application": "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe",
"extensions":".*"
}
},
// firefox
{
"keys": ["f3"], "command": "side_bar_files_open_with",
"args": {
"paths": [],
"application": "D:/Program Files (x86)/Mozilla Firefox/firefox.exe",
"extensions":".*"
}
},
// ie
{
"keys": ["f4"], "command": "side_bar_files_open_with",
"args": {
"paths": [],
"application": "C:/Program Files/Internet Explorer/iexplore.exe",
"extensions":".*"
}
}
上面的代码中有两处需要注意的地方,一个是keys
表示快捷键,即f2
可以启动chrome进行预览。另一个是application
,表示浏览器所在的安装路径,只有路径配置正确,才能够正常调用浏览器。
这里列出了chrome
, firefox
, ie
的配置,快捷键分别为f2
, f3
, f4
,当然快捷键可以自行修改,如果需要添加其他浏览器,只需再增加一条即可。
历史文章,发布于2014年,现迁移到issues
npm
全称Node Package Manager
,是node.js的模块依赖管理工具。由于npm
的源在国外,所以国内用户使用起来各种不方便。下面整理出了一部分国内优秀的npm
镜像资源,国内用户可以选择使用。
有很多方法来配置npm
的registry地址,下面根据不同情境列出几种比较常用的方法。以淘宝npm
镜像举例:
npm --registry https://registry.npm.taobao.org install express
npm config set registry https://registry.npm.taobao.org
// 配置后可通过下面方式来验证是否成功
npm config get registry
// 或者
npm info express
cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
// 使用
cnpm install express
历史文章,发布于2014年,现迁移到issues
PS:当前已经有很多编辑器可以实时编辑和预览markdown,如Visual Studio Code/Atom等,历史文章,仅供参考
markdown是一种简单的、轻量级的标记语言,由John Gruber和Aaron Swartz创建。markdown的优点非常多,如:语法简单,能让文档更易阅读、维护和修改,但是我觉得更吸引人的一个优点是:
markdown让我们专注于文章内容,而不是关注排版
确实是这样,不管是写博客还是写其他文章,如果用word来写,排版势必会是一个让人烦恼的问题。而如果用html来写的话,虽然很直观,但是不停的输入标签必然大大降低了写作效率。比如写一个简单的列表:
<ul>
<li>sublime text2</li>
<li>markdown</li>
<li>notepad++</li>
</ul>
其实我们只是想输出一个简单的列表,但是编辑标签花费的时间都快要赶上编辑内容的时间了。那么我们来看下用markdown来实现这个列表。
- sublime text2
- markdown
- notepad++
只需在每个列表内容前加上“-”符号,便可以直接生成一个无序列表。
- sublime text2
- markdown
- notepad++
再来看一下怎样用markdown输出标题
# This is h1
## This is h2
### This is h3
#### This is h4
##### This is h5
###### This is h6
This is h1
This is h2
This is h3
This is h4
This is h5
This is h6
更多markdown语法可参考http://wowubuntu.com/markdown/ 这里不在一一列举,基本上花个5-10分钟的时间便可以掌握markdown的基本语法
那么作为一个sublime爱好者我们要怎样使用markdown呢?首先当然是安装sublime和Package Control了。。。具体可参考文章Sublime Text 2 入门及技巧
markdown插件这里只推荐markdown Preview,其他的确实也没怎么用过。Mardown Preview不仅支持在浏览器中预览markdown文件,还可以导出html代码,这样极大方便了我们导出代码发布到博客上。
下面简单说明下markdown Preview插件的安装和使用
sublime自带的主题风格中没有markdown语法的高亮功能,于是从网上找了一个做了些简单的修改,感觉色彩搭配还行。
附上代码地址:Monokai-custom.tmTheme
将上面代码下载并命名为:Monokai-custom.tmTheme,放入"Packages/User/"文件目录中,然后在面板中选择:Preferences-->Color Scheme-->User-->Monokai-custom,如下图所示:
高亮后的效果如上图中所示。
总结:整体来说用markdown语法来写文章还是挺方便的,这篇文章也是通过markdown来写的,比之前用Windows Liver Writer效率要高。当然美中不足的一点就是图片的处理,因为markdown中只能插入图片地址,没法上传图片,而我是先通过ftp将图片上传到站点上再获取链接插入。日后若发现更好的方法再进行补充。
css雪碧图又叫css精灵或css sprite,是一种背景图片的拼合技术。使用css雪碧图,能够减少页面的请求数、降低图片占用的字节,以此来达到提升页面访问速度的目的。但是它也有令人诟病的地方,就是拼图和后期维护的成本比较大。也正是因为这一点,导致很多开发者懒于使用css雪碧图。
对于这种耗时、枯燥、重复性的工作,最好的解决方法还是交给工具去处理。本文就介绍下怎样使用compass来自动合并css雪碧图。
首先请确认电脑已经安装ruby
及sass
环境,ruby
及sass
的安装过程可参考:
安装完成后可通过以下指令确认:
$ ruby -v
ruby 2.0.0p451 (2014-02-24) [x64-mingw32]
$ sass -v
Sass 3.4.6 (Selective Steve)
接着安装compass
:
$ gem install compass
// 查看compass版本
$ compass -v
Compass 1.0.1 (Polaris)
ps: 本文中代码运行环境为:sass: 3.4.6
, compass: 1.0.1
, 测试时请确认sass版本不低于3.4.6
,compass版本不低于1.0.1
。
进入项目目录,命令行中运行:
$ compass init
会生成相应的目录和配置文件。在images
目录下建立share
目录存放需合并的图标。项目目录结构如下:
- sass
- stylesheet
- images
|-- share
|-- magic
|-- setting
config.rb
文件配置如下:
http_path = "/"
css_dir = "stylesheets"
sass_dir = "sass"
images_dir = "images"
javascripts_dir = "javascripts"
relative_assets = true // 使用相对目录
line_comments = false // 关闭行注释
完整的项目目录示例可在github上查看:https://github.com/8788/compass-sprite
在sass
目录下新建share.scss
文件,并写入以下代码:
@import "compass/utilities/sprites"; // 加载compass sprites模块
@import "share/*.png"; // 导入share目录下所有png图片
@include all-share-sprites; // 输出所有的雪碧图css
命令行调用compass compile
进行编译,此时会发现images
目录下出现了一个合并后的图片share-xxxxxxxx.png
, stylesheet
目录下生成了对应的share.css
文件:
.share-sprite, .share-github, .share-qq, .share-weibo {
background-image: url('../images/share-s7fefca4b98.png');
background-repeat: no-repeat;
}
.share-github {
background-position: 0 0;
}
.share-qq {
background-position: 0 -23px;
}
.share-weibo {
background-position: 0 -47px;
}
至此,我们就实现了一个简单的雪碧图合并,而且只用了三行代码。是不是有点小激动^_^。
生成的代码中.share-sprite
是雪碧图的基础类,后面介绍配置时会详细说明。生成的每个雪碧图默认的class规则是:.目录名-图片名
。如果想自定义,我们可以通过下面调用单个雪碧图的方式来实现。
在sass
目录下新建single-share.scss
文件,并写入以下代码:
@import "compass/utilities/sprites"; // 加载compass sprites模块
@import "share/*.png"; // 导入share目录下所有png图片
.test {
@include share-sprites(github);
}
编译后的css为:
.share-sprite, .test {
background-image: url('../images/share-s7fefca4b98.png');
background-repeat: no-repeat;
}
.test {
background-position: 0 -23px;
}
有的时候我们的图标会有多种状态,比如hover
, active
, focus
, target
等。利用compass的魔术精灵选择器我们就可以智能的合并各状态的图标,并输出对应的css。使用时,我们需要将图标按照一定的规则命名。例如:
weibo.png // 默认状态图标
weibo_hover.png // hover状态图标
weibo_active.png // active状态图标
在sass
目录下新建magic.scss
文件,并写入以下代码:
@import "compass/utilities/sprites";
@import "magic/*.png";
@include all-magic-sprites;
编译后的css为:
.magic-sprite, .magic-weibo {
background-image: url('../images/magic-s758f6928e8.png');
background-repeat: no-repeat;
}
.magic-weibo {
background-position: 0 0;
}
.magic-weibo:hover, .magic-weibo.weibo-hover {
background-position: 0 -48px;
}
.magic-weibo:active, .magic-weibo.weibo-active {
background-position: 0 -24px;
}
我们已经利用compass
实现了简单雪碧图的合成。当然compass
还提供了很多可供配置的选项,下面来一一介绍。
PS: 以下的配置选项不再单独举例,可参考示例项目中的setting.scss
文件。
先来看下配置相关的语法:
$<map>-<property>: setting; // 配置所有sprite
$<map>-<sprite>-<property>: setting; // 配置单个sprite
说明:
<map>
: 对应图标存放的文件夹名称,如上面例子中的:share
和magic
<sprite>
: 对应单个图标的名称,如上面例子中的: weibo
, qq
, github
等$<map>-spacing: 5px; // 配置所有sprite间距为5px,默认为0px
$<map>-<sprite>-spacing: 10px; // 配置单个sprite间距为10px,默认继承$<map>-spacing的值
$<map>-repeat: no-repeat/repeat-x; // 配置所有sprite的重复性,默认为no-repeat
$<map>-<sprite>-repeat: no-repeat/repeat-x;// 配置单个sprite的重复性,默认继承$<map>-repeat的值
$<map>-position: 0px; // 配置所有sprite的位置,默认为0px
$<map>-<sprite>-position: 0px; // 配置单个sprite的位置,默认继承$<map>-position的值
$<map>-layout: vertical/horizontal/diagonal/smart; // 默认布局方式为vertical
$<map>-clean-up: true/false; // 默认值为true
每当添加、删除或改变图片后,都会生成新的sprite,默认情况下compass会自动的移除旧的sprite,当然也可以通过配置$<map>-clean-up: false;
来保留旧的sprite。
在使用sprite时,compass会自动的生成一个基础类来应用公用的样式(如background-image
),默认的类名为$<map>-sprite
,上面例子中的.share-sprite
, .magic-sprite
就是这个基础类,当然compass也提供了自定义这个类名的选项:
$<map>-sprite-base-class: ".class-name";
上面已经介绍了怎样利用利用魔术精灵选择器智能输出sprite,默认情况下compass是开启这个功能的,也就是说compass默认会将以_hover
, _active
等名字结尾的图片自动输出对应的:hover
, :active
等伪类样式。当然如果不想这样的话,也可以禁用它。
$disabled-magic-sprite-selectors: false; // 默认为true
我们在合并雪碧图时,很多时候图片的尺寸都不一样,那么在使用时我们如何给每个sprite设置尺寸呢?compass有提供自动设置每个sprite尺寸的配置,默认是关闭的,我们只需手动启用即可。
$setting-sprite-dimensions: true; // 启用自动设置sprite尺寸,默认值为false
这时输出的样式中会自动加上图片的尺寸,例如:
.setting-compass {
background-position: -5px 0;
height: 35px;
width: 200px;
}
当然,如果只对某个sprite单独设置的话,compass也提供了这个功能。语法如下:
$<map>-sprite-width($name); // $name为合并前的图片名称
$<map>-sprite-height($name);
例如:
.special {
@include setting-sprite(compass);
width: setting-sprite-width(compass);
height: setting-sprite-height(compass);
}
则输出的css为:
.special {
background-position: -5px 0;
width: 200px;
height: 35px;
}
github上放了一个简单的示例可供参考:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.