Prembo
Prembo

Reputation: 2256

How to convert integer to hex in SASS

In lieu of something like the Map data structure that Chris Eppstein mentions as a work in progress for SASS, I'm trying to achieve something similar - mapping a string to a corresponding hex value, which will be used to specify a unicode character for CSS content property. (I'm trying to refactor some font icon SASS code.)

At the moment I have something rudimentary like:

/*icon1  -->  \F000
  icon2  -->  \F001
  icon3  -->  \F002*/

@function u-char($name) {
    @if $name == icon1 {
        @return "000";
    } @else if $name == icon2 {
        @return "001";
    } @else if $name == icon3 {
        @return "001";
    }
}

@mixin icon-class($name) {
    ...
    content: "\f#{u-char($name)}";
    ...
}

But I'm actually trying to map a large number of characters, so this approach is arduous. I was hoping to be able to do something like:

@function u-char($name) {
    $i: 0;
    $itemList: item1, item2, item3;

    @each $currItem in $itemList {
        @if $name == item1 {
            @return i-to-hex-str($i);
        }
        $i: $i + 1;
    }
}

Is there anything that does and integer to hex string conversion in SASS? Is there another elegant way around this?

Upvotes: 5

Views: 3150

Answers (5)

Jan Stanicek
Jan Stanicek

Reputation: 1281

My functions for changing numbers back and forth between hexadecimal and decimal numbers is

$hex-chars: "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F";

@function dec-to-hex($d) {
    $result: "";
    $rest: $d;
    @while $rest > 0 {
        $result: nth($hex-chars, $rest % 16 + 1) + $result;
        $rest: floor($rest / 16);
    }
    @return $result;
}

@function pow($number, $exponent) {
    $value: 1;
    @if $exponent > 0 {
        @for $i from 1 through $exponent {
            $value: $value * $number;
        }
    }
    @return $value;
}

@function hex-to-dec($d) {
    $result: 0;
    $number: inspect($d);
    $power: 0;
    @for $index from str-length($number) through 1 {
        $digit: str-slice($number, $index, $index);
        $value: index($hex-chars, $digit) - 1;
        $result: $result + ($value * pow(16, $power) );
        $power: $power + 1;
    }
    @return $result;
}

Decimal number is considered as Number, while hexadecimal is considered as String

Upvotes: 2

EchoCrow
EchoCrow

Reputation: 33

The previous answers didn't work for us, so here are two quick functions for converting an integer into multiple different bases, including hexadecimal:

@function decimal-to-base($decimal, $to_base, $chars: '0123456789abcdefghijklmnopqrstuvwxyz')
  @if type-of($decimal) != 'number'
    @error '$decimal must be an integer.'
  @if type-of($to_base) != 'number'
    @error '$to-base must be an integer.'
  @if type-of($chars) != 'string'
    @error '$chars must be a string.'
  @if $to_base < 2
    @error '$to-base must be larger than 1.'
  @if $to_base > str-length($chars)
    @error 'Length of $chars must be equal or larger than $to-base.'
  @return _decimal-to-base($decimal, $to_base, $chars)

@function _decimal-to-base($decimal, $to_base, $chars, $_accum: '')
  @if $decimal <= 0
    @return if($_accum != '', $_accum, '0')
  $remainder: $decimal % $to_base
  $char: str-slice($chars, $remainder + 1, $remainder + 1)
  $remaining_decimal: ($decimal - $remainder) / $to_base
  @return _decimal-to-base($remaining_decimal, $to_base, $chars, $char + $_accum)

If you don't care about error handling, you can skip the long first function (which really only validates the arguments and sets the default characters) and just copy the second function.

Also, note that this is written in SASS, not SCSS. For SCSS support, you'll want to sprinkle in some curly brackets and semicolons.

Examples:

  • Decimal to Hexadecimal:
    decimal-to-base(15731618, 16) // "f00ba2".

  • Decimal to binary:
    decimal-to-base(34, 2) // "100010".

  • Timestamp to query string:
    decimal-to-base(1547598870, 2) // "pleb0y".

  • Definitely not Morse code:
    decimal-to-base(34, 2, '-.') // "-...-.".

  • Over-engineered integer to string:
    decimal-to-base(123456, 10) // "123456".

Known caveats: (because this is a dirty implementation)

  • Input decimal must be an integer >= 0.
  • Minimum base is 2.
  • You will want to be careful with large integers.

Upvotes: 2

Pierpaolo Cira
Pierpaolo Cira

Reputation: 1477

Another implementation of the last question in your post: "Is there anything that does an integer to hex string conversion in SASS?" this is a shortest version (not working on oldest version, because str-slice may be missing).

@function decToHex($dec) {
    $hex: "0123456789ABCDEF";
    $first: (($dec - $dec % 16)/16)+1;
    $second: ($dec % 16)+1;
    @return str-slice($hex, $first, $first) + str-slice($hex, $second, $second)
}

Upvotes: 3

JPGringo
JPGringo

Reputation: 61

To answer the last question in your post, "Is there anything that does an integer to hex string conversion in SASS?". Well… not built-in, but I think this does the trick fairly clearly and with relatively few lines of code:

/** Returns an at least one byte hex value */
@function dec-to-hex($d) {
    $hexVals: "A" "B" "C" "D" "E" "F";
    $base: 16;
    $quotient: $d;
    $result: "";
    @if $d == 0 {
        $result: "00";
    }
    @while $quotient != 0 {
        $mod: $quotient % $base;
        $quotient: floor($quotient / $base);
        @if $mod > 9 {
            $mod: nth($hexVals, $mod - 9);
        }
        @if $d < $base {
            $result: "0" + $mod;
        } @else {
            $result: $mod + $result;
        }
    }
    @return $result;
}

This doesn't prepend a hex qualifier to the string (such as "0x" or "#"), but you could either hard-code that into the last line (@return "#" + $result;), or apply it in-place when you call the function.

Upvotes: 6

bookcasey
bookcasey

Reputation: 40473

I would do this:

$icons: "000", "001", "002";

@function icon($i) {
  @return "\F#{nth($icons, 1)}";
}

h1::before {
  content: icon(1);
}

Edit:

If you want to associate a word with a value, try using a list of lists and iterating through them. I'm not going to pretend this is very efficient, but it works. It would be nice if Sass had hashes.

$icons: '000' calendar, '001' inbox, '002' home

@function icon($call)
  @for $i from 1 through length($icons)
    @if $call == nth(nth($icons, $i), 2)
      @return "\F#{nth(nth($icons, $i), 1)}"

h1::before
  content: icon(calendar)

Upvotes: -2

Related Questions