1

注意:我不想使用~"parameters"符号来提供参数,因为它对用户不友好,开发人员总是必须考虑这一点。我正在使用这个技巧和 javascript 评估来获取正确格式的参数,可以在下面的 mixin 中看到。

我有一个 LESS 混合

.gradient(...) {
    @def = ~`"@{arguments}".replace(/[\[\]]/g,"")`;

    background-color: mix(/* first and last argument color */)
    background-image: linear-gradient(to bottom, @def);
}

由于渐变可以有多个颜色停止定义,我将其定义为支持任意数量的参数。

现在。我想要得到的只是第一个和最后一个参数的颜色定义。问题是这些可以以不同的方式提供,一些简单的提取其他复杂的:

.gradient(#000, #fff); // easy
.gradient(fade(#000, 50) 25%, #ccc 50%, fade(#fff, 90) 80%); // complicated

问题

  1. @arguments是否可以在不求助于字符串转换的情况下访问单个参数?
  2. 如果必须进行字符串转换(as ~'"@{arguments}"'),我如何拆分单个参数以忽略括号内的逗号(上面的复杂示例将它们转换为rbga值)?
4

2 回答 2

2

LESS 1.4.0 解决方案

以下是需要 LESS 1.4.0(撰写本文时为测试版)的解决方案,因为它利用了新extract()功能。它还假定颜色将始终是每个参数的值集中的第一个值(我相信对于linear-gradientcss 的正确语法应该是这种情况)。

通过使用extract()LESS 1.4.0 的功能,我们可以允许将参数作为非字符串传递,这可以缓解您在我们讨论的其他问题中遇到的字符串到颜色转换问题(然而,这仍然是一个好问题),同时也允许访问个人价值观。

较少的

.gradient(...) {

  //setting up your argument definition string
  @def: ~`"@{arguments}".replace(/[\[\]]/g,"")`;

  //getting the number of arguments 
  //(weeding out nested commas in parenthesis to do it)
  @numStops: unit(`"@{arguments}".replace(/\([^)]*\)/g,"").split(',').length`);

  //extracting raw form of first and last arguments
  //which may be more than just a single color
  @rawFirst: extract(@arguments,1);
  @rawLast: extract(@arguments,@numStops);

  //mixins to recursively evaluate the raw arguments down to a color
  .setFirstColor(@color) when (isColor(@color)) {
     @FirstColor: @color;
  }
  .setFirstColor(@color) when not (isColor(@color)) {
     .setFirstColor(extract(@color,1));
  }
  .setLastColor(@color) when (isColor(@color)) {
     @LastColor: @color;
  }
  .setLastColor(@color) when not (isColor(@color)) {
     .setLastColor(extract(@color,1));
  }

  //call mixins to get the first & last color from first & last arguments
  .setFirstColor(@rawFirst);
  .setLastColor(@rawLast);

  //set your css using the extracted and formatted info
  background-color: mix(@FirstColor, @LastColor);
  background-image: linear-gradient(to bottom, @def);
}

.myClass1 {
  .gradient(#000, #fff); 
}

.myClass2 {
  .gradient(fade(#000, 50) 25%, #ccc 50%, fade(#fff, 90) 80%); //complicated
}

CSS 输出

.myClass1 {
  background-color: #808080;
  background-image: linear-gradient(to bottom, #000000, #ffffff);
}
.myClass2 {
  background-color: rgba(179, 179, 179, 0.7);
  background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.5) 25%, #cccccc 50%, rgba(255, 255, 255, 0.9) 80%);
}
于 2013-03-28T18:56:34.300 回答
1

可以在此处找到有关此解决方案的详细博客文章。

回答我自己的问题并提供可行的解决方案

是否可以在不求助于字符串转换的情况下访问单个参数?@arguments

如果没有 LESS 1.4(目前处于测试阶段),似乎不可能直接执行此操作并获得实际参数,而无需求助于字符串转换然后操作它们。

如果必须进行字符串转换(as ~'"@{arguments}"'),我如何拆分单个参数以忽略括号内的逗号(上面的复杂示例将它们转换为 rgba 值)?

答案是立即执行返回所需结果的匿名函数。让我们从问题中举个例子:

.gradient(fade(#000, 50) 25%, #ccc 50%, fade(#fff, 90) 80%);

在 mixin@def中执行第一行后,分配了这个值:

@def: "rgba(0, 0, 0, 0.5) 25%, #ccc 50%, rgba(255, 255, 255, 0.9) 80%";

现在我们要做的是替换那些不应该拆分的逗号。这些是括号内的逗号。使用前瞻正则表达式很容易检测到这一点。所以我们用分号替换这些逗号,然后拆分剩下的逗号:

val.replace(/,\s+(?=[\d ,.]+\))/gi, ";").split(/,\s*/g)

这导致了这个字符串数组或单个梯度参数

["rgba(0;0;0;0.5) 25%", "#ccc 50%", "rgba(255;255;255;0.9) 80%"]

现在我们有了可以使用的数据。由于也不可能提供mix不是color对象的 LESS 参数,我们必须手动进行混合。

这是.gradient作为第一个和最后一个渐变颜色的结果输出#xxxxxx的结果混合:

.gradient (...) {
    @all: ~`"@{arguments}".replace(/[\[\]]/g,"")`;
    @mix: ~`(function(a){a=a.replace(/,\s+(?=[\d ,.]+\))/gi,";").split(/,\s*/g);var f=a[0].split(/\s+/g)[0];var l=a.pop().split(/\s+/g)[0];var c=function(c){var r=[];/rgb/i.test(c)&&c.replace(/[\d.]+/g,function(i){r.push(1*i);return"";});/#.{3}$/.test(c)&&c.replace(/[\da-f]/ig,function(i){r.push(parseInt(i+i,16));return"";});/#.{6}/.test(c)&&c.replace(/[\da-f]{2}/ig,function(i){r.push(parseInt(i,16));return"";});if(r.length)return r;return[100,0,0];};var p=function(v){return("0"+v.toString(16)).match(/.{2}$/)[0];};f=c(f);l=c(l);var r={r:((f.shift()+l.shift())/2)|0,g:((f.shift()+l.shift())/2)|0,b:((f.shift()+l.shift())/2)|0};return"#"+p(r.r)+p(r.g)+p(r.b);})("@{arguments}")`;
    background-color: @mix;
    background-image: -webkit-linear-gradient(top, @all);
    background-image: -moz-linear-gradient(top, @all);
    background-image: -o-linear-gradient(top, @all);
    background-image: linear-gradient(to bottom, @all);
}

我们当然可以进一步复杂化并计算所有渐变颜色的平均值,但对于我的需要,这已经足够了。以下是解析参数以及计算渐变中第一种和最后一种颜色的混合并在上@mix变量中缩小的函数:

(function(args) {
    args = args.replace(/,\s+(?=[\d ,.]+\))/gi, ";").split(/,\s*/g);
    var first = args[0].split(/\s+/g)[0];
    var last = args.pop().split(/\s+/g)[0];

    var calculateValues = function(color) {
        var result = [];
        /rgb/i.test(color) && color.replace(/[\d.]+/g, function(i) {
            result.push(1*i);
            return "";
        });
        /#.{3}$/.test(color) && color.replace(/[\da-f]/ig, function(i) {
            result.push(parseInt(i+i, 16));
            return "";
        });
        /#.{6}/.test(color) && color.replace(/[\da-f]{2}/ig, function(i) {
            result.push(parseInt(i, 16));
            return "";
        });
        if (result.length) return result;
        return [100,0,0];
    };

    var padZero = function(val) {
        return ("0" + val.toString(16)).match(/.{2}$/)[0];
    };

    first = calculateValues(first);
    last = calculateValues(last);

    var result = {
        r: ((first.shift() + last.shift()) / 2) | 0,
        g: ((first.shift() + last.shift()) / 2) | 0,
        b: ((first.shift() + last.shift()) / 2) | 0
    };
    return "#"+ padZero(result.r) + padZero(result.g) + padZero(result.b);
})("@{arguments}")
于 2013-03-29T09:52:32.033 回答