Enhancing your website's design with dynamic CSS variables using JavaScript

Is there a way to update CSS variables specifically scoped under a certain CSS class (or even other complex CSS selectors) that are predefined in a stylesheet? This question extends beyond just CSS variables and includes other CSS properties as well, questioning whether class-specific CSS properties can be updated without directly targeting a specific HTML element, but rather by targeting the class definition itself.

Below are code snippets illustrating an example scenario. Comments within the code provide insight into what is happening on specific lines.

var toggle = true;
function changeColor() {
  document.documentElement.style.setProperty('--bg-color', toggle ? 'green' : 'red');
  // This works for the "outer" div since we are receiving the global value (defined in :root) of --bg-color
  toggle = !toggle;

  // Here I also want to change the scoped value of --bg-color for "inner-primary" and "inner-secondary"
  // Currently, I am doing this by:
  document.querySelectorAll('.inner-primary').forEach(ele => ele.style.setProperty('--bg-color', toggle ? 'blue' : 'yellow'))
  document.querySelectorAll('.inner-secondary').forEach(ele => ele.style.setProperty('--bg-color', toggle ? 'yellow' : 'blue' ))

  // Another approach could involve dynamically inserting a style tag, however, this can become messy with multiple iterations
}
:root {
  --bg-color: red;
}
body {
  margin: 0;
}
.outer {
  width: 100vw;
  height: auto;
  min-height: 100vh;
  text-align: center;
  background-color: var(--bg-color); /* receives value from :root */
}
.inner-primary,
.inner-secondary {
  width: 100px;
  height: 100px;
  /* Receives scoped value from .inner-primary or .inner-secondary defined below*/
  background-color: var(--bg-color);
  border: 1px solid black;
  margin: auto;
  margin-bottom: 10px;
}
.inner-secondary {
  --bg-color: yellow;
}
.inner-primary {
  --bg-color: blue;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Testing</title>
  </head>
  <body>
    <div class="outer">
      <div class="inner-primary"></div>
      <div class="inner-secondary"></div>
      <div class="inner-primary"></div>
      <div class="inner-secondary"></div>
      <button onclick="changeColor()">Change Color</button>
  </body>
</html>

Running this code will demonstrate the intended effect. Clicking the "Change Color" button at the bottom will showcase the effects in action.

To override the CSS variable --bg-color for classes inner-primary and inner-secondary, I had to use querySelectorAll with the necessary CSS selector (in this case, just a class name) and iteratively set the CSS variable for each individual element found.

Considering how CSS is interpreted by the browser, it seems like an alternative solution would be to dynamically insert a style element tag into the DOM with the required CSS variable updates scoped under the necessary class name (or any other required selector). However, this method can get messy if not managed properly to avoid multiple unnecessary inserts.

Are there any other methods to achieve this task? Is there a native API that can handle this without needing to access individual elements or inserting style tags dynamically?

Answer №1

Following the suggestion of A Haworth, I have updated the changeColor function based on discussions in this thread about changing CSS of a class using Javascript. The new approach now utilizes the CSSStyleSheet API from MDN. Below is the revised function incorporating this technique:

var toggle = true;
function changeColor() {
  document.documentElement.style.setProperty('--bg-color', toggle ? 'green' : 'red');

  // solution using document stylesheets
  const styleSheet = document.styleSheets[0]
  const cssRules = Array.from(styleSheet.cssRules);
  const primaryClassIndex = cssRules.findIndex(cssRule => cssRule.selectorText === '.inner-primary');
  const secondaryClassIndex = cssRules.findIndex(cssRule => cssRule.selectorText === '.inner-secondary');

  //update primary:
  styleSheet.deleteRule(primaryClassIndex);
  styleSheet.insertRule(`.inner-primary {--bg-color: ${toggle ? 'yellow' : 'blue'};}`, primaryClassIndex)

  //update secondary:
  styleSheet.deleteRule(secondaryClassIndex);
  styleSheet.insertRule(`.inner-secondary {--bg-color: ${toggle ? 'blue' : 'yellow'};}`, secondaryClassIndex)
  
  //toggle
  toggle = !toggle;
}

There are still some concerns regarding overwriting entire cssRules for specific selectors instead of individual properties, but it may be a more efficient approach compared to manipulating each element's style individually or adding style tags dynamically as mentioned in the original question.

For a complete working example, you can view the codepen at => https://codepen.io/yadus/pen/mdWZmXX

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

The AngularJS routing template fails to load

I am currently working on the app.js file: 'use strict'; var app = angular.module('app', [ 'auth0', 'angular-storage', 'angular-jwt', 'ui.router', 'Environment', ...

What is the best way to include text in an editor access notification email?

I've developed a script to assign editors to a spreadsheet, but I'm looking to personalize the emails sent to them. The screenshot below illustrates the step where I can input a message for the email recipients who have been granted access. f ...

Error: Angular is encountering an issue with accessing the property 'push' as it is currently undefined

I have successfully created a news ticker that works well in my codepen example. However, I am encountering an issue with integrating it into my code structure. The error message I am currently receiving is: Cannot read property 'push' of undefi ...

How can I modify the CSS styles for a custom jQuery widget?

I have been working on creating a custom widget with a textarea that has multiple rows. I am now looking to change the background color of this widget on the Onfocus and OnfocusOut events. Can anyone guide me on how to achieve this? <!doctype html> ...

The specified type '{ children: Element; ref: MutableRefObject<HTMLDivElement>; }' cannot be matched with type 'IntrinsicAttributes & RefAttributes<HTMLDivElement>' in the assignment

Encountering an issue with fowardRef in ReactJS where everything seems fine, but an error pops up: Type '{ children: Element; ref: MutableRefObject<HTMLDivElement>; }' is not assignable to type 'IntrinsicAttributes & SectionContent ...

Simultaneous asynchronous access to a single object

I have been working with JS/TS for quite some time now, but the concept of race conditions still perplexes me. I am currently attempting to execute the following logic: class Deployer { protected txDataList: Array<TXData>; constructor() { this ...

Is it possible to host multiple React applications on a single port? Currently experiencing issues with running both an Admin panel and the Front side in production mode on the same Node.js API server

Is it possible to host multiple React applications on the same port? I am experiencing issues with running both an Admin panel and a Front side React app in production mode on the same Node.js API server. ...

Create a JavaScript function that adds cells to a table, each containing an input field and a corresponding

I successfully developed a function that appends a table with rows and cells, then fills those cells with data from an array. However, I am now faced with the challenge of modifying it so that the generated cells contain an input field where the value= att ...

Change a camelCase string to ALL_CAPS while adding underscores in JavaScript

Currently, I'm dealing with a situation where I have a list of variables stored in a file that I need to convert into all capital letters and separate them with underscores using JavaScript. The variable pattern looks something like this: AwsKey Aw ...

Attempting to eliminate the parent container of a slide generated by the Slick Slider Plugin

I have developed a filter mechanism that hides specific classes within a slick slider based on the data-tag associated with the objects and the value of checkboxes. However, when these classes are hidden, they still occupy space because I should be hiding ...

Reading JavaScript files using the HTML 5 File Reader

Currently, I am working on a feature that allows users to drag and drop a folder containing JavaScript files into an HTML5 page. Here is the code snippet for my implementation: $scope.files = []; //Establish dropzone var dropbox; dropbox = document.getEle ...

Using Angular UI Router to Access $scope Beyond the Scope of the UI View

Looking for a way to access $scope outside the UI view in my todo app. The structure is simple, with three panels as shown in this design For the full code, visit here I need to access the to-do detail on the third panel using $rootScope, which currently ...

Select specific columns from an array using Typescript

I have a collection of objects and I'm looking for a way to empower the user to choose which attributes they want to import into the database. Is there a method to map and generate a separate array containing only the selected properties for insertion ...

Change "Only" regular text into clickable links without altering any current hyperlinks

Looking to transform plain links into hyperlinks, while leaving existing hyperlinks untouched. A string of text is classified as a link if: It starts at the beginning of a line or after a space ((^|\s)) It is not part of an HTML hyperlink or any ot ...

``Is there a way to effectively assess the Angular UI-Grid cellTemplate function in the attribute value only when it is displayed

Utilizing angularjs and ui-grid with a custom cellTemplate, each cell contains an object referred to as COL_FIELD. This object is passed to a function that generates an image data URI used in the src attribute of the cellTemplate to display images within e ...

Steps for creating a tileView from scratch

Have you noticed websites using a tile view layout lately? It seems like a popular trend. The concept involves having multiple elements on an HTML page with various widths and heights. These websites often use JavaScript to randomly arrange each element n ...

Creating a default option in a Select tag with React when iterating over elements using the map method

After learning that each element in the dropdown must be given by the Option tag when using Select, I created an array of values for the dropdown: a = ['hai','hello','what'] To optimize my code, I wrote it in the following ...

Highlighting syntax on the server side

I have some code blocks that I want to emphasize. Currently, I am using prismjs for this purpose. However, when I try to highlight several code blocks, the page takes more than 5 seconds to load on my somewhat slow PC. Interestingly, if I remove the prism ...

Utilizing Ajax for Dynamically Filling a Dropdown Menu

My journey into the world of Ajax has led me to a state of confusion and frustration. The task at hand is to populate the first box with customer data from the database, then use the customerID to retrieve all vehicleID's using the select.php script. ...

Error Message: Execution Not Recognized and Missing Requirement

After going through numerous threads, I couldn't find a solution to my specific issue. It's quite unclear what I've installed or uninstalled, but I'm hoping that this error message and its details might provide some clarity. Even though ...