CSS in Imba - Inlined Syntax
Tags: imba, css, javascript, vue
Published: 2019-11-15 08:09:04

In this post, I want to go into the language support Imba has for CSS. I am not talking about using `<link href="..." rel="stylesheet">`, but writing the CSS code within the same file of the element you are styling.

## What is Imba?

Quickly before diving into the CSS,  let me tell you a little bit about Imba 😊

Imba is a programming language for writing powerful web apps. It compiles down to JavaScript. The name comes from the gaming term `imbalance`. The interactive learning platform [Scrimba](https://scrimba.com) is a heavy user of Imba. If you want to learn about the language, check out the official documentation at [imba.io](https://www.imba.io/). It's all work in progress so feel free to report any issues you see or lack of things at the [imba.io repository](https://github.com/imba/imba.io/issues).

{% github imba/imba.io %} 


## Inline Styles Properties on Tags

Before the 1.5.0 release, Imba already had syntax for writing CSS. Let's take a look at a line from the private Scrimba codebase (I have permission to use this ;)

```javascript
    var embed = <div css:position="relative" css:paddingBottom="{9/16*100}%">
    
    # Compiled output below
    var _t1, Imba = require('imba'), _1 = Imba.createElementFactory(/*SCOPEID*/);
    var embed = (_1('div').css('position',"relative")).css('paddingBottom',("" + (9 / 16 * 100) + "%")).end();
```

In the above snippet, we set the `position` and `padding-bottom` on the `div` element. The lines can get pretty long since it's inlined into the tag. One thing that some Imba programmers do is break it up into multiline: 

```javascript
    var embed = <div 
    			css:position="relative" 
    			css:paddingBottom="{9/16*100}%">
```

But is that more readable? What if you want to set 7 - 23 different properties? This gets ugly fast. What is the solution to this? Enter SFC!

## Single File Components

In Imba 1.5 experimental multi-line syntax for writing CSS landed. This is how it looks like:

```javascript
    tag embed
    	### css
    	.embed {
    		position: relative;
    		padding-bottom: 40px 
    	}
    	###
    
    # Compiled output below 
    var styles = document.createElement('style');
    styles.textContent = ".embed{position:relative;padding-bottom:40px;}\n";
    document.head.appendChild(styles);
    var Imba = require('imba'), _1 = Imba.createTagScope("fcedc580");
    _1.defineTag('embed', function(tag){
    	/* css
    		.embed {
    			position: relative;
    			padding-bottom: 40px 
    		}
    		*/
    	
    });
```

This enables us to create single file components and makes it so much easier to design interfaces one component at a time 😍

### Optionally Scoped

Similar to Vue.js, the syntax also supports scoping the style to the specific component. 


```javascript
    tag embed
    	### css scoped
    	.embed {
    		position: relative;
    		padding-bottom: 40px 
    	}
    	###
    
    # Compiled output below
    var styles = document.createElement('style');
    styles.textContent = ".embed._fcedc580{position:relative;padding-bottom:40px;}\n";
    document.head.appendChild(styles);
    var Imba = require('imba'), _1 = Imba.createTagScope("fcedc580");
    _1.defineTag('embed', function(tag){
    	/* css scoped
    		.embed {
    			position: relative;
    			padding-bottom: 40px 
    		}
    		*/
    	
    });
```

By using `css scoped` instead of `css` in the comment a class suffix is added. In the above example, `._fcedc580` is appended to the class name `.embed`.
What scoped means in simple terms is that only the elements of that tag type will be affected by the defined style.

Using `scoped` becomes very beneficial when you have lots of tags and files with various styles and would like to select specific things without affecting others. It might not make sense on a landing page but can pay off nicely when you have lots of different layouts and components.

### Implementation - How is Imba doing it?

The syntax is heavily inspired by the way Vue.js does it in vue-loader and Vue SFC. Even the initial prototype used the [@vue/component-compiler-utils](https://www.npmjs.com/package/@vue/component-compiler-utils) package. While useful, unfortunately, that package has a lot of dependencies that would add too much overhead to the Imba language. 

Fortunately, @sombee managed to replace the feature-set by using projects that could be added directly to the vendor directory. This keeps Imba at 0 dependencies 😊 

{% github mdevils/node-css-selector-parser %}
{% github thysultan/stylis.js %}

Both of these projects were picked due to their small footprint.

## Imba Changelog

If you would like to learn about this interactively from a Cast, check out this screencast I did with @somebee on Scrimba 

[https://scrimba.com/p/pdq9quP/c7P26Ehg](https://scrimba.com/p/pdq9quP/c7P26Ehg)

## Heads Up

The syntax is still considered experimental so its possible things will change but hopefully not too much. Some other temporary limitations in the compiler are 

- Not being able to handle values like `!` and `'` which are not encoded / decoded properly [#243](https://github.com/imba/imba/pull/243)
- Also `/* [...] */` css comments cause compile errors [#242](https://github.com/imba/imba/pull/242)

Those errors have been resolved and the related pull requests need to be merged as of this writing.

## Summary

Writing CSS in Imba just got a whole lot easier and even maintaining it now is easier. If you would like to get started with Imba, I have created a boilerplate project based on the [hello-world-imba](https://github.com/imba/hello-world-imba) template.
{% github imba/hello-world-imba-sfc %} 


If you find the boilerplate useful, please star it ⭐️ GitHub stars are appreciated also to our main repository 🙏🏾
{% github imba/imba %}


If you would like to keep up with the Imba development attend our [Bi-Weekly Community meetings via zoom](https://us04web.zoom.us/j/230170873). For the next date see the last [meeting notes.](https://docs.google.com/document/d/1ABGjOJut9eXrajYjdN4G4-UGGU4gvKznLk5CAaXYjso/edit?usp=sharing)

Thank you for reading.