LESS 语言功能的深入指南。 有关 Less 的快速摘要,请参阅 概述。
有关安装和设置 Less 环境的深入指南,以及有关 Less 开发的文档,请参阅: 使用 Less.js.
在单个位置控制常用值。
相同的值在您的样式表中重复数十次甚至数百次的情况并不少见:
a,
.link {
color: #428bca;
}
.widget {
color: #fff;
background: #428bca;
}
变量为您提供了一种从单个位置控制这些值的方法,从而使您的代码更易于维护:
// Variables
@link-color: #428bca; // sea blue
@link-color-hover: darken(@link-color, 10%);
// Usage
a,
.link {
color: @link-color;
}
a:hover {
color: @link-color-hover;
}
.widget {
color: #fff;
background: @link-color;
}
上面的示例着重于使用变量来控制 CSS 规则中的值,但它们也可以用在其他地方,例如选择器名称、属性名称、URL 和 @import
语句。
v1.4.0
// Variables
@my-selector: banner;
// Usage
.@{my-selector} {
font-weight: bold;
line-height: 40px;
margin: 0 auto;
}
编译为:
.banner {
font-weight: bold;
line-height: 40px;
margin: 0 auto;
}
// Variables
@images: "../img";
// Usage
body {
color: #444;
background: url("@{images}/white-sand.png");
}
v1.4.0
语法: @import "@{themes}/tidal-wave.less";
请注意,在 v2.0.0 之前,仅考虑在根或当前范围内声明的变量,并且在查找变量时仅考虑当前文件和调用文件。
例子:
// Variables
@themes: "../../src/themes";
// Usage
@import "@{themes}/tidal-wave.less";
v1.6.0
@property: color;
.widget {
@{property}: #0ee;
background-@{property}: #999;
}
编译为:
.widget {
color: #0ee;
background-color: #999;
}
在 Less 中,您可以使用另一个变量定义一个变量的名称。
@primary: green;
@secondary: blue;
.section {
@color: primary;
.element {
color: @@color;
}
}
编译为:
.section .element {
color: green;
}
变量在使用前不必声明。
有效的 Less 片段:
.lazy-eval {
width: @var;
}
@var: @a;
@a: 9%;
这也是有效的 Less:
.lazy-eval {
width: @var;
@a: 9%;
}
@var: @a;
@a: 100%;
都编译成:
.lazy-eval {
width: 9%;
}
两次定义变量时,使用变量的最后定义,从当前范围向上搜索。 这类似于 css 本身,其中定义中的最后一个属性用于确定值。
例如:
@var: 0;
.class {
@var: 1;
.brass {
@var: 2;
three: @var;
@var: 3;
}
one: @var;
}
编译为:
.class {
one: 1;
}
.class .brass {
three: 3;
}
本质上,每个范围都有一个 "final" 值,类似于浏览器中的属性,就像这个使用自定义属性的例子:
.header {
--color: white;
color: var(--color); // the color is black
--color: black;
}
这意味着,与其他 CSS 预处理语言不同,Less 变量的行为与 CSS 非常相似。
v3.0.0
您可以使用 $prop
语法轻松地将属性视为变量。 有时这可以使您的代码更轻一些。
.widget {
color: #efefef;
background-color: $color;
}
编译为:
.widget {
color: #efefef;
background-color: #efefef;
}
请注意,与变量一样,Less 将选择当前/父范围内的最后一个属性作为 "final" 值。
.block {
color: red;
.inner {
background-color: $color;
}
color: blue;
}
编译为:
.block {
color: red;
color: blue;
}
.block .inner {
background-color: blue;
}
我们有时会收到对默认变量的请求——只有在变量尚未设置的情况下才能设置它。 此功能不是必需的,因为您可以通过在之后放置定义来轻松覆盖变量。
例如:
// library
@base-color: green;
@dark-color: darken(@base-color, 10%);
// use of library
@import "library.less";
@base-color: red;
这工作正常,因为 延迟加载 - @base-color
被覆盖并且 @dark-color
是深红色。
使用
&
引用父选择器
&
运算符表示 nested rule 的父选择器,在将修改类或伪类应用于现有选择器时最常使用:
a {
color: blue;
&:hover {
color: green;
}
}
结果是:
a {
color: blue;
}
a:hover {
color: green;
}
请注意,如果没有 &
,上面的示例将导致 a :hover
规则(匹配 <a>
标签内的悬停元素的后代选择器),这不是我们通常想要的嵌套 :hover
。
"父选择器" 运算符有多种用途。 基本上任何时候您需要以默认方式之外的其他方式组合嵌套规则的选择器。 例如,&
的另一个典型用途是生成重复的类名:
.button {
&-ok {
background-image: url("ok.png");
}
&-cancel {
background-image: url("cancel.png");
}
&-custom {
background-image: url("custom.png");
}
}
output:
.button-ok {
background-image: url("ok.png");
}
.button-cancel {
background-image: url("cancel.png");
}
.button-custom {
background-image: url("custom.png");
}
&
&
可能会在一个选择器中出现多次。 这使得重复引用父选择器而不重复其名称成为可能。
.link {
& + & {
color: red;
}
& & {
color: green;
}
&& {
color: blue;
}
&, &ish {
color: cyan;
}
}
将输出:
.link + .link {
color: red;
}
.link .link {
color: green;
}
.link.link {
color: blue;
}
.link, .linkish {
color: cyan;
}
请注意,&
代表所有父选择器(不仅仅是最近的祖先)所以下面的例子:
.grand {
.parent {
& > & {
color: red;
}
& & {
color: green;
}
&& {
color: blue;
}
&, &ish {
color: cyan;
}
}
}
结果是:
.grand .parent > .grand .parent {
color: red;
}
.grand .parent .grand .parent {
color: green;
}
.grand .parent.grand .parent {
color: blue;
}
.grand .parent,
.grand .parentish {
color: cyan;
}
将选择器添加到继承的(父)选择器之前可能很有用。 这可以通过将 &
放在当前选择器之后来完成。
例如,在使用 Modernizr 时,您可能希望根据支持的功能指定不同的规则:
.header {
.menu {
border-radius: 5px;
.no-borderradius & {
background-image: url('images/button-background.png');
}
}
}
选择器 .no-borderradius &
会将 .no-borderradius
添加到其父 .header .menu
的前面,以在输出中形成 .no-borderradius .header .menu
:
.header .menu {
border-radius: 5px;
}
.no-borderradius .header .menu {
background-image: url('images/button-background.png');
}
&
也可用于在逗号分隔列表中生成选择器的所有可能排列:
p, a, ul, li {
border-top: 2px dotted #366;
& + & {
border-top: 0;
}
}
这扩展到指定元素的所有可能 (16) 组合:
p,
a,
ul,
li {
border-top: 2px dotted #366;
}
p + p,
p + a,
p + ul,
p + li,
a + p,
a + a,
a + ul,
a + li,
ul + p,
ul + a,
ul + ul,
ul + li,
li + p,
li + a,
li + ul,
li + li {
border-top: 0;
}
Extend 是一个 Less 伪类,它将它所放置的选择器与与其引用的匹配的选择器合并。
已发布 v1.4.0
nav ul {
&:extend(.inline);
background: blue;
}
在上面的规则集中,:extend
选择器会将 "继承选择器" (nav ul
) 应用于 .inline
类,无论 .inline
类出现在哪里。 声明块将保持原样,但不会引用扩展(因为扩展不是 css)。
所以如下:
nav ul {
&:extend(.inline);
background: blue;
}
.inline {
color: red;
}
输出
nav ul {
background: blue;
}
.inline,
nav ul {
color: red;
}
请注意 nav ul:extend(.inline)
选择器如何将输出输出为 nav ul
- 扩展在输出之前被删除并且选择器块保持原样。 如果该块中没有放置任何属性,那么它将从输出中删除(但扩展仍然可能影响其他选择器)。
扩展要么附加到选择器,要么放入规则集中。 它看起来像一个带有选择器参数的伪类,可选地后跟关键字 all
:
例子:
.a:extend(.b) {}
// the above block does the same thing as the below block
.a {
&:extend(.b);
}
.c:extend(.d all) {
// extends all instances of ".d" e.g. ".x.d" or ".d.x"
}
.c:extend(.d) {
// extends only instances where the selector will be output as just ".d"
}
它可以包含一个或多个要扩展的类,以逗号分隔。
例子:
.e:extend(.f) {}
.e:extend(.g) {}
// the above and the below do the same thing
.e:extend(.f, .g) {}
附加到选择器的扩展看起来像一个普通的伪类,将选择器作为参数。 一个选择器可以包含多个扩展子句,但所有扩展都必须位于选择器的末尾。
pre:hover:extend(div pre)
.pre:hover :extend(div pre)
.pre:hover:extend(div pre):extend(.bucket tr)
- 注意这与 pre:hover:extend(div pre, .bucket tr)
相同pre:hover:extend(div pre).nth-child(odd)
. 扩展必须在最后。如果规则集包含多个选择器,则其中任何一个都可以具有 extend 关键字。 在一个规则集中扩展的多个选择器:
.big-division,
.big-bag:extend(.bag),
.big-bucket:extend(.bucket) {
// body
}
可以使用 &:extend(selector)
语法将 Extend 放入规则集的主体中。 将 extend 放入主体是将其放入该规则集的每个选择器的快捷方式。
在体内延伸:
pre:hover,
.some-class {
&:extend(div pre);
}
与在每个选择器之后添加扩展完全相同:
pre:hover:extend(div pre),
.some-class:extend(div pre) {}
Extend 能够匹配嵌套的选择器。 关注 less:
例子:
.bucket {
tr { // nested ruleset with target selector
color: blue;
}
}
.some-class:extend(.bucket tr) {} // nested ruleset is recognized
输出
.bucket tr,
.some-class {
color: blue;
}
本质上,extend 着眼于编译后的 css,而不是原始的 less。
例子:
.bucket {
tr & { // nested ruleset with target selector
color: blue;
}
}
.some-class:extend(tr .bucket) {} // nested ruleset is recognized
输出
tr .bucket,
.some-class {
color: blue;
}
默认情况下扩展会查找选择器之间的精确匹配。 选择器是否使用前导星并不重要。 两个第 n 个表达式具有相同的含义并不重要,它们需要具有相同的形式才能匹配。 唯一的例外是属性选择器中的引号,less 知道它们具有相同的含义并匹配它们。
例子:
.a.class,
.class.a,
.class > .a {
color: blue;
}
.test:extend(.class) {} // this will NOT match the any selectors above
明星确实很重要。 选择器 *.class
和 .class
是等价的,但 extend 不会匹配它们:
*.class {
color: blue;
}
.noStar:extend(.class) {} // this will NOT match the *.class selector
输出
*.class {
color: blue;
}
伪类的顺序确实很重要。 选择器 link:hover:visited
和 link:visited:hover
匹配同一组元素,但 extend 将它们视为不同的:
link:hover:visited {
color: blue;
}
.selector:extend(link:visited:hover) {}
输出
link:hover:visited {
color: blue;
}
第 N 种表达形式很重要。 第 N 个表达式 1n+3
和 n+3
是等价的,但扩展不会匹配它们:
:nth-child(1n+3) {
color: blue;
}
.child:extend(:nth-child(n+3)) {}
输出
:nth-child(1n+3) {
color: blue;
}
属性选择器中的引用类型无关紧要。 以下所有内容都是等价的。
[title=identifier] {
color: blue;
}
[title='identifier'] {
color: blue;
}
[title="identifier"] {
color: blue;
}
.noQuote:extend([title=identifier]) {}
.singleQuote:extend([title='identifier']) {}
.doubleQuote:extend([title="identifier"]) {}
输出
[title=identifier],
.noQuote,
.singleQuote,
.doubleQuote {
color: blue;
}
[title='identifier'],
.noQuote,
.singleQuote,
.doubleQuote {
color: blue;
}
[title="identifier"],
.noQuote,
.singleQuote,
.doubleQuote {
color: blue;
}
当你在扩展参数中最后指定 all 关键字时,它会告诉 Less 将该选择器作为另一个选择器的一部分进行匹配。 选择器将被复制,然后选择器的匹配部分将被扩展替换,从而形成一个新的选择器。
例子:
.a.b.test,
.test.c {
color: orange;
}
.test {
&:hover {
color: green;
}
}
.replacement:extend(.test all) {}
输出
.a.b.test,
.test.c,
.a.b.replacement,
.replacement.c {
color: orange;
}
.test:hover,
.replacement:hover {
color: green;
}
您可以将这种操作模式视为本质上进行非破坏性搜索和替换。
Extend 不能 能够将选择器与变量匹配。 如果选择器包含变量,extend 将忽略它。
但是,extend 可以附加到插值选择器。
带有变量的选择器将不会被匹配:
@variable: .bucket;
@{variable} { // interpolated selector
color: blue;
}
.some-class:extend(.bucket) {} // does nothing, no match is found
并在目标选择器中使用变量扩展不匹配:
.bucket {
color: blue;
}
.some-class:extend(@{variable}) {} // interpolated selector matches nothing
@variable: .bucket;
以上两个例子编译成:
.bucket {
color: blue;
}
但是,附加到插值选择器的 :extend
有效:
.bucket {
color: blue;
}
@{variable}:extend(.bucket) {}
@variable: .selector;
编译为:
.bucket, .selector {
color: blue;
}
目前,@media
声明中的 :extend
只会匹配同一媒体声明中的选择器:
@media print {
.screenClass:extend(.selector) {} // extend inside media
.selector { // this will be matched - it is in the same media
color: black;
}
}
.selector { // ruleset on top of style sheet - extend ignores it
color: red;
}
@media screen {
.selector { // ruleset inside another media - extend ignores it
color: blue;
}
}
编译成:
@media print {
.selector,
.screenClass { /* ruleset inside the same media was extended */
color: black;
}
}
.selector { /* ruleset on top of style sheet was ignored */
color: red;
}
@media screen {
.selector { /* ruleset inside another media was ignored */
color: blue;
}
}
注意: 扩展与嵌套 @media
声明内的选择器不匹配:
@media screen {
.screenClass:extend(.selector) {} // extend inside media
@media (min-width: 1023px) {
.selector { // ruleset inside nested media - extend ignores it
color: blue;
}
}
}
这编译成:
@media screen and (min-width: 1023px) {
.selector { /* ruleset inside another nested media was ignored */
color: blue;
}
}
顶级扩展匹配所有内容,包括嵌套媒体内的选择器:
@media screen {
.selector { /* ruleset inside nested media - top level extend works */
color: blue;
}
@media (min-width: 1023px) {
.selector { /* ruleset inside nested media - top level extend works */
color: blue;
}
}
}
.topLevel:extend(.selector) {} /* top level extend matches everything */
编译成:
@media screen {
.selector,
.topLevel { /* ruleset inside media was extended */
color: blue;
}
}
@media screen and (min-width: 1023px) {
.selector,
.topLevel { /* ruleset inside nested media was extended */
color: blue;
}
}
目前没有重复检测。
例子:
.alert-info,
.widget {
/* declarations */
}
.alert:extend(.alert-info, .widget) {}
输出
.alert-info,
.widget,
.alert,
.alert {
/* declarations */
}
经典用例是避免添加基类。 例如,如果你有
.animal {
background-color: black;
color: white;
}
并且您想要一种动物子类型来覆盖背景颜色,那么您有两个选择,首先更改您的 HTML
<a class="animal bear">Bear</a>
.animal {
background-color: black;
color: white;
}
.bear {
background-color: brown;
}
或者简化 html 并在你的 less 中使用 extend。 例如
<a class="bear">Bear</a>
.animal {
background-color: black;
color: white;
}
.bear {
&:extend(.animal);
background-color: brown;
}
Mixins 将所有属性复制到一个选择器中,这会导致不必要的重复。 因此,您可以使用 extends 而不是 mixins 将选择器向上移动到您希望使用的属性,这会导致生成更少的 CSS。
示例 - 使用 mixin:
.my-inline-block() {
display: inline-block;
font-size: 0;
}
.thing1 {
.my-inline-block;
}
.thing2 {
.my-inline-block;
}
输出
.thing1 {
display: inline-block;
font-size: 0;
}
.thing2 {
display: inline-block;
font-size: 0;
}
示例(带扩展):
.my-inline-block {
display: inline-block;
font-size: 0;
}
.thing1 {
&:extend(.my-inline-block);
}
.thing2 {
&:extend(.my-inline-block);
}
输出
.my-inline-block,
.thing1,
.thing2 {
display: inline-block;
font-size: 0;
}
另一个用例是作为 mixin 的替代方案——因为 mixins 只能与简单的选择器一起使用,如果你有两个不同的 html 块,但需要对两者应用相同的样式,你可以使用 extends 来关联两个区域。
例子:
li.list > a {
// list styles
}
button.list-style {
&:extend(li.list > a); // use the same list styles
}
合并属性
merge
功能允许将来自多个属性的值聚合到单个属性下的逗号或空格分隔列表中。 merge
对于背景和转换等属性很有用。
用逗号附加属性值
已发布 v1.5.0
例子:
.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;
}
用空格附加属性值
已发布 v1.7.0
例子:
.mixin() {
transform+_: scale(2);
}
.myclass {
.mixin();
transform+_: rotate(15deg);
}
输出
.myclass {
transform: scale(2) rotate(15deg);
}
为了避免任何无意的连接,merge
要求在每个连接挂起声明上都有一个明确的 +
或 +_
标志。
现有样式的 "mix-in" 属性
您可以混合使用类选择器和 ID 选择器,例如
.a, #b {
color: red;
}
.mixin-class {
.a();
}
.mixin-id {
#b();
}
结果是:
.a, #b {
color: red;
}
.mixin-class {
color: red;
}
.mixin-id {
color: red;
}
从历史上看,mixin 调用中的括号是可选的,但可选的括号已被弃用,在未来的版本中将是必需的。
.a();
.a; // currently works, but deprecated; don't use
.a (); // white-space before parentheses is also deprecated
如果你想创建一个 mixin 但你不希望那个 mixin 出现在你的 CSS 输出中,请在 mixin 定义之后加上括号。
.my-mixin {
color: black;
}
.my-other-mixin() {
background: white;
}
.class {
.my-mixin();
.my-other-mixin();
}
输出
.my-mixin {
color: black;
}
.class {
color: black;
background: white;
}
Mixin 不仅可以包含属性,还可以包含选择器。
例如:
.my-hover-mixin() {
&:hover {
border: 1px solid red;
}
}
button {
.my-hover-mixin();
}
输出
button:hover {
border: 1px solid red;
}
如果你想在更复杂的选择器中混合属性,你可以堆叠多个 id 或类。
#outer() {
.inner {
color: red;
}
}
.c {
#outer.inner();
}
注意: 遗留的 Less 语法允许 >
和名称空间与混入之间的空格。 此语法已弃用,可能会被删除。 目前,这些做同样的事情。
#outer > .inner(); // deprecated
#outer .inner(); // deprecated
#outer.inner(); // preferred
像这样命名你的混入可以减少与其他库混入或用户混入的冲突,但也可以成为 "organize" 组混入的一种方式。
例子:
#my-library {
.my-mixin() {
color: black;
}
}
// which can be used like this
.class {
#my-library.my-mixin();
}
如果一个命名空间有一个守卫,只有当守卫条件返回真时,它定义的混合才会被使用。 名称空间守卫的评估与混合上的守卫完全相同,因此以下两个混合的工作方式相同:
#namespace when (@mode = huge) {
.mixin() { /* */ }
}
#namespace {
.mixin() when (@mode = huge) { /* */ }
}
假定 default
函数对所有嵌套命名空间和混入具有相同的值。 下面的 mixin 永远不会被评估; 它的一名警卫保证是假的:
#sp_1 when (default()) {
#sp_2 when (default()) {
.mixin() when not(default()) { /* */ }
}
}
!important
关键字在 mixin 调用后使用 !important
关键字将其继承的所有属性标记为 !important
:
例子:
.foo (@bg: #f5f5f5; @color: #900) {
background: @bg;
color: @color;
}
.unimportant {
.foo();
}
.important {
.foo() !important;
}
结果是:
.unimportant {
background: #f5f5f5;
color: #900;
}
.important {
background: #f5f5f5 !important;
color: #900 !important;
}
如何将参数传递给mixins
Mixins 也可以接受参数,这些参数是在混合时传递给选择器块的变量。
例如:
.border-radius(@radius) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
border-radius: @radius;
}
以下是我们如何将其混合到各种规则集中:
#header {
.border-radius(4px);
}
.button {
.border-radius(6px);
}
参数混合也可以为其参数设置默认值:
.border-radius(@radius: 5px) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
border-radius: @radius;
}
我们现在可以像这样调用它:
#header {
.border-radius();
}
它将包括一个 5px 的边框半径。
您还可以使用不带参数的参数混合。 如果您想从 CSS 输出中隐藏规则集,但又想将其属性包含在其他规则集中,这将很有用:
.wrap() {
text-wrap: wrap;
white-space: -moz-pre-wrap;
white-space: pre-wrap;
word-wrap: break-word;
}
pre { .wrap() }
哪个会输出:
pre {
text-wrap: wrap;
white-space: -moz-pre-wrap;
white-space: pre-wrap;
word-wrap: break-word;
}
参数当前以分号或逗号分隔。
最初,参数只用逗号分隔,但后来添加了分号以支持将逗号分隔的列表值传递给单个参数。
.name(1, 2, 3; something, else)
,.name(1, 2, 3)
,.name(1, 2, 3;)
,.name(@param1: red, blue;)
.~()
] 来包装列表值,例如 .name(@param1: ~(red, blue))
。 这类似于引用转义语法: ~"quote"
定义多个具有相同名称和参数数量的混合是合法的。 Less 将使用所有可以应用的属性。 如果您使用带有一个参数的 mixin,例如 .mixin(green);
,然后将使用具有一个强制参数的所有 mixin 的属性:
.mixin(@color) {
color-1: @color;
}
.mixin(@color, @padding: 2) {
color-2: @color;
padding-2: @padding;
}
.mixin(@color, @padding, @margin: 2) {
color-3: @color;
padding-3: @padding;
margin: @margin @margin @margin @margin;
}
.some .selector div {
.mixin(#008000);
}
编译成:
.some .selector div {
color-1: #008000;
color-2: #008000;
padding-2: 2;
}
mixin 引用可以通过名称而不是位置来提供参数值。 任何参数都可以通过其名称来引用,并且它们不必按任何特殊顺序排列:
.mixin(@color: black; @margin: 10px; @padding: 20px) {
color: @color;
margin: @margin;
padding: @padding;
}
.class1 {
.mixin(@margin: 20px; @color: #33acfe);
}
.class2 {
.mixin(#efca44; @padding: 40px);
}
编译成:
.class1 {
color: #33acfe;
margin: 20px;
padding: 20px;
}
.class2 {
color: #efca44;
margin: 10px;
padding: 40px;
}
@arguments
变量@arguments
在 mixin 中有特殊含义,它包含调用 mixin 时传递的所有参数。 如果您不想处理单个参数,这很有用:
.box-shadow(@x: 0, @y: 0, @blur: 1px, @color: #000) {
-webkit-box-shadow: @arguments;
-moz-box-shadow: @arguments;
box-shadow: @arguments;
}
.big-block {
.box-shadow(2px, 5px);
}
结果是:
.big-block {
-webkit-box-shadow: 2px 5px 1px #000;
-moz-box-shadow: 2px 5px 1px #000;
box-shadow: 2px 5px 1px #000;
}
@rest
变量如果你希望你的 mixin 接受可变数量的参数,你可以使用 ...
。 在变量名之后使用它会将这些参数分配给变量。
.mixin(...) { // matches 0-N arguments
.mixin() { // matches exactly 0 arguments
.mixin(@a: 1) { // matches 0-1 arguments
.mixin(@a: 1, ...) { // matches 0-N arguments
.mixin(@a, ...) { // matches 1-N arguments
此外:
.mixin(@a, @rest...) {
// @rest is bound to arguments after @a
// @arguments is bound to all arguments
}
有时,您可能希望根据传递给它的参数更改混入的行为。 让我们从一些基本的东西开始:
.mixin(@s, @color) { ... }
.class {
.mixin(@switch, #888);
}
现在假设我们希望 .mixin
表现不同,基于 @switch
的值,我们可以这样定义 .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);
}
我们将得到以下 CSS:
.class {
color: #a2a2a2;
display: block;
}
传递给 .mixin
的颜色变浅了。 如果 @switch
的值为 dark
,则结果将是较深的颜色。
这是发生了什么:
dark
作为第一个参数。light
。仅使用匹配的 mixin 定义。 变量匹配并绑定到任何值。 除了变量之外的任何东西都只与等于其自身的值匹配。
我们也可以匹配元数,下面是一个例子:
.mixin(@a) {
color: @a;
}
.mixin(@a, @b) {
color: fade(@a, @b);
}
现在如果我们用一个参数调用 .mixin
,我们将得到第一个定义的输出,但如果我们用两个参数调用它,我们将得到第二个定义,即 @a
淡化为 @b
。
从 mixin 调用中选择属性和变量
已发布 v3.5.0
从 Less 3.5 开始,您可以使用属性/变量访问器从已评估的混入规则中选择一个值。 这可以让你使用类似于函数的混合。
例子:
.average(@x, @y) {
@result: ((@x + @y) / 2);
}
div {
// call a mixin and look up its "@result" value
padding: .average(16px, 50px)[@result];
}
结果是:
div {
padding: 33px;
}
如果您有多个匹配的 mixins,所有规则都会被评估和合并,并返回具有该标识符的最后一个匹配值。 这类似于 CSS 中的级联,它允许您混合 "override" 值。
// library.less
#library() {
.mixin() {
prop: foo;
}
}
// customize.less
@import "library";
#library() {
.mixin() {
prop: bar;
}
}
.box {
my-value: #library.mixin[prop];
}
输出:
.box {
my-value: bar;
}
如果您没有在 [@lookup]
中指定查找值,而是在 mixin 或规则集调用之后写入 []
,则所有值将级联并且将选择最后声明的值。
意义: 上面例子中的平均 mixin 可以写成:
.average(@x, @y) {
@result: ((@x + @y) / 2);
}
div {
// call a mixin and look up its final value
padding: .average(16px, 50px)[];
}
输出是相同的:
div {
padding: 33px;
}
对于混入调用别名的规则集或变量,同样的级联行为也是如此。
@dr: {
value: foo;
}
.box {
my-value: @dr[];
}
这输出:
.box {
my-value: foo;
}
已弃用 - 使用属性/值访问器
mixin 中定义的变量和 mixin 是可见的,可以在调用者的范围内使用。 只有一个例外: 如果调用者包含具有相同名称的变量(包括由另一个 mixin 调用定义的变量),则不会复制该变量。 只有存在于调用者本地范围内的变量才受到保护。 从父作用域继承的变量被覆盖。
注意: 这种行为已被弃用,将来,变量和混合将不会以这种方式合并到调用者范围中。
例子:
.mixin() {
@width: 100%;
@height: 200px;
}
.caller {
.mixin();
width: @width;
height: @height;
}
结果是:
.caller {
width: 100%;
height: 200px;
}
不能覆盖直接在调用者范围内定义的变量。 但是,调用者父范围中定义的变量不受保护,将被覆盖:
.mixin() {
@size: in-mixin;
@definedOnlyInMixin: in-mixin;
}
.class {
margin: @size @definedOnlyInMixin;
.mixin();
}
@size: globaly-defined-value; // callers parent scope - no protection
结果是:
.class {
margin: in-mixin in-mixin;
}
最后,mixin 中定义的 mixin 也作为返回值:
.unlock(@value) { // outer mixin
.doSomething() { // nested mixin
declaration: @value;
}
}
#namespace {
.unlock(5); // unlock doSomething mixin
.doSomething(); //nested mixin was copied here and is usable
}
结果是:
#namespace {
declaration: 5;
}
创建循环
在 Less 中,mixin 可以调用自己。 当与 守卫表达式 和 模式匹配 结合使用时,此类递归混合可用于创建各种迭代/循环结构。
例子:
.loop(@counter) when (@counter > 0) {
.loop((@counter - 1)); // next iteration
width: (10px * @counter); // code for each iteration
}
div {
.loop(5); // launch the loop
}
输出:
div {
width: 10px;
width: 20px;
width: 30px;
width: 40px;
width: 50px;
}
使用递归循环生成 CSS 网格类的通用示例:
.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%;
}
当你想匹配表达式时,守卫很有用,而不是简单的值或元数。 如果您熟悉函数式编程,您可能已经遇到过它们。
为了尽可能接近 CSS 的声明性本质,Less 选择通过 guarded mixins 而不是 if
/else
语句来实现条件执行,这与 @media
查询功能规范保持一致。
让我们从一个例子开始:
.mixin(@a) when (lightness(@a) >= 50%) {
background-color: black;
}
.mixin(@a) when (lightness(@a) < 50%) {
background-color: white;
}
.mixin(@a) {
color: @a;
}
关键是when
关键字,它引入了一个守卫序列(这里只有一个守卫)。 现在,如果我们运行以下代码:
.class1 { .mixin(#ddd) }
.class2 { .mixin(#555) }
这是我们将得到的:
.class1 {
background-color: black;
color: #ddd;
}
.class2 {
background-color: white;
color: #555;
}
守卫中可用的比较运算符的完整列表是: >
、>=
、=
、=<
、<
。 此外,关键字 true
是唯一的真值,这使得这两个 mixins 等效:
.truth(@a) when (@a) { ... }
.truth(@a) when (@a = true) { ... }
除关键字 true
之外的任何值都是假的:
.class {
.truth(40); // Will not match any of the above definitions.
}
请注意,您还可以将参数相互比较,或与非参数进行比较:
@media: mobile;
.mixin(@a) when (@media = mobile) { ... }
.mixin(@a) when (@media = desktop) { ... }
.max(@a; @b) when (@a > @b) { width: @a }
.max(@a; @b) when (@a < @b) { width: @b }
您可以将逻辑运算符与守卫一起使用。 语法基于 CSS 媒体查询。
使用 and
关键字组合守卫:
.mixin(@a) when (isnumber(@a)) and (@a > 0) { ... }
您可以通过用逗号 ,
分隔守卫来模拟 or 运算符。 如果任何一个守卫评估为真,它被认为是一场比赛:
.mixin(@a) when (@a > 10), (@a < -10) { ... }
使用 not
关键字否定条件:
.mixin(@b) when not (@b > 0) { ... }
最后,如果你想根据值类型匹配 mixins,你可以使用 is
函数:
.mixin(@a; @b: 0) when (isnumber(@b)) { ... }
.mixin(@a; @b: black) when (iscolor(@b)) { ... }
下面是基本的类型检查函数:
iscolor
isnumber
isstring
iskeyword
isurl
如果你想检查一个值除了是一个数字之外是否在一个特定的单位中,你可以使用以下之一:
ispixel
ispercentage
isem
isunit
已发布 v3.5.0
将 mixin 调用分配给变量
Mixins可以赋值给一个变量来作为变量调用调用,也可以用于map lookup。
#theme.dark.navbar {
.colors(light) {
primary: purple;
}
.colors(dark) {
primary: black;
secondary: grey;
}
}
.navbar {
@colors: #theme.dark.navbar.colors(dark);
background: @colors[primary];
border: 1px solid @colors[secondary];
}
这将输出:
.navbar {
background: black;
border: 1px solid grey;
}
整个 mixin 调用都可以使用别名并称为变量调用。 如:
#library() {
.colors() {
background: green;
}
}
.box {
@alias: #library.colors();
@alias();
}
输出:
.box {
background: green;
}
请注意,与 root 中使用的 mixin 不同,分配给变量和不带参数调用的 mixin 调用始终需要括号。 以下内容无效。
#library() {
.colors() {
background: green;
}
}
.box {
@alias: #library.colors;
@alias(); // ERROR: Could not evaluate variable call @alias
}
这是因为如果变量被分配一个选择器列表或一个 mixin 调用是不明确的。 例如,在 Less 3.5+ 中,这个变量可以这样使用。
.box {
@alias: #library.colors;
@{alias} {
a: b;
}
}
以上将输出:
.box #library.colors {
a: b;
}
"if" 的周围选择器
已发布 v1.5.0
与 Mixin Guards 一样,guards 也可以应用于 css 选择器,这是声明 mixin 然后立即调用它的语法糖。
例如,在 1.5.0 之前你必须这样做:
.my-optional-style() when (@my-option = true) {
button {
color: white;
}
}
.my-optional-style();
现在,您可以将守卫直接应用于样式。
button when (@my-option = true) {
color: white;
}
您还可以通过将其与 &
功能相结合来实现 if
类型声明,从而允许您对多个守卫进行分组。
& when (@my-option = true) {
button {
color: white;
}
a {
color: blue;
}
}
请注意,您还可以通过使用实际的 if()
函数和变量调用来实现类似的模式。 如:
@dr: if(@my-option = true, {
button {
color: white;
}
a {
color: blue;
}
});
@dr();
将规则集分配给变量
已发布 v1.7.0
分离的规则集是一组 css 属性、嵌套规则集、媒体声明或存储在变量中的任何其他内容。 您可以将它包含到规则集或其他结构中,并且它的所有属性都将被复制到那里。 您还可以将它用作 mixin 参数并将其作为任何其他变量传递。
简单示例:
// declare detached ruleset
@detached-ruleset: { background: red; }; // semi-colon is optional in 3.5.0+
// use detached ruleset
.top {
@detached-ruleset();
}
编译成:
.top {
background: red;
}
分离规则集调用后的括号是强制性的(除非后跟 lookup value)。 呼叫 @detached-ruleset;
不起作用。
当您想要定义一个 mixin 来抽象出包装媒体查询中的一段代码或不支持的浏览器类名时,它很有用。 可以将规则集传递给 mixin,以便 mixin 可以包装内容,例如
.desktop-and-old-ie(@rules) {
@media screen and (min-width: 1200px) { @rules(); }
html.lt-ie9 & { @rules(); }
}
header {
background-color: blue;
.desktop-and-old-ie({
background-color: red;
});
}
这里的 desktop-and-old-ie
mixin 定义了媒体查询和根类,这样你就可以使用 mixin 来包装一段代码。 这将输出
header {
background-color: blue;
}
@media screen and (min-width: 1200px) {
header {
background-color: red;
}
}
html.lt-ie9 header {
background-color: red;
}
现在可以将规则集分配给变量或传递给混合,并且可以包含完整的 Less 功能集,例如
@my-ruleset: {
.my-selector {
background-color: black;
}
};
例如,您甚至可以利用 媒体查询冒泡
@my-ruleset: {
.my-selector {
@media tv {
background-color: black;
}
}
};
@media (orientation:portrait) {
@my-ruleset();
}
这将输出
@media (orientation: portrait) and tv {
.my-selector {
background-color: black;
}
}
一个分离的规则集调用解锁(返回)它所有的 mixin 到调用者,就像 mixin 调用一样。 但是,它确实不返回变量。
返回混入:
// detached ruleset with a mixin
@detached-ruleset: {
.mixin() {
color: blue;
}
};
// call detached ruleset
.caller {
@detached-ruleset();
.mixin();
}
结果是:
.caller {
color: blue;
}
私有变量:
@detached-ruleset: {
@color:blue; // this variable is private
};
.caller {
color: @color; // syntax error
}
分离的规则集可以在定义和调用的地方使用所有可访问的变量和混合。 换句话说,定义和调用者范围都对它可用。 如果两个范围包含相同的变量或混合,则声明范围值优先。
声明范围是定义分离规则集主体的范围。 将分离的规则集从一个变量复制到另一个变量不能修改其范围。 规则集不会仅仅通过在新范围内被引用而获得对新范围的访问权。
最后,分离的规则集可以通过解锁(导入)到其中来访问范围。
注意: 通过调用的 mixin 将变量解锁到范围内已被弃用。 使用 属性/变量访问器。
一个分离的规则集可以看到调用者的变量和混合:
@detached-ruleset: {
caller-variable: @caller-variable; // variable is undefined here
.caller-mixin(); // mixin is undefined here
};
selector {
// use detached ruleset
@detached-ruleset();
// define variable and mixin needed inside the detached ruleset
@caller-variable: value;
.caller-mixin() {
variable: declaration;
}
}
编译成:
selector {
caller-variable: value;
variable: declaration;
}
从定义中可访问的变量和 mixins 胜过调用者中可用的那些:
@variable: global;
@detached-ruleset: {
// will use global variable, because it is accessible
// from detached-ruleset definition
variable: @variable;
};
selector {
@detached-ruleset();
@variable: value; // variable defined in caller - will be ignored
}
编译成:
selector {
variable: global;
}
规则集不会仅仅通过在此处被引用而获得对新范围的访问权限:
@detached-1: { scope-detached: @one @two; };
.one {
@one: visible;
.two {
@detached-2: @detached-1; // copying/renaming ruleset
@two: visible; // ruleset can not see this variable
}
}
.use-place {
.one > .two();
@detached-2();
}
抛出错误:
ERROR 1:32 The variable "@one" was not declared.
分离的规则集通过在范围内解锁(导入)来获得访问权限:
#space {
.importer-1() {
@detached: { scope-detached: @variable; }; // define detached ruleset
}
}
.importer-2() {
@variable: value; // unlocked detached ruleset CAN see this variable
#space > .importer-1(); // unlock/import detached ruleset
}
.use-place {
.importer-2(); // unlock/import detached ruleset second time
@detached();
}
编译成:
.use-place {
scope-detached: value;
}
已发布 v3.5.0
从 Less 3.5 开始,您可以使用属性/变量访问器(也称为 "lookups")从变量(分离的)规则集中选择一个值。
@config: {
option1: true;
option2: false;
}
.mixin() when (@config[option1] = true) {
selected: value;
}
.box {
.mixin();
}
输出:
.box {
selected: value;
}
如果查找返回的是另一个分离的规则集,您可以使用第二个查找来获取该值。
@config: {
@colors: {
primary: blue;
}
}
.box {
color: @config[@colors][primary];
}
返回的查找值本身可以是可变的。 如在,你可以写:
@config: {
@dark: {
primary: darkblue;
}
@light: {
primary: lightblue;
}
}
.box {
@lookup: dark;
color: @config[@@lookup][primary];
}
这将输出:
.box {
color: darkblue;
}
从其他样式表导入样式
在标准 CSS 中,@import
at 规则必须在所有其他类型的规则之前。 但是 Less 不关心你把 @import
语句放在哪里。
例子:
.foo {
background: #900;
}
@import "this-is-valid.less";
Less 可能会根据文件扩展名对 @import
语句进行不同的处理:
.css
扩展名,它将被视为 CSS 并且 @import
语句保持原样(参见下面的 inline option)。.less
并将其作为导入的 Less 文件包含在内。例子:
@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
以下选项可用于覆盖此行为。
Less 为 CSS
@import
CSS at 规则提供了几个扩展,以提供比您可以对外部文件执行的操作更大的灵活性。
语法: @import (keyword) "filename";
已实施以下导入选项:
reference
: 使用 Less 文件但不输出它inline
: 在输出中包含源文件但不处理它less
: 将文件视为 Less 文件,无论文件扩展名是什么css
: 将文件视为 CSS 文件,无论文件扩展名是什么once
: 只包含文件一次(这是默认行为)multiple
: 多次包含文件optional
: 找不到文件时继续编译每个
@import
允许多个关键字,您必须使用逗号分隔关键字:
例子: @import (optional, reference) "foo.less";
使用 @import (reference)
导入外部文件,但除非引用,否则不将导入的样式添加到编译输出。
已发布 v1.5.0
例子: @import (reference) "foo.less";
想象一下,reference
在导入文件中用引用标志标记每个 at-rule 和选择器,正常导入,但是当生成 CSS 时,"reference" 选择器(以及任何仅包含引用选择器的媒体查询)不会输出。 reference
样式不会出现在您生成的 CSS 中,除非引用样式用作 mixins 或 extended。
此外,reference
根据使用的方法(mixin 或 extend)产生不同的结果:
@import
语句的位置。reference
样式用作 implicit mixin 时,其规则被混入,标记为 "not reference",并正常出现在引用的位置。这允许您通过执行以下操作仅从 Bootstrap 等库中提取特定的、有针对性的样式:
.navbar:extend(.navbar all) {}
并且您将从 Bootstrap 中仅引入与 .navbar
相关的样式。
使用 @import (inline)
包含外部文件,但不处理它们。
已发布 v1.5.0
例子: @import (inline) "not-less-compatible.css";
当 CSS 文件可能不兼容时,您将使用它; 这是因为虽然 Less 支持大多数已知标准的 CSS,但它在某些地方不支持注释,并且在不修改 CSS 的情况下不支持所有已知的 CSS hack。
因此,您可以使用它在输出中包含文件,以便所有 CSS 都在一个文件中。
使用 @import (less)
将导入的文件视为 Less,而不考虑文件扩展名。
已发布 v1.4.0
例子:
@import (less) "foo.css";
使用 @import (css)
将导入的文件视为常规 CSS,而不考虑文件扩展名。 这意味着导入语句将保持原样。
已发布 v1.4.0
例子:
@import (css) "foo.less";
输出
@import "foo.less";
@import
语句的默认行为。 这意味着该文件仅导入一次,该文件的后续导入语句将被忽略。
已发布 v1.4.0
这是 @import
语句的默认行为。
例子:
@import (once) "foo.less";
@import (once) "foo.less"; // this statement will be ignored
使用 @import (multiple)
允许导入多个同名文件。 这是与一次相反的行为。
已发布 v1.4.0
例子:
// file: foo.less
.a {
color: green;
}
// file: main.less
@import (multiple) "foo.less";
@import (multiple) "foo.less";
输出
.a {
color: green;
}
.a {
color: green;
}
使用 @import (optional)
允许仅在文件存在时导入该文件。 如果没有 optional
关键字,Less 会在导入找不到的文件时抛出 FileError 并停止编译。
已发布 v2.3.0
已发布 v2.5.0
导入 JavaScript 插件以添加 Less.js 功能和特性
使用 @plugin
规则类似于对 .less
文件使用 @import
。
@plugin "my-plugin"; // automatically appends .js if no extension
由于 Less 插件在 Less 范围内进行评估,因此插件定义可以非常简单。
registerPlugin({
install: function(less, pluginManager, functions) {
functions.add('pi', function() {
return Math.PI;
});
}
})
或者您可以使用 module.exports
(可以在浏览器和 Node.js 中使用)。
module.exports = {
install: function(less, pluginManager, functions) {
functions.add('pi', function() {
return Math.PI;
});
}
};
请注意,其他 Node.js CommonJS 约定(如 require()
)在浏览器中不可用。 在编写跨平台插件时请记住这一点。
您可以使用插件做什么? 很多,但让我们从基础开始。 我们将首先关注您可能放入 install
函数中的内容。 假设你这样写:
// my-plugin.js
install: function(less, pluginManager, functions) {
functions.add('pi', function() {
return Math.PI;
});
}
// etc
恭喜! 你写了一个 Less 插件!
如果您要在样式表中使用它:
@plugin "my-plugin";
.show-me-pi {
value: pi();
}
你会得到:
.show-me-pi {
value: 3.141592653589793;
}
但是,如果您想将其与其他值相乘或执行其他 Less 操作,则需要返回一个正确的 Less 节点。 否则样式表中的输出是纯文本(这可能适合您的目的)。
意思是,这是更正确的:
functions.add('pi', function() {
return new tree.Dimension(Math.PI);
});
注意: 维度是一个带或不带单位的数字,如 "10px",它将是 less.Dimension(10, "px")
。 有关单位列表,请参阅 Less API。
现在您可以在操作中使用您的函数。
@plugin "my-plugin";
.show-me-pi {
value: pi() * 2;
}
您可能已经注意到您的插件文件有可用的全局变量,即函数注册表(functions
对象)和 less
对象。 这些是为了方便。
@plugin
@ 规则添加的函数遵循 Less 作用域规则。 这对于希望在不引入命名冲突的情况下添加功能的 Less 库作者来说非常有用。
例如,假设您有来自两个第三方库的 2 个插件,它们都有一个名为 "foo" 的函数。
// lib1.js
// ...
functions.add('foo', function() {
return "foo";
});
// ...
// lib2.js
// ...
functions.add('foo', function() {
return "bar";
});
// ...
没关系! 您可以选择哪个库的函数创建哪个输出。
.el-1 {
@plugin "lib1";
value: foo();
}
.el-2 {
@plugin "lib2";
value: foo();
}
这将产生:
.el-1 {
value: foo;
}
.el-2 {
value: bar;
}
对于共享插件的插件作者来说,这意味着您还可以通过将它们放在特定范围内来有效地创建私有函数。 就像这样,这将导致错误:
.el {
@plugin "lib1";
}
@value: foo();
从 Less 3.0 开始,函数可以返回任何类型的 Node 类型,并且可以在任何级别调用。
这意味着,这会在 2.x 中引发错误,因为函数必须是属性值或变量赋值的一部分:
.block {
color: blue;
my-function-rules();
}
在 3.x 中,情况不再如此,函数可以返回 At-Rules、Rulesets、任何其他 Less 节点、字符串和数字(后两者被转换为 Anonymous 节点)。
有时您可能想要调用一个函数,但您不想要任何输出(例如存储一个值供以后使用)。 在这种情况下,您只需要从函数返回 false
。
var collection = [];
functions.add('store', function(val) {
collection.push(val); // imma store this for later
return false;
});
@plugin "collections";
@var: 32;
store(@var);
稍后您可以执行以下操作:
functions.add('retrieve', function(val) {
return new tree.Value(collection);
});
.get-my-values {
@plugin "collections";
values: retrieve();
}
Less.js 插件应该导出具有一个或多个这些属性的对象。
{
/* Called immediately after the plugin is
* first imported, only once. */
install: function(less, pluginManager, functions) { },
/* Called for each instance of your @plugin. */
use: function(context) { },
/* Called for each instance of your @plugin,
* when rules are being evaluated.
* It's just later in the evaluation lifecycle */
eval: function(context) { },
/* Passes an arbitrary string to your plugin
* e.g. @plugin (args) "file";
* This string is not parsed for you,
* so it can contain (almost) anything */
setOptions: function(argumentString) { },
/* Set a minimum Less compatibility string
* You can also use an array, as in [3, 0] */
minVersion: ['3.0'],
/* Used for lessc only, to explain
* options in a Terminal */
printUsage: function() { },
}
install()
函数的 PluginManager 实例提供了添加访问者、文件管理器和后处理器的方法。
这里有一些示例 repos,显示了不同的插件类型。
虽然 @plugin
调用适用于大多数情况,但有时您可能希望在解析开始之前加载插件。
查阅: "使用 Less.js" 部分中的 预加载插件 介绍了如何做到这一点。
已发布 v3.5.0
使用规则集和混合作为值映射
通过将命名空间与查找 []
语法相结合,您可以将您的规则集/mixins 转换为映射。
@sizes: {
mobile: 320px;
tablet: 768px;
desktop: 1024px;
}
.navbar {
display: block;
@media (min-width: @sizes[tablet]) {
display: inline-block;
}
}
输出:
.navbar {
display: block;
}
@media (min-width: 768px) {
.navbar {
display: inline-block;
}
}
由于命名空间和重载混入的能力,混入比映射更通用。
#library() {
.colors() {
primary: green;
secondary: blue;
}
}
#library() {
.colors() { primary: grey; }
}
.button {
color: #library.colors[primary];
border-color: #library.colors[secondary];
}
输出:
.button {
color: grey;
border-color: blue;
}
您也可以通过 aliasing mixins 使这更容易。 那是:
.button {
@colors: #library.colors();
color: @colors[primary];
border-color: @colors[secondary];
}
请注意,如果查找值生成另一个规则集,您可以附加第二个 []
查找,如:
@config: {
@options: {
library-on: true
}
}
& when (@config[@options][library-on] = true) {
.produce-ruleset {
prop: val;
}
}
这样规则集和变量调用就可以模拟出"namespacing"的一种类型,类似于mixins。
至于是否使用分配给变量的混合或规则集作为映射,由您决定。 您可能希望通过重新声明分配给规则集的变量来替换整个地图。 或者您可能想要 "merge" 个单独的键/值对,在这种情况下,混合作为映射可能更合适。
需要注意的一件重要事情是 [@lookup]
中的值是键(变量)名称 @lookup
,并且未作为变量求值。 如果希望键名本身是可变的,可以使用 @@variable
语法。
例如。
.foods() {
@dessert: ice cream;
}
@key-to-lookup: dessert;
.lunch {
treat: .foods[@@key-to-lookup];
}
这将输出:
.lunch {
treat: ice cream;
}