4

First of all, I am aware that to turn a unitless value into one with a unit I can multiply a unitless value by a single unit:

$value: 25 * 1px; // 25px

However I would like to know if there is any way to do this when the unit is dynamic.

$unit: rem;
$value: 23;

.Box {
  // Try interpolation
  $united-value: #{$value}#{$unit};
  value: $united-value; // Appears to be correct
  // Check it is actually a number using unitless 
  check: unitless($united-value); // $number: "23rem" is not a number for `unitless'
}

Obviously if I was to make the value of $unit 1rem I could just multiply as in my first example, but is there a way to do this with a naked unit value.

Sassmeister here

[Edit] As @zessx correctly states, CSS doesn't care about the type and will treat both string and number values identically in this case. However I need to perform operations on the value once the unit has been appended.

[Edit] I'm not sure how I can be any clearer. I don't want / need a function that uses multiplication under the hood. I already know how that works and how to do it. I am interested if there is a way to take a unitless value and a unit and make a united number out of it.

Is there a a way to take px and 22 and make 22px that is a number and can have mathematical operations performed on it? Any answer that shows me how I can take 1px and 22 and do the same thing is not answering the question I'm asking.

Undistraction
  • 42,754
  • 56
  • 195
  • 331
  • 1
    Due that you've used interpolation in the `$united-value`, the type of this variable is a string but you can't use the `unitless` sass function with a string. So, the only way to achieve your goal is to set `$unit` to `1rem`. Why don't you want to set `$unit` to `1rem`? Check out this [sassmeister](http://sassmeister.com/gist/4fa18d1d5f86bcb95411) – Alex Guerrero Oct 14 '14 at 09:59
  • @AlexGuerrero This is part of a much bigger library that uses a lot of validations and dynamic interpolations. As I think I made clear I don't want to multiply. I currently need two lists - one of plain units and one of single value units. I'm trying to remove the need for the second list. – Undistraction Oct 14 '14 at 10:29
  • You haven't made it clear as to why it is unacceptable that multiplication is involved. As it stands, this is something you'll need to take up with the maintainers of Sass. You know what they'll tell you? [Please. Just use unit based arithmetic](https://github.com/sass/sass/issues/533). – cimmanon Oct 14 '14 at 13:46
  • @cimmanon What has the context got to do with anything? I've deliberately removed all context from the question to make it simple. If the answer is that you can't do it, then that's the answer. – Undistraction Oct 15 '14 at 08:34
  • @Pedr And you've failed to explain *why* multiplication is unacceptable. – cimmanon Oct 15 '14 at 12:56

2 Answers2

4

There's no sass native way to achieve your goals. The problem is that $unit is a string and in sass, like other languages, when you make operations with a string and a number, it automatically concatenates both and returns a string. And there is no native function that performs this operation, here's the reason of the creator of sass:

these functions would encourage more sloppy code than they do add expressive power.

More info about this topic here

Alternatives

So you can only use multiplication, as you've mentioned before or if you don't want to use multiplication you can use this function to convert unit strings into numbers:

@function length($number, $unit) {
  $strings: 'px' 'cm' 'mm' '%' 'ch' 'pica' 'in' 'em' 'rem' 'pt' 'pc' 'ex' 'vw' 'vh' 'vmin' 'vmax';
  $units:   1px  1cm  1mm  1%  1ch  1pica  1in  1em  1rem  1pt  1pc  1ex  1vw  1vh  1vmin  1vmax;
  $index: index($strings, $unit);

  @if not $index {
    @warn "Unknown unit `#{$unit}`.";
    @return false;
  }

  @return $number * nth($units, $index);
}

As you can see, it takes a number and a unit as arguments and it returns them as a length number. So in your case, you only need to change this declaration:

$united-value: #{$value}#{$unit};

By this other:

$united-value: lenght($value, $unit);

This is an idea grabbed from Hugo Giraudel's blog

Alex Guerrero
  • 2,109
  • 1
  • 19
  • 28
  • That function is using two lists and does what it does by using multiplication: `$number * nth($units, $index)`. It's just a more complex version of my first example and doesn't address my question at all. – Undistraction Oct 14 '14 at 11:48
  • @Pedr And? This function is returning a number which is exactly what you're asking for. This is the correct way to solve the problem. – cimmanon Oct 14 '14 at 15:59
  • @cimmanon Try reading more than just the title of the question for once. – Undistraction Oct 15 '14 at 08:35
  • @Pedr I don't understand why you've downvote my answer, I've tried to give you another workaround without multiplication, it doesn't use `1rem`, use `rem` only and obviously doesn't use multiplication, even under the hood. As I've said before there's no sass native way to do that you want. But anyway, with this solution you can *"perform operations on the value once the unit has been appended"* – Alex Guerrero Oct 15 '14 at 09:00
  • I downvoted it because it doesn't answer my question. It ignores the first line: 'I am aware that to turn a unitless value into one with a unit I can multiply a unitless value by a single unit:'. You've just copy-pasted a function that does exactly this under the hood. I am interested in solutions that don't involve multiplying by 1px or whatever. If there is no native way to do it, then the correct answer is that there is no native way to do it. If you prefix your answer with this and back this up with evidence I will give you the win. – Undistraction Oct 15 '14 at 09:10
  • @Pedr I don't want to win, I've edited my answer to reflects what I've said before, sorry but I don't know you just wanted to know if there's a native solution, I think that you need to edit your question and reflect that you are searching a native sass solution – Alex Guerrero Oct 15 '14 at 10:01
  • 1
    Well that is an admirable sentiment. However I'm afraid I'm going to force you to do so, while at the same time bestowing an extra point on you with an upvote. Sorry about that. – Undistraction Oct 15 '14 at 10:07
1

Even if $united-value looks like a united number, it's no more than a string, as Sass can't differentiate "rem" string from "rem" unit. Luckily, this string will be interpreted by any CSS engine.

You can check it with type-of() :

$unit: rem;
$value: 23;

.Box {
  $united-value: #{$value}#{$unit};
  value: $united-value;
  check: type-of($united-value); // check: string;
}

AFAIK, the only way to cast a string as "rem" is effectively to use * 1 rem.

EDIT:
As mentioned by Alex Guerrero, Hugo Giraudel built a function to cast a string into a number, you should really have a look on it blog. The good thing with it is that you can simply write this :

$unit: rem;
$value: 23;

.Box {
  $united-value: number($value+$unit);
  value: $united-value; 
  check: unitless($united-value);
}
zessx
  • 68,042
  • 28
  • 135
  • 158
  • Thanks. But unfortunately my use-case requires I perform multiplication on the value after I have appended the unit. If I was just outputting the value you're correct. CSS doesn't care. Unfortunately the Sass compiler does care. – Undistraction Oct 14 '14 at 15:30
  • Not sure to understand. Using this `number()` function, you've got a **real** united number, like you were manually defining it. This means you multiply it : `value: number($value + $unit) * 5;` – zessx Oct 14 '14 at 16:04
  • The number function just uses multiplication under the hood. It doesn't take 1. A unitless number and 2. A unit, and combine them into a workable number. – Undistraction Oct 14 '14 at 21:44
  • That's exactly what does the `_length()` function in this example. Sure it still uses multiplication, but you've got a generic function for every unit supported by Sass, which should be enough for you as there's no native and clean way to cast a string into a number in Sass. – zessx Oct 15 '14 at 06:58
  • It takes 1. A unitless number and 2. A united number with a value of one. This is not the same thing. – Undistraction Oct 15 '14 at 08:26
  • No, it takes a unitless number (`$number`), and a string which represents a unit (`$unit`). This string is used to retrieve the united number with a value of one. But this research is **internal to the function**. – zessx Oct 15 '14 at 08:46
  • All I care about is what's going on under the hood. A utility function is of no interest to me. – Undistraction Oct 15 '14 at 09:05
  • Then you've got your answer : impossible. – zessx Oct 15 '14 at 09:23