JavaScript has been injecting life to the websites for a long time and has only evolved since its inception. It is dynamic in every sense and is associated with web development to an extent that one cannot fathom it without JavaScript. Earlier, the use of JavaScript was confined to writing the backend code but swiftly and steadily, it made its foray into the front-end development too. The introduction of JSX by Facebook made it possible to blend HTML markup with JavaScript and spin the magic.
A website essentially comprises three main components- markup, logic and style. Where markup and logic are handled by HTML/HTML5 and JavaScript respectively, it is the CSS that has to take care of the website™s style. HTML and JavaScript are already working hand in hand and the only component that is left out is CSS. Would it not be great if CSS too also worked in conjugation of JS. It would imply that the entire website could be distributed as one .js file that would contain the logic, markup as well as the style. In that case, there would be just one basic style sheet file and the dynamic CSS part would be included in the single .js file.
This idea is not a far fetched one and such a solution has already been devised. Called CSSX, this paradigm brings together JavaScript and CSS and offers a set of tools using which it is possible to write Vanilla CSS in JS. In terms of encapsulation, CSSX resembles JSX and supports the concept of encapsulation. When each component associated with the web development is at one place, managing them becomes a lot easier. There is a concept called separation of concerns which follows the paradigm of separating a computer program into different sections, each one addressing a separate concern. However, as the web is changing, we are becoming more dependent on the browser and unifying CSS and JavaScript makes a lot of sense.
The Working Of CSSX
The idea behind CSSX is to create objects in JavaScript and convert the object literals into CSS code. In a way, the styles are actually coupled with JavaScript and will load as soon as JavaScript is loaded. This also implies that there is no need to have an external style sheet. It sounds simple and easy on the face of it but there are certain issues that need to be resolved before CSSX comes to life.
- Reliance on JavaScript for delivering CSS means that the page would appear without any style for the time that JS takes to load leading to a bad user experience.
- As there is no style sheet, the style property of DOM elements will need to be modified. Changing the attributes of all the elements is not possible and also, media queries and pseudo-classes cannot be kept in a style attribute.
CSSX presents a solution for these problems by creating a library that acts a bridge between the JavaScript code and the style sheet to be applied on the page. The library will be responsible for creating a virtual style sheet and a <style> tag will be associated with it. The CSS rules will be managed with the help of an API also provided by the library. The <style> tag that has been injected with the virtual CSS will have every interaction with JavaScript mirrored to it. Following this approach, we will be able to keep the dynamic styling in sync with the JavaScript. There wouldn™t be any need to define new CSS classes as the rules will be generated at every interaction at runtime.
It is always preferable to inject CSS rather than using inline styling because it does not scale. Having CSS in the JavaScript will enable us to control it just like a regular style sheet. All the operations including new styles definition and their addition & removal are possible without any hassle. The changes will be applied to the pages exactly in the same manner as in the case of CSS static files.
The problem of appearance of unstyled text for a flash second as mentioned above can be resolved by making clear what part of CSS we put in JavaScript. The parts of the CSS that should not be merged with JavaScript and must be kept in static file are typography, color and grid as they are required by the browser to be loaded with the web page. Apart from these components, parts of CSS like classes associated with some action on the page can be loaded with the JavaScript. Single page websites benefit from this paradigm a lot and once the JS is loaded, the style for entire page is also loaded. However, in the case of large web applications, different blocks need to be formed and managed and kept separated. In such cases, how we keep the dependencies of CSS and HTML on JavaScript under check is by grouping them together in one place.
We achieve this grouping by introducing the CSSX library. In order to make this library available to your web application, you can either add the cssx.min.js file on the page or do it using the npm package. This library is required in order to inject the CSSX at runtime.
Let™s have a look at the example to inject a <style> tag in the document in one style sheet.
1 2 3 4 | var sheet = cssx(); sheet.add('p > a', { 'font-size': '20px' }); |
Running this code will add a style tag in the document as seen here.
1 | <style id="_cssx1" type="text/css">p > a{font-size:20px;}</style> |
However, using this code in JavaScript does not serve the purpose. Here, the add method considers the CSS properties as Object literals and this works fine only in the case of a static style declaration.
If we modify the code a little as shown below, we will be able to change the size of the font dynamically.
1 2 3 4 5 6 7 8 9 | var sheet = cssx(); var rule = sheet.add('p > a'); var setFontSize = function (size) { return { 'font-size': size + 'px' }; }; rule.update(setFontSize(20)); ¦ rule.update(setFontSize(24)); |
The above code will produce this output.
1 2 3 | p > a { font-size: 24px; } |
We can clearly see that writing CSS with JavaScript is now object literal composition. It implies that we can use the features of JS to build the object literals. You get options like implementing factory functions, defining variable and other stuff by default. Features like encapsulation and modularity of the code are available to you without putting in the extra effort.
The CSSX library has a basic API with minimalist features because the flexibility is brought about by JavaScript. The actual CSS composition is done by the developers. The functions that are made available are for the actual styles. For instance, groups are created when we write CSS codes and some of these groups are also for the layout structure that includes header, footer and sidebar style.
A CSSX rule object can be used to scope style with this code
1 2 3 4 5 6 7 8 | var sheet = cssx(); // `header` is a CSSX rule object var header = sheet.add('.header'); header.descendant('nav', { margin: '10px' }); header.descendant('nav a', { float: 'left' }); header.descendant('.hero', { 'font-size': '3em' }); |
The output that you will get by using this code snippet is:
1 2 3 4 5 6 7 8 9 | .header nav { margin: 10px; } .header nav a { float: left; } .header .hero { font-size: 3em; } |
You can also use this API for media queries creation and is known to give great results. It is abundantly clear how to write CSS that is valid and can be applied to web page at the runtime. However, this code is nowhere near to vanilla CSS in terms of quality.
Optimizing the CSS for JavaScript
The kind of CSS code we have written so far is not the perfect way to do it. We have wrapped everything inside quotes and optimizations like camel casing and helpers can be performed. However, we will still not be able to achieve the quality that comes with regular CSS. Furthermore, writing vanilla CSS syntax in JavaScript produces an error because JS does not support that format. This is where JSX and transpiler come into the picture.
In the case of JSX, the actual HTML tags do not work in JavaScript. It is the transpiler that translates the JSX to JavaScript at the time of build. Although the build process becomes more complex, lengthy, you get the scalable code and its better organization. This process of transpiling the JSX is performed by Babel- the transpiler for JSX using Babylon Module and it can also be helpful in doing the same with CSS code. All that is needed to be done is to make the Babel understand CSS nodes by substituting it with something the transpiler comprehends. In the CSSX, the cssx notation is replaced by <style> opening and closing tags. Along with it, a regex replacement was run like this:
1 | code = code.replace(/<style>/g, 'cssx(').replace(/<\/style>/g, ')'); |
And the result was what we expected.
Going the Dynamic Way
The benefit that we want to achieve by writing CSS in JavaScript is to lay our hands on a vast range of tools that enable us to do much more than what we are currently able to. The dynamic parts of the CSS, however, are hard to write in JavaScript as wrapping the codes in braces gives rise to other conflicts. Instead, using the grave accent as shown in the code below does the trick.
1 2 3 4 5 6 7 | var size = 20; var styles = <style> .header > nav { font-size: `size + 2`px; padding: 0; } </style>; |
The result of this code snippet was
1 2 3 4 | .header > nav { padding: 0; font-size: 22px; } |
Using this fix, we can use the dynamic parts of the CSS anywhere we like.
Wrapping Up
CSS in JavaScript might look strange to many but the fact is that they have been together since the time we have been using it. We have been compiling the templates in HTML and keeping them inside JavaScript file. CSSX is a way to use the syntax directly in JavaScript and might resemble JSX in terms of workflow and execution. It is still in the experimental mode and will gain maturity as people start to use it more frequently.