Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

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.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

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.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div class="preview">
  <div class="preview__header">
    <h2 class="header__name">You! <span class="header__badge">dashing</span></h2>
    <div class="header__username">@TheHandsomestAvatar</div>
  </div>
  <div class="preview__bottom-bar">
    <svg class="avatar" id="avatar" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 247 247">
      <title>CodePen Profile Avatar</title>
      <rect class="avatar__bg" width="247" height="247"/>
      <path class="avatar__glow--5" d="M247 33a201 201 0 0 0-55-33H56A207 207 0 0 0 0 33v214h247V33z"/>
      <path class="avatar__glow--4" d="M247 56C214 26 171 7 124 7S33 26 0 56v191h247V56z"/>
      <path class="avatar__glow--3" d="M247 80A169 169 0 0 0 0 80v167h247V80z"/>
      <path class="avatar__glow--2" d="M247 105c-30-36-74-59-123-59S30 69 0 105v142h247V105z"/>
      <path class="avatar__glow--1" d="M247 131a149 149 0 0 0-123-66C72 65 27 91 0 131v116h247V131z"/>
      <path id="body" class="avatar__body" d="M187 152l-64 37-64-38a117 117 0 0 0-51 96h231c0-40-21-75-52-95z"/>
      <g class="avatar__head">
        <g class="avatar__head--positive-diagonal">
          <path d="M60 124l56 38v-34l-31-20-25 16zM186 74l-56-37v33l31 21 25-17z"/>
        </g>
        <g class="avatar__head--middle">
          <path d="M55 87v24l18-12-18-12zM123 83L98 99l25 17 25-17-25-16zM192 111V87l-18 12 18 12z"/>
        </g>
        <g class="avatar__head--negative-diagonal">
          <path d="M116 70V37L61 74l24 17 31-21zM130 128v33l56-37-25-17-31 21z"/>
        </g>
      </g>
    </svg>
  </div>
  <button class="save" id="save">
    <svg class="dl-icon" width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1344 1344q0-26-19-45t-45-19-45 19-19 45 19 45 45 19 45-19 19-45zm256 0q0-26-19-45t-45-19-45 19-19 45 19 45 45 19 45-19 19-45zm128-224v320q0 40-28 68t-68 28h-1472q-40 0-68-28t-28-68v-320q0-40 28-68t68-28h465l135 136q58 56 136 56t136-56l136-136h464q40 0 68 28t28 68zm-325-569q17 41-14 70l-448 448q-18 19-45 19t-45-19l-448-448q-31-29-14-70 17-39 59-39h256v-448q0-26 19-45t45-19h256q26 0 45 19t19 45v448h256q42 0 59 39z"/></svg>
    Download as PNG!
  </button>
</div>

<div class="settings">
  <h2 class="settings__header">Settings</h2>
  <h3>Foreground Colors</h3>
  <div class="settings__input settings__input--padded">
    <input type="checkbox" id="syncHead"/>
    <label for="syncHead" class="label--secondary">Advanced head color controls</label>
  </div>
  <div class="settings__input">
    <input id="body-color" type="text" class="spectrum"/>
    <label for="body-color" class="label--primary">Body Color</label>
  </div>
  <div class="settings__input">
    <input id="head-color" type="text" class="spectrum"/>
    <label for="head-color" class="label--primary">Head Color</label>
  </div>
  <div class="settings__input">
    <input id="head-pos-diagonal" type="text" class="spectrum"/>
    <label for="head-pos-diagonal" class="label--primary">Head Positive Diagonal</label>
  </div>
  <div class="settings__input">
    <input id="head-neg-diagonal" type="text" class="spectrum"/>
    <label for="head-neg-diagonal" class="label--primary">Head Negative Diagonal</label>
  </div>
  <div class="settings__input">
    <input id="head-middle" type="text" class="spectrum"/>
    <label for="head-middle" class="label--primary">Head Middle</label>
  </div>
  <h3>Background Colors</h3>
  <div class="settings__input settings__input--padded">
    <input checked type="checkbox" id="blendBackground"/>
    <label for="blendBackground" class="label--secondary">Automatically blend background colors</label>
  </div>
  <div class="settings__input">
    <input id="glow1-color" type="text" class="spectrum"/>
    <label for="glow1-color" class="label--primary">Glow Front</label>
  </div>
  <div class="settings__input">
    <input id="glow2-color" type="text" class="spectrum"/>
    <label for="glow2-color" class="label--primary">Glow Tier 2</label>
  </div>
  <div class="settings__input">
    <input id="glow3-color" type="text" class="spectrum"/>
    <label for="glow3-color" class="label--primary">Glow Tier 3</label>
  </div>
  <div class="settings__input">
    <input id="glow4-color" type="text" class="spectrum"/>
    <label for="glow4-color" class="label--primary">Glow Tier 4</label>
  </div>
  <div class="settings__input">
    <input id="glow5-color" type="text" class="spectrum"/>
    <label for="glow5-color" class="label--primary">Glow Tier 5</label>
  </div>
  <div class="settings__input">
    <input id="bg-color" type="text" class="spectrum"/>
    <label for="bg-color" class="label--primary">Glow Back</label>
  </div>
</div>
              
            
!

CSS

              
                // https://codepen.io/guide <3 <3
$gray-very-light: #ccc;
$gray-light: #555;
$gray-medium: #343436;
$gray-medium-dark: #28282B;
$gray-dark: #1E1E1E;
$gray-very-dark: #111;

$blue: #0ebeff;
$purple: #AE63E4;
$green: #47CF73;
$yellow: #fcd000;
$red: #ff3c41;
$lightBlue: #76daff;

@font-face {
  font-family: "TelefonBold";
  src: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/186499/telefon-bold.woff");
  font-weight:700;
}

@font-face {
  font-family: "TelefonBlack";
  src: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/186499/telefon-black.woff");
  font-weight:900;
}

* {
  box-sizing: border-box;
}
*, *:before, *:after {
  box-sizing: inherit;
}

body {
  min-height:100vh;
  display:flex;
  font-family: Lato, sans-serif;
  color: $gray-dark;
}

h3 {
  margin-top: 30px;
  margin-bottom: 15px;
  font-family: Lato;
  font-weight: 700;
}

.preview {
  min-width: 400px;
  background: $gray-very-dark;
  flex-grow:1;
}

.preview__header {
  background-color:#343338;
  background-image:url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/186499/profile-bg.svg');
  background-size:cover;
  text-align:center;
  padding-top: 50px;
  padding-bottom: 130px;
}

.header__name {
  margin-top:0;
  font-size: 4rem;
  font-family: "TelefonBlack", sans-serif;
  color: white;
  font-weight:900;
  margin-bottom: 7.5px;
}

.header__username {
  color: #999;
  font-size: 1.1rem;
}

.header__badge {
  font-family: Lato;
  font-size: .8rem;
  color:black;
  background: $yellow;
  padding: 1px 3px;
  border-radius: 3px;
  vertical-align:top;
  position: relative;
  top: 15px;
  font-weight: 700;
  text-transform:uppercase;
}

.settings {
  flex-basis: 37.5%;
  min-width: 400px;
  padding:20px;
}

.preview__bottom-bar {
  background:$gray-very-dark;
  height: 90px;
}

.avatar {
  height:180px;
  width: auto;
  border: 8px solid $gray-very-dark;
  display:block;
  margin: 0 auto;
  transform:translateY( calc(-50% - 8px) );
}

.avatar__bg {
  fill:#dc2a7b;
}

.avatar__glow {
  &--1 {
    fill: #FECC5E;
  }
}

$avatarBase: #26233B;
.avatar__head {
  fill:$avatarBase;
}

.avatar__body {
  fill:$avatarBase;
}

.settings__header {
  font-family:"TelefonBold";
  font-size: 2rem;
  font-weight: 700;
  margin-top:0;
}
.picker, .picker-input {
  border:0;
  border-radius: 3px;
  
}

// FORGIVE ME FOR I HAVE NESTED SELECTORS 
// IN THE INTEREST OF THEMING MORE EASILY.
// MAY THE BEM GODS SMITE ME WHERE I STAND.

.picker-input {
  background: $gray-very-light;
  padding: 8px;
  &.sp-disabled {
    opacity: .35;
    & + label {
      opacity: .35;
    }
  }
  &.sp-active {
    background: lighten($gray-very-light, 5%);
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
  }
  .sp-preview {
    border-radius: 3px;
  }
}

.picker {
  background: lighten($gray-very-light, 5%);
  border-top-left-radius: 0;
  .sp-palette-container, .sp-picker-container {
    border:0;
  }
  .sp-picker-container {
    background: $gray-dark;
  }
  .sp-input {
    background:#F3F0EB;
    border: 3px solid $gray-very-light;
    margin-bottom: 5px;
    color: #222;
  }
  .sp-cancel {
    color: $gray-very-light!important; // r u srs? the plugin made me do it
  }
  .sp-thumb-el:hover {
    border-color: $blue;
  }
  .sp-choose {
    background: $green;
    &:hover {
      background: darken($green, 5%);
    }
    color:white;
    border:0!important; // sshhhh
    text-shadow:none!important; // sssssshhhh
    box-shadow: none!important; // I can feel you juuudginnnggg meee
    padding: 8px 10px;
  }
}

.settings__input {
  margin-bottom:15px;
  &--padded {
    margin-top: 25px;
    margin-bottom: 25px;
  }
}

.label--primary {
    font-size: .9rem;
    text-transform:uppercase;
    font-weight: 400;
    padding-left: 10px;

}

.label--secondary {
  color: $gray-light;
  margin-left: 5px;
}


.save {
  cursor:pointer;
  color: white;
  display:block;
  border: 0;
  border-radius: 4px;
  background: $green;
  margin: 0 auto;
  margin-top: 50px;
  &:hover {
    background: darken($green, 5%);
  }
  font-size: 1.5rem;
  padding: 15px 20px;
}

.dl-icon {
  fill: white;
  width: 20px;
  height: 20px;
  display:inline-block;
  padding-right: 10px;
}

              
            
!

JS

              
                var avatar = {
  bg: $('.avatar__bg'),
  head: $('.avatar__head'),
  headPosDiagonal: $('.avatar__head--positive-diagonal'),
  headNegDiagonal: $('.avatar__head--negative-diagonal'),
  headMiddle: $('.avatar__head--middle'),
  body: $('.avatar__body'),
  glow1: $('.avatar__glow--1'),
  glow2: $('.avatar__glow--2'),
  glow3: $('.avatar__glow--3'),
  glow4: $('.avatar__glow--4'),
  glow5: $('.avatar__glow--5'),
}

// cache stuff! 
var $bodyInput = $("#body-color"),
    $headInput = $("#head-color"),
    $headPosDiagonalInput = $("#head-pos-diagonal"),
    $headNegDiagonalInput = $("#head-neg-diagonal"),
    $headMidInput = $("#head-middle"),
    $bgInput = $("#bg-color"),
    $glow1Input = $("#glow1-color"),
    $glow2Input = $("#glow2-color"),
    $glow3Input = $("#glow3-color"),
    $glow4Input = $("#glow4-color"),
    $glow5Input = $("#glow5-color"),
    $headAdvanced = $("#syncHead"),
    $bgBlend = $('#blendBackground');

//init stuff! This could likely all be done with input[type=color] but this is so much easier to style...
$bodyInput.spectrum(createColorChanger(avatar.body));
$headInput.spectrum(createColorChanger(avatar.head, syncHead));
$headPosDiagonalInput.spectrum(createColorChanger(avatar.headPosDiagonal));
$headNegDiagonalInput.spectrum(createColorChanger(avatar.headNegDiagonal));
$headMidInput.spectrum(createColorChanger(avatar.headMiddle));
$bgInput.spectrum(createColorChanger(avatar.bg, bgBlend));
$glow1Input.spectrum(createColorChanger(avatar.glow1, bgBlend));
$glow2Input.spectrum(createColorChanger(avatar.glow2));
$glow3Input.spectrum(createColorChanger(avatar.glow3));
$glow4Input.spectrum(createColorChanger(avatar.glow4));
$glow5Input.spectrum(createColorChanger(avatar.glow5));
$secondaryGlowInputs = [$glow2Input, $glow3Input, $glow4Input, $glow5Input];
$advancedHeadInputs = [$headPosDiagonalInput, $headMidInput, $headNegDiagonalInput];


// mmmmmmmmmmmk gross boilerplate mostly done?
// let's build an app!


// Listens for the checkbox that controls whether or not
// the more advanced head color options are enabled
$headAdvanced.on("change", function(){
  if (!this.checked) {
    // If they're not, turn those inputs off
    disableAdvancedHeadInputs();
  }
  else {
    enableAdvancedHeadInputs();
  }
});

// Pretty straight forward. Disable the inputs and sync everything
// to the main head color.
function disableAdvancedHeadInputs(){
  $headInput.spectrum("enable");
  $.each($advancedHeadInputs, function(){
    this.spectrum("disable");
    syncHead();
  }); 
}
disableAdvancedHeadInputs(); // starts in this state

// Makes sure all the colors for the different head bits are synced up.
// This (like a lot of things in here) gets pretty repetitive...  
// There's likely a DRYer way to do things.
function syncHead() {
  var color = $headInput.spectrum("get").toHexString();
  avatar.head.css('fill', color);
  $.each($advancedHeadInputs, function(){
    this.spectrum("set", color);
  })
  avatar.headPosDiagonal.removeAttr('style'); 
  avatar.headNegDiagonal.removeAttr('style'); 
  avatar.headMiddle.removeAttr('style'); 
}

// Turns on the advanced inputs! 
// (and disables the standard one)
function enableAdvancedHeadInputs(){
  $.each($advancedHeadInputs, function(){
    $headInput.spectrum("disable");
    this.spectrum("enable");
    bgBlend();
  }); 
}

// Watches the checkbox that controls whether or not the background should be auto blended
$bgBlend.on("change", function(){
  if (this.checked) {
    // If it's toggled on, disable all of the controls for
    // the inbetween colors
    disableSecondaryGlowInputs();
  }
  else {
    enableSecondaryGlowInputs();
  }
});

function disableSecondaryGlowInputs() {
  $.each($secondaryGlowInputs, function(){
    this.spectrum("disable");
    bgBlend(); //makes sure the background is all blended up!
  });
}
disableSecondaryGlowInputs(); // starts in this state

function enableSecondaryGlowInputs() {
  $.each($secondaryGlowInputs, function(){
    this.spectrum("enable");
  });
}

// this is used when initializing Spectrum.
// I figured this makes things a bit less redundant?
// basically just calls Spectrum on a jquery object,
// then queues any callbacks etc.
function createColorChanger(target, callback){
  var spectrumOpts = {
    color: avatar.head.css('fill'),
    showPalette: true,
    showSelectionPalette: true,
    maxSelectionSize: 3,
    showInput: true,
    preferredFormat: 'hex',
    color: target.css('fill'),
    showInitial: true,
    palette: [ // Some brand colors! Grays, content colors, accents.
      ['#ccc', '#555', '#343436'],
      ['#28282B', '#1E1E1E', '#111'],
      ['#0ebeff', '#47CF73', '#AE63E4'],
      ['#fcd000', '#ff3c41', '#76daff']
    ],
    containerClassName: 'picker',
    replacerClassName: 'picker-input',
    chooseText: "Select",
    cancelText: "Cancel",
    localStorageKey: "spectrum"
  }
  changeFunc = function(color){
    target.css('fill', color.toHexString());
    if (callback) {
      callback();
    }
  }
  return $.extend(spectrumOpts, {change:changeFunc});
}

// Creates auto-generated BG blends
function bgBlend() {
  // bail early if we're not meant to be in here
  if (!$bgBlend.is(":checked")) {
    return;
  }
  var bgFront = $bgInput.spectrum("get").toString();
  var bgBack = $glow1Input.spectrum("get").toString();
  var blend = steppedBlend(bgFront, bgBack, 6);
  avatar.glow1.css('fill', blend[0]);
  avatar.glow2.css('fill', blend[1]);
  avatar.glow3.css('fill', blend[2]);
  avatar.glow4.css('fill', blend[3]);
  avatar.glow5.css('fill', blend[4]);
  avatar.bg.css('fill', blend[5]);
  $glow2Input.spectrum('set', blend[1]);
  $glow3Input.spectrum('set', blend[2]);
  $glow4Input.spectrum('set', blend[3]);
  $glow5Input.spectrum('set', blend[4]);
}

// Internal function, blends two colors.
// There might be a better way to do this, but I wanted
// to write it to learn.
// 
// The weight param skews toward the first color if <0.5,
// and toward the second color if >0.5
function blend(color1, color2, weight){
  if (weight===undefined) {
    weight = .5;
  }
  // set the colors up as arrays of RGB vals
  color1 = prepColor(color1);
  color2 = prepColor(color2);
  var colorBlended = [];
  for (var i=0; i<3; i++) {
    colorBlended.push(weightedAverage(color1[i], color2[i], weight));
  }
  
  return rgbArrayToHex(colorBlended);
};

// Given a number of steps `n`, returns an array of `n` colors,
// evenly blended throughout each.
// 
// Again, probably a cleaner way to do this but I wrote it and that's neat!
function steppedBlend(color1, color2, steps) {
  var blendedArray = [];
  for (var i=0; i<steps; i++) {
    var weight = (i*steps)/(steps*(steps-1));
    blendedArray.push(blend(color1, color2, weight));
  }
  return blendedArray;
}

// Used when blending stuff
function weightedAverage(num1, num2, weight) {
  return Math.floor((num1*weight) + (num2*(1-weight)));
}

// Probably the world's least useful abstraction eyyyy
function stripHash(color) {
  if (color[0]=="#") {
    color = color.replace('#','');
  }
  return color;
}

// Sooo.... turns out one of the libs I used already does this.
// But hey, learning opportunities gone <del>wild</del>mild. (let's be honest)
function hexToRgbArray(color) {
  color =  color.match(/.{1,2}/g);
  color.forEach(function(hexVal, index){
    color[index] = parseInt(hexVal, 16);
  });
  return color;
}

// Inverse of the above
function rgbArrayToHex(color) {
  color.forEach(function(rgbVal, index){
    color[index] = ("0" + rgbVal.toString(16)).slice(-2); //force leading 0
  });
  return "#"+color.join('');
}

// Takes a hex color code and returns an array of rbg values
// because they're heaps easier to work with
function prepColor(color) {
  color = stripHash(color);
  return hexToRgbArray(color);
}

// Magic yo. https://github.com/exupero/saveSvgAsPng
$("#save").click(function(){
  saveSvgAsPng(document.getElementById("avatar"), "avatar.png", {scale:2.844});
})
              
            
!
999px

Console