cssAudio - Activefile-genericCSS - ActiveGeneric - ActiveHTML - ActiveImage - ActiveJS - ActiveSVG - ActiveText - Activefile-genericVideo - ActiveLovehtmlicon-new-collectionicon-personicon-teamlog-outoctocatpop-outspinnerstartv

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

Quick-add: + add another resource

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

Quick-add: + add another resource

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

            
              <input type="text" id="hidden" />
<main>
  <form id="color-blend-form">
    <section>
      <fieldset>
        <label for="color1">From</label>
        <input id="color1" type="color" value="#0000ff">
        <span id="color1-span">#0000ff</span>
      </fieldset>
      <fieldset>
        <label for="color2">To</label>
        <input id="color2" type="color" value="#ff0000">
        <span id="color2-span">#ff0000</span>
      </fieldset>
      <fieldset>
        <label for="midpoints">Midpoints</label>
        <input id="midpoints" type="number" value="1" min="1" max="50">
      </fieldset>
    </section>
  </form>

  <section id="output" class="placeholder-text">
    <h1>Colour blender</h1>
    <p>Select two colours and the number of midpoints to create a series of intermediately blended colours.</p>
  </section>
  
  <section class="copy">
    <button id="copy-array">Copy as array</button>
  </section>
</main>
            
          
!
            
              $input-height: 3rem;
$padding: 1rem;
$border-color: gainsboro;
$border-radius: 2px;
$font-size: 0.75rem;
$font-color: #222;
$row-content-height: 2rem;

// quick and dirty reset
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  border: 0;
}

body {
  font: {
    family: Poppins, sans-serif;
    size: $font-size;
  }
  color: $font-color;
}

section {
  max-width: 40rem;
  margin: #{$padding * 2} auto;
  padding: {
    right: $padding;
    left: $padding;
  }
}

#color-blend-form {
  display: block;
  background-color: white;
  border: 1px solid transparent;
  box-shadow: 0 0 14px rgba(black, 0.3);
  
  section {
    display: flex;
    
    > * {
      flex: 1;
      display: block;
      padding: $padding 0;
      justify-content: space-between;
      
      & + * {
        margin-left: #{$padding * 2};
      }
    }
    
    input {
      display: block;
      width: 100%;
      height: $input-height;
      padding: #{$padding * 0.5};
      border: 1px solid $border-color;
      border-radius: $border-radius;
      
      &[type="color"] {
        padding: 0;
      }
      
      &::-webkit-color-swatch-wrapper {
        padding: 0;
      }
      
      &:focus {
        outline: 0;
        box-shadow: 0 2px 10px rgba(black, 0.2);
      }
    }
  }
}

.midpoint {
  padding: $padding $padding $padding 0;
  
  + .midpoint {
    border-top: 1px solid $border-color;
  }
  
  &:first-of-type,
  &:last-of-type {
    color: rgba($font-color, 0.4);
  }
  
  span,
  p {
    display: inline-block;
    height: $row-content-height;
    vertical-align: middle;
    line-height: $row-content-height;
  }
  
  span {
    width: #{$row-content-height * 2};
    margin-right: $padding;
    border-radius: 2px;
  }
}

// for copying to clipboard
#hidden {
  position: fixed;
  top: -10000px;
}
#copy-array {
  padding: 0.5rem 1rem;
  border-radius: 2px;
  background-color: #292326;
  color: white;
  text-transform: uppercase;
  
  &:focus {
    outline: 0;
  }
}

.placeholder-text ~ .copy {
  display: none;
}

            
          
!
            
              console.clear();

var col = {
  /** @function _stripHash
      @private
      removes any leading hash tag (#) from a string
      @param {string} hex - colour
      @returns {string}
  */
  _stripHash: function(hex) {
    return (hex.substr(0, 1) === '#') ? hex.substr(1) : hex;
  },
  
  /** @function _containsValidHexChars
      @private
      checks that a string contains only characters
      valid for a hexadecimal colour code (excluding #)
      @param {string} hex - candidate for testing as valid hex colour
      @returns {bool}
  */
  _containsValidHexChars: function(hex) {
    return (/^[0-9a-f]+$/i.test(hex));
  },
  
  /** @function _padWith0
      @private
      adds leading 0s if a string is shorter than 6 characters
      (it assumes a number has originally been entered with leading 0s
      that have been stripped away)
      @param {string} hex
      @returns {string}
  */
  _padWith0: function(hex) {
    return '000000'.substr(0, 6 - hex.length) + hex;
  },
  
  /** @function _expandHex
      @private
      expands a shorthand hex colour code (a03)
      to a longhand (full-length) hex colour code (aa0033)
      (i could have used a loop but found it pointless for six chars)
      @param {string} hex - possible shorthand
      @returns {string} longhand
  */
  _expandHex: function(hex) {
    if (hex.length === 3) {
      hex.split('');

      hex = [
        hex[0], hex[0],
        hex[1], hex[1],
        hex[2], hex[2]
      ].join('');
    }

    return hex;
  },
  
  /** @function _validateHex
      @private
      makes sure that a usable hex colur code is being used, by
       - stripping leading #
       - checks for valid characters only
       - expanding shorthand codes
       - pads short numbers with leading 0s
       - removes excess characters
      if tests fails it returns hex code for black
      @param {string} candidate - the string to be validates
      @returns {string} valid hex code or '#000000'
      @requires col._stripHash, col._containsValidHexChars, col._expandHex, col._padWith0
  */
  _validateHex: function(candidate) {
    var hex = col._stripHash(candidate.toString());
    
    if (col._containsValidHexChars(hex)) {
      if (hex.length === 3) {
        hex = col._expandHex(hex);
      } else if (hex.length < 6) {
        hex = col._padWith0(hex);
      } else if (hex.length > 6) {
        hex = hex.substr(0, 6);
      }
      
      return hex;
    }
    
    return '000000';
  },
  
  /** @function _decimalToHex
      @private
      converts a decimal colour code (0-255) to hex code (00-ff)
      @param {string || number} decimal
      @returns {string} hex
  */
  _decimalToHex: function(decimal) {
    return decimal.toString(16);
  },

  /** @function _hexToDecimal
      @private
      converts a hex code (00-ff) to decimal colour code (0-255)
      @param {string} hex
      @returns {number} decimal
  */
  _hexToDecimal: function(hex) {
    return parseInt(hex, 16);
  },
  
  /** @function mix
      @public
      mixes two colours based on the weight specified
      @author based on https://gist.github.com/jedfoster/7939513
      @param {string} color1 - the first hex colour to be mixed
      @param {string} color2 - the second hex colour to be mixed
      @param {number} weight - the weight of colour1 used in the mix
      @returns {string} hex code of colour mix
      @requires col._validateHex, col._hexToDecimal, col._decimalToHex
      
      @example
        // returns '#7f007f'
        col.mix('#00f', '#f00')
        
        // returns '#69006f'
        col.mix('#d300de', '#000', 75)
  */
  mix: function(color1, color2, weight) {
    // make sure the colors are 6 digit hex colors without leading #
    color1 = col._validateHex(color1);
    color2 = col._validateHex(color2);
    
    // if weight hasn't been set (undefined)
    // or outside allowed range (0-100)
    // well make it 50 (an equal mix of both colors)
    weight = (typeof(weight) === 'undefined' || parseInt(weight) < 0 || parseInt(weight) > 100) ? 50 : weight;
    
    // holding variable for new colour
    var newColor = '';
    
    // loop through hex
    // we want to extract each of the colour triplets (rr, gg, bb)
    // so we use a step of 2
    for (var i = 0; i < 6; i += 2) {
      // retrieve individual color triplet
      // and convert to decimal
      var color1triplet = col._hexToDecimal(color1.substr(i, 2));
      var color2triplet = col._hexToDecimal(color2.substr(i, 2));
      
      // blend colour triplets
      var calculatedTriplet = Math.floor(color1triplet + ((color2triplet - color1triplet) * (weight / 100)));
      
      // convert decimal back to hex
      calculatedTriplet = col._decimalToHex(calculatedTriplet);
      
      // if only one digit prepend with 0
      // and add to newColor variable
      newColor += (calculatedTriplet.length === 1) ? '0' + calculatedTriplet : calculatedTriplet;
    }
    return '#' + newColor;
  },
  
  /** @function blendRange
      @public
      creates an array of colours from two colours with a requested number of midpoints
      the array contains the original two colours
      @param {string} color1 - the first hex colour to be mixed
      @param {string} color2 - the second hex colour to be mixed
      @param {number} midpoints - number of intermediate colours to be created
      @returns {array} intermediate colours' hex codes bookended by the original colours
      @requires col._validateHex, col.mix
  */
  blendRange: function(color1, color2, midpoints) {
    // make sure the colors are 6 digit hex colors without leading #
    color1 = col._validateHex(color1);
    color2 = col._validateHex(color2);
    
    // make sure that the number of midpoints is bigger than 0
    // and add 1 because we want to include the original colours
    midpoints = (parseInt(midpoints) >= 1) ? parseInt(midpoints) + 1 : 2
    
    // create array for the blended colours
    var blendArray = [];
    
    // loop through number of midpoints
    for (var i = 0, len = midpoints; i < (len + 1); i++) {
      
      // mix the two colours with a weight calculated on the position in the blend
      // and add to blendArray
      blendArray.push(col.mix(color1, color2, (100/len) * i));
    }
    
    // ... and ship back
    return blendArray;
  }
};

// --------------------------------------
// ui stuff:

document.querySelector('#color-blend-form').addEventListener('change', function() {
  // get references
  var color1 = document.querySelector('#color1').value;
  var color2 = document.querySelector('#color2').value;
  var color1span = document.querySelector('#color1-span');
  var color2span = document.querySelector('#color2-span');
  var midpoints = parseInt(document.querySelector('#midpoints').value);
  var output = document.querySelector('#output');
  
  // stuff required for adding to clipboard
  var hiddenInput = document.querySelector('#hidden');
  
  // write the hex code of the selected colours in the spans
  // below the colour inputs 
  color1span.textContent = color1;
  color2span.textContent = color2;
  
  // create the array of mixed colours
  var mix = col.blendRange(color1, color2, midpoints);
  
  // nastily clear the output area
  output.innerHTML = '';
  
  // loop through the array of mixed colours
  for (var i = 0, len = mix.length; i < len; i++) {
    
    // create a new div for each colour
    // this contains
    //  - a span to show the colour
    //  - the hex code of the colour
    var colDiv = document.createElement('div');
    colDiv.innerHTML = '<span style="background-color: ' + mix[i] + ';"><\/span><p>' + mix[i] + '<\/p>';
    colDiv.classList.add('midpoint');
    
    // output it
    output.appendChild(colDiv);
  }
  
  // remove placeholder class to reveal button
  output.classList.remove('placeholder-text');
  
  // add it to our hidden input so we can copy it
  hidden.value = mix;
}, false);

document.querySelector('#copy-array').addEventListener('click', function() {
  // get hidden input value
  document.querySelector('#hidden').select();
  
  try {
    var success = document.execCommand('copy');

    alert(success ? 'Colours copied as array.' : 'Unable to copy.');
  } catch (err) {
    alert('Unable to copy.');
  }
}, false);
            
          
!
999px
Loading ..................

Console