在Sass中,将计算结果附加到单位类型。

71

最近我一直在将CSS重构为SASS样式表。我正在使用VS2012的Mindscape Web Workbench扩展程序,每次保存SCSS时都会重新生成CSS。我从类似于以下代码开始:

/* Starting point: */
h1 { font-size: 1.5em; /* 24px ÷ 16px */ }

然后我试图先将其重构为以下内容:
/* Recfator: */
h1 { font-size: (24px / 16px)em; }

但是这样做会不幸地产生:
/* Result: */
h1 { font-size: 1.5 em; }              /* doesn't work, gives "1.5 em" */

注意到有额外的空格,我不想要那个。我尝试了几种替代方案,以下是其中一些:
h1 { font-size: (24/16)em; }           /* doesn't work, gives "1.5 em" */
h2 { font-size: 24 / 16em; }           /* doesn't work, gives "24/16em" */
h3 { font-size: (24px / 16px) * 1em; } /* works but "* 1 em" feels unnecessary */
h4 { font-size: (24em) / 16; }         /* works, but without "px" it's not 
                                          really conveying what I mean to say */

我也尝试了使用变量的不同变体(因为我无论如何都需要它们),但是那并没有改变情况。为了使本问题中的示例简洁,我略去了变量。然而,我很乐意接受依赖于使用变量的解决方案(以清晰的方式)。
我已经阅读了相关SASS文档,并且理解这对SASS来说是一个棘手的问题,因为“/”字符在基本CSS中已经有一定的含义。无论如何,我希望有一个清晰的解决方案。我错过了什么吗?
PS. 这篇博客文章提供了一种解决方案,使用用户定义的函数。虽然这似乎有点重量级,但我对与我的尝试相符的“更简洁”的解决方案感兴趣。如果有人能解释“函数方法”是更好的(甚至是唯一的)解决方案,那么我也会接受它作为答案。

PS. 这个相关问题 看起来是关于同一个事情,尽管那个问题特别想要进行进一步的计算。那里被接受的答案 是我的第三种解决方法(乘以1em),但如果我愿意放弃进行进一步计算的能力,我很想知道是否有不同(更干净)的方法。也许在上述问题中提到的方法(“插值”)对我有用?


底线:在SASS中,如何干净地将单位类型(例如em)附加到计算结果中?

@cimmanon 感谢您的帮助和回答,但我觉得我的问题并不完全是重复的。我明确提到“乘以1em”是一种解决方法,但我更倾向于不使用它,并且在这个问题的上下文中,我并不关心能否进行进一步的计算。虽然您可能不同意,但我所问的问题的答案实际上是插值。 (鉴于插值不是那个其他问题的答案,我不明白它们如何成为重复问题...)。请考虑取消将其标记为重复。 - Jeroen
你的评论或许可以当做一条良好的评论或竞争性答案,但可能不足以成为金徽章重复锤的理由。如果在提出这个问题的时候我知道还有其他问题,我仍然可能会问这个问题。我的最新编辑试图反映这一点,在此基础上我也投了一票请求社区重新开放它。 - Jeroen
1
你重新打开这个问题,给Sass作者带来了极大的伤害。现在它已经成为谷歌搜索结果的首选。你所谓的“首选方法”是将单位附加到数字的最糟糕方式,只会在未来不按预期工作时引起混乱。 - cimmanon
1
如果您不同意最受欢迎和被接受的答案,您应该编写更好的答案,而不是在评论中发牢骚。 - 解释为什么/何时插值不是最佳选择工具,或告诉大家我已经提到的方法之一是首选方式。 - Jeroen
@cimmanon,感谢您回答我的问题。为了避免给未来的访问者带来困惑,最好请版主清除我们在这里的评论对话。如果您同意,请标记我的这条评论以请求定制版主注意并清除所有评论。 - Jeroen
显示剩余7条评论
5个回答

79

唯一将单位添加到数字的方法是通过算术运算

执行类似于连接(例如1 + px)或内插(例如#{1}px)的操作只会创建一个看起来像数字的字符串。即使您绝对肯定您永远不会在另一个算术运算中使用您的值,您也不应该这样做

比无法执行算术运算更重要的是,您将无法将其与其他期望数字的函数一起使用:

$foo: 1; // a number
$foo-percent: $foo + '%'; // a string

.bar {
    color: darken(blue, $foo-percent); //Error: "1%" is not a number!
}

$amount:"1%"不是`darken'的数字

把你的数字转换成字符串没有任何好处。使用算术运算(乘以1或加上0)来添加单位:

$foo: 1; // a number
$foo-percent: $foo * 1%; // still a number! //or: $foo + 0%

.bar {
    color: darken(blue, $foo-percent); //works!
}

输出:

.bar {
  color: #0000fa;
}

这是我作为Flexbox mixin库的一部分编写的混入函数,如果你传递一个字符串它将无法正常工作(针对不熟悉Flexbox的人,原始规范只允许在box-flex属性中使用整数。 flex:autoflex:30em无法与相应的box-flex属性兼容,因此混入函数不会尝试这样做)

@mixin flex($value: 0 1 auto, $wrap: $flex-wrap-required, $legacy: $flex-legacy-enabled) {
    @if $legacy and unitless(nth($value, 1)) {
        @include legacy-flex(nth($value, 1));
    }

    @include experimental(flex, $value, flex-support-common()...);
}

@mixin legacy-flex($value: 0) {
    @include experimental(box-flex, $value, $box-support...);
}

2
有趣的事实:刚找到这里(单位转换)的答案几秒钟后,我搜索了一下 Sass 是否有开关结构,并在此着陆:https://github.com/sass/sass/issues/554#issuecomment-18304635。好巧合啊,感谢您! :D - maryisdead
3
对于一个百分数和一个Sass变量$var,我使用了:#{$var}#{"%"}。 - Tyler
也许将“增加数字单位的唯一方法是通过算术运算。”更改为“...是通过乘法运算。”会更清晰明了。我之前尝试过使用加法运算,后来才意识到那正是不该做的事情。 - Atav32
1
@Atav32 实际上,如果你有 $foo: 1;,那么 加法 也是可能的,你可以使用 $foo-percent: $foo + 0% 将其转换为百分比,就像 $foo * 1% 一样。 - S.Serpooshan
1
TL;DR $foo-percent: $foo * 1%; 简而言之,$foo-percent: $foo * 1%; - panepeter
下次请把解决方案放在顶部。 - Dirigible

46

你可以尝试以下两种方法:

font-size: $size * 1px;
或者
font-size: $size + unquote("px");

其中$size是您计算的结果。


2
第二种方法对我非常有效。我发现 unquote("px"); 是关键所在。如果我们不应用 unquotepx 将被渲染在引号内,浏览器将无法正确地呈现该值。因此,应用 unquote 是必要的。 - Devner
请注意,font-size: $size + px;(不带任何引号)也是可能的,比第二种方法更简单!请参见下面的我的答案 - S.Serpooshan

22

选择您喜欢的方法

$font: 24px;
$base: 16px;

没有变量

.item1 { font-size: #{(24px / 16px)}em; }

仅使用变量

.item2 { font-size: #{$font / $base}em; }

一个变量

.item3 { font-size: #{$font / 16px}em; }
.item4 { font-size: #{24px / $base}em; }

所有它们的输出

.item1 { font-size: 1.5em; }
.item2 { font-size: 1.5em; }
.item3 { font-size: 1.5em; }
.item4 { font-size: 1.5em; }

所使用的方法称为内插 #{}


这种方法能否与百分号一起使用?SCSS似乎有些抱怨... - iamkeir
8
百分号也需要使用插值方法,例如#{(24px / 16px)}#{"%"}将输出1.5% - electric_g
12
永远不要这样做,无论任何情况下都不要。这将总是给你一个字符串,意味着你永远无法在后面的数学运算中使用结果。 - cimmanon
7
Sass首席设计师来了! @cimmanon说得对;这不是一种健壮或惯用的转换单位的方式。 Sass的单位是其算术的一部分,利用单位算术可以生成更好、更易于维护的样式表。 - Natalie Weizenbaum
对于百分比,您可以选择使用#{(24px / 16px)}unquote("%") - dude
@NatalieWeizenbaum 那你的建议是什么?从不在变量大小之后添加单位吗? - dude

6
我猜你问这个的原因是因为在周围的上下文中,1个em = 16个像素,并且你想利用这个关系将目标字体大小从像素转换为ems。
如果是这样,正确的做法是乘以缩放因子1em / 16px,就像这样:
$h1-font-size: 24px;
$body-font-size: 16px;

$body-em-scale: 1em / $body-font-size;

h1 {
  font-size: $h1-font-size * $body-em-scale;  // -> 1.5em
}

或者只是:
h1 {
  font-size: $h1-font-size * (1em / $body-font-size);  // -> 1.5em
}

这就是物理学的工作原理:如果有50摩尔的水,并且您想知道它在克(grams)中的重量,那么您需要将您拥有的水的数量(= 50摩尔)与水的摩尔质量(≈18g / mol)相乘,以找出您的水样重约900克。在SASS中将像素转换为ems也是同样的原理:首先在您打算使用规则的上下文中找出每个像素的ems数量,然后用em / px单位表示的比率乘以px大小。

顺便提一下,如果你要转换的单位之间有一个固定的比率,而SASS已经知道了这个比率,那么你可以使用“零加技巧”让它自动进行转换。例如,如果你想将字体大小从像素(px)转换为厘米(cm),你只需要这样做:

h1 {
  font-size: 0cm + $h1-font-size;  // -> 0.635cm
}

这个方法有效是因为SASS允许你将两个以兼容单位(如px和cm)表示的值相加,并将结果以与第一个值相同的单位表示。之所以这个技巧不能用于px -> em,是因为这里的转换因子不是固定的,而是取决于周围的上下文,因此SASS无法自动进行转换。

那么换句话说,这个问题是一个已经存在的问题的副本吗?(参见:https://dev59.com/YWUp5IYBdhLWcg3wHUri) - cimmanon
3
并不完全如此。那个问题是关于如何在没有单位的数字后添加单位。这个问题是关于如何在两个不同单位之间转换尺寸测量值(px -> em)。 - Ilmari Karonen
我们已经有一个关于去除单位的问题(请参见:https://dev59.com/72ct5IYBdhLWcg3wIp_W)。 - cimmanon
1
@cimmanon: 我想要表达的是,在这里随意剥离和添加单位是错误的。这些单位存在是有原因的,你真的应该与它们一起工作,而不仅仅是在进行数学计算之前使用技巧去除它们,然后再把它们粘回去。对于两个没有固定比率的单位之间的转换,正确的方法是找到你的情况下的正确转换比率并乘以它。 - Ilmari Karonen

2

添加单位的最佳方式是使用... * 1em... + 0em,其中em是您想要获得的单位:

font-size: (24px/16px) + 0em; // ... + 0px for px
//or
font-size: (24px/16px) * 1em; 
//both produce: font-size: 1.5em;

这样,它将保持为一个数字,因此您可以在数学运算或其他函数中使用它。

但是,如果您希望结果为字符串或者出于某种原因不关心结果的数值,您也可以通过以下方式获取它:

font-size: (24px/16px) + em; //font-size: 1.5em; //em does not include quotations

这里不需要使用unquote#{}(如其他答案所述)!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接