# Modern CSS solution: CSS mathematical functions

2022-05-15 05:03:14chokcoco

stay CSS in , In fact, there are various functions . It can be divided into ：

this paper , We will introduce in detail CSS Mathematical functions （Math functions） in , Has been massively supported by browsers 4 individual ：

• calc()
• min()
• max()
• clamp()

Why is it supported by browsers on a large scale ？ Because apart from this 4 A mathematical function that has been supported on a large scale , In fact, the standard CSS Values and Units Module Level 4 We have defined some related functions such as trigonometric function `sin()``cos()``tan()` etc. , Exponential function correlation `pow()``sqrt()` Wait, mathematical functions , It's just that they're all in the laboratory now , No browser supports them yet , Need some time .

## Calc()

calc() this CSS Function allows you to declare CSS Some calculations are performed when the property is valued .

The syntax is similar to

```{
width: calc(100% - 80px);
}```

Some points to pay attention to ：

• `+` and `-` Operators must have white space characters on both sides . such as ,`calc(50% -8px)` Will be resolved into an invalid expression , Must be written as `calc(8px + -50%)`
• `*` and `/` You don't need white space around these two operators , But if you think about unity , It's still recommended to add white space
• use 0 Divisor makes HTML The parser throws an exception
• Table columns in tables involving automatic layout and fixed layout 、 List group 、 Table row 、 Mathematical expression for the width and height percentages of table row groups and table cells ,auto Can be regarded as specified .
• calc() Functions support nesting , But the way to support it is ： Put the nested calc() All functions are treated as ordinary brackets .（ therefore , Just use parentheses directly in the function .）
• calc() Support and CSS Variables are mixed

Look at one of the most common examples , The page structure is as follows ：

```<div class="g-container">
<div class="g-content">Content</div>
<div class="g-footer">Footer</div>
</div>```

Page `g-footer` High for 80px, We hope that no matter how long the page is ,`g-content` Some of them can take up the remaining space , It's like this. ： This layout uses flex Flexible layout can be easily realized , Of course , You can also use `calc()` Realization ：

```.g-container {
height: 100vh;
}
.g-content {
height: calc(100vh - 80px);
}
.g-footer {
height: 80px;
}```

Here is a list of Calc() Advanced techniques for .

### Calc The difference between addition and subtraction and multiplication and division in

Be careful ,calc() The difference between addition and subtraction and multiplication and division in ：

```{
font-size: calc(1rem + 10px);
width: calc(100px + 10%);
}```

You can see , The operands on both sides of the addition and subtraction method need units , And multiplication and division , Need a unitless number , It only represents a magnification ：

```{
width: calc(100% / 7);
animation-delay: calc(1s * 3);
}```

### Calc Nesting of

calc() Functions can be nested , It's like this. ：

```{
width: calc(100vw - calc(100% - 64px));
}```

here , Inside calc() The function can be degenerated into a bracket (), So the above code is equivalent to ：

```{
width: calc(100vw - (100% - 64px));
}```

That is, nested calc(),calc Several function characters can be omitted .

### Calc Mixed operation of different units in

calc() Support mixed operation of different units , For length , As long as it belongs to length related units, mixed operation can be carried out , Contains the ：

• px
• %
• em
• rem
• in
• mm
• cm
• pt
• pc
• ex
• ch
• vh
• vw
• vmin
• vmax

Here's an interesting point , Computing must be performance consuming , Early years , There is such a passage CSS Code , You can directly Chrome Browser crashes Crash：

`<div></div>`

CSS The style is as follows ：

```div {
--initial-level-0: calc(1vh + 1% + 1px + 1em + 1vw + 1cm);

--level-1: calc(var(--initial-level-0) + var(--initial-level-0));
--level-2: calc(var(--level-1) + var(--level-1));
--level-3: calc(var(--level-2) + var(--level-2));
--level-4: calc(var(--level-3) + var(--level-3));
--level-5: calc(var(--level-4) + var(--level-4));
--level-6: calc(var(--level-5) + var(--level-5));
--level-7: calc(var(--level-6) + var(--level-6));
--level-8: calc(var(--level-7) + var(--level-7));
--level-9: calc(var(--level-8) + var(--level-8));
--level-10: calc(var(--level-9) + var(--level-9));
--level-11: calc(var(--level-10) + var(--level-10));
--level-12: calc(var(--level-11) + var(--level-11));
--level-13: calc(var(--level-12) + var(--level-12));
--level-14: calc(var(--level-13) + var(--level-13));
--level-15: calc(var(--level-14) + var(--level-14));
--level-16: calc(var(--level-15) + var(--level-15));
--level-17: calc(var(--level-16) + var(--level-16));
--level-18: calc(var(--level-17) + var(--level-17));
--level-19: calc(var(--level-18) + var(--level-18));
--level-20: calc(var(--level-19) + var(--level-19));
--level-21: calc(var(--level-20) + var(--level-20));
--level-22: calc(var(--level-21) + var(--level-21));
--level-23: calc(var(--level-22) + var(--level-22));
--level-24: calc(var(--level-23) + var(--level-23));
--level-25: calc(var(--level-24) + var(--level-24));
--level-26: calc(var(--level-25) + var(--level-25));
--level-27: calc(var(--level-26) + var(--level-26));
--level-28: calc(var(--level-27) + var(--level-27));
--level-29: calc(var(--level-28) + var(--level-28));
--level-30: calc(var(--level-29) + var(--level-29));

--level-final: calc(var(--level-30) + 1px);

border-width: var(--level-final);
border-style: solid;
}```

You can see , from ` --level-1` To ` --level-30`, The amount of computation increases exponentially every time , Finally arrive ` --level-final` Variable , There will be 2^30 = 1073741824 individual `--initial-level-0` The content of the expression .

also , Every `--initial-level-0` The content of the expression -- `calc(1vh + 1% + 1px + 1em + 1vw + 1cm)`, When the browser parses , It's complicated enough .

Mix it up , This leads to the of the browser BOOM（Chrome 70 Previous version ）, In order to see the effect , We assign the above style to an element, which is hover When , The results are as follows ： Of course , This BUG It has been repaired , We can also use this small DEMO come to know , One is calc It can perform mixed operations of different units , Another is to pay attention to the specific use, if the amount of calculation is huge , It may lead to large performance consumption .

Of course , Don't Mix length units with non length units , It's like this. ：

```{
animation-delay: calc(1s + 1px);
}```

### Calc collocation CSS Custom variables use

calc() A very important feature of functions is the ability to match CSS Customize and CSS @property Variables are used together .

The easiest one DEMO：

```:root {
--width: 10px;
}
div {
width: calc(var(--width));
}```

Of course , It looks like , I can't see the function of this writing at all , It doesn't seem to make any sense . In the actual application scenario , Will be better than the above DEMO It's a little more complicated .

Suppose we want to realize such a loading Animation effect , At first, there was only 3 A ball ： The possible way to write it is like this , We give 3 Add the same rotation animation to all balls , Then control their `animation-delay`

```<div class="g-container">
<div class="g-item"></div>
<div class="g-item"></div>
<div class="g-item"></div>
</div>```
```.item:nth-child(1) {
animation: rotate 3s infinite linear;
}
.item:nth-child(2) {
animation: rotate 3s infinite -1s linear;
}
.item:nth-child(3) {
animation: rotate 3s infinite -2s linear;
}```

If one day , This animation needs to be expanded into 5 If it's a ball , It's like this. ： We have to , Have to add HTML, Modify again CSS. And with the help of Calc and CSS Variable , This scene can be simplified a little .

Assuming that only the 3 A ball ：

```<div class="g-container">
<div class="g-item" style="--delay: 0"></div>
<div class="g-item" style="--delay: 1"></div>
<div class="g-item" style="--delay: 2"></div>
</div>```

We go through HTML Of Style label , Pass in `--delay` Variable , stay CSS Use them directly in ：

```.g-item {
animation: rotate 3s infinite linear;
animation-delay: calc(var(--delay) * -1s);
}
@keyframes rotate {
to {
transform: rotate(360deg);
}
}```

And when the animation changes to 5 Ball time , We don't need to modify CSS, Directly modifying HTML that will do , It's like this. ：

```<div class="g-container">
<div class="g-item" style="--delay: 0"></div>
<div class="g-item" style="--delay: 0.6"></div>
<div class="g-item" style="--delay: 1.2"></div>
<div class="g-item" style="--delay: 1.8"></div>
<div class="g-item" style="--delay: 2.4"></div>
</div>```

The core CSS Still this sentence , No modification required ：

```{
animation-delay: calc(var(--delay) * -1s);
}```

complete DEMO, You can poke here ：CodePen Demo -- Calc & CSS Variable Demo

### calc The default value when matching with custom variables

Or the above Loading Animation effect , If my HTML In the label , One label forgot to fill `--delay` The value of the , What will happen then ？

It's like this. ：

```<div class="g-container">
<div class="g-item" style="--delay: 0"></div>
<div class="g-item" style="--delay: 0.6"></div>
<div class="g-item"></div>
<div class="g-item" style="--delay: 1.8"></div>
<div class="g-item" style="--delay: 2.4"></div>
</div>```
```{
animation-delay: calc(var(--delay) * -1s);
}```

because HTML The tag was not passed in `--delay` Value , And in CSS The corresponding value cannot be found by looking up in the middle , here ,`animation-delay: calc(var(--delay) * -1s)` This sentence is actually invalid , amount to `animation-delay: 0`, The effect is the effect of missing a ball ： therefore , Based on this situation , You can use CSS Custom variable `var()` Of fallback Mechanism ：

```{
// (--delay, 1)  Medium  1  It's a fault-tolerant mechanism
animation-delay: calc(var(--delay, 1) * -1s);
}```

here , If nothing is read `--delay` value , It will use the default 1 And `-1s` Carry out operations .

### Calc String splicing

Many people are using CSS When , String splicing will try , It's like this. ：

`<div style="--url: 'bsBD1I.png'"></div>`
```:root {
--urlA: 'url(https://s1.ax1x.com/2022/03/07/';
--urlB: ')';
}
div {
width: 400px;
height: 400px;
background-image: calc(var(--urlA) + var(--url) + var(--urlB));
}```

I want to take advantage of `calc(var(--urlA) + var(--url) + var(--urlB))` Spell out the complete in `background-image` Available in URL `url(https://s1.ax1x.com/2022/03/07/bsBD1I.png)`.

However , This is not allowed （ Impossible ）.calc Without the ability of string splicing .

The only possible way to complete string splicing is in the pseudo element of the element `content` Properties of the . But it's not using calc.

Here's an example , This is a error Of ：

```:root {
--stringA: '123';
--stringB: '456';
--stringC: '789';
}

div::before {
content: calc(var(--stringA) + var(--stringB) + var(--stringC));
}```

here , Unwanted calc, You can add directly with custom variables .

therefore , correct Writing ：

```:root {
--stringA: '123';
--stringB: '456';
--stringC: '789';
}
div::before {
content: var(--stringA) + var(--stringB) + var(--stringC);
}```

here , The content can be displayed normally ： Just a little bit more ,calc Without the ability of string splicing , The following usage methods are unrecognized wrong Syntax ：

```.el::before {
//  String splicing is not supported
content: calc("My " + "counter");
}
.el::before {
//  String multiplication is not supported
content: calc("String Repeat 3 times" * 3);
}```

## min()、max()、clamp()

min()、max()、clamp() Suitable for speaking together . Their functions are related to each other .

• max()： Select the maximum... From a comma separated list of expressions （ Positive direction ） As the value of the property
• min()： Select the smallest value from a comma separated list of expressions as the value of the property
• clamp()： Limit a value between an upper and lower limit , When this value exceeds the range of minimum and maximum , Choose a value between the minimum value and the maximum value to use

Because in reality , The attributes of many elements are not invariable , But according to the context 、 Change with the environment .

For example, such a layout ：

`<div class="container"></div>`
```.container {
height: 100px;
background: #000;
}```

The effect is as follows ,`.container` Block, which will increase as the screen increases , Always occupy the whole screen ： For a responsive project , We certainly don't want its width to grow all the time , But when a certain threshold is reached , Width has changed from relative units to absolute units , This applies to `min()`, Simple transformation of the code ：

```.container {
width: min(100%, 500px);
height: 100px;
background: #000;
}```

The width value of the container will be in `width: 100%` And `width: 500px` Choose between , Choose the relatively small one .

When the screen width is insufficient 500px When , That is to say `width: 100%`, conversely , It is shown as `width: 500px` Empathy , In a similar scene , We can also use `max()` From multiple values , Choose a relatively larger value .

### min()、max() Support a list of multiple values

min()、max() Support a list of multiple values , for example `width: max(1px, 2px, 3px, 50px)`.

Of course , For the above expression ：

`width: max(1px, 2px, 3px, 50px)` In fact, it is equal to `width: 50px`. therefore , about min()、max() For the specific use of , It should contain at most one specific absolute unit . otherwise , Such code like the above , Although the syntax supports , But in any case , The calculated values are determined , It doesn't make sense .

### coordination calc

min()、max()、clamp() All can cooperate with calc Use it together .

for example ：

```div {
width: max(50vw, calc(300px + 10%));
}```

under these circumstances ,calc And the brackets of the corresponding package can be omitted , therefore , The above code can be written as ：

```div {
width: max(50vw, 300px + 10%);
}```

### be based on max、min simulation clamp

Now? , There's a scenario like this , If , We need to limit the maximum , You also need to limit the minimum , What shall I do? ？

A scene like this ,** Font size , The minimum is 12px, As the screen gets bigger , Gradually get bigger , But in order to avoid the phenomenon of old people's machines （ As the screen gets bigger , Unlimited increase ）, We also need to limit a maximum 20px.

We can use vw To assign dynamic values to Fonts , Suppose at the mobile end , The width of the equipment CSS The pixel is 320px when , The minimum font width of the page is 12px, The conversion vw That is `320 / 100 = 3.2`, That is to say 1vw stay The screen width is 320px When , Manifested as 3.2px,12px About equal to 3.75 vw.

meanwhile , We need to limit the maximum font value to 20px, Corresponding CSS as follows ：

```p {
font-size: max(12px, min(3.75vw, 20px));
}```

Look at the effect ： adopt `max()``min()` In combination with , And match a relative unit vw, We successfully set the upper and lower limits for Fonts , The dynamic change is realized between the upper and lower limits .

Of course , The paragraph above the core `max(12px, min(3.75vw, 20px))` It looks a little windy , therefore ,CSS Launched `clamp()` Simplify this syntax , The following two expressions are equivalent ：

```p {
font-size: max(12px, min(3.75vw, 20px));
//  Equivalent to
font-size: clamp(12px, 3.75vw, 20px);
}```

### clamp()

`clamp()` The function limits a value between an upper limit and a lower limit , When this value exceeds the range of minimum and maximum , Choose a value between the minimum value and the maximum value to use . It takes three parameters ： minimum value 、 Preferred value 、 Maximum .

What's interesting is that ,`clamp(MIN, VAL, MAX)` In fact, it means `max(MIN, min(VAL, MAX))`.

## Use vw coordination clamp Achieve responsive layout

Let's continue with the above topic .

In the near past , Adaptation of mobile terminal , Use more rem Adaptation scheme , Some ready-made libraries may be used , Be similar to flexible.js、hotcss.js Such as the library .rem One of the big problems of the scheme is that it needs a period of time JavaScript Respond to viewport changes , Reset the root element `font-size`, also , Use rem More or less hack The feeling of .

At present , Adapt on the mobile end , More highly of us vw pure CSS programme , And rem Similar scheme , Its essence is the equal scaling of the page . One of its problems is , If you just use vw, As the screen gets bigger or smaller , Content elements will keep getting bigger and smaller , This also leads to a big screen , Many elements look too big ！

therefore , We need a way to control the maximum 、 The way of minimum threshold , It's like this. ： here ,clamp It can be very useful , Or our above example , This code `font-size: clamp(12px, 3.75vw, 20px)`, You can limit the font to `12px - 20px` Within the scope of .

therefore , For mobile pages , All units of length involved , We can all use vw Set it up . And things like Fonts 、 Inside and outside the margin 、 The width should not be scaled exactly , use `clamp()` Control the maximum and minimum threshold .

stay Modern Fluid Typography Using CSS Clamp In the article , To use clamp() There is a more in-depth discussion on the flow response layout , Those who are interested can read deeply .

To sum up , For mobile pages , We can use vw coordination clamp() The way ,​ Complete the adaptation of the whole mobile terminal layout . Its advantage is ：

• No extra JavaScript The introduction of code , pure CSS Solution
• It can well control the boundary threshold , Reasonable zoom display

### Reverse responsive change

There's another trick , utilize `clamp()` Fit negative , We can also reverse the operation , Get a bigger screen , The smaller the font, the more responsive the effect is ：

```p {
font-size: clamp(20px, -5vw + 96px, 60px);
}```

Look at the effect ： This technique is very interesting , because `-5vw + 96px` The calculated value of will increase as the screen becomes smaller , A reverse font responsive change is realized .

### summary

To sum up , Rational use min()、max()、clamp(), It is the focus of building a modern responsive layout , We can say goodbye to traditional needs JavaScript Some auxiliary schemes , be based on CSS These mathematical functions can complete all the demands .