Mather

We create our own demons.

从 Bootstrap 源码学习 Less 编写方法

默认分类 0 评

中文站点与官方文档

官方给出的英文文档实在难啃,加上国内中文站点翻译又不给力,先放几个站点:

需要了解的一些事儿

前端世界里家喻户晓的Bootstrap.css 便是由Less源码编译得来的(当然这儿我并不讨论Sass项目)。从Less得到CSS,你可以使用构建工具或者带图形界面的编译器,如 GruntKoala,这都取决于你的工作环境。


首先来些开胃菜,Button 样式往往需要一些 背景、边框以及字体颜色,实际大小由 Button 内文字行高和数量决定。

参考文件
bootstrap-3.3.6/less/mixins/button.less

.button-variant 类在定义button的背景、边框以字体颜色的同时,也给不忘定义伪类和伪元素。来看看他们在Bootstrap 中用Less是怎么组合的。

// Button variants
//
// Easily pump out default styles,as well as:hover,:focus,:active,// and disabled options for all buttons
.button-variant(@color;
@background;
@border) {
    color: @color;
    background-color: @background;
    border-color: @border;
    &:hover, &:focus, &.focus, &:active, &.active, .open > .dropdown-toggle& {
        color: @color;
        background-color: darken(@background, 10%);
        border-color: darken(@border, 12%);
    }
    &:active, &.active, .open > .dropdown-toggle& {
        background-image: none;
    }
    &.disabled, &[disabled], fieldset[disabled] & {
        &, &:hover, &:focus, &.focus, &:active, &.active {
            background-color: @background;
            border-color: @border;
        }
    }
    .badge {
        color: @background;
        background-color: @color;
    }
} // Button sizes
.button-size(@padding-vertical;
@padding-horizontal;
@font-size;
@line-height;
@border-radius) {
    padding: @padding-vertical @padding-horizontal;
    font-size: @font-size;
    line-height: @line-height;
    border-radius: @border-radius;
}

这一段比较绕的,删减些重复的样式,不必要在意花括号内的具体样式。

.button-variant {
    :active, .active, .open > .dropdown-toggle & {
        background-image: none;
    }
    .disabled,
    [disabled],
    fieldset[disabled] & {
        :hover, :focus, .focus {
            background-color: #000;
        }
    }
}

手动编译之后得到

.button-variant:active,
.button-variant.active,
.open > .dropdown-toggle.button-variant {
    background-image: none;
}

.button-variant.disabled:hover,
.button-variant[disabled]:hover,
fieldset[disabled] .button-variant:hover,
.button-variant.disabled:focus,
.button-variant[disabled]:focus,
fieldset[disabled] .button-variant:focus,
.button-variant.disabled.focus,
.button-variant[disabled].focus,
fieldset[disabled] .button-variant.focus {
    background-color: #000;
}

哇塞好长一段,直接不看。

Nested Rules - 嵌套规则

先来看一个简单的例子:

.button-variant:active, .button-variant.active {
    background-image: none;
}

使用嵌套规则的同时,配合 & 使用可选择其父元素,

.button-variant:active,
.button-variant.active

& 符号使 button-variantactive 紧贴在一起,表达为
.button-variant:active(状态)(效果)的样式;
.button-varian和类.active同时被应用时元素的样式。
所有二层选择都会和一层选择紧贴在一起组成新的选择器,有多少个二层选择编译后就有多少种选择器情况。
举个例子

.A {
    &.B, &.C, &.D {
        color: #ABC;
    }
}

二层嵌套中,有三个类选择器 .B .C .D。这里的 & 符号紧跟着后面的选择器,编译后就像乘法因式分解一样。

.A.B, .A.C, .A.D {
    color: #ABC;
}
/*or */
.A.B {
    color: #ABC;
}
.A.C {
    color: #ABC;
}
.A.D {
    color: #ABC;
}

.A.B .A.C .A.D 两两必须成对存在此选择器才在HTML中生效。
HTML应该这么写,A B间存在空格。

<!--HTML-->
<p class="A B"></p>
<p class="A C"></p>
<p class="A D"></p>

Changing Selector Order - 更改选择器顺序

上面的两层嵌套很容易被看出,那么继续来看三成嵌套。我截取了上面栗子的一小段,先来解析一下这7行。

.button-variant {
    &:active, &.active, .open > .dropdown-toggle& {
        background-image: none;
    }
}

同样,用上述的方法可以简单地把2 3行编译出来。但是 第4行的选择器并没有在开头用到 & ,而在尾部。其中还用到了

> 子元素选择器

太复杂的话我选择把尾部的 & 拿掉之后再来理解,首部没有 & 那么两两不连贯,猜想应该是这样子的:

/*this is inaccuracy result */
.button-variant:active, .button-variant.active, .button-variant .open > .dropdown-toggle {
    background-image: none;
}

剩下尾部的 ** 我们不用胡乱猜,参见一下官方手册 Changing Selector Order - 更改选择器顺序
尾部的 & 可以让当前选择器直接成为新的父选择器,也就是成为当前父选择器的父选择器。
还是举个栗子:

.header {
    .menu {
        border-radius: 5px;
        //putting the & after current selector
        .no-borderradius & {
            background-image: url('images/button-background.png');
        }
    }
}

编译之后 本来是 子选择器的 .no-borderradius 摇身一变成了其父选择器的父选择器,放在了第一位。
要注意的是,新的后代选择顺序不是与原本的相反,而是当前选择器直接成为父选择器,就像移动到前面一样。

.header .menu {
    border-radius: 5px;
}

.no-borderradius .header .menu {
    /*now no-borderradius is a perent selector*/
    background-image: url('images/button-background.png');
}

这样,大概我可以猜到上一题的答案是:

/*this is inaccuracy result */
.button-variant:active,
.button-variant.active,
.open > .dropdown-toggle .button-variant {
    background-image: none;
}

等等!好像并不一样 .dropdown-toggle.button-variant 之间存在了一个空格,其选择效果却是有差别的。这肯定是&前后出现了空白写法才会到这这种问题。有没有发现:

.no-borderradius &

.dropdown-toggle&

选择器名称后面少一个空格。产生的结果是不同的:

/*has blank */
.open > .dropdown-toggle .button-variant {
    background-image: none;
}

/*none */
.open > .dropdown-toggle.button-variant {
    background-image: none;
}

最后我们再把文章开头剩下的Less解析完。

.button-variant {
    &.disabled, &[disabled], fieldset[disabled] & {
        &:hover, &:focus, &.focus {
            background-color: #000;
        }
    }
}

编译之后。每条规则先解析一层,从

.button-variant -> .disabled ->:hover

在选择器结尾处遇到 & 时就前置当前选择器

.button-variant -> fieldset[disabled] & ->:hover

前置 fieldset[disabled] , 注意伪类选择器应紧跟前面的内容。

fieldset[disabled] -> .button-variant ->:hover

这么走一轮,有9种不同的选择器方案,最终结果:

.button-variant.disabled:hover,
.button-variant[disabled]:hover,
fieldset[disabled] .button-variant:hover,
.button-variant.disabled:focus,
.button-variant[disabled]:focus,
fieldset[disabled] .button-variant:focus,
.button-variant.disabled.focus,
.button-variant[disabled].focus,
fieldset[disabled] .button-variant.focus {
    background-color: #000;
}

从 Animate.css 学习编写 CSS 动画

发表评论
撰写评论