DISCOVERY

June 29th, 2021

JSS: The New Standard for Stylesheets

JSS

JavaScript

CSS

Sass

In my relatively short time as a software engineer, I've used many different approaches to writing stylesheets for web applications. My initial naive approach was writing a single CSS stylesheet per application, such as the styles.css file for my SaintsXCTF application that I wrote in college. Although this was a common practice in the early days of web development, lumping an entire website's styles into a single file has many downsides. First, a single stylesheet is difficult to read and gets very long. Second, it doesn't follow programming principles like DRY (Don't Repeat Yourself), abstraction, and encapsulation. Third, CSS lacks many programming language features which enable scalable and reusable code, such as functions, conditional statements, and variables.

June 29th, 2021

While writing this article I learned that CSS recently added variables into its specification1. Variable support is a great new addition (although, unsurprisingly, it is not supported by Internet Explorer). If CSS continues to improve, I may consider its use in certain future applications.

To help bring order to the chaos of CSS stylesheets, different CSS methodologies were introduced. These ensured that CSS code followed certain conventions, thus making it easier to read. One common CSS methodology is BEM, which sets naming conventions for HTML element classes, which are used in CSS code2. I never used these conventions since I believed there was a better alternative: Sass.

Sass is a CSS preprocessor that adds features such as mixins, conditionals, extensions, variables, and more on top of CSS. I've used Sass in both prototype code and production level code. In fact, Sass is the stylesheet language used for this website!

The Sass code for this website (which is written in React) is structured so that each React component has its own stylesheet file. Reusable Sass code is achieved with mixins; mixins are groups of styles that are “mixed in” with other styles. While Sass is nice to work with, it's not without its shortcomings.

For starters, there is no easy way to dynamically change styles based on application state. You can't pass JavaScript variables containing values to Sass to determine which styles to show. Also, even though Sass code can be split into many files, it still creates styles in a global namespace, which can result in unexpected conflicts between stylesheets. One way to remedy this is to give each stylesheet a unique root level CSS selector and make all other styles exist in child CSS selectors.

For example, in a UI component called Note with a Note.scss stylesheet, I defined a root level .jarbek-note CSS selector and two child CSS selectors: .jarbek-note-icon and .jarbek-note-body.

@import "./styles/mixins/elegantIcons"; @import "./styles/mixins/sylexiads"; @import "./styles/variables"; .jarbek-note { display: flex; background-color: lighten($color-warning, 10%); .jarbek-note-icon { @include elegantIcons; font-size: 32px; padding: 10px 30px 10px 10px; color: #555; } .jarbek-note-body { @include sylexiad; } }

These Sass shortcomings are remedied in JSS, my new favorite stylesheet approach for React applications. Although JSS isn't perfect, it has many great qualities which are worth discussing.

JSS, sometimes referred to as “CSS in JavaScript”, is a JavaScript library which allows stylesheets to be authored in JavaScript code. These stylesheets take advantage of the JavaScript language and its ability to create reusable code. JSS also creates unique class names from your stylesheet code, removing any worries of conflicting stylesheet selectors3. As for all those fancy Sass features such as functions, conditional statements, and variables - JSS uses JavaScript, which has all these features and more. In my opinion, JavaScript has a far superior syntax to Sass.

The greatest advantage of JSS is its ability to conditionally change styles depending on application state. Application state for UI applications written in JavaScript is stored in variables, containing primitive or object data types. I'll demonstrate this ability in this article, along with my followup article on React JSS.

JSS code is written with the jss npm module. JSS also supports plugins, although I utilize the default plugins provided by the jss-preset-default npm module4.

I created an npm project which uses JSS to style some basic HTML elements. The code for this project, located on GitHub, consists of an index.html application entrypoint file, an index.js file which adds additional elements and styles them with JSS, and a server.js file which starts a server with Express to host the webpage.

The JSS application displays a running exercise log, similar to those shown on my SaintsXCTF website. When viewed in the browser, the UI looks like the following screenshot:

The JSS code in index.js will be our main focus going forward. At the top of the file, I install JSS and initialize it with the default plugin preset.

import jss from "jss"; import preset from "jss-preset-default"; jss.setup(preset());

Next, I create all the JSS styles.

const styles = { '@global': { body: { backgroundColor: '#000', margin: 0 } }, page: { width: '100%', height: '100vh', minHeight: 500, backgroundColor: '#222', margin: 0, paddingTop: 25 }, exerciseLog: { width: '70%', backgroundColor: FeelColors[currentFeel], border: '2px solid rgb(136, 136, 136)', margin: '0 auto', padding: 7, boxShadow: '0 2px 4px 0 rgba(0, 0, 0, 0.2)', borderRadius: 3 }, headerSection: { display: 'flex' }, titles: { display: 'block' }, titleLink: { color: 'rgb(51, 51, 51)', fontSize: 16, textDecoration: 'none', ...robotoSlabMixin }, title: { fontSize: 16, margin: 0, textDecoration: 'underline', ...robotoSlabMixin }, metadata: { display: 'block', margin: '0 0 0 auto', '& > p': { margin: 0, fontSize: 14, textAlign: 'right', ...robotoSlabMixin } }, bodySection: { marginTop: 20 }, dataField: { margin: 0, fontSize: 14, ...robotoSlabMixin }, description: { marginTop: 10, fontSize: 14, ...robotoSlabMixin }, };

As you can see, JSS styles are simply a JavaScript object! This object contains properties, most of which represent class names. For example, page, exerciseLog, and headerSection are classes that are attached to HTML elements. While most styles created with JSS are written with classes, you can also use CSS at-rules such as media queries (@media) and keyframes (@keyframes)5,6. JSS also allows you to nest CSS selectors within classes, enabling more fine-grained control. JSS has some great examples of these approaches on their website.

As I previously mentioned, JSS creates unique class names for its stylesheets. This means that those page, exerciseLog, and headerSection properties in the JavaScript object aren't the exact class names when rendered in the browser. Instead, JSS creates custom names loosely based on the property names. This behavior is proven by opening the developer tab of our web page and viewing the classes assigned to HTML elements.

As you can see, page was replaced with page-0-0-1, exerciseLog was replaced with exerciseLog-0-0-2, and headerSection was replaced with headerSection-0-0-1. This name mangling prevents naming conflicts when writing multiple classes with the same name in a different JSS style objects.

One thing you may have noticed in the JSS styles was a property called @global.

'@global': { body: { backgroundColor: '#000', margin: 0 } }

This property allows you to define styles in the global namespace as you would in traditional CSS code. In other words, it bypasses JSS' unique class naming, instead applying styles to all HTML elements that match certain CSS selectors.

Another thing demonstrated in my JSS code is how to utilize JavaScript language features to create reusable code. For example, I use a separate object and the JavaScript spread operator to apply matching styles to multiple classes.

const robotoSlabMixin = { fontStyle: 'normal', fontWeight: 'normal', fontFamily: 'RobotoSlab-Regular, Helvetica, serif' } const styles = { ... titleLink: { color: 'rgb(51, 51, 51)', fontSize: 16, textDecoration: 'none', ...robotoSlabMixin }, title: { fontSize: 16, margin: 0, textDecoration: 'underline', ...robotoSlabMixin }, ... }

This code applies the styles in robotoSlabMixin to both the titleLink and title classes. In another example, I create an array of hex color codes and a number corresponding to an index in the array. Both the array and index are used in the JSS style object to determine the background color of an element.

const FeelColors = [ '#EA9999', '#FFAD99', '#EAC199', '#FFD699', '#FFFFAD', '#E3E3E3', '#C7F599', '#99D699', '#99C199', '#A3A3FF' ]; const currentFeel = 6; const styles = { ... exerciseLog: { backgroundColor: FeelColors[currentFeel], ... }, ... };

In my upcoming article on React JSS, I will show how reusability and dynamic styling can be used in a production application.

The final piece of the index.js code creates a stylesheet from the JavaScript object containing JSS styles and attaches them to HTML elements.

const { classes } = jss.createStyleSheet(styles).attach(); document.body.innerHTML = ` >div class="${classes.page}"> >div class="${classes.exerciseLog}"> >div class="${classes.headerSection}"> >div class="${classes.titles}"> >a class="${classes.titleLink}">Andrew Jarombek>/a> >h6 class="${classes.title}">Long Run>/h6> >/div> >div class="${classes.metadata}"> >p>Apr. 11th, 2021>/p> >p>RUN>/p> >/div> >/div> >div class="${classes.bodySection}"> >div> >p class="${classes.dataField}">Location: Riverside, CT>/p> >p class="${classes.dataField}">14.01 miles>/p> >p class="${classes.dataField}">1:39:03 (7:04/mi)>/p> >/div> >div class="${classes.description}"> Went home to CT for the weekend to use the track on Saturday. Got a nice long run in this morning as well, longest since last summer. >/div> >/div> >/div> >/div> `;

In this article I discussed many positive qualities of the JSS library. These include the use of JavaScript syntax, style reusability, dynamic styling, and naming conflict resolution. Despite these great qualities, JSS is not perfect. IDE support isn't great, meaning you won't get the same autocompletion as you would with CSS or Sass. Styles also need to be wrapped in quotes since they are string values assigned to properties. This isn't quite as elegant as CSS or Sass where values such as auto or flex are built into the language itself. Finally, you need to remember to use camel case instead of dash case for styles. For example, font-size in CSS and Sass is fontSize in JSS. Once you get accustomed to JSS that last point isn't much of an issue.

Even with these downsides, JSS is a great library that I highly recommend for new frontend applications, especially those written in React. In my next article, I will discuss React JSS, a library that integrates JSS with React components. I will also showcase how it is used in my SaintsXCTF application. All the code from this article is located on GitHub.