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 is a heavy user of Imba. If you want to learn about the language, check out the official documentation at 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.
Official site for Imba. Work in progress.
Run
# clone the repository
git clone https://github.com/imba/imba.io
# enter the folder
cd imba.io
# install dependencies
npm install
# package content from content/ (continously)
npm run watch
# run server
npm start
Because the site uses service workers it requires https: with a trusted certificate. To test things in development you need to do it via Chrome launched with specific args:
open -na Google\ Chrome --args --ignore-certificate-errors --allow-insecure-localhost --unsafely-treat-insecure-origin-as-secure=https://localhost:9000
# if this does not work - try
# /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --allow-insecure-localhost --ignore-certificate-errors --unsafely-treat-insecure-origin-as-secure=https://localhost:9000
Now visit https://localhost:9000/ in that browser.
Having trouble with https?
https is required to be able to run the examples and snippets. You can still run the rest of the site and work on documentation without this. So, if you're having trouble setting up https use the npm start-without-https
command instead of the normal npm start
…
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 ;)
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:
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:
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.
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 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 😊
mdevils
/
css-selector-parser
Just a CSS selector parser.
node-css-selector-parser
Fast and low memory CSS selector parser.
Parses CSS selector into object-model.
Installation
npm install css-selector-parser
Usage
var CssSelectorParser = require('css-selector-parser').CssSelectorParser,
parser = new CssSelectorParser();
parser.registerSelectorPseudos('has');
parser.registerNestingOperators('>', '+', '~');
parser.registerAttrEqualityMods('^', '$', '*', '~');
parser.enableSubstitutes();
var util = require('util');
console.log(util.inspect(parser.parse('a[href^=/], .container:has(nav) > a[href]:lt($var)'), false, null));
Produces:
{ type: 'selectors',
selectors
[ { type: 'ruleSet',
rule:
{ tagName: 'a',
attrs: [ { name: 'href', operator: '^=', valueType: 'string', value: '/' } ],
type: 'rule'
…STYLIS
A Light–weight CSS Preprocessor.
Installation
- Use a Direct Download:
<script src=stylis.js></script>
- Use a CDN:
<script src=unpkg.com/stylis></script>
- Use NPM:
npm install stylis --save
Features
- nesting
a { &:hover {} }
- selector namespacing
- vendor prefixing (flex-box, etc...)
- minification
- esm module compatible
- tree-shaking-able
Abstract Syntax Structure
const declaration = {
value: 'color:red;',
type: 'decl',
props: 'color',
children: 'red',
line: 1, column: 1
}
const comment = {
value: '/*@noflip*/',
type: 'comm',
props: '/',
children: '@noflip',
line: 1, column: 1
}
const ruleset = {
value: 'h1,h2',
type: 'rule',
props: ['h1', 'h2'],
children: [/* ... */],
line: 1, column: 1
}
const atruleset = {
value: '@media (max-width:100), (min-width:100)',
type: '@media',
…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
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 - Also
/* [...] */
css comments cause compile errors #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 template.
imba
/
hello-world-imba-sfc
Barebones Imba example using SFC
Hello World Imba SFC
Tiny template for testing out Imba SFC. The project is based on the hello-world-imba template.
This example uses vanilla CSS to show scoped and global examples which was introduced in Imba v1.5.1.
Getting started
git clone https://github.com/imba/hello-world-imba-sfc
cd hello-world-imba-sfc
yarn # npm install
You can run the app in two ways, either served via the webpack-dev-server or Express.
Webpack
# start webpack-dev-server and compiler
yarn run dev # npm run dev
Server side
./node_modules/.bin/imba src/server.imba
If you find the boilerplate useful, please star it ⭐️ GitHub stars are appreciated also to our main repository 🙏🏾
Imba is a friendly full-stack programming language for the web that compiles to performant JavaScript It has language-level support for defining, extending, subclassing, instantiating and rendering DOM nodes.
Get started
npx imba create hello-world
cd hello-world
npm start
Documentation
To get started with Imba, we recommend reading through the official guide.
Why Imba?
Minimal syntax
Imba's syntax is minimal, beautiful, and packed with clever features. It combines logic, markup and styling in a powerful way. Fewer keystrokes and less switching files mean you'll be able to build things fast.
Runs on both server and client
Imba powers both the frontend and the backend of Scrimba.com, our learning platform with 100K+ monthly active users. On the frontend, Imba replaces e.g., Vue or React, and on the backend, it works with the Node ecosystem (e.g., npm).
Integrated styling
Inspired by Tailwind, Imba brings styles directly into your code. Styles can be…
If you would like to keep up with the Imba development attend our Bi-Weekly Community meetings via zoom. For the next date see the last meeting notes.
Thank you for reading.
Top comments (3)
Thanks, Alexander. I loved this :)
Is there a pythonic way mm like imba.
I am still new to writing here so hopefully, the quality will improve over time, but glad you like it :D
Ahem... I don't really know Python web stuff that much other than Django, Brython and some other random projects. Unfortunately, I don't know of any projects similar to Imba in the Python ecosystem.
Thanks.