CSS Houdini Collection

Typed OM Numeric Value: Math Values

Let's see how we create a CSSMathValue and whilst doing so see what is available within the type:

const mathVal = new CSSMathSum(CSS.px(10), CSS.vw(20));
/*
Returns: CSSMathSum {
	operator: "sum",
	values: CSSNumericArray
		0: CSSUnitValue {value: 10, unit: "px"},
		1: CSSUnitValue {value: 20, unit: "vw"},
		length: 2
}
*/

This creates a new CSSMathValue with the operator type "sum". CSSMathValues always take CSSUnitValues. As you can see with what is created in the above example, CSSMathSum actually takes a CSSNumericArray which is an array of CSSNumericValues.

If we use the toString() method on a CSSMathValue, it returns the ready made calc() function as a string. Handy.

console.log(mathVal.toString());
// Logs: calc(10px + 20vw)

NB As with the previous part on numeric types, there is an associated javascript file which you can find here. It is logging code to the console which you can see in the developer tools pane.

Other CSSMathValue types that associate with the calc() function are 'sum', 'product', 'negate' and 'invert'. Each of the mathematical operations returns it's own interface. Here's an example of each them, how to create each, set() the value on an element and in turn get() that value to see the interface returned:

CSSMathSum

Addition & Subtraction. Values are of type CSSNumericValue and it takes a CSSNumericArray, so you can put in as many values as you want.

const sumVal = new CSSMathSum(CSS.px(10), CSS.vw(20), CSS.em(1.2));

el.attributeStyleMap.set('width', sumVal);

const gotSumVal = el.attributeStyleMap.get('width');
/*
Returns: CSSMathSum {
	operator: "sum",
	values: CSSNumericArray
		0: CSSUnitValue {value: 10, unit: "px"},
		1: CSSUnitValue {value: 20, unit: "vw"},
		2: CSSUnitValue {value: 1.2, unit: "em"},
		length: 3
}
*/

To subtract use a negative number

const subVal = new CSSMathSum(CSS.s(2), CSS.ms(-200));

el.attributeStyleMap.set('animation-duration', subVal);

const gotSubVal = el.attributeStyleMap.get('animation-duration');
/*
Returns: CSSMathSum {
	operator: "sum",
	values: CSSNumericArray
		0: CSSUnitValue {value: 2, unit: "s"},
		1: CSSUnitValue {value: -200, unit: "ms"},
		length: 2
}
*/

CSSMathProduct

Multiplication. Again here you can pass in a CSSNumericArray.

const productVal = new CSSMathProduct(CSS.em(1.6), CSS.number(1.2));

el.attributeStyleMap.set('font-size', productVal);

const gotProductVal = el.attributeStyleMap.get('font-size');
/*
Returns: CSSMathProduct {
	operator: "product",
	values: CSSNumericArray
		0: CSSUnitValue {value: 1.6, unit: "em"},
		1: CSSUnitValue {value: 1.2, unit: "number"},
		length: 2
}
*/

CSSMathNegate

Negation. Only takes one CSSNumericValue. Note here how we have to use the aforementioned toString() method, as the type itself does not negate the value, it just specifies it is of negated type.

const negVal = new CSSMathNegate(CSS.px(20));

// negVal.toString() returns 'calc(-20px)'
el.attributeStyleMap.set('margin-top', negVal.toString());

const gotNegVal = el.attributeStyleMap.get('margin-top');
/*
Returns: CSSMathNegate {
	operator: "negate",
	value: CSSUnitValue {value: 20, unit: "px"}
}
*/

The calc() function is not the only mathematical function we have in CSS however, there is also the min(), max() and yet to be implemented clamp() functions. These all have their own CSSMathValue types. Let's take a look at creating each in turn, and what each interface contains.

CSSMathMin

Takes a CSSNumericArray. If you are unfamiliar with the min() function you can find out more here.

const minVal = new CSSMathMin(CSS.vh(10), CSS.px(300));
/*
Returns: CSSMathMin {
	operator: "min",
	values: CSSNumericArray
		0: CSSUnitValue {value: 10, unit: "vh"},
		1: CSSUnitValue {value: 300, unit: "px"},
		length: 2
}
*/

CSSMathMax Again, takes a CSSNumericArray. If you are unfamiliar with the max() function you can find out more here.

const maxVal = new CSSMathMax(CSS.px(50), CSS.percent(20));
/*
Returns: CSSMathMax {
	operator: "max",
	values: CSSNumericArray
		0: CSSUnitValue {value: 50, unit: "px"},
		1: CSSUnitValue {value: 20, unit: "percent"},
		length: 2
}
*/

Nested calculations

In CSS you can nest any of the above functions: calc(), min() or max(). Consider the following CSS: min( calc(1.2em * 1.4), 10vw), to recreate this using CSSMathValues we would also need to nest them:

const nestedVal = new CSSMathMin(
  new CSSMathProduct(CSS.em(1.2), CSS.number(1.4)),
  CSS.vw(10)
);
/*
Returns: CSSMathMin {
	operator: "min",
	values: CSSNumericArray
		0: CSSMathProduct {
			operator: "product"
			values: CSSNumericArray
				0: CSSUnitValue {value: 1.2, unit: "em"},
				1: CSSUnitValue {value: 1.4, unit: "number"},
				length: 2
			}
		1: CSSUnitValue {value: 300, unit: "px"},
		length: 2
}
*/

On the surface this could seem overly complex, however it makes sense and we have to remember it's the underlying information about these CSSValueTypes that is being exposed and we have access to. It might be a bit to take in at this point, but as support starts to advance and we gain familiarity with this API, we'll probably wonder how we ever managed without it.

There is also more. There's methods that each CSSNumericValue is privy to, let's check them out in the next part.