htmlcsscss-variablesviewport-unitscss-calc

Get the numeric part of an amount from CSS


Is there a way, using pure CSS to fetch the numeric value without pulling back the unit too? e.g. say I have a CSS variable defined as :root {--maxWidth: 100px;}. If I want to get the ratio of that value to my viewport's width I can't as calc(100vw / var(--maxWidth)) would fail as you can't divide a number with units by another number with units; even where they're the same unit.

I can get around this example case by omitting the units from my variable (e.g. :root {--maxWidth: 100;}), but I'm wondering how to do this in cases where you can't.

More specifically, I want to get the ratio / conversion value for 1vw to 1px so that I can write code which uses px values, then use transform: scale(var(--horizontalRatio), var(--verticalRatio)) to resize everything to fit perfectly in the viewport; but to do that I need a way to convert between pixels and viewport units.

There is a way to work around this; everywhere I set a size in pixels I could instead set the size to calc(100vw * X/var(--maxWidthInPx)) where X is the size in pixels of what I'm setting and --maxWdithInPx is a numeric only value giving the max width of the static px size. However, that means putting these little equations everywhere, rather than just having 1 place where things get scaled.

I've found several javascript solutions for this; but I need something that's CSS only.


Solution

  • In the near (or a far) future this will be possible using only CSS. The specification has changed to allow the division and multiplication of different types.

    You can read the following:

    At a * sub-expression, multiply the types of the left and right arguments. The sub-expression’s type is the returned result.

    At a / sub-expression, let left type be the result of finding the types of its left argument, and right type be the result of finding the types of its right argument and then inverting it.

    The sub-expression’s type is the result of multiplying the left type and right type.

    As you can see, there are new rules that defines how types are multiplied and how the result is calculated so I am pretty sure what you want is possible but there is no implementation for this to test.


    The current specification is more restrictive:

    At *, check that at least one side is <number>. If both sides are <integer>, resolve to <integer>. Otherwise, resolve to the type of the other side.

    At /, check that the right side is <number>. If the left side is <integer>, resolve to <number>. Otherwise, resolve to the type of the left side.

    If an operator does not pass the above checks, the expression is invalid