简体   繁体   English

较少-参数混合,带有简写的数字和/或字符串值,带有rem和px后备

[英]Less - parametric mixin with shorthand numeric and or string values, with rem and px fallback

Using Less, I'm trying output css combination shorthand values for properties, whilst detecting the type of a value passed as a variable depending on how many values are passed as variables. 使用Less,我尝试输出属性的css组合速记值,同时根据作为变量传递多少值来检测作为变量传递的值的类型。

  • one value @v1 一个值@v1
  • two values @v1 and @v2 两个值@v1@v2
  • four values @v1 , @v2 , @v3 and @v4 四个值@v1@v2@v3@v4

And for each variable detected, check if is is a number greater than 0, and if so output a rem and px value for each property value, so the complied css might be something like: 对于检测到的每个变量,请检查是否是大于0的数字,如果是,则为每个属性值输出一个rem和px值,因此编译的css可能类似于:

.demobox{
  border-width: 10px 20px 0 0;
  border-width: 1rem 2rem 0 0;
  padding: 0 50px;
  padding: 0 2rem;
  margin: 20px auto;
  margin: 2rem auto;
  font-size: 16px;
  font-size: 1.6rem;
}

This is fairly easy to solve where no more than two values are ever declared, but If I need four values, the number of nested mixins and guards becomes pretty complicated. 这很容易解决,只要声明两个以上的值即可,但是如果我需要四个值,则嵌套的mixin和守卫的数量将变得非常复杂。

The reason for opting for rems is the ease of implementation compared to ems, and prevents having the headache of remembering to have to reset the font-size to every parent item. 选择rems的原因是,与ems相比,它易于实现,并且避免了不得不记住必须将字体大小重置为每个父项的麻烦。 Additionally the older device support issues are comparable, for both rems and ems, so I figure a px fallback works best. 此外,对于rems和ems,较旧的设备支持问题是可比较的,因此我认为px后备效果最佳。

Here's' the code pen of where I am so far, but I'll try and explain my workings so far as best as I can. 这是到目前为止我的代码笔 ,但我会尽我所能尽力解释我的工作方式。

Is there a way to simplify this process? 有没有办法简化这个过程? I'm new to less. 我是新手。 I imagine there is a much simpler way to detect 我想有一种更简单的检测方法

  • the number of declared values 声明值的数量
  • the type of each value 每个值的类型
  • if the number value requires a rem and px value fallback 如果数字值需要rem和px值回退

Thanks 谢谢

I have a parametric mixin which outputs a rem value and px fallback value along with the declared property 我有一个参数mixin,它输出rem值和px后备值以及声明的属性

@root-font-size: 10;

.rem(@property, @v1) when (@v1 = @v1){
    @px1: @v1 * @root-font-size;
    @{property}:  ~'@{px1}px';
    @{property}: ~'@{v1}rem';
}

This is great for quickly generating both the rem and pixel fallback for a set css property 这对于为一组css属性快速生成rem和像素回退非常有用

/* call the rem mixin */
.demobox {
    .rem(margin, 2);
}
/* output */
.demobox {
    margin: 20px;
    margin: 2rem;
}

One really useful case for this is generating font-size and line-height values with fallbacks 一种非常有用的情况是生成带有回退的font-sizeline-height

/* call the font-classes mixin */
.font-classes(@fontsize, @lineheight) {
    .rem(font-size, @fontsize);
    .rem(line-height, @lineheight);
}
/* output */
.demobox {
    font-size: 16px;
    font-size: 1.6rem;
    line-height: 24px;
    line-height: 2.4rem;
}

So far so good, i can output a rem and pixel fallback for a single value and nest the .rem mixin with in another mixin. 到目前为止,我可以为单个值输出一个rem和像素回退,然后将.rem mixin与另一个mixin嵌套在一起。

At the moment, if I want to pass more than one value I have to call the .rem mixin for each required value: 目前,如果我要传递多个值,则必须为每个必需的值调用.rem mixin:

/* call the rem mixin */
.demobox {
    .rem(margin-left, 2);
    .rem(margin-right, 2);
}
/* output */
.demobox {
    margin-left: 20px;
    margin-left: 2rem;
    margin-right: 20px;
    margin-right: 2rem;
}

Ideally I'd like to be able to do is pass either one two or four values with a property to the .rem mixin. 理想情况下,我希望能够将具有属性的一两个或四个值传递给.rem mixin。

.demobox {
    .rem(margin, 2, 1);
}

As I mentioned earier this is not so difficult for two values, and to check what the value type is. 正如我提到的,对于两个值,并检查值类型是什么,这并不困难。 This requires a version of the .rem mixin with a gaurd applied to check that @v2 is declared. 这需要.rem mixin版本,并使用一个gaurd来检查是否声明了@v2

This the triggers a nested .rem-two mixin. 这将触发嵌套的.rem-two mixin。

// when there are two values
.rem(@property, @v1, @v2) when (@v1 = @v1) and (@v2 = @v2){
    .rem-two(@property, @v1, @v2);
}

There are three versions of the .rem-two , where the guards are different for each. .rem-two共有三个版本,每个版本的防护措施都不同。

Detect if both @v1 and @v2 are numbers greater than 0 检测@v1@v2是否都大于0

.rem-two(@property, @v1, @v2) when (@v1 = @v1) and not (@v1 = 0) and (isnumber(@v1)) and (@v2 = @v2) and not (@v2 = 0) and (isnumber(@v2)) {
    @px1: @v1 * @root-font-size;
    @px2: @v2 * @root-font-size;
    @{property}:  ~'@{px1}px @{px2}px';
    @{property}: ~'@{v1}rem @{v2}rem';
}

Detect if both @v1 and @v2 are numbers greater than 0 检测@v1@v2是否都大于0

.rem-two(@property, @v1, @v2) when (@v1 = @v1) and not (@v1 = 0) and (isnumber(@v1)) and (@v2 = 0), not (isnumber(@v2)){
    @px1: @v1 * @root-font-size;
    @{property}:  ~'@{px1}px @{v2}';
    @{property}: ~'@{v2}rem @{v2}';
}

/* call the rem mixin */
.demobox {
    .rem(margin, 2, 1);
}
/* outputs */
.demobox {
    margin: 10px 20px;
    margin: 1rem 2rem;
}

Detect if both @v1 is a number greater than 0 and @v2 is either a value of 0 or not a number 检测两个@v1是否都是大于0的数字,并且@v2是否为0或不是数字

the '@px2' pixel fallback is not required, so is removed. 不需要'@ px2'像素后备广告,因此将其删除。

.rem-two(@property, @v1, @v2) when (@v1 = @v1) and not (@v1 = 0) and (isnumber(@v1)) and (@v2 = 0), not (isnumber(@v2)){
    @px1: @v1 * @root-font-size;
    @{property}:  ~'@{px1}px @{v2}';
    @{property}: ~'@{v2}rem @{v2}';
}
/* call the rem mixin */
.demobox {
    .rem(margin, 2, auto);
}
/* outputs */
.demobox {
    margin: 10px auto;
    margin: 1rem auto;
}

Detect if both @v1 is either a value of 0 or not a number and @v2 is a number greater than 0 检测两个@v1是否均为0或不是数字,以及@v2是否为大于0的数字

the '@px1' pixel fallback is not required, so is removed. 不需要'@ px1'像素后备广告,因此将其删除。

.rem-two(@property, @v1, @v2) when (@v1 = 0), not (isnumber(@v1)) and (@v2 = @v2) and not (@v2 = 0) and (isnumber(@v2)){
    @px2: @v2 * @root-font-size;
    @{property}:  ~'@{v1} @{px2}px';
    @{property}: ~'@{v1} @{v2}rem';
}
/* call the rem mixin */
.demobox {
    .rem(margin, 0, 20);
}
/* outputs */
.demobox {
    margin: 0 20px;
    margin: 0 2rem;
}

As there are only 3 possibilities for this two value version of the mixin It is easy to solve this problem, but with 3 or four values the number of nested mixins and guards expands to cover all possibilities. 由于mixin的两个值版本只有3种可能性,因此很容易解决这个问题,但是使用3或4个值时,嵌套的mixin和防护的数量会扩展以涵盖所有可能性。

As additional examples. 作为其他示例。 I have repurposed the .rem mixin to output px and rem , border-radius values with vendor prefixing, to ensure that it only processes numeric values, I have guards to check if the value being passed is a number that is greater that 0 我已经重新调整了.rem mixin的用途,以输出pxrem ,并使用供应商前缀作为border-radius值,以确保它仅处理数字值,我.rem检查所传递的值是否为大于0的数字

.prefix(@property, @v1) when (isnumber(@v1)) and (@v1 > 0) {
    @px1: @v1 * @root-font-size;
    -webkit-@{property}: ~'@{px1}px';
    -moz-@{property}: ~'@{px1}px';
    @{property}: ~'@{px1}px';
    -webkit-@{property}: ~'@{v1}rem';
    -moz-@{property}: ~'@{v1}rem';
    @{property}: ~'@{v1}rem';
}
/* call prefix mixin */
.demobox{
    .prefix(border-radius,5);
}
/* output */
.demobox{
    -webkit-border-radius: 50px;
    -moz-border-radius: 50px;
    border-radius: 50px;
    -webkit-border-radius: 5rem;
    -moz-border-radius: 5rem;
}

I can swap the guards around to check that the value is either 0 (so i can reset a property) or if it is anything else than a number, such as outputting prefixed box sizing. 我可以调换警惕,以检查该值是否为0(以便我可以重置属性)或是否为数字以外的其他值,例如输出带前缀的框大小。

The reason I ask a guard of not (isnumber(@v1)) , rather than (isstring(@v1)) , is so I don't have to add single quotes the the value `'border-box'. 我要求not (isnumber(@v1))而不是(isstring(@v1))是,这样我就不必在单引号中添加值'border-box'。

.prefix(@property, @v1) when (@v1 = 0), not (isnumber(@v1)) {
    -webkit-@{property}: ~'@{v1}';
    -moz-@{property}: ~'@{v1}';
    @{property}: ~'@{v1}';
}
/* call prefix mixin */
.demobox {
    .prefix(box-sizing, border-box);
}
/* output */
.demobox {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}

You can simplify things if you treat passed arguments as an array (a simplified impl., there're too many requirements in your snippet to cover in an example ), Less 1.7.x or higher: 如果将传递的参数视为数组(可以简化表示, 示例中包含的要求太多),则可以简化事情, 小于1.7.x或更高:

// usage

@root-font-size: 10;

div {
    .rem(border-radius, 1, margin, 2 auto, padding, 4 5 6 inherit);
}

// impl:

.rem-value_(@p, @v, @u) when (isnumber(@v)) {
    @{p}+_: (@v * @u);
}

.rem-value_(@p, @v, @u) when (default()) {
    @{p}+_: @v;
}

.rem(@args...) {
    .i; .i(@i: length(@args)) when (@i > 0) {
        .i((@i - 2));
        @property: extract(@args, (@i - 1));
        @values:   extract(@args,  @i);
        .j(@property, @values, (1px * @root-font-size));
        .j(~'@{property} ', @values, 1rem); // have to use ~'@{property} ' hack to isolate rem and px properties;
    }
    .j(@p, @v, @u, @j: length(@v)) when (@j > 0) {
        .j(@p, @v, @u, (@j - 1));
        .rem-value_(@p, extract(@v, @j), @u);
    }
} 

The loop is quite scary but the value output mixin is pretty transparent and fully customizable (you can add more conditions if you need to). 循环非常可怕,但是值输出mixin非常透明并且可以完全自定义(如果需要,可以添加更多条件)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM