A neat but hacky way to add customisable style changes to a web application
Tags: javascript, jQuery, dotnet, css
Published: 2020-04-17 16:34:26


## Adding configurable HTML css variables styling and the css jquery attribute with Bootstrap

## The challenge faced with my website development
I am not a full-on website developer - nope. If I could happily not worry about the umpteen other tiers within the framework, I would HAPPILY raise my game on the web development front. Certainly am very interested in Svelte.js in the future and recognise the drawbacks to jQuery. I still use Knockout.js and have zero intention of going anywhere near Angular.js.

My website is using .Net Core where I have added my own view components and plugins to incorporate Piranha CMS. The goal is to be able to have enough core functionality so that, if other developers work with me with superior web skills to my own (shouldn't be hard) - we should be able to enhance the quality of the website and let me move more towards the data and the back-end.

Equally, I don't want to be completely tied to Piranha CMS just in case there are major problems with it (which I don't think there is).

## Quick concepts
#### CSS variables
```css
    --ir-primarycolor: var(--primary); /*#FF9400;*/
```
As we can see, --primary is the twitter bootstrap variable for primary. To give some form of abstraction from bootstrap, I map it to my own variable (which might make things worse :).
#### The Opacity and background color css properties
```css
    opacity:0.5;background-color:var(--danger);
```

#### CSS RGBA function
```css
    background-color:rgba(255,0,0,0.3);
```
Not much use if we work with hexadecimal and there is no CSS way to map from hexadecimal to rgba.

#### A translation library to the rescue
https://github.com/BramVanroy/rgba-generator

#### Twitter Bootstrap (or Bootstrap as it is known)
[https://getbootstrap.com/docs/4.0/getting-started/introduction/](https://getbootstrap.com/docs/4.0/getting-started/introduction/)
So... I like Bootstrap, but it is obtrusive. It gets into your codebase. To get around some of these limitations, I do make quite a lot of use of Dependency injection of classes from .Net Core into views with some bootstrap. Sounds like overkill but it can reduce having css hard coded in razor views.

### Framing the problem
On a lot of more modern web pages, we see panelled backgrounds covering the whole screen, sometimes with filter overlays. Sometimes we want insets or objects within objects - i.e. a div inside a div. We want the outer div to be a different colour and the inner div to overlay it to enhance the text but to have a transparent feel.

One other thing is to avoid the RGB translation from the named bootstrap variables. Indeed why not use other variables?

#### Big CAVEAT
- Yes, I know full well, we can use css mixins with js pre-processors.
- Agreed it is 2020, not 2010.

BUT... 
> "How many frigin technologies does it take to create a website?"
> "How many men does it take to change a lightbulb?"
> "How many medical staff can appear in a TikTok dance video?"
#### Other Challenges
I want to still try to retain as much control inside the css file, but without having to continually keep adding to the CSS file for more advanced styling.

## The JavaScript/jQuery code
I will just dump a load of code snippets in and explain them in the next section.
### My approach when developing with JavaScript
A great deal of the JavaScript gurus will go mad at this. Unfortunately, JavaScript has been made too hard and uses too many frameworks for me to ever get excited about it. I thought about plugging in require.js, read their documentation, looked inside the node_modules folder after running the quick page installer to find the documentation didn't match what was in the folder and thought - "Perfection shouldn't be at the cost of sanity. Somebody out there loves this nonsense, but not me." I do make use of node_modules BUT if something seems too hard, better just get on with living.

### The use of the bundleconfig.json in a smart way
```json
  [{
    "outputFileName": "wwwroot/plugins/irplugin.js",
    "inputFiles": [
      "assets/plugins/*.js"
    ],
    "minify": { "enabled": false }
  }]
```
### The JavaScript code
```javascript
function IRGetFile() {
    var json = $.getJSON({'url': "/localdata/FormattingConfiguration.json", 'async': false });

    //The next line of code will filter out all the unwanted data from the object.
    json = JSON.parse(json.responseText); 
    return json;
}

function IRGetRGBAText(variableSetting) {
    /* using https://github.com/BramVanroy/rgba-generator */
/*This is bad code as I should probably pass in each specific field in...*/
    const variableValue = IRTryGetVariable(variableSetting.cssVariable);

    const rgbaText = $.rgbaGenerator(variableValue, { addAlpha: variableSetting.alpha });

    return rgbaText;

}

function IRTryGetVariable(cssVariable) {
    try {
        const variableValue = getComputedStyle(document.documentElement, null).getPropertyValue(cssVariable);
        if (variableValue.length > 0) {
            return variableValue;
        }
    }
    catch (exception) {
        console.log(exception);
    }
    return cssVariable;
}

function IRApplyStyles(variables) {


    $(variables).each(function (index, value) {
        var cssProperties = {};

        var backgroundFilter = IRGetRGBAText(value);

        var cssString = "";

        if (backgroundFilter !== null)
        {
            cssProperties['background-color'] = IRGetRGBAText(value);
        }

        if (value.additionalClasses !== null) {
            $(value.additionalClasses).each(function (position, additionalClass) {

                cssProperties[additionalClass.property] = IRTryGetVariable(additionalClass.value);
            });


        }
        $(value.class).css(cssProperties);
    });

}

let cssVariables = IRGetFile();

IRApplyStyles(cssVariables);
```
### The current json configuration file
```json
[
  {
    "class": "div.ir-content-data:nth-of-type(even) > div",
    "cssVariable": "--dark",
    "alpha": 0.7,
    "additionalClasses": [
      {
        "property": "font-family",
        "value": "'Comic Sans'"
      },
      {
        "property": "border-radius",
        "value": "30px"
      },
      {
        "property": "color",
        "value": "var(--light)"
      }
    ]
    
  },
  {
    "class": "div.ir-content-data:nth-of-type(odd) > div",
    "cssVariable": "--success",
    "alpha": 0.9,
    "additionalClasses": [
      {
        "property": "font-family",
        "value": "'Comic Sans'"
      },
      {
        "property": "border-radius",
        "value": "30px"
      },
      {
        "property": "color",
        "value": "var(--danger)"
      }

    ]
  }
]
```
## Explanation of the code
### Bundle Config.json
A relatively neat way to drop modules into a plugin area which are pure JS is to let the bundler pull *.js files from a folder and dump them into a single file. Now... This isn't great as it is bound to slow the page load times down, but better developers than me can optimise this sort of stuff.
### The FormattingConfiguration.json
I decided to make this a configurable json file. The main goal was to permit styling of a div class within a div class, but it was decided that rather than hard coding/soft coding inside razor views (.Net Core html like files) some extra flexibility could be gained by allowing configuration of css properties.
Certainly, the structure of it is not quite right.
### The JavaScript (JS) code
So... again, I could probably improve the whole code structure with another half a day. For example, encapsulate the code, maybe make it an extension method on top of jQuery etc.

However, the code is focused on taking a set of configurations for a css selector and applying certain css properties and values without having to change the style sheet.

The code utilises jQuery and a neat little helper library to translate from named css variables OR Hexadecimal to RGBA.

Finally, the code has a little defensiveness to try and handle errors.

## Conclusion on adding a little bit of configurable styling outside of any compiled files
I feel pretty happy with this approach. I find Bootstrap to have a few crinkles the less hard coding I do of variables inside the custom.css file which overrides Bootstrap default styles the better.

There has been no need to force a recompilation or build of anything, we could drop a new configuration file into test new looks and feels.

Certainly we should not over rely on this approach used here. We understand that jQuery does have some performance issues with updating the DOM. It would be great to modernise the client-side stack being used.

Unfortunately, building websites entails a lot of trial and error with different frameworks, some people are crazy enough to build their own :). My approach is to avoid getting too ensnared into another framework's way of doing things as too often, when it has an upgrade it no longer works.


> Written with [StackEdit](https://stackedit.io/).