Color Changer

Or: How Messing Around with AI Became The Backbone of This Website

Initial Inspiration

It started at the intersection of two websites I was obsessed with:

A streamlined website seemed like the perfect vehicle to test drive that color change feature in context. The idea sort of died with my total lack of javascript know-how.

Proof of Concept

I used Chat GPT to make up for my “javascript gap,” and got to a working proof-of-concept relatively quickly.

I opted for SVG icons (shoutout to Phospher Icons) to populate the site since their color could be manipulated via the button.

What's Actually Happening

The code itself is running through a few steps:

  • Generate a color for the page background
  • Generate a color for the on-page elements
  • Check that the contrast between these colors is at least 7:1 (AAA)*
  • If not, generate a new on-page element color until it is

*At first I was using AA (4:1) but that lead to some seriously rough color combos. AAA contrast tended to yield more visually appealing pairs more often than not.

See the Code

Here's the code that's making all this work. I'm sure there's ways to clean this up and optimize it, but for now, this is the best I've got.

<script>
  function getRandomColor() {
    const letters = '0123456789ABCDEF';
    let color = '#';
    for (let i = 0; i < 6; i++) {
      color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
  }

  function calculateContrastRatio(foregroundColor, backgroundColor) {
    const getLuminance = (color) => {
      const hex = color.slice(1);
      const r = parseInt(hex.slice(0, 2, 16), 16) / 255;
      const g = parseInt(hex.slice(2, 4, 16), 16) / 255;
      const b = parseInt(hex.slice(4, 6, 16), 16) / 255;
      const sRGB = [r, g, b].map((channel) =>
        channel <= 0.03928 ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4)
      );
      return sRGB[0] * 0.2126 + sRGB[1] * 0.7152 + sRGB[2] * 0.0722;
    };

    const calculateContrast = (foreground, background) => {
      const L1 = getLuminance(foreground);
      const L2 = getLuminance(background);
      return (Math.max(L1, L2) + 0.05) / (Math.min(L1, L2) + 0.05);
    };

    return calculateContrast(foregroundColor, backgroundColor);
  }

  function generateADACompliantColors() {
    let bgColor, elementColor;
    do {
      bgColor = getRandomColor();
      elementColor = getRandomColor();
    } while (
      calculateContrastRatio(elementColor, bgColor) < 7 || // AAA for normal text
      calculateContrastRatio(elementColor, bgColor) < 4.5 || // AA for large text
      calculateContrastRatio(bgColor, elementColor) < 7 // Ensure AAA-level contrast for both combinations
    );

    // Update the background color
    document.body.style.backgroundColor = bgColor;

    // Update all on-page elements
    const elements = document.querySelectorAll("body *");
    for (let i = 0; i < elements.length; i++) {
      elements[i].style.color = elementColor;
      elements[i].style.backgroundColor = bgColor;
      elements[i].style.borderColor = elementColor;
      
      // Update the SVG fill color
const svgElement = document.querySelector(".svg-element");
if (svgElement) {
  svgElement.style.setProperty('--svgFill', elementColor);
}

    }
  }

function setTextColorSameAsBackground() {
  const elements = document.querySelectorAll(".text-same-color");
  const bgColor = getComputedStyle(document.body).backgroundColor; // Get the background color

  elements.forEach((element) => {
    element.style.color = bgColor;
  });
}

    function changeFont() {
    const fonts = ['Arial', 'Helvetica', 'Times New Roman', 'Courier New', 'Verdana', 'Georgia'];
    const randomFont = fonts[Math.floor(Math.random() * fonts.length)];
    document.body.style.fontFamily = randomFont;
  }
  
  
  //

document.addEventListener("DOMContentLoaded", function () {
  const button = document.getElementById("generateColorsButton");
  button.addEventListener("click", function () {
    generateADACompliantColors();
    setTextColorSameAsBackground(); // Call the function to set text color
  });
});

document.addEventListener("DOMContentLoaded", function () {
  const button = document.getElementById("generateColorsButtonNav");
  button.addEventListener("click", function () {
    generateADACompliantColors();
    setTextColorSameAsBackground(); // Call the function to set text color
  });
});

document.addEventListener("DOMContentLoaded", function () {
  const button = document.getElementById("generateColorsButton2");
  button.addEventListener("click", function () {
    generateADACompliantColors();
    setTextColorSameAsBackground(); // Call the function to set text color
  });
});

document.addEventListener("DOMContentLoaded", function () {
  const button = document.getElementById("generateColorsButtonNavMobile");
  button.addEventListener("click", function () {
    generateADACompliantColors();
    setTextColorSameAsBackground(); // Call the function to set text color
  });
});

document.addEventListener("DOMContentLoaded", function () {
    const button = document.getElementById("changeButton");
    button.addEventListener("click", function () {
      generateADACompliantColors();
      setTextColorSameAsBackground(); // Call the function to set text color
      changeFont();
    });
  });

</script>

back