<h1>Lightness functions</h1>
  <div class="container">
    <div class="innercont inputcont">
      <label for="color">Enter color:</label>

      <input type="color" name="color" id="color">
    </div>

    <div class="innercont buttoncont">
      <button id="increase-sat">Increase lightness
      </button>
      <button id="decrease-sat">Decrease lightness</button>
    </div>

    <div class="innercont outputcont">
      <label for="output" id="output-label"> Resulting color: </label>
      <span id="hash-output">#000000</span>
      <span id="rgb-output">rgb(0,0,0)</span>
      <span id="hsl-output">hsl(0°,0%,0%)</span>
    </div>
  </div>

* {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
    Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  margin: 0px;
  padding: 0px;
  box-sizing: border-box;
}
body {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.container {
  margin: 3em;
  display: flex;
  align-items: flex-start;
  max-width: 800px;
}
@media only screen and (max-width: 800px) {
  .container {
    display: flex;
    flex-direction: column;
    height: 400px;
    justify-content: space-around;
  }
}
label {
  font-weight: bold;
}
button {
  padding: 1vw;
  margin: 1vw 0vw;
  border-radius: 1.5vw;
  font-weight: bold;
  width: 15vw;
  min-width: 100px;
}
.inputcont {
  order: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.buttoncont {
  order: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
.outputcont {
  order: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.innercont {
  height: 20vw;
  max-height: 250px;
  width: 50vw;
  margin: 0vw 1vw;
}

#color {
  display: block;
  background-color: inherit;
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  flex-grow: 1;
  box-sizing: inherit;
  border-radius: 1.5vw;
}
#color::-webkit-color-swatch {
  border-radius: 1.5vw;
}
#color::-moz-color-swatch {
  border-radius: 1.5vw;
}


//Grab dom nodes

const colorInput = document.getElementById("color");
const hashOutput = document.getElementById("hash-output");
const rgbOutput = document.getElementById("rgb-output");
const hslOutput = document.getElementById("hsl-output");
const increase = document.getElementById("increase-sat");
const decrease = document.getElementById("decrease-sat");

//Add event listeners

colorInput.addEventListener("input", onColorInput);
increase.addEventListener("click", onIncreaseClick);
decrease.addEventListener("click", onDecreaseClick);

//Set output to match input on change

function onColorInput(e) {
  hashOutput.textContent = e.target.value;
  rgbOutput.textContent = hexToRgb(e.target.value);
  hslOutput.textContent = rgbToHsl(hexToRgb(e.target.value));
}

//functionality for saturation buttons

function onIncreaseClick(e) {
  result = rgbToHex(lightenByTenth(hexToRgb(colorInput.value)));
  hashOutput.textContent = result;
  rgbOutput.textContent = hexToRgb(result);
   hslOutput.textContent = rgbToHsl(hexToRgb(result));
  colorInput.value = result;
}
function onDecreaseClick(e) {
  result = rgbToHex(darkenByTenth(hexToRgb(colorInput.value)));
  hashOutput.textContent = result;
  rgbOutput.textContent = hexToRgb(result);
  hslOutput.textContent = rgbToHsl(hexToRgb(result));
  colorInput.value = result;
}

//manipulation functions

function hexToRgb(h) {
  var r = parseInt(cutHex(h).substring(0, 2), 16),
    g = parseInt(cutHex(h).substring(2, 4), 16),
    b = parseInt(cutHex(h).substring(4, 6), 16);
  return "rgb(" + r + "," + g + "," + b + ")";
}
function cutHex(h) {
  return h.charAt(0) == "#" ? h.substring(1, 7) : h;
}

function rgbToHex(rgb) {
  const [red, green, blue] = rgb
    .replace(/ /g, "")
    .slice(4, -1)
    .split(",")
    .map((e) => parseInt(e));
  return "#" + toHex(red) + toHex(green) + toHex(blue);
}

function toHex(n) {
  n = parseInt(n, 10);
  if (isNaN(n)) return "00";
  n = Math.max(0, Math.min(n, 255));
  return (
    "0123456789ABCDEF".charAt((n - (n % 16)) / 16) +
    "0123456789ABCDEF".charAt(n % 16)
  );
}

function lightenByTenth(rgb) {

  // Our rgb to int array function again
  const rgbIntArray = rgb.replace(/ /g, '').slice(4, -1).split(',').map(e => parseInt(e));
  
  
 const [lowest,middle,highest]=getLowestMiddleHighest(rgbIntArray);
  
  if(lowest.val===255){
    return rgb;
  }
  
  const returnArray = [];
  
  returnArray[lowest.index]= Math.round(lowest.val+(Math.min(255-lowest.val,25.5)));
  const increaseFraction  = (returnArray[lowest.index]-lowest.val)/ (255-lowest.val);
  returnArray[middle.index]= middle.val +(255-middle.val)*increaseFraction ;
  returnArray[highest.index]= highest.val +(255-highest.val)*increaseFraction ;
  
  // Convert the array back into an rgb string
  return (`rgb(${returnArray.join()})`);
}
  

function darkenByTenth(rgb) {
  
  // Our rgb to int array function again
  const rgbIntArray = rgb.replace(/ /g, '').slice(4, -1).split(',').map(e => parseInt(e));
  
  const [lowest,middle,highest]=getLowestMiddleHighest(rgbIntArray);
  
  if(highest.val===0){
    return rgb;
  }

  
  const returnArray = [];
  returnArray[highest.index] = highest.val-(Math.min(highest.val,25.5));
   const decreaseFraction  =(highest.val-returnArray[highest.index])/ (highest.val);
  returnArray[middle.index]= middle.val -middle.val*decreaseFraction; 
  returnArray[lowest.index]= lowest.val -lowest.val*decreaseFraction;                                       
  
  // Convert the array back into an rgb string
  return (`rgb(${returnArray.join()}) `);
}

function getLowestMiddleHighest(rgbIntArray) {
  let highest = {val:-1,index:-1};
  let lowest = {val:Infinity,index:-1};

  rgbIntArray.map((val,index)=>{
    if(val>highest.val){
      highest = {val:val,index:index};
    }
    if(val<lowest.val){
       lowest = {val:val,index:index};
    }
  });
  if(lowest.index===highest.index){
    lowest.index=highest.index+1;
  }
  let middle = {index: (3 - highest.index - lowest.index)};
  middle.val = rgbIntArray[middle.index];
  console.log([lowest,middle,highest]);
  return [lowest,middle,highest];
}


function getLightnessOfRGB(rgbString) {
  // First convert to an array of integers by removing the whitespace, taking the 3rd char to the 2nd last then splitting by ','
  const rgbIntArray = rgbString.replace(/ /g, '').slice(4, -1).split(',').map(e => parseInt(e));

  // Get the highest and lowest out of red green and blue
  const highest = Math.max(...rgbIntArray);
  const lowest = Math.min(...rgbIntArray);

  // Return the average divided by 255
  return (highest + lowest) / 2 / 255;
}


function rgbToHsl(rgb){
  let [r,g,b]= rgb.replace(/ /g, '').slice(4, -1).split(',').map(e => parseInt(e));
  r /= 255;
  g /= 255;
  b /= 255;

  // Find greatest and smallest channel values
  let cmin = Math.min(r,g,b),
      cmax = Math.max(r,g,b),
      delta = cmax - cmin,
      h = 0,
      s = 0,
      l = 0;
if (delta == 0)
    h = 0;
  // Red is max
  else if (cmax == r)
    h = ((g - b) / delta) % 6;
  // Green is max
  else if (cmax == g)
    h = (b - r) / delta + 2;
  // Blue is max
  else
    h = (r - g) / delta + 4;

  h = Math.round(h * 60);
    
  // Make negative hues positive behind 360°
  if (h < 0)
      h += 360;
l = (cmax + cmin) / 2;

  // Calculate saturation
  s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
    
  // Multiply l and s by 100
  s = +(s * 100).toFixed(1);
  l = +(l * 100).toFixed(1);

  return "hsl(" + h + "," + Math.round(s) + "%," + Math.round(l) + "%)";
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.