Jonnie Grieve Digital Media: Blog

Home
by on 13th September, 2023 - 9:48am (0)

Blog: How to create customisable stylesheet themes for a website (More Posts)

In my latest blog, I want to talk about how to create a customisable set of style themes for your website or app. It’s an important but relatively simple skill using variables in CSS and a little JavaScript.

CSS Variables, also known as Custom Properties, are the key to creating customizable stylesheets. They allow you to define variables for various CSS properties that can be changed dynamically.

Here’s how to define a CSS variable:

:root {
    --primary-color: #007bff;
}

The syntax for a CSS variable is 2 double dashes — and a further separating dash if you’re using multiple words in the name.

--primary-color:
--primaryColor:

You can use variables to define any CSS value or keyword. The main rule of thumb is that a variable goes into the :root selector, because the selector in which the variable is declared becomes the scope of that selector. The root selector ensures that variable can be used anywhere else in the page.

To make your stylesheets customizable, you can create theme options that users can interact with. This can be done through settings, buttons, or even a separate settings panel. For example, you can have options to change the primary color, font size, and other style-related settings.

const primaryColorInput = document.getElementById('primary-color-input');

primaryColorInput.addEventListener('input', (event) => {
    document.documentElement.style.setProperty('--primary-color', event.target.value);
});

Often you’ll need to provide a new value to a custom property. Like so:

const primaryColorInput = document.getElementById('primary-color-input');

primaryColorInput.addEventListener('input', (event) => {
    document.documentElement.style.setProperty('--primary-color', '#00ff00');
});

I’ll demonstrate how to do this with a simple example.

Consider the following HTML. Which contains an aside element with 3 buttons and a section element where the main content goes.

<body>

    <header>
        <h1>Title</h1>
    </header>

    <aside id="style_buttons">
        <button id="one">One</button>
        <button id="two">Two</button>
        <button id="monochrome">Monochrome</button>
    </aside>

    <section id="main_content">

        <p> . . . </p>
        <p> . . . </p>

    </section>
    <footer>&copy; All Rights Reserved</footer>
    <script type="text/javascript" src="app.js"></script>
</body>

The first step, as we talked about is to define variables with the following syntax in with the root selector.

:root {
    --primary-color: #007bff;
    --test-variable: lightblue;
}

To reference the variable value you need to use the var() method. It can either be changed in the root selector or dynamically with JavaScript.

body {
   background: var(--primary-color); //#007bff
   font-family: times;
}

So now the colour #007bff will be used whenever the --primary-color) variable is referenced.

We need JavaScript to tap into the Custom Properties and to swap out these values so that we see changes to the styles in real-time.

First, we use DOM selection methods to select the 3 buttons.

// select buttons
const primaryColorInput = document.getElementById('one');
const secondaryColorInput = document.getElementById('two');
const monochromeColorInput = document.getElementById('monochrome');

I assigned each one, via its ID attribute to a variable. Each of these variables is the target of an event listener. There are properties in JavaScript that you can use to pass in a custom property and set these to a new value. You can use various events for these but the most common one is a click event.

// theme customiser event listeners
primaryColorInput.addEventListener('click', (event) => {
    document.documentElement.style.setProperty('--primary-color', event.target.value);
});
secondaryColorInput.addEventListener('click', (event) => {

    document.documentElement.style.setProperty('--primary-color', 'lightgreen');
});

monochromeColorInput.addEventListener('click', (event) => {

    document.documentElement.style.setProperty('--primary-color', 'gray');
});

To allow users to set a “default” theme,  you can simply set the property of the first button to be the same value as the custom property in the CSS Root Selector.

:root {

    --primary-color: lightblue;
    --test-variable: lightblue;
    --theme-two: lightblue;
    --theme-three: lightblue;
}
document.documentElement.style.setProperty('--primary-color', 'lightblue');

You can add more properties easily for each button with any number of style properties and styles possible.

// theme customiser event listeners
primaryColorInput.addEventListener('click', (event) => {

    document.documentElement.style.setProperty('--primary-color', 'lightblue');
    document.documentElement.style.setProperty('--main-color', '#d7fdff');
});

secondaryColorInput.addEventListener('click', (event) => {

    document.documentElement.style.setProperty('--primary-color', 'lightgreen');
    document.documentElement.style.setProperty('--main-color', '#b3ffe3');
});

monochromeColorInput.addEventListener('click', (event) => {

    document.documentElement.style.setProperty('--primary-color', 'gray');
    document.documentElement.style.setProperty('--main-color', '#dbdbdb');
});

Now, you should be seeing the styles change to react to the click of each of the 3 buttons.

Persisting with localStorage

There’s no point in having these customisable options if the changes are not persisting  (i.e stay the same when you refresh or come back to the page.

So let’s finish by addressing that, and again we’re going to use localStorage to do this. This process generally involves 3 steps: set the item so it’s saved to the browser, get the item which is kind of like holding the data you’ve saved in a container in your browser, and then load the item so the saved data is visible on the screen.

Let’s see this in action.

Once we’ve declared custom properties in the root selector we can use a JavaScript function to set all these properties in one place. The function arguments tell us the CSS properties we want to change at the click of each button and are passed in with each call.

function setThemeProperties(primaryColor, mainColor, buttonBg, borderColor) {

    document.documentElement.style.setProperty('--primary-color', primaryColor);
    document.documentElement.style.setProperty('--main-color', mainColor);
    document.documentElement.style.setProperty('--button-bg', buttonBg);
    document.documentElement.style.setProperty('--border-color', borderColor);
}

Using a string argument, we can store the values of all these new properties by passing in the very same arguments of the setThemeProperties() function.

// Save the theme properties to localStorage
localStorage.setItem('themeProperties', JSON.stringify({
    primaryColor,
    mainColor,
    buttonBg,
    borderColor
})

This function checks if there are saved theme properties in localStorage, and if there are, it applies those properties to the page.

function loadThemeProperties() {
    const themeProperties = JSON.parse(localStorage.getItem('themeProperties'));

    if (themeProperties) {
        setThemeProperties(
            themeProperties.primaryColor,
            themeProperties.mainColor,
            themeProperties.buttonBg,
            themeProperties.borderColor
    );
}

Now we can pass in the values to each button by calling setThemeProperties, once for each button.

// Theme customizer event listeners
primaryColorInput.addEventListener('click', () => {

    setThemeProperties('lightblue', '#d7fdff', '#6ff2ff', '#1313a1');
});

Finally, to put these changes into effect make sure to use the event listener that triggers when the page has finished loading.

// Load theme properties from localStorage when the page loads
window.addEventListener('load', loadThemeProperties);

Removing localStorage

I also like to make sure there’s a way for users to take localStorage values off their system if they wish.

A link is provided as the way to revert to the default setting, after which no key-value pairs remain in localStorage.

// Reset theme properties to default values and clear localStorage
function resetToDefault() {
    // Set default theme properties
    setThemeProperties('lightblue', '#d7fdff', '#6ff2ff', '#1313a1');

    // Clear localStorage
    localStorage.removeItem('themeProperties');
}

Add click event listener to the reset link to trigger the removal of the data and clear localStorage. It clears any data that exists and is added again at the simple click of any of the buttons.

// Add click event listener to the reset link
resetLink.addEventListener('click', (event) => {
    event.preventDefault(); // Prevent the link from navigating

    // Reset to default theme properties and clear localStorage
    resetToDefault();
});

Conclusion

Visit the project in action here, https://projects.jonniegrieve.co.uk/front_end_experiments/12/

This post has been assigned to the following categories

    Uncategorised

    Leave a Reply

    Your email address will not be published. Required fields are marked *