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.
Imba's official website and documentation.
Contributing
Contributions are highly appreciated. The easiest way to contribute to the documentation is by editing /content/docs/undocumented.md.
This includes:
-
Polishing any of the undocumented examples or creating your own examples.
-
Moving examples from undocumented to a relevant location on the documentation.
-
Coming up with proper names for undocumented features with ambiguous names.
For big changes it's best to ask first. You can reach out to us on Discord or create an issue here on Github. We don't bite!
Installation
Fork the repository, then:
git clone https://github.com/your-fork/imba.io
cd imba.io
npm i
npm run dev
Contributing Guide
Adding Documentation
You can find the main documentation in /content/docs/
.
See our proprietary markdown syntax guide below.
Adding API Reference Examples
To add your own example, add it to /content/examples/api/
.
The API docs are unique in that they are automatically included as examples for any…
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.
css-selector-parser
- Fast and low memory CSS selector parser.
- Parses CSS selector into object-model (AST).
- Compliant with all historical and modern CSS specs.
- Covered with tests.
- Documented.
- Supported CSS selector standards
-
css1
: https://www.w3.org/TR/CSS1/ -
css2
: https://www.w3.org/TR/CSS2/ -
css3
/selectors-3
: https://www.w3.org/TR/selectors-3/ -
selectors-4
: https://www.w3.org/TR/selectors-4/ -
latest
: refers toselectors-4
-
progressive
:latest
+ accepts unknown psudo-classes, psudo-elements and attribute case sensitivity modifiers
-
Important:
Latest releases: Changelog.
Installation
npm install css-selector-parser
Usage
Parsing
import {createParser} from 'css-selector-parser';
const parse = createParser();
const selector = parse('a[href^="/"], .container:has(nav) > a[href]:nth-child(2)::before');
console.log(selector);
Produces:
({
type: 'Selector',
rules: [
{
type: 'Rule',
items: [
{ type: 'TagName', name: 'a' }
…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
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
Try Imba instantly in your browser with our playground, or create a new project with:
npx imba create
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.
import './util/reset.css'
global css html,body m:0 p:0 w:100% h:100%
tag login-form < form
css input rd:md bc:gray3 h:20px fs:md
css button rd:md c:white
…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 (2)
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.