CSS in JavaScript with Angular
Background
For many years the CSS styling world was uneventful. Most new browser styling features were to fix missing and underlying issues with grid systems, web fonts and vector shapes.
Most developers still didn’t have DRY (don’t repeat yourself) ways of coding stylesheets, and resorted to duplicating classes, abstracting classnames or creating hierarchies and applying them to every DOM element. These approaches usually come at a cost of speed of coding and readability for team members who need to pick up the code and make changes.
Compile-to-css revolution
Then along came compile-to-css frameworks such as SCSS, allowing new patterns such as variables, loops, mix-ins and more. When using compile-to-css frameworks such as LESS, SASS, SCSS and others, code is written and compiled into compatible browser CSS, allowing developers more flexibility in choosing source formats and tools which benefit their specific workflows.
In the future we will see functionality from compile-to-css frameworks added to browsers out-of-the-box. But until browsers add the features we have to use compile-to-css tools or css polyfill libraries.
First a caveat
For those who want to stick to browser standards, I suggest using CSSNext to polyfill features until they arrive seems the most logical solution. But for those writing single-page apps who want ease and functionality over standards, JSS provides interesting alternative source format for JavaScript developers.
Advantages of JSS
Some immediate advantages of writing CSS as JavaScript:
- Write just one language (JavaScript or TypeScript)
- Allows auto-suggestions while you type
- Proper type-checking for properties
- Faster compiling and live-reload
- Easier QA and unit testing using values from JavaScript
There are quite a few CSS-in-JS projects out there, and currently no definitive leader, so I picked JSS which I was already familiar with. I wanted to see how easy it was to use JSS in an Angular project (spoiler: It was easy!).
Adding JSS to an Angular project
First start a new Angular app using the ng-cli:
ng new angular-jss
Add the JSS library:
cd angular-jss
npm install jss jss-preset-default
In your angular.json remove any default stylesheets from styles:
"styles": []
In src/app/app.module.ts import the library and run the setup() function:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';import jss from 'jss';
import preset from 'jss-preset-default';jss.setup(preset());@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Create your styles file e.g. src/app/app.component.styles.ts. This will contain your variables, styles etc. In this example we are using different approaches in the same file to show off JSS functionality (variables, functions):
export const red: string = '#F44336'
export const green: string = '#4CAF50'
export const blue: string = '#2196F3'export const styles: Object = {
title: {
textAlign: 'center',
backgroundColor: '#E0E0E0',
'&:hover': {
backgroundColor: '#BDBDBD'
}
},
area: {
width: '100%',
height: '10rem',
color: 'white',
backgroundColor: data => data.area.backgroundColor
}
}
You can now start using the JSS in src/app/app.component.ts. Here we import the styles and variables we want to use, and can dynamically switch them afterwards using JavaScript:
import { Component, OnInit } from '@angular/core';
import jss from 'jss';import { styles, red, green, blue } from './app.component.styles';interface sheet {
readonly classes: Object
readonly update: Function
}@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
public classes: Objectpublic ngOnInit(): void {
const sheet: sheet = jss.createStyleSheet(styles, { link: true }).attach()
this.classes = sheet.classes
sheet.update({
area: { backgroundColor: red }
})
}
}
Finally our app.component.html maps the classes to the DOM elements. As you see here, you reference the variable name, instead of classnames. I find this clearer and it’s easy for error checking than using a string:
<h1 [class]="classes.title">Angular JSS example</h1>
<input [class]="classes.area" type="textarea">
When run in the browser the styles are compiled to css, with auto-generated classnames, and injected into the page!
Demo and source code
You can view a full working example here:
https://kimturley.co.uk/angular-jss/dist/index.html
And grab the full source code here:
https://github.com/kmturley/angular-jss