css3中的calc方法简介

最近在开发的过程中遇到一个方法:calc,可以动态的去计算元素的宽高边距等等样式,但是却遇到一个大坑!(此处应该有unbelievable的表情包)

代码如下:

1
2
3
4
5
6
7
8
9
    //...
    img{
        display: block;
        width: 100%;
        &.haibao {
            min-height: calc((100vw - 185px) / 3 / 3.41);
        }
    }
    //...

实际效果如图:

图片

calc中的值居然是负的,难以置信!!

—————————————-正文开始————————————–

1、什么是calc

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

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

2、calc()语法

1
    calc(expression); //expression是一个表达式,用来计算尺寸的表达式。

3、calc()的运算规则

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

1)使用“+”、“-”、“*” 和 “/”四则运算;

2)可以使用百分比、px、em、rem等单位;

3)可以混合使用各种单位进行计算;

4)表达式中有“+”和“-”时,其前后必须要有空格,如”widht: calc(12%+5em)”这种没有空格的写法是错误的;

5)表达式中有“*”和“/”时,其前后可以没有空格,但建议留有空格。

4、calc兼容性

图片

此部分参考: CSS3的calc()使用

5、calc的新单位

1)vw、vh、vmin、vmax 的含义

a. vw、vh、vmin、vmax 是一种视窗单位,也是相对单位。它相对的不是父节点或者页面的根节点。而是由视窗(Viewport)大小来决定的,单位 1,代表类似于 1%。
b. 视窗(Viewport)是你的浏览器实际显示内容的区域—,换句话说是你的不包括工具栏和按钮的网页浏览器。
c. 具体描述如下:

vw:视窗宽度的百分比(1vw 代表视窗的宽度为 1%)

vh:视窗高度的百分比

vmin:当前 vw 和 vh 中较小的一个值

vmax:当前 vw 和 vh 中较大的一个值

2)vw、vh 与 % 百分比的区别

a. % 是相对于父元素的大小设定的比率,vw、vh 是视窗大小决定的。
b. vw、vh 优势在于能够直接获取高度,而用 % 在没有设置 body 高度的情况下,是无法正确获得可视区域的高度的,所以这是挺不错的优势。

3)vmin、vmax 用处

a. 做移动页面开发时,如果使用 vw、wh 设置字体大小(比如 5vw),在竖屏和横屏状态下显示的字体大小是不一样的。
b. 由于 vmin 和 vmax 是当前较小的 vw 和 vh 和当前较大的 vw 和 vh。这里就可以用到 vmin 和 vmax。使得文字大小在横竖屏下保持一致。

4)浏览器兼容性

a. 桌面 PC

Chrome:自 26 版起就完美支持(2013年2月)

Firefox:自 19 版起就完美支持(2013年1月)

Safari:自 6.1 版起就完美支持(2013年10月)

Opera:自 15 版起就完美支持(2013年7月)

IE:自 IE10 起(包括 Edge)到现在还只是部分支持(不支持 vmax,同时 vm 代替 vmin)

b. 移动设备

Android:自 4.4 版起就完美支持(2013年12月)

iOS:自 iOS8 版起就完美支持(2014年9月)

此部分参考:CSS3 - 新单位vw、vh、vmin、vmax使用详解(附样例)

———————————–正文结束—————————————-

为了复习知识(检测写法),我自己写了个demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <!--<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />-->
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        body {
            font-size: 12px;
            font-family: "Microsoft Yahei", "PingFang SC";
            background-size: 100% auto;
            height: 800px;
        }

        .clear {
            clear: both;
            margin-top: 10px;
            overflow: hidden;
        }
        .left {
            float: left;
            width: 200px;
            height: 200px;
            background: #fed;
        }

        .right {
            margin-left: 200px;
            height: 200px;
            background: #edf;
        }

        .right2 {
            float: left;
            /*在这种情况下 100% 和100vw是一样的*/
            width: calc(100% - 200px);
            /*width: calc(100vw - 200px - 15px);!*15像素是滚动条宽度*!*/
            height: 200px;
            background: #aef;
        }

        .right3 {
            margin-left: 200px;
            height: 200px;
        }

        .right4 {
            float: left;
            height: 200px;
            /*height: calc(100vh - 800px);*/
            background: #c0a2f4;
            /*在这种情况下 100% 和100vw是不一样的 vw代表视口宽度 100%是根据父级元素宽度的百分比进行计算,
            也就是说,第一种方式宽度刚好可以放在一行内,第二种会被挤掉*/
            width: calc(100% - 200px);
            /*width: calc(100vw - 200px - 15px);*/
        }

        ul {
            width: 100%;
        }

        li {
            margin-right: 20px;
            /*width: calc((100vw / 3) - 20px);*/
            width: calc((100% / 3) - 20px);

            /*width: 31.5%;*/
            /*margin-right: 1.5%;*/
            display: inline-block;
            float: left;
        }
        img {
            width: 100%;
            /*height: calc(31.5% / 1.6);!*更准确些*!*/
            height: calc(((100vw/ 3) - 20px) / 1.6);
        }
    </style>
    </head>
    <body>
        <div class="clear">
            <div class="left"></div>
            <div class="right"></div>
        </div>
        <div class="clear">
            <div class="left"></div>
            <div class="right2"></div>
        </div>
        <div class="clear">
            <div class="left"></div>
            <div class="right3">
                <div class="clear" style="float: left;">
                    <div class="left"></div>
                    <div class="right4"></div>
                </div>
            </div>
        </div>
        <ul class="clear">
            <li>
                <img src="u420.png" alt="">
            </li>
            <li>
                <img src="u420.png" alt="">
            </li>
            <li>
                <img src="u420.png" alt="">
            </li>
        </ul>
    </body>
    </html>

效果如图:

图片

打开控制台,发现我定义的calc属性还是个表达式,一脸懵逼。。。

图片

那么为什么会被编译成负数呢,还是按前面数据的单位进行的计算,我灵机一动发现事情并不简单,是不是webpack打包影响到了呢,打开百度,搜索一下,发现跟webpack还真没啥关系(webpack:这锅我不背!)

实际上是在less当中写了calc,会被直接计算出一个确定值应用到元素上,所以在less中要这样写:

1
2
3
4
    calc(~"100% - 30px");
    calc(~"100% - @{cap}");
    /*或者*/
    e("calc(100% - 7rem)")

问题完美解决,那么问题又来了:

1、Q:less中的calc又是什么?

2、 Q:css3中的calc的工作原理是怎样的?

A:calc 的基本工作原理