Less.js: 添加对“默认”变量的支持(类似于 SASS 中的 !default)

创建于 2013-12-03  ·  35评论  ·  资料来源: less/less.js

我们正在考虑从 SASS 迁移到 LESS,但我们的主要障碍是缺乏“默认变量”功能(请参阅 http://sass-lang.com/documentation/file.SASS_REFERENCE.html#variable_defaults_)

在将 SASS 代码作为库分发时,此功能非常有用,其中变量充当用户的一种“API”。 在这样的用例中,用户所要做的就是确保预先包含他的变量以覆盖他想要更改的默认值,瞧! 不要摆弄(可能)许多可能包含需要覆盖的变量的文件的顺序。

我已经开始着手实现,还没有编写任何测试,但是,希望我们可以使用这个拉取请求作为讨论的起点: https ://github.com/less/less.js/pull/1705

我选择了以下语法:

?foo: value;

与 SASS 方式相反:

<strong i="13">@foo</strong>: value !default;

有两个原因 - 它更简洁,并且 !default 语法可能会在将来出现右侧表达式解析的潜在问题(但我可能错了)。

我想出的实现非常简单——希望我没有错过任何重要的事情。 我非常感谢您提供的任何反馈。

干杯,
菲尔

consider closing feature request low priority

最有用的评论

我打算推荐我写的文章,然后看到@seven-phases-max 与它相关联。 😄 相信我们,您所要求的已经存在! 但是您必须了解 Less 的变量评估才能了解它如何/为什么存在。

所有35条评论

请参阅文档


更新:删除了我之前对这篇文章的评论,以免混淆未来的访问者(在这里我试图回答“如果尚未定义变量,如何定义变量”的问题,但错过了它是“XY 问题”的正确答案Sass-like !default是:在 Less 中,您不需要类似的东西,因为 Less 变量的工作方式已经提供了必要的功能(“使用后(重新)定义”)。

如果你定义同一个变量两次,最后一个声明获胜并且在整个范围内有效。 因此,另一种选择是正常声明变量并要求用户在您的库之后包含他的变量。

无库

<strong i="7">@width</strong>: 0;
.mixin {
  width: @width;
}

用户少:

<strong i="11">@import</strong> "library.less"; //first declaration of <strong i="12">@width</strong>
<strong i="13">@width</strong>: 1; //this will override <strong i="14">@width</strong> defined previously
.class {
  .mixin();
}

编译成:

.mixin {
  width: 1;
}
.class {
  width: 1;
}

感谢您对我们 PR 的反馈。 如果我们有一个单一的东西或一些小东西要消耗,这些解决方案将是可行的。 因此,让我详细说明为什么这些解决方案在我们的案例中不可行。

我们将一个大型组件框架实现为类层次结构。 我们在自己的文件中为每个组件声明变量......在我们的基本主题中。 然后我们从这里“派生”出想要修改这些变量的主题。 用户可以进一步这样做以根据他们的需要调整主题。

此外,变量通常“派生”自其他变量。 这最明显的是基色。 我们花了很多时间讨论使用激进的变量值传播结合主题和它们自己的继承行为来解决组件的大型类层次结构问题的替代方案。

到目前为止,这些问题的最佳解决方案是_总是_将变量定义为“!default”(用 Sass 术语)。 这允许用户在使用这些值计算进一步的值之前简单地先进入并设置他们的值。 对于我们的用户来说,时间管理非常简单。 由于我们所有主题中的每个变量都是这种情况,因此像上面建议的语法斗争将是一个相当大的负担,而且容易出错。

随着我们的继续,我们很乐意为 Less 贡献其他功能。 我认为我们的(不寻常的?)大规模用例可能有助于验证扩展语言/功能集所需的内容。

我希望您会考虑合并它或提供一些更具声明性的替代方案。 利用范围技巧真的对我们不起作用。

再次感谢您的时间和考虑!

似乎你最好定义 mixins 而不是直接的类。 然后,可以在主样式表或其他派生主题中覆盖变量。 这就是我在导入网格后能够覆盖网格中的排水沟宽度等内容的方式。

只是为了澄清我们在这里只讨论变量。 而且我们没有主样式表——每个主题每个类都有一个。 :)

也许我没有遵循您的建议,但作为示例,我们的一个主题变量文件如下所示:

$panel-base-color: $neutral-light-color !default;
$panel-header-color: $base-color !default;
$panel-frame-border-width: 1px !default;
$panel-header-font-size: round($font-size * 1.15) !default;
$panel-body-border-color: $neutral-dark-color !default;

$panel-light-header-color: #000 !default;
$panel-light-header-background-color: #fff !default;
$panel-light-tool-background-image: 'tools/tool-sprites-dark' !default;
$panel-light-body-border-color: $neutral-dark-color !default;
$panel-ignore-frame-padding: true !default;

此文件为具有 4 深基本主题链的主题设置各种面板值。 这些基本主题有自己的 Panel 变量值,但这些是首先加载的,因此请覆盖它们。 除非用户主题派生自该主题并提供自己的值。

这种模式重复_a lot_ :)

好的,为什么不在你的主要少表中覆盖@panel-base-color呢? LESS 变量是全局变量,所以最后发生的就是赢家。

<strong i="7">@import</strong> 'theme.less';

@panel-base-color: red;

现在,主题中使用的任何地方都将被覆盖。 如果没有人在你的导入链中覆盖它,那么它最初设置的将是默认值。

我们没有“主要少表” :) 感谢您的帮助和建议,但是我们在内部对此进行了很多讨论,并且它们往往会持续一段时间。 可以这么说,我们认为我们需要在这里提出的默认变量设置。 这个特性存在于 Sass 中,我们发现它非常有助于降低复杂性并为用户提供配置主题的灵活性。

我很好奇这一切是否意味着这个拉取请求或一些类似的衍生品会被接受? 如果这令人反感,我们很乐意调整语法。

我们没有“主要少表”:)

只需将上面答案中的“您的主要少表”替换为“任何用户的少表”即可。 到目前为止,似乎 SASS !default (无论它具有什么语法)是为了解决 LESS 中不存在的问题而发明的。
@dongryphon ,我当然可能是错的,但你还没有解释为什么你不能使用@SomMeri和@Soviut 建议的解决方案。

换句话说,想象一下如果您没有导入,而是将所有变量放在同一张表中。 这实际上就是导入的作用。 因此,在这种情况下,如果您有两个具有相同名称的变量声明,则工作表中的最后一个将获胜。

@base-color: green;

div {
    background: @base-color;
}

@base-color: red;

因为最后再次声明了基色,所以 div 中使用的基色将是红色。 它将编译为:

div {
    background: red;
}

这之前就出现过,事实上我相信它甚至已经实现了,我们收到了来自那些想要在 bootstrap 中使用它的人的拉取请求,他们在经过一些讨论后同意它在 less.. 中是一个毫无意义的功能。

它允许您做的唯一一件事是让用户在导入之前定义变量。 如果用户在之后定义覆盖,那么它就好像它有一个默认值一样工作。这是因为即使在导入的文件中,它也会以与 css 相同的方式采用最后一个定义,即使在使用后定义也是如此。

对于库的用户来说,说他们在导入后覆盖变量(或在导入后导入变量文件)与向 less 中添加更多语法相比并没有太大的负担。我们认为这是 less 的优点之一,你可以做与 sass 相同的数量,但大多数时候使用更简单的语法。

这与 JavaScript 程序员的想法相反,但其背后的想法是它更接近于 css。

请您详细说明为什么要求消费者考虑订单是不可能或不可取的? 我们将接受具有强大用例的功能,但我们必须严格避免语言和复杂性膨胀。

见 #1109 #1104 #313

澄清一下,我们绝不会说“不”。 我们试图证明他的这个功能可能已经存在。

我在 less-docs 中添加了一些信息

关闭已可用(以“较少方式”)功能(http://lesscss.org/features/#variables-feature-default-variables)。

我认为这种混淆经常出现,因为虽然存在重叠的_syntax_,但 SASS 从上到下“执行”但 LESS 没有,而是更像 CSS 操作。 LESS 就像 CSS+(带有附加功能的 CSS),而 SASS 就像“带有 CSS 语法的 PHP”。 我想知道是否有办法(如有必要)我们可以做出这种区分。

请您详细说明为什么要求消费者考虑订单是不可能或不可取的? 我们将接受具有强大用例的功能,但我们必须严格避免语言和复杂性膨胀。

因为我们教导图书馆用户(和消费者)永远不要自己编辑图书馆代码。 缺少的!default功能意味着我们必须做这两件事中的一件 - 两者都同样糟糕:

  • 用户必须自己编辑库样式表才能编辑声明它们的变量(这是一种被禁止的事情,使库更新更加困难),或者,
  • 该库必须提供两个样式表:一个用于默认变量,另一个用于实际规则。 然后用户必须@import第一个,然后声明自己的变量,然后@import第二个。 它比应有的复杂,尤其是要将这两个文件保持在同一版本。

sass 方法意味着库只需要提供一个文件,然后用户就可以自定义该文件。

my-color: red;
<strong i="15">@import</strong> "./my-library.less";

代替:

<strong i="19">@import</strong> "./my-library-variables.less";
my-color: red;
<strong i="20">@import</strong> "./my-library-rules.less";

我认为你应该重新考虑这个问题。

@arcanis其实我不明白你为什么这么认为:

该库必须提供两个样式表:一个用于默认变量,另一个用于实际规则。
sass 方法意味着库只需要提供一个文件

在 Less 中,它是完全一样的库设计:

<strong i="11">@import</strong> "./my-library.less";
@my-color: red;

我猜你只是错过了“延迟加载”的东西(并且在文档中使用完全相同的例子来说no, thanks!!default )。

我猜你只是错过了“延迟加载”的东西

@seven-phases-max WTF,你是对的。 该死的,我可能应该删除我的整个回复(并且刚刚删除)。 你告诉我你可以导入引导程序,只覆盖特定的变量,它会起作用吗?

我不相信你,并做了我自己的测试来验证它。 我怎么错过了这个?? 我认为这是因为我在 Bootstrap 上看到的每篇文章(包括自定义)都建议您复制 variables.less 文件并设置自己的值,这当然会在向库中添加更多变量时引起问题。 而且我认为我的印象是选择器在导入的直接点被输出。 变量是否总是以这种方式“延迟加载”?

这必须是 Less 中最重要的一个最常被忽略的功能。 我从未见过有关 Less 或 Less 库的博客文章提及此功能。 即使这里有线程中的所有内容和文档,也不是很明显这对现实世界的库意味着什么。 我以为每个人都只是说您可以通过稍后设置它们来覆盖之前声明的变量,我从来没有想过它会影响对早期导入文档中的变量的评估。

我不敢相信直到现在我才得到这个。 这基本上改变了我如何构建我的 less 文档的所有内容,并且它在没有显示输出的文档中有一个小小的提及。

也许我们在 Less 中收到这么多对!default功能的请求的原因是因为很少有人凭直觉了解此功能或从文档中的简短示例中理解它(显然包括我)。

至少,感谢您再次解释@seven-phases-max!

哎呀。 嗯,你是对的。 我也误解了文档,我的错!

@Soviut你真是个天才! 我不知道变量声明在 SASS/LESS 中是这样工作的。 谢谢!

我仍然在拍我的额头,这对于我在 Less 中写的所有其他内容来说并不是明显的行为。 我认为我的问题是我看到了那些不了解如何做的人写的糟糕的示例文章。

另外,请注意: @spikesagal就您的陈述而言:“我不知道变量声明在 SASS/LESS 中的工作方式”——据我所知,两种语言之间的变量行为并不相同,因为SASS 和 LESS 对事物的评价非常不同。

由于迁移到 Sass,他们正在杀死 BS4 中的这个功能...... :-1: 仍然对这一举动感到非常难过。

所以它开始了,争取更多!默认变量:[twbs/bootstrap#17418]

好吧,他们不能通过以任何方式更改 SCSS 源来杀死 Less 功能。 (从技术上讲,它甚至不是“特征”(如某种“综合行为”),而是惰性评估的基本属性/推论)。 只要有较少版本的 BS(这只是愿意为其做出贡献的人数的问题),并且至少有一个全局变量 - 您将始终能够覆盖该变量。

好吧。 bootstrap 的官方 v4-alpha 移至 Sass。 至少在我的理解中,这在他们的官方文档中减少了 - 这意味着也取消了对这个功能的支持,因为 Sass 没有延迟加载变量这样的东西。 他们只支持 !default,在某种程度上,这意味着:“哦,是的,我们只允许您从外部覆盖我们的变量一次,而且只有在我们允许的情况下。所以,如果我们忘记让您访问通过简单地省略 !default 来创建一个变量,你几乎搞砸了,必须覆盖文件中的整个该死的选择器。处理它。”

这也意味着取消对这个特性的支持,因为 Sass 没有延迟加载变量之类的东西。

好吧,这只意味着“他们在 Bootstrap 中杀死它”(这显然超出了这个线程范围 - 只要没有更少版本的 BS,我们不应该关心 _this_ 存储库中的任何 Bootstrap 功能,不是吗?)。

因为这个讨论几乎是关于在引导程序中覆盖变量......

我们坚持少:微笑:

我有一个最初陈述的困境的用例。 考虑以下简化示例:

  1. 我有一个更少的文件,它定义了 h1 的字体大小,像这样
    <strong i="8">@font_size__h1</strong> = 30px;
  2. 我有(因为没有更好的短语)一个插件,其中包含一个单独的 LESS 文件,该文件使用@font_size__h1声明。 所以我<strong i="12">@import</strong> (reference) "path/to/file.less";它。 没问题,现在可以使用了。
  3. 现在我把那个“插件”放到一个没有在任何地方定义@font_size__h1的新站点中。 此时最好说“如果定义@font_size__h1 ,则使用该值。如果未定义,则使用我在此处定义的值。”

据我所知,第 3 项目前是不可能的。

@theMikeD

据我所知,第 3 项目前是不可能的。

您似乎没有阅读过该主题:

<strong i="10">@import</strong> "path/to/file.less";
<strong i="11">@import</strong> "here.less"; // if it's not defined <elsewhere>, then use the value I define <here>
<strong i="12">@import</strong> "elsewhere.less";

当然可以简化为:

<strong i="16">@import</strong> "path/to/file.less"; // <- define default value there
@font-size-h1: foo;          // if it's not defined here then use the value defined above

这与http://lesscss.org/features/#variables -feature-default-variables 的示例基本相同

是的,我读了线程。 看起来你不明白我在问什么,因为你的例子让我的问题倒退了。

当然可以简化为:
@import "路径/到/file.less"; // <- 在此处定义默认值
@font-size-h1: 富; // 如果这里没有定义,那么使用上面定义的值

这与我需要的相反。 无论如何,这将用本地值覆盖path/to/file.less @font-size-h1的值。 我需要的是仅在以下情况下使用本地文件中的值:
a) path/to/file.less未加载,或
b) '@ font_size__h1 is not set in path/to/file.less` 的值

IOW @font-size-h1: foo;的本地值将始终存在于本地文件中,但如果在path/to/file.less中设置,则应覆盖它

不管怎样,昨晚我找到了解决办法,就是先赋值本地值,然后把@import语句放在文件末尾,而不是开头。 如果找到,它将覆盖本地值。

不管怎么说,还是要谢谢你。

看来你不明白我在问什么

我宁愿建议您从一些变量较少的基础知识开始刷新您的视图:

(因为看起来你只是想以类似 C/PHP 的命令式方式来考虑这一切,而在 Less/CSS 中它完全是“声明性的颠倒”)。
这些年来一直在谈论它,如果与原生的 Less 变量覆盖相比, !default可以添加 _nothing_ new 。 时期。 (我们之前已经去过那里很多次了:如果有人认为他在 Less 中找到了!default的用例,那只意味着他对 Less 变量语义的误解)。

我需要的是仅在以下情况下使用本地文件中的值:
a) path/to/file.less未加载,或
b) @ font_size__h1的值未在path/to/file.less中设置

然后它只是相反:

@font-size-h1: foo;
<strong i="27">@import</strong> "path/to/file.less"; 

多田!

...正如我所说,这就是我降落的地方。

我打算推荐我写的文章,然后看到@seven-phases-max 与它相关联。 😄 相信我们,您所要求的已经存在! 但是您必须了解 Less 的变量评估才能了解它如何/为什么存在。

我有一个组件 - 这是一个数据网格。 这个组件应该有一个默认样式 - 由组件包定义。 但是,如果已经定义了来自外部的某个变量,则应该具有优先权。

无应用程序
/grid/grid.less

由于网格是一个组件,因此忘记在此处添加任何内容 - 或在 grid.less 文件之后添加任何代码。
我看不出有多少少涵盖了这个问题。 Scss 提供此功能是有充分理由的。

@geri777

但是,如果已经定义了来自外部的某个变量,则应该具有优先权。

Less 像 CSS 一样评估。

.css {  
  --color: blue;
  color: var(--color);  // --color will be red
  --color: red;
  border-color: var(--color);  // --color will still be red, red is the scope's final value
}

.less {  
  <strong i="10">@color</strong>: blue;
  color: @color;  // <strong i="11">@color</strong> will be red
  <strong i="12">@color</strong>: red;
  border-color: @color;  // <strong i="13">@color</strong> will still be red, red is the scope's final value
}
````

Scss, instead, doesn't mimic CSS evaluation and instead evaluates more like, say, PHP.

```scss
.scss {  
  $color: blue;
  color: $color;  // $color will be blue
  $color: red;
  border-color: $color;  // $color will be red
}

所以,在 Sass/SCSS 中,为了覆盖根变量的值,你不得不做两件事:

  1. 您必须使用!default标记所有变量声明
  2. 您必须在这些默认声明之前插入您的全局变量。

如:

// main.scss
<strong i="22">@import</strong> "overrides.scss";
<strong i="23">@import</strong> "library.scss";

// overrides.scss
$color: red;

// library.scss
$color: blue !default;

.scss {
  color: $color;
}

在 Less 中,主题化要容易得多。 您(通常)不需要更改您的库的任何内容,您只需要在之后放置您的覆盖。 你只需要做一件事。

// main.less
<strong i="27">@import</strong> "library.less";
<strong i="28">@import</strong> "overrides.less";

// overrides.less
<strong i="29">@color</strong>: red;

// library.less
<strong i="30">@color</strong>: blue;

.less {
  color: @color;
}

因此,您不需要!default ,因为 Less 将始终接受您的最终值。

想像 CSS 的级联这样的 Less 评估。 它只是工作。 最后的宣言获胜。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

seven-phases-max picture seven-phases-max  ·  6评论

awebdev picture awebdev  ·  4评论

vecerek picture vecerek  ·  5评论

Oskariok picture Oskariok  ·  6评论

chricken picture chricken  ·  6评论