Have you ever wanted to know how to get from color A to color B, programmatically? I have found myself on several occasions using a button, or some other styled html element and wanting to change the colors. The problem is I can’t tell how the original author got from, say, the main button color to the shadow of the button color. I’m going to give you how I got there first with SCSS, then converted that JS as a tool for anyone to use.

First, the SCSS:

/**
 * Solves "how to programmatically go from #BADA55 to #B0BCA7"?
 * Give a start color, and a target color, this will output the SCSS function
 * necessary to get to that color in terms of lighten/darken, hue, saturation/desat
 * ---
 * @author Elliot Boney <elliotboney@gmail.com>
 */

// Pick your colors
$start: #983709;
$target: #46A6DE;

/**
 * Solves how to programmatically go from #BADA55 to #B0BCA7"?
 * --------------------------------------------------------------------------------
 * @param (color) start: start color
 * @param (color) target: target color
 * --------------------------------------------------------------------------------
 * @return (map) returns the color operations to do in order to find $target from $start
 *   where keys are the color functions to apply
 *   and values are the values to pass to these functions
 */

@function color-diff($start, $target) {
  $sat: saturation($start) - saturation($target);
  $lig:  lightness($start) -  lightness($target);
  $fn-sat: if($sat > 0%, 'desaturate', 'saturate');
  $fn-lig: if($lig > 0, 'darken', 'lighten');


  // Output the colors
  $newtarget: #{$start};

  // Do we need a hue adjustment?
  @if -(hue($start) - hue($target)) != 0deg {
    $newtarget: 'adjust-hue(#{$start}, #{-(hue($start) - hue($target))})';
  }

  // Do we need to saturate/desaturate?
  @if abs($sat) != 0% {
    @if #{abs($sat)} != '100%' {
      $newtarget: #{$fn-sat}(#{$newtarget}, #{abs($sat)})
    }
  }

  // Do we need to lighten/darken?
  @if abs($lig) != 0% {
    $newtarget: #{$fn-lig}(#{$newtarget}, #{abs($lig)});
  }

  @debug    '

  #{$newtarget}; //

  ';

  @if #{abs($sat)} == '100%' {
    @return (
      adjust-hue: -(hue($start) - hue($target)),
      #{$fn-lig}: abs($lig)
      );
  }

  @return (
    adjust-hue: -(hue($start) - hue($target)),
    #{$fn-sat}: abs($sat),
    #{$fn-lig}: abs($lig)
    );

}

/**
 * Apply differences returned from `color-diff` function to a color
 * In order to retrieve the second color
 *
 * @param  {color} $color color to transform
 * @param  {map}   $diff  diff map
 *
 * @return {color}        [description]
 */
@function apply-diff($color, $diff) {
  // We call the $key (function),
  // passing the $color and the $value as parameters
  // e.g. `call(adjust-hue, #BADA55, 42)`
  @each $key, $value in $diff {
    $color: call($key, $color, $value);
  }
  @return $color;
}

// Calculate the diff map between those 2
$diff: color-diff($start, $target);
// This is a map looking like this:
// $diff: (
//   adjust-hue: 42,
//   saturation: 13.37%,
//   lightness: 1.5%
// );

// Apply the diff to one of the two colors to find the second one
$c: apply-diff($start, $diff);

// Is everything okay?
sass {
  a: $start;
  b: $target;
  c: $c; // $target == $c, awesome!
}

$allcaps: to-upper-case(#{$c+''});

@debug '#{$start} --> #{$target} = #{$allcaps}';
// Visual representation if you prefer
// left part is $start
// middle part is $target
// third part is $c, generated from $start
html {
  background: -webkit-linear-gradient(left, $start 33%, $target 33%, $target 66%, $c 66%);
  height: 100%;
}