Skip to content
/ blink Public
forked from jednano/blink

Blink is an open-source CSS Authoring Framework.

License

Notifications You must be signed in to change notification settings

prabinv/blink

 
 

Repository files navigation

blink

Blink is an open-source BEM CSS Authoring Framework on Node.js.

Build Status Dependency Status NPM version Views

NPM

Requirements

Features

  • Runs on Node
  • OOCSS with BEM syntax
  • Extenders
  • Rules
  • API
  • TypeScript source

Feature Roadmap

  • Spriting

Runs on Node

Because blink runs on Node, you have access to all JavaScript syntax, including variables and functions, as well as file I/O. The possibilities are endless.

OOCSS with BEM

Blink is designed with BEM syntax in mind. You can create blocks, elements and modifiers and their CSS selectors will be generated for you. You can configure your BEM format however you want, but the default naming convention follows that which is defined in MindBEMding – getting your head 'round BEM syntax.

Here's an example of a block with both an element and a modifier:

///<reference path="./node_modules/blink/blink.d.ts"/>
import blink = require('blink');

var btn = new blink.Block('btn', {

	min: {
		width: 80
	},

	elements: [
		new blink.Element('foreground', {
			color: 'black'
		})
	],

	modifiers: [
		new blink.Modifier('wide', {
			min: {
				width: 120
			}
		})
	]
});

export = btn;

This would generate the following CSS:

.btn {
	min-width: 80px;
}

.btn__foreground {
	color: black;
}

.btn--wide {
	min-width: 120px;
}

Extenders

Extenders are named functions that return an array that is described in more detail below. An extender with no parameters always returns the same output. For example, here's an extender named fill that fills its container:

export function fill() {
	return [arguments, () => {
		return [
			['position', 'absolute'],
			['top', '0'],
			['right', '0'],
			['bottom', '0'],
			['left', '0']
		];
	}];
}

Let's create two blocks named .foo and bar that both extend fill.

console.log(blink.compileRules([
	new blink.Block('foo', {
		extend: [ fill ]
	}),
	new blink.Block('bar', {
		extend: [ fill ]
	})
]));

These two blocks share the same extender, so there's no reason to generate the same CSS twice. The above code would output the following:

.foo, .bar {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
}

This is very powerful, especially when you want to spit-out multiple declarations. Why, you ask? Because you only have to spit-out those declarations once! You can extend it from hundreds of blocks, but those lines never get written more than once. This keeps your CSS as lean as possible.

Now, let's talk about building your own extenders. The basic structure of an extender is thus:

export function nothing() {
	return [arguments, () => {
		return [];
	}];
}

This extender, as its name suggests, does nothing. The name, however, must be provided and must be unique.

In this case, the extender has no arguments; yet, they must also be returned for unique registration purposes.

Let's see what a more complicated, inlineBlock extender would look like.

export function inlineBlock() {
	return [arguments, () => {
		return ['display', 'inline-block'];
	}];
}

This is all fine and good, but it's pretty useless. We can add a verticalAlign option to make it more dynamic.

export function inlineBlock(options?: { verticalAlign?: string }) {

	options = options || {};

	return [arguments, () => {
		var decs = [];
		decs.push(['display', 'inline-block']);

		if (options.verticalAlign !== null) {
			decs.push(['vertical-align', options.verticalAlign || 'middle']);
		}

		return decs;
	}];
}

Great, but what about inline-block CSS hacks? Glad you asked! You can gain access to the configuration for a case like this.

///<reference path="./node_modules/blink/blink.d.ts"/>
import blink = require('blink');

function inlineBlock(options?: { verticalAlign?: string; }) {

	options = options || {};

	return [arguments, (config: blink.Configuration) => {
		var decs = [];

		if (config.firefox < 3) {
			decs.push(['display', '-moz-inline-stack']);
		}

		decs.push(['display', 'inline-block']);

		if (options.verticalAlign !== null) {
			decs.push(['vertical-align', options.verticalAlign || 'middle']);
		}

		if (config.ie < 8) {
			decs.push(['*vertical-align', 'auto']);
			decs.push(['zoom', '1']);
			decs.push(['*display', 'inline']);
		}

		return decs;
	}];
}

Now, that's a nice extender! Once you change your configuration to support newer browsers, the CSS hacks disappear. No need to change any of your source code. It's all about the configuration.

Extender registration

It's important for you to know that, behind the scenes, blink is really smart about extender registration. It doesn't just register your extender by function name, but also by the arguments you pass in. This means if you extend inlineBlock({ verticalAlign: 'top' }) 50 times and inlineBlock({ verticalAlign: 'bottom' }) 20 times, only two rules will be generated. Different input yields different output, so it has to generate two rules for this scenario.

Where are the includes and mixins?

You might be wondering if blink supports includes and mixins. The answer is yes and no. It is a blink philosophy that includes have traditionally been used in cases where extension was more appropriate. As such, the include paradigm has been included in the extenders themselves. All you have to do is extend everything and blink will determine whether your extension can be shared across rules or not. It's just one less thing for you to worry about and it results in automatically leaner CSS.

As for mixins, they are really no different than functions, which are made available to you in normal JavaScript syntax.

That said, you can, technically, include extenders in your rules. That is how blink works behind the scenes, so it does work, but it's undocumented, unsupported and encouraged against. If you come up with a valid use case, open an issue and it will be discussed.

Rules

Outside of BEM blocks, you'll definitely need to write rules for page defaults. For this, a Rule class is made available to you:

///<reference path="./node_modules/blink/blink.d.ts"/>
import blink = require('blink');

var normalize = [

	new blink.Rule(['html'], {
		font: {
			family: 'sans-serif'
		}
	}),

	new blink.Rule(['body'], {
		margin: 0
	}),

	new blink.Rule(['a:active', 'a:hover'], {
		outline: 0
	})

	// ...

];

export = normalize;

You are encouraged to use BEM blocks for all of your components. There's nothing stopping you from using basic rules, but you should avoid them if at all possible.

Node API

With all the new build tools and taks runners springing up, blink was built with that in mind, that various tools would need access to the compiled results without writing any files to the disk.

TypeScript source

Since blink source code is written in TypeScript, you don't need to constantly look-up documentation to gain insight as to how you can use the blink API. Unfortunately, although there is TypeScript support for other editors, you won't get the powerful feature of Intellisense unless you are using Visual Studio.

BTW, you can write your blink files in TypeScript or JavaScript. It really doesn't matter as long as it ends up in JavaScript.

Getting Started

CLI Usage

$ npm install -g blink

Library Usage

$ npm install --save-dev blink
///<reference path="./node_modules/blink/blink.d.ts"/>
import blink = require('blink');

compile(options: IConfigurationOptions, files: string[], callback: (exitCode: number) => void): void

Compiler(public config?: Configuration)

compile(files: string[], callback: (err: Error, results?: ICompiledResult[]) => void): void
compileRules(rules: Rule[]): string

ICompiledResult

interface ICompiledResult {
	src: string;
	dest: string;
	contents: string;
}

IConfigurationOptions

interface IConfigurationOptions {

	config?: string;

	// Output style
	style?: string;
	oneIndent?: string;
	quote?: string;
	newline?: string;

	// BEM
	block?: string;
	element?: string;
	modifier?: string;

	// Cross-Browser Support
	chrome?: number;
	firefox?: number;
	ie?: number;
	opera?: number;

}

License

Released under the MIT license.

Bitdeli Badge

About

Blink is an open-source CSS Authoring Framework.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published