通过开源文档学LESS系列1

1.引言

今天开始一个系列教程,通过一些国外开源LESS文档来学习LESS。这些开源的文档一般都是前端开发实际项目经验的总结,从中可以看出LESS的基本语法和日常使用,也可以从中管窥大牛开发者的智慧。

首先,我们来看一个开源项目Preboot,大家可以看看他的官方网站,或者到github中学习、下载中学习、下载本项目。作者Mark Otto,大家可以关注他的github

A collection of LESS mixins and variables for writing better CSS.

好的,言归正传。

2.代码解析

来吧,先看注释,注释的习惯要养成,要学会尊重别人的成果。有的时候灵感来源也可以一并写上,表示感谢。
/*!
 * Preboot v2
 *
 * Open sourced under MIT license by @mdo.
 * Some variables and mixins from Bootstrap (Apache 2 license).
 */
正文开始,首先是一些变量
//
// Variables
// --------------------------------------------------

// Grayscale
@black-10:                 darken(#fff, 10%);
@black-20:                 darken(#fff, 20%);
@black-30:                 darken(#fff, 30%);
@black-40:                 darken(#fff, 40%);
@black-50:                 darken(#fff, 50%);
@black-60:                 darken(#fff, 60%);
@black-70:                 darken(#fff, 70%);
@black-80:                 darken(#fff, 80%);
@black-90:                 darken(#fff, 90%);

// Brand colors
@brand-primary:           #428bca;
@brand-success:           #5cb85c;
@brand-warning:           #f0ad4e;
@brand-danger:            #d9534f;
@brand-info:              #5bc0de;

// Scaffolding
@body-background:         #fff;
@text-color:              @black-50;

// Links
@link-color:              @brand-primary;
@link-color-hover:        darken(@link-color, 15%);

// Typography
@font-family-sans-serif:  "Helvetica Neue", Helvetica, Arial, sans-serif;
@font-family-serif:       Georgia, "Times New Roman", Times, serif;
@font-family-monospace:   Monaco, Menlo, Consolas, "Courier New", monospace;
@font-family-base:        @font-family-sans-serif;

@font-size-base:          14px;
@font-size-large:         @font-size-base * 1.25; // ~18px
@font-size-small:         @font-size-base * 0.85; // ~12px
@font-size-mini:          @font-size-base * 0.75; // ~11px

@line-height-base:        1.4;

@headings-font-family:    inherit; // empty to use BS default, @font-family-base
@headings-font-weight:    500;

// Forms
@input-color-placeholder: lighten(@text-color, 25%);

// Grid
// Used with the grid mixins below
@grid-columns:          12;
@grid-column-padding:   15px; // Left and right inner padding
@grid-float-breakpoint: 768px;

这里区块的注释的方式可以借鉴,有的时候也可以给区块加上标号,形成一个目录的方式。例如

//
// index
//-----------------------------------------
//  1.Variables
//  2.Grid system
//  3.Mixins: vendor prefixes


//
// 1.Variables
// --------------------------------------------------
全局变量的方式也可以借鉴,进行网站开发的时候可以将这部分单独剥离出来,便于日后的更新与维护。

将品牌颜色和灰度颜色作为全局变量,具有很好的可读性和可维护性。这里给大家推荐一个品牌颜色设计的工具-BrandColors,大家可以去围观。

链接、字体和网格的一些设置也可以作为全局变量。

好的,这里我们来学点LESS的基础,变量和注释。

2.1变量

变量可能是大部分爱上CSS预处理器的原因,也是诸如LESS、SASS中使用最普遍,争议最少的。
变量的定义和使用很简单,例如
@font-size-base:          14px;
变量的值可以是一个具体的数值,也可以是一个运算表达式,可以调用一个函数,甚至可以调用一个新的变量,来看看示例。
//变量的值可以是值和表达式
@font-size-base:          14px;
@font-size-large:         @font-size-base * 1.25; // ~18px
//变量的值也可以调用另一变量或者函数
@brand-primary:           #428bca;
@link-color:              @brand-primary;
@link-color-hover:        darken(@link-color, 15%);

2.2注释

LESS支持两种注释方式,一种是CSS的注释,也即块注释,另一种是类似js里的行注释,这种双斜线的注释会在编译成CSS的时候被过滤掉。
好的,接着来看preboot文档
//
// Grid system
// --------------------------------------------------

// Grid
.make-row() {
  // Negative margin the row out to align the content of columns
  margin-left: -@grid-column-padding;
  margin-right: -@grid-column-padding;
  // Then clear the floated columns
  .clearfix();
}
.make-column(@columns) {
  @media (min-width: @grid-float-breakpoint) {
    float: left;
    // Calculate width based on number of columns available
    width: percentage(@columns / @grid-columns);
  }
  // Prevent columns from collapsing when empty
  min-height: 1px;
  // Set inner padding as gutters instead of margin
  padding-left: @grid-column-padding;
  padding-right: @grid-column-padding;
  // Proper box-model (padding doesn't add to width)
  .box-sizing(border-box);
}
.make-column-offset(@columns) {
  @media (min-width: @grid-float-breakpoint) {
    margin-left: percentage(@columns / @grid-columns);
  }
}
这里是实现网格布局的LESS mixins。

2.3 混合(Mixin)

在 LESS 中我们可以定义一些通用的属性集为一个 class,然后在另一个 class 中去调用这些属性,例如
//定义Mixin
.border{
	border:2px solid #f00;
}
//使用Mixin
someDiv{
	width:200px;
	height:200px;
	.border;
}
又如清除浮动的代码经常用到,我们就可以弄成一个Mixin,然后在需要的时候使用,例如
//清除浮动
.clearfix() {
  *zoom: 1;
  &:before,
  &:after {
    content: " "; // 1
    display: table; // 2
    // Fixes Opera/contenteditable bug:
    // http://nicolasgallagher.com/micro-clearfix-hack/#comment-36952
    line-height: 0;
  }
  &:after {
    clear: both;
  }
}
// Grid
.make-row() {
  // Negative margin the row out to align the content of columns
  margin-left: -@grid-column-padding;
  margin-right: -@grid-column-padding;
  // Then clear the floated columns,使用“清除浮动”的混合
  .clearfix();
}
Mixin可以像上面那样不带参数,也可以像其他语言的函数那样接受参数,例如
.make-column(@columns) {
  @media (min-width: @grid-float-breakpoint) {
    float: left;
    // Calculate width based on number of columns available
    width: percentage(@columns / @grid-columns);
  }
  // Prevent columns from collapsing when empty
  min-height: 1px;
  // Set inner padding as gutters instead of margin
  padding-left: @grid-column-padding;
  padding-right: @grid-column-padding;
  // Proper box-model (padding doesn't add to width)
  .box-sizing(border-box);
}
我们来继续preboot文档解析,LESS等预处理的一个重要用处就是处理vendor prefixes。
//
// Mixins: vendor prefixes
// --------------------------------------------------

// Box sizing
.box-sizing(@box-model) {
  -webkit-box-sizing: @box-model; // Safari <= 5
     -moz-box-sizing: @box-model; // Firefox <= 19
          box-sizing: @box-model;
}

// Single side border-radius
.border-top-radius(@radius) {
  border-top-right-radius: @radius;
   border-top-left-radius: @radius;
}
.border-right-radius(@radius) {
  border-bottom-right-radius: @radius;
     border-top-right-radius: @radius;
}
.border-bottom-radius(@radius) {
  border-bottom-right-radius: @radius;
   border-bottom-left-radius: @radius;
}
.border-left-radius(@radius) {
  border-bottom-left-radius: @radius;
     border-top-left-radius: @radius;
}

// Drop shadows
.box-shadow(@shadow) {
  -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1
          box-shadow: @shadow;
}

// Transitions
.transition(@transition) {
  -webkit-transition: @transition;
     -moz-transition: @transition;
       -o-transition: @transition;
          transition: @transition;
}
.transition-delay(@transition-delay) {
  -webkit-transition-delay: @transition-delay;
     -moz-transition-delay: @transition-delay;
       -o-transition-delay: @transition-delay;
          transition-delay: @transition-delay;
}
.transition-duration(@transition-duration) {
  -webkit-transition-duration: @transition-duration;
     -moz-transition-duration: @transition-duration;
       -o-transition-duration: @transition-duration;
          transition-duration: @transition-duration;
}

// Transformations
.rotate(@degrees) {
  -webkit-transform: rotate(@degrees);
     -moz-transform: rotate(@degrees);
      -ms-transform: rotate(@degrees);
       -o-transform: rotate(@degrees);
          transform: rotate(@degrees);
}
.scale(@ratio) {
  -webkit-transform: scale(@ratio);
     -moz-transform: scale(@ratio);
      -ms-transform: scale(@ratio);
       -o-transform: scale(@ratio);
          transform: scale(@ratio);
}
.translate(@x, @y) {
  -webkit-transform: translate(@x, @y);
     -moz-transform: translate(@x, @y);
      -ms-transform: translate(@x, @y);
       -o-transform: translate(@x, @y);
          transform: translate(@x, @y);
}
.skew(@x, @y) {
  -webkit-transform: skew(@x, @y);
     -moz-transform: skew(@x, @y);
      -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twitter/bootstrap/issues/4885
       -o-transform: skew(@x, @y);
          transform: skew(@x, @y);
  -webkit-backface-visibility: hidden; // See https://github.com/twitter/bootstrap/issues/5319
}
.translate3d(@x, @y, @z) {
  -webkit-transform: translate3d(@x, @y, @z);
     -moz-transform: translate3d(@x, @y, @z);
       -o-transform: translate3d(@x, @y, @z);
          transform: translate3d(@x, @y, @z);
}

// Backface visibility
//
// Prevent browsers from flickering when using CSS 3D transforms.
// Default value is `visible`, but can be changed to `hidden
// See git pull https://github.com/dannykeane/bootstrap.git backface-visibility for examples
.backface-visibility(@visibility){
  -webkit-backface-visibility: @visibility;
     -moz-backface-visibility: @visibility;
          backface-visibility: @visibility;
}

// User select
//
// For selecting text on the page
.user-select(@select) {
  -webkit-user-select: @select;
     -moz-user-select: @select;
      -ms-user-select: @select;
       -o-user-select: @select;
          user-select: @select;
}

// Opacity
.opacity(@opacity) {
  opacity: @opacity;
  @opacity-ie: @opacity * 100;
  filter: ~"alpha(opacity=@{opacity-ie})"; // IE8
}

// Placeholder text
.placeholder(@color: @input-color-placeholder) {
  &:-moz-placeholder            { color: @color; } // Firefox 4-18
  &::-moz-placeholder           { color: @color; } // Firefox 19+
  &:-ms-input-placeholder       { color: @color; } // Internet Explorer 10+
  &::-webkit-input-placeholder  { color: @color; } // Safari and Chrome
}

// Resize anything
.resizable(@direction) {
  resize: @direction; // Options: horizontal, vertical, both
  overflow: auto; // Safari fix
}

// CSS3 Content Columns
.content-columns(@width, @count, @gap) {
  -webkit-column-width: @width;
     -moz-column-width: @width;
          column-width: @width;
  -webkit-column-count: @count;
     -moz-column-count: @count;
          column-count: @count;
  -webkit-column-gap: @gap;
     -moz-column-gap: @gap;
          column-gap: @gap;
}

// Optional hyphenation
.hyphens(@mode: auto) {
  word-wrap: break-word;
  -webkit-hyphens: @mode;
     -moz-hyphens: @mode;
      -ms-hyphens: @mode;
       -o-hyphens: @mode;
          hyphens: @mode;
}

// Gradients
#gradient {
  .horizontal(@startColor: #555, @endColor: #333) {
    background-color: @endColor;
    background-image: -moz-linear-gradient(left, @startColor, @endColor); // FF 3.6+
    background-image: -webkit-gradient(linear, 0 0, 100% 0, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+
    background-image: -webkit-linear-gradient(left, @startColor, @endColor); // Safari 5.1+, Chrome 10+
    background-image: -o-linear-gradient(left, @startColor, @endColor); // Opera 11.10
    background-image: linear-gradient(to right, @startColor, @endColor); // Standard, IE10
    background-repeat: repeat-x;
    filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@startColor),argb(@endColor))); // IE9 and down
  }
  .vertical(@startColor: #555, @endColor: #333) {
    background-color: @endColor;
    background-image: -moz-linear-gradient(top, @startColor, @endColor); // FF 3.6+
    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+
    background-image: -webkit-linear-gradient(top, @startColor, @endColor); // Safari 5.1+, Chrome 10+
    background-image: -o-linear-gradient(top, @startColor, @endColor); // Opera 11.10
    background-image: linear-gradient(to bottom, @startColor, @endColor); // Standard, IE10
    background-repeat: repeat-x;
    filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down
  }
  .directional(@startColor: #555, @endColor: #333, @deg: 45deg) {
    background-color: @endColor;
    background-repeat: repeat-x;
    background-image: -moz-linear-gradient(@deg, @startColor, @endColor); // FF 3.6+
    background-image: -webkit-linear-gradient(@deg, @startColor, @endColor); // Safari 5.1+, Chrome 10+
    background-image: -o-linear-gradient(@deg, @startColor, @endColor); // Opera 11.10
    background-image: linear-gradient(@deg, @startColor, @endColor); // Standard, IE10
  }
  .horizontal-three-colors(@startColor: #00b3ee, @midColor: #7a43b6, @colorStop: 50%, @endColor: #c3325f) {
    background-color: mix(@midColor, @endColor, 80%);
    background-image: -webkit-gradient(left, linear, 0 0, 0 100%, from(@startColor), color-stop(@colorStop, @midColor), to(@endColor));
    background-image: -webkit-linear-gradient(left, @startColor, @midColor @colorStop, @endColor);
    background-image: -moz-linear-gradient(left, @startColor, @midColor @colorStop, @endColor);
    background-image: -o-linear-gradient(left, @startColor, @midColor @colorStop, @endColor);
    background-image: linear-gradient(to right, @startColor, @midColor @colorStop, @endColor);
    background-repeat: no-repeat;
    filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down, gets no color-stop at all for proper fallback
  }
  .vertical-three-colors(@startColor: #00b3ee, @midColor: #7a43b6, @colorStop: 50%, @endColor: #c3325f) {
    background-color: mix(@midColor, @endColor, 80%);
    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), color-stop(@colorStop, @midColor), to(@endColor));
    background-image: -webkit-linear-gradient(@startColor, @midColor @colorStop, @endColor);
    background-image: -moz-linear-gradient(top, @startColor, @midColor @colorStop, @endColor);
    background-image: -o-linear-gradient(@startColor, @midColor @colorStop, @endColor);
    background-image: linear-gradient(@startColor, @midColor @colorStop, @endColor);
    background-repeat: no-repeat;
    filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down, gets no color-stop at all for proper fallback
  }
  .radial(@innerColor: #555, @outerColor: #333) {
    background-color: @outerColor;
    background-image: -webkit-gradient(radial, center center, 0, center center, 460, from(@innerColor), to(@outerColor));
    background-image: -webkit-radial-gradient(circle, @innerColor, @outerColor);
    background-image: -moz-radial-gradient(circle, @innerColor, @outerColor);
    background-image: -o-radial-gradient(circle, @innerColor, @outerColor);
    background-repeat: no-repeat;
  }
  .striped(@color: #555, @angle: 45deg) {
    background-color: @color;
    background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,.15)), color-stop(.75, rgba(255,255,255,.15)), color-stop(.75, transparent), to(transparent));
    background-image: -webkit-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
    background-image: -moz-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
    background-image: -o-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
    background-image: linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent);
  }
}

// Reset filters for IE
//
// Useful for when you want to remove a gradient from an element.
.reset-filter() {
  filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)"));
}
首先来说说什么是vendor prefixes。大家知道,CSS3的标准制定是远超于浏览器的发展,不同浏览器对CSS3的属性实现方式,实现程度不一样。在CSS3属性的浏览器实验支持阶段,厂商在标准CSS属性前加上厂商前缀加以区分。
  • Android: -webkit-
  • Chrome: -webkit-
  • Firefox: -moz-
  • Internet Explorer: -ms-
  • iOS: -webkit-
  • Opera: -o-
  • Safari: -webkit-
这就给CSS的开发者加大了难度,所幸现在火狐基本上支持了标准属性,去掉了前缀。这些前缀最终肯定会去掉,考虑到代码未来兼容性,建议大家在开发时统一处理前缀问题,可以使用诸如prefix free等工具,或者使用相关的LESS mixin集。关于vender prefixs大家可以参考以下几篇文章。

2.4 Mixin的参数

LESS的混合可以不带参数,可以带一个或多个参数,参数可以有默认值,看看例子

// 带一个参数
.box-sizing(@box-model) {
  -webkit-box-sizing: @box-model; // Safari <= 5
     -moz-box-sizing: @box-model; // Firefox <= 19
          box-sizing: @box-model;
}
// 带多个参数,之间用逗号隔开
.translate3d(@x, @y, @z) {
  -webkit-transform: translate3d(@x, @y, @z);
     -moz-transform: translate3d(@x, @y, @z);
       -o-transform: translate3d(@x, @y, @z);
          transform: translate3d(@x, @y, @z);
}
//有默认值的参数
.opacity(@opacity:.5) {
  opacity: @opacity;
  @opacity-ie: @opacity * 100;
  filter: ~"alpha(opacity=@{opacity-ie})"; // IE8
}
//参数个数不固定
.box-shadow(...) {
    -webkit-box-shadow: @arguments;
       -moz-box-shadow: @arguments;
            box-shadow: @arguments;
}
LESS 提供了通过参数值控制 mixin 行为的功能,看看下面的例子。

.mixin (@s, @color) { ... }

.class {
    .mixin(@switch, #888);
}
如果要根据 @switch 的值控制 .mixin 行为,只需按照下面的方法定义 .mixin:

.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;
}
或者也可以用关键词 when,引入一个 guard 条件实现。上面的案例改造为

.mixin(@s, @color) when (@s = dark) {
	color: darken(@color, 10%);
}
.mixin(@s, @color) when (@s = light) {
	color: lighten(@color, 10%);
}
.mixin(@s, @color){
	display: block;
}
好的,接着来看preboot,他还分享了一些有用的混合。

//
// Mixins: utilities
// --------------------------------------------------

// Clearfix
//
// Source: http://nicolasgallagher.com/micro-clearfix-hack/
//
// For modern browsers
// 1. The space content is one way to avoid an Opera bug when the
//    contenteditable attribute is included anywhere else in the document.
//    Otherwise it causes space to appear at the top and bottom of elements
//    that are clearfixed.
// 2. The use of `table` rather than `block` is only necessary if using
//    `:before` to contain the top-margins of child elements.
.clearfix() {
  *zoom: 1;
  &:before,
  &:after {
    content: " "; // 1     --注释引用
    display: table; // 2
    // Fixes Opera/contenteditable bug:
    // http://nicolasgallagher.com/micro-clearfix-hack/#comment-36952
    line-height: 0;
  }
  &:after {
    clear: both;
  }
}

// Center-align a block level element
.center-block() {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

// Sizing shortcuts
.size(@width, @height) {
  width: @width;
  height: @height;
}
.square(@size) {
  .size(@size, @size);
}

// Text overflow
//
// Requires inline-block or block for proper styling
.text-truncate() {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

// Retina images
//
// Retina background-image support with non-retina fall back
.retina-image(@file-1x, @file-2x, @width-1x, @height-1x) {
  background-image: url("@{file-1x}");

  @media
  only screen and (-webkit-min-device-pixel-ratio: 2),
  only screen and (   min--moz-device-pixel-ratio: 2),
  only screen and (     -o-min-device-pixel-ratio: 2/1),
  only screen and (        min-device-pixel-ratio: 2),
  only screen and (                min-resolution: 192dpi),
  only screen and (                min-resolution: 2dppx) {
    background-image: url("@{file-2x}");
    background-size: @width-1x @height-1x;
  }
}
这段代码里面注释引用的方式不错。

最后有个Retina images的解决方案。Retina images也是目前前端开发的一个难题,大家可以参考相关的教程

1.走向视网膜(Retina)的Web时代

2.image-set实现Retina屏幕下图片显示

3.Retina.js为Retina设备显示高清图片

3.总结和展望

暂时到这里,本教程是一个系列教程,待续。

---------------------------------------------------------------
前端开发whqet,关注web前端开发技术,分享网页相关资源。
---------------------------------------------------------------


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值