Spontaneous gradient background occasionally failing to load as expected

My to-do list is simple and functional, but I'm encountering an unusual issue with the background. The background is supposed to be a random gradient set using JS upon loading the HTML, but sometimes it doesn't apply at all. If you refresh the Codepen page (linked below) multiple times, you'll notice that the background may not appear until after several attempts. Despite this, the code functions correctly for the most part, but I aim to resolve this inconsistency.

The code itself seems fine, but the background loading inconsistency persists.

// Get elements
const inputBox = document.getElementById("input-box");
const listContainer = document.getElementById("list-container");

// Function to add a task
function addTask() {
    if (inputBox.value === '') {
        alert("You need to write something you silly goose.");
    } else {
        const li = document.createElement("li");
        li.innerHTML = inputBox.value;

        const span = document.createElement("span");
        span.innerHTML = "\u00d7";
        li.appendChild(span);

        listContainer.appendChild(li);
    }

    inputBox.value = "";
    saveData();
}

// Event listener for listContainer
listContainer.addEventListener("click", function (e) {
    if (e.target.tagName === "LI") {
        e.target.classList.toggle("checked");
        saveData();
    } else if (e.target.tagName === "SPAN") {
        e.target.parentElement.remove();
        saveData();
    }
});

// Event listener for Enter key in inputBox
inputBox.addEventListener("keypress", function (event) {
    if (event.key === "Enter") {
        event.preventDefault();
        addTask();
    }
});

// Function to save data to local storage
function saveData() {
    localStorage.setItem("data", listContainer.innerHTML);
}

// Function to show tasks from local storage
function showTask() {
    listContainer.innerHTML = localStorage.getItem("data");
}

document.addEventListener("DOMContentLoaded", function () {
    requestAnimationFrame(function () {
        backgroundColor();
    });
});


const calculateContrast = (color1, color2) => {
    const luminance1 = calculateLuminance(color1);
    const luminance2 = calculateLuminance(color2);

    const lighterLuminance = Math.max(luminance1, luminance2);
    const darkerLuminance = Math.min(luminance1, luminance2);

    return (lighterLuminance + 0.05) / (darkerLuminance + 0.05);
};

const calculateLuminance = (color) => {
    const rgb = parseInt(color, 16);
    const r = (rgb >> 16) / 255;
    const g = ((rgb >> 8) & 0xff) / 255;
    const b = (rgb & 0xff) / 255;

    const gammaCorrect = (value) => value <= 0.03928 ? value / 12.92 : Math.pow((value + 0.055) / 1.055, 2.4);

    const sRGB = gammaCorrect(r) * 0.2126 + gammaCorrect(g) * 0.7152 + gammaCorrect(b) * 0.0722;

    return sRGB;
};

function backgroundColor() {
    const getRandomColor = () => Math.floor(Math.random() * 0xffffff).toString(16);

    const calculateAndSetBackground = () => {
        let color1, color2;

        do {
            color1 = getRandomColor();
            color2 = getRandomColor();
        } while (calculateContrast(color1, color2) < 4.5);

        document.body.style.background = `linear-gradient(to left top, #${color1}, #${color2})`;
    };

    // Ensure that showTask function is complete before setting the background
    showTask();

    // Call calculateAndSetBackground after showTask is complete
    calculateAndSetBackground();
}

I have reviewed the syntax and tested various timing adjustments in the JS code to address the background loading issue, but to no avail.

I have tried the following timing fixes:

  • Combining 'window.onload' event and 'setTimeout' to allow extra time for complete page rendering before setting the background.

  • Using the defer attribute on the tag in conjunction with the DOMContentLoaded event and requestAnimationFrame to execute the script after HTML parsing.

document.addEventListener("DOMContentLoaded", function () {
    requestAnimationFrame(function () {
        backgroundColor();
    });
});

  • Created a new function (calculateAndSetBackground) to separate background calculation and setting, ensuring showTask function is called first to resolve possible timing issues.

Despite these efforts, the issue remains unresolved. It seems to be more complex than just a timing problem, possibly related to caching.

Check out the Codepen link here

Answer №1

Having an issue? Let's solve it:

https://i.sstatic.net/BQVMl.png

At times, the variable randomColor may initially start with zero, causing the hex code passed to the CSS to be incorrect. To ensure the color code is a 6-digit hex color, a padding function is necessary.

// original
document.body.style.background = `linear-gradient(to left top, #${color1}, #${color2})`;

// improved
function pad(num, size) {
    num = num.toString();
    while (num.length < size) num = "0" + num;
    return num;
}
color1 = pad(color1, 6);
color2 = pad(color2, 6);
document.body.style.background = `linear-gradient(to left top, #${color1}, #${color2})`;

Answer №2

The Issue

You should have checked the output of your colors in the console!

If you included the following code...

function changeBackgroundColor() {
  //...
  console.log(color1, color2);
  document.body.style.background = `linear-gradient(to left top, #${color1}, #${color2})`;
  //...
}

You will notice the issue when it occurs. One of the hex colors will only have 4 or 5 digits. This means the console will display something like 90f67. Therefore, the timing is not the reason for this problem.

Potential Solutions

There are several solutions available!

Firstly, you can implement what @takid1412 recommended, which is to add a padding function to ensure the color code is a 6-digit hex color.

Secondly, consider using HSL colors as they work well when generating random colors. This method is effective because you have three components: a 360° color value known as Hue, and two percentage values—Saturation and Lightness.

function generateRandomColor() {
  return `hsl(${Math.random() * 360}deg, 100%, 50%)`;
}

Then, utilize the generateRandomColor() function as needed!

Quick Tip?

I observed that your code employs different ways of defining functions, such as function name(){} and the more recent and preferable const name = () => {}.

I highly recommend sticking with arrow functions, as they can be incredibly useful when working with modules. Unless you have a valid reason not to use them, it's best to make them your default choice!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When functions are sent to children of a react component, they do not inherit the context of the parent

I'm facing an issue while working with React where I am encountering difficulty passing a function from a parent component to multiple children components. The function calls other functions that are also housed within the parent component. Although ...

Despite my attempts to force a repaint, the progress bar remained static during intensive tasks

My JavaScript method works fine in Chrome, taking about 2000 ms to iterate over ~200 inputs, insert values, and trigger onchange events. However, it's a different story in IE where it takes about 10000 ms. To show the progress of this process, I deci ...

How can I show a Spinner component overlay in a TextField, replacing the usual iconProps rendering the icon in Fluent UI?

I am looking for a way to conditionally display the Spinner component in the exact location where an icon would normally appear if passed to iconProps in TextField. I have managed to implement conditional rendering of the icon and spinner, but incorporat ...

The backdrop moving in a reverse direction

I recently made a tweak to this code that successfully moves the background in the opposite direction of the scroll. However, there is now an issue where it leaves a blank space at the top, even when the background is set to repeat. The change I made was s ...

Using React Redux to Calculate the Grand Total Price of all Products Added to Cart

<div className='container py-4 my-5'> {item.length === 0 ? ( <p> cart is empty, <NavLink to='/'>continoue shopping</NavLink> </p> ) : ( item.map((cart) => { return ( & ...

What is the best way to increase the value of a variable using jQuery?

As I work on adding dates to a slider, I find myself needing to increment the values with each click. Initially, I start with the year - 2. $('#adddates').click(function() { var year = 2; $("#slider").dateRangeSlider({ bounds: { ...

Adding a character at the beginning of each loop iteration in a nested array with Vue.js

When working inside a v-for loop, I am attempting to add a character at the beginning of each item in a nested array that may contain multiple items. I have explored various options but have not been successful: :data-filter="addDot(item.buttonFilter ...

Is it possible to utilize the WebGL camera in order to create dynamic transitions between various polygons?

Recently, a friend suggested exploring WebGL as an alternative to CSS transitions. I have a collection of polygons that form a 2D board game. https://i.sstatic.net/D0dnc.png In essence, the application moves the player space by space starting at the top ...

I am trying to locate the source of the unexpected token error

Hi there! I've encountered a syntax error in my code, specifically pointing to the closing curly bracket right above the render method. The error message indicates that it's expecting a comma, but all my curly brackets seem to have opening and cl ...

How can you switch alignment from left to right when the current alignment settings are not functioning as expected in HTML?

I need the buttons +, count, and - to be right-aligned on my page. The numbers on the right are taking up the same amount of space, while the names on the left vary in length. I want the buttons to always remain in the same position, regardless of the name ...

Only dispatch to props upon being clicked

I am encountering an issue with the mapDispatchToProps function being sent as a whole, rather than only when I click on the delete button. My class successfully fetches the list data and everything works as expected. However, upon adding the delete button ...

NodeJS is facing a severe challenge in properly rendering HTML and its accompanying CSS code, causing a major

Once upon a time, I built a beautiful website while practicing HTML, CSS, and JS. It had multiple web pages and used Express for the backend. Unfortunately, I lost all the files associated with it and took a break from web programming for some time. Now, w ...

Google Maps Shifting Focus

I'm currently working on an AngularJS app that involves multiple locations, and the goal is for users to click on a location which then redirects them to the specific spot on Google Maps. However, I've encountered an issue when trying to relocate ...

Attach functions to elements added dynamically

I've been struggling with trying to attach functions to newly added elements using jQuery. Despite experimenting with various online examples, I haven't been able to get anything to work properly. My setup involves a form with an ID and a button. ...

Ways to create a back-and-forth transition across a sequence

Is it possible to create an animation that changes the width of an element once, then reverts back after a pause? I want this transition to occur over a three-second interval followed by a two-second delay. How can I achieve this? Below is the code I have ...

Issues with relocating function during the NgOnInit lifecycle hook in an Angular 2 application

Currently, I am facing an issue with my Angular 2 app where the data sometimes lags in populating, causing a page component to load before the information is ready to display. When this happens, I can manually refresh the page for the data to appear correc ...

Modifying npm packages within a web application

I have a web application where I recently installed an npm package. However, I've realized that I need to customize it by adding some code. My attempt to modify the package directly in node_modules hasn't resulted in any visible changes. Is there ...

Alter the arrow to dynamically point towards the location of the click source

I am currently working on creating a popover dialog that should point to the element triggering its appearance. The goal is for the arrow to align with the middle of the button when clicked. While I am familiar with using CSS to create pointing arrows, th ...

Upload a user-sent image to a remote SFTP server for safekeeping

Can someone help me figure out how to upload a file to an SFTP remote server using ssh2-sftp-client? I am trying to retrieve the file from the user via a post request along with the destination. To process the file, I am utilizing multer. const Client = r ...

Ignoring custom elements does not occur when the child is set to display as inline-block

My code includes custom elements that exhibit strange behavior when a child element has the "display: inline-block" style. Let's examine these two div elements: <div style="padding: 4px;"> <randomcustomelement style="background-color: y ...