[英]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组合速记值,同时根据作为变量传递多少值来检测作为变量传递的值的类型。
@v1
一个值@v1
@v1
and @v2
两个值@v1
和@v2
@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 我想有一种更简单的检测方法
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-size
和line-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的用途,以输出px
和rem
,并使用供应商前缀作为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.