CSS3 的 calc 使用

2017/12/19

什么是 calc ?

学习 calc 之前,我们有必要先知道 calc 是什么?只有知道了他是个什么东东?在实际运用中更好的使用他。

calc 从字面我们可以把他理解为一个函数 function。其实 calc 是英文单词 calculate(计算) 的缩写,是 css3 的一个新增的功能,用来指定元素的长度。比如说,你可以使用 calc 给元素的 bordermarginpadingfont-sizewidth 等属性设置动态值。为何说是动态值呢? 因为我们使用的表达式来得到的值。不过 calc 最大的好处就是用在流体布局上,可以通过 calc 计算得到元素的宽度。

calc 能做什么?

calc 能让你给元素的做计算,你可以给一个 div 元素,使用百分比、empxrem 单位值计算出其宽度或者高度,比如说 width:calc(50% + 2em),这样一来你就不用考虑元素 DIV 的宽度值到底是多少,而把这个烦人的任务交由浏览器去计算。

calc 语法

calc 语法非常简单,就像我们小时候学加(+)、减(-)、乘(*)、除(/)一样,使用数学表达式来表示:

.elm {
  width: calc(expression);
}

其中 “expression” 是一个表达式,用来计算长度的表达式。

calc 的运算规则

calc 使用通用的数学运算规则,但是也提供更智能的功能:

  • 使用 “+”、“-”、“*” 和 “/” 四则运算;
  • 可以使用百分比、px、em、rem 等单位;
  • 可以混合使用各种单位进行计算;
  • 表达式中有 “+” 和 “-” 时,其前后必须要有空格,如 “widht: calc(12%+5em)” 这种没有空格的写法是错误的;
  • 表达式中有 “*” 和 “/” 时,其前后可以没有空格,但建议留有空格。

浏览器的兼容性

浏览器对 calc 的兼容性还算不错,在 IE9+、FF4.0+、Chrome19+、Safari6+ 都得到较好支持,同样需要在其前面加上各浏览器厂商的识别符,不过可惜的是,移动端的浏览器仅有 “firefox for android 14.0” 支持,其他的全军覆没。

大家在实际使用时,同样需要添加浏览器的前缀

.elm {
	/*Firefox*/
	-moz-calc(expression);
	/*chrome safari*/
	-webkit-calc(expression);
	/*Standard */
	calc();
}

简单的实例

通过上面的了解,大家对 calc 不再那么陌生,但对于实际的运用可能还是不太了解,那么大家就接下来跟我一起动手,通过实例来了解他吧。首先我们来看一个最常用的实例:

<div class="demo">
	<div class="box"></div>
</div>

上面的结构很简单,就是一个 div.demo 的元素中包含了一个 div.box 的元素,接下来我们一步一步来看其中的变化。

第一步:添加普通样式:

.demo {
  width: 300px;
  background: #60f;
}
.box {
  width: 100%;
  background: #f60;
  height: 50px;
}

此时的效果很简单,就是 div.box 完全遮盖了 div.demo,如下图所示:

第二步,在 div.box 上添加 border 和 padding

这一步很棘手的事情来了,在 div.box 上添加 10px 的内距 padding,同时添加 5pxborder

.demo {
  width: 300px;
  background: #60f;
}
.box {
  width: 100%;
  background: #f60;
  height: 50px;
  padding: 10px;
  border: 5px solid green;
}

为了更好的说明问题,我在 div.demo 上添加了一个 padding:3px 0;

.demo {
  width: 300px;
  background: #60f;
  padding: 3px 0;
}
.box {
  width: 100%;
  background: #f60;
  height: 50px;
  padding: 10px;
  border: 5px solid green;
}

这个时候大家不知道能否想到问题会发生在哪?其实很简单,这个时候 div.box 的宽度大于了其容器 div.demo 的总宽度,从而撑破容器伸出来了,如图所示:

第三步,calc 的运用

为了解决撑破容器的问题,以前我们只能去计算 div.box 的宽度,用容器宽度减去 paddingborder 的值,但有时候,我们苦于不知道元素的总宽度,比如说是自适应的布局,只知道一个百分值,但其他的值又是 px 之类的值,这就是难点,死卡住了。随着 CSS3 的出现,其中利用 box-sizing 来改变元素的盒模型类型实使实现效果,但今天我们学习的 calc 方法更是方便。

知道总宽度是 100%,在这个基础上减去 boder 的宽度(5px * 2 = 10px), 再减去 padding 的宽度(10px * 2 = 20px),即 “100% - (10px + 5px) * 2 = 30px” ,最终得到的值就是 div.boxwidth 值:

.demo {
  width: 300px;
  background: #60f;
  padding: 3px 0;
}
.box {
  background: #f60;
  height: 50px;
  padding: 10px;
  border: 5px solid green;
  width: 90%; /* 写给不支持 calc 的浏览器 */
  width: -moz-calc(100% - (10px + 5px) * 2);
  width: -webkit-calc(100% - (10px + 5px) * 2);
  width: calc(100% - (10px + 5px) * 2);
}

这样一来,通过 calc 计算后,div.box 不再会超出其容器 div.demo 的宽度,如图所示:

calc 在 less 中的问题

lesscalc(100% - 4rem) 等带单位混合运算会被 less 解析忽略单位,全部按照数值计算,此例中的计算被 less 编译成 calc(96%)

有三种解决方法如下:

  • width: e(“calc(100% - 4rem)”);
  • width: calc(~”100% - 4rem”);
  • width: ~”calc(100% - 4rem)”;

如果有变量,则需要使用 {} 括起来

div {
 @diff : 30px;
 width : calc(~"100% - @{diff}");
}

calc 在 scss 中的问题

要想在 sasscalc 中使用变量,必须对这个变量使用 sass 的插值方法 (#{$variable})。 例如:

.app-inner {
  display: flex;
  height: calc(100% - #{$topbar-height});
}

参考资料