Skip to content
bkardell edited this page Dec 12, 2011 · 20 revisions

Plugins is a thin layer that sits in the browser and provides an "opt-in" extension model which allows you to use (or even define) additional selectors which are not currently a part of a standard. The plugins engine essentially turns uses of these in your CSS into standard CSS which includes a hashed class name in place of your use and gives it back to CSS - it then simply manages the toggling on and off of those class names.

Getting Started

The fastest way to get started is to setup and use interpreted mode. This will parse/compile as you go - once your changes are all finalized and you are very comfortable using plugins, you might consider precompiling.

Once you are setup, you can start using plugins...

USING PLUGIN LIBRARIES: ======================= Using 3rd party plugins (and being able to create them) is really what we're all about... To use additional plugins, you just have to find one (or more) that you like use the require processing instruction to require them in your CSS...
@-plugins-require LIBRARYPATH

And then go ahead and use them as advertised...For example:

@-plugins-require 	math-plugins.js

/* div's which have a cost attribute whose value is numeric and under 100 */
div:-math-lessthan(cost,100){
    background-color: blue;
}
Writing Plugin Libraries ========================= Users can create new filter plugin definitions and register them with the plugin engine. Filter definitions include a test function which is called by the engine when necessary according to their use in CSS. The truthfulness of the rule is determined by the truthfulness of the function's return value. Filters are passed the matched element, any arguments to the filter as a String (and a third object with various meta data described |here|).

Below is a sample (from the -math-* library posted |here|) of a filter which allows filtering of elements based on whether they have a particular attribute, that attribute is numeric and above a certain threshold...

cssPlugins.addFilters([{  
    name: '-my-lessthan',   
    fn:   function(match, argsString){
        var args = argsString.split(",");
        var value = match.getAttribute(args[0]);
        if(!isNaN(value) && !isNaN(args[1])){
            return (value > parseInt(args[1],10));
        };
        return false;
    }
}]);

Definitions can also provide an optional 'base' property whose value is a selector list which must apply in order for the filter to be called - it is essentially an optimization. The advantage of using a base selector is that the engine can potentially better optimize the work/scope that needs to be done, limiting the number of calls to the filter regardless of how the rule is written. In the case of the example above, if we knew that this filter would only ever apply to something with the 'score' attribute, we might choose to optimize it by adding a base:

cssPlugins.addFilters([{  
    name: '-my-lessthan',   
    base: '[score]',
    fn:   function(match, argsString){
        var args = argsString.split(",");
        var value = match.getAttribute(args[0]);
        if(!isNaN(value) && !isNaN(args[1])){
            return (value > parseInt(args[1],10));
        };
        return false;
    }
}]);
Simple Constants ================= A simple mechanism for you to define your own constants for use in CSS.
@-plugin-const  CONSTANTNAME   WHATITREPRESENTS

Did you ever get sick of having to remember, retype and read long selectors?

With constants you can define and reuse them... Instead of:

nav div.toolbox .titlebar span:nth-child(2) .icon:nth-child(1){...}
nav div.toolbox .titlebar span:nth-child(2) .icon:nth-child(2){...}
nav div.toolbox .titlebar span:nth-child(2) .icon:nth-child(3){...}

You can define:

@-plugins-const  -my-toolboxTbButtons    nav div.toolbox .titlebar span:nth-child(2) .icon;

and then your sheet becomes:

-my-toolboxTbButtons:nth-child(1){...}
-my-toolboxTbButtons:nth-child(2){...}
-my-toolboxTbButtons:nth-child(3){...}

it's marginally smaller, to use, but there are considerable advantages in the fact that you need not write/remember/repeat the formulas. If you do this well, it will be considerably easier to read. Because of all of this, you wil find that you require less 'hooks' in your html. A considerably bigger benefit though is that if you change the structure, it is trivial to do so in one place. The top section of your sheet also becomes a nice form of documentation for your most complex structures as well.

But, the values/possible uses of consts are not strictly related to selectors -- they are actually just text-replacements, they will work out for you anywhere... Design a pallette...

@-plugins-const  -my-color1              #f134f4;
@-plugins-const  -my-color2              #gf7892;


h1{
	background-color:   -my-color1;
	color:              -my-color2;
}

In fact, if you are very adventureous you could define blocks (though you will have to escape semi-colons)...

@-plugins-const  -my-panelprops  margin: 10px\; border: 1px solid green\; padding: 1em\;;  


.xPanel{
	-my-panelprops
	background-color: red;
}


.yPanel{
	-my-panelprops
	background-color: blue;
}

However, if you find yourself defining a lot of blocks like this, you should probably look into a more advanced pre-processing tool like SAAS or Less for those purposes.

WHY? ==== The system that we have today, in retrospect, seems like a kind of a bad idea. Having a core standard is definitely a good thing, but innovation in standards bodies is inherently slow and sometimes the things that come out, while beautiful in theory just aren't palletable or sometimes even that useful.

Add to this the fact that browsers have to deal with 100% of the implementation, 100% of the complaints, 100% of the backward support forever, etc. and the fact that browsers have to consider all of their users... HTML and CSS are used for such different things. Consider the living HTML standard single page version which weighs in around 30mb/130k elements and growing every day vs the average web page which is only a tiny fraction of that. Things that are easily plausible for many pages are totally implausible for gigantic pages and the browser manufacturers and working groups need to consider everyone.

Simply put: We feel that the current system puts in place an unfortunate imbalance of incentive/risk/reward and stifles really useful innovation. We feel that it should not be the case that things that are useful to large segments are impossible or made considerably more difficult merely because they are not pragmatic for another segment. It is our hope that this approach will correct some of that imbalance by allowing innovation to be easier and more open - to not be dependent on the browser manufacturer or a standards body and for simple grassroots competition to allow the really useful ideas to gain traction and the really bad ones to die off. When an idea is wildly successful, maybe it's worth considering why and attempting to fill that gap with a native/standard implementation.

These ideas work in many other languages and there is little reason to believe it won't here.

FAQ ======================= **Are there any known limitations?**

_Why, yes there are. What a great question! _

Err... What are they?

We're not telling... If you find one submit it as a bug.

That's not funny.

We disagree.

Seriously: what are the limitations.

Ok, ok... The parser is currently really stupid. It doesn't follow @imports, it will probably puke on media rules or animations. Currently it only runs on "modern" browsers.

Isn't that limiting?

Maybe.

Do you plan to correct that?

In all liklihood we will pattern things so that if you have jquery loaded it will degrade nicely - but beyond that, no. I have IE7 and 70% of websites I visit have clear errors. So what's the point? Choose to use it or don't. You don't need to wait for FF 27 or Chome 32 or IE 52... that's the point.

Any limitations/things to know about speed? How fast is it?

The engine used at runtime is pretty quick... we've tested it with some fairly big trees and it performs really well... But look - it's still running a part of the evaluation as script, so please don't add 1,000 really complex filters and 1,000 uses of those filters which are all based on * and throw it on your crazy page with 100,000 elements and then say "it's really slow". If you have a few dozen rules based on decent selectors (a few * are ok) that employ semi-efficient plugins and your page is within even a few times as big as "average" it will be 'beyond human comprehension' kind of fast - and isn't that what really matters?.

Can I add new tokens for use in selectors? For example, I would like to say something like "div < .x".

No. Not now, not ever. Forget it.

Can I add new modules?

No, not now at least...

Why not?

Modules in CSS are (currently at least) all about rendering pretty specific kinds of things and they involve very specific cascade and calculation semantics which make them considerably more difficult to extend in this manner.

So I never will be able to?

Never say never. There might be some possibilities... If you have some suggestions or ideas, send them our way.

Can I add new types/functions?

No, not now at least - for most of the same reasons as above. In all likelihood this would be even more difficult to add with the current APIs available to us. Hopefully changes in CSSOM will make this things more plausible... It seems as if this would be an ideal extension point, however, it's not nearly as difficult add a mechanism for that from the browser's perspective as it is from outside the browser. Again, if you have some ideas - we're all ears.

Setup (interpreted mode) ======================== Interpreted mode currently relies on JQuery 1.5 or greater. To get started, mark a link or style tag in your page with the -plugins-interpret attribute, include your preferred version of jQuery (we recommend using one of the existing CDNs) and the interpreted version of the library. It should look something like this:
<link rel="stylesheet" href="styles.css" type="text/css" -plugins-interpret="true"  />
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js"></script>	
<script type="text/javascript" src="plugin-interp-jquery.js"></script>

Setup (pre-compiled/production mode) ==================================== You can use the rulecompiler tool to create precompiled versions (very fast) for production. The output of the tool will show you what to include. In the end it will look something like this (note there are no dependencies in this version and the engine itself is <2k):
<link rel="stylesheet"  href="styles-compiled.css" type="text/css" />
<script type="text/javascript" src="cssPlugins.js"></script>
<script type="text/javascript" src="myPlugins.js"></script>
<script type="text/javascript" src="styles-compiled.js"></script>
"Out of the Box" Extensions =========================== The library itself adds one (we think) very useful selector.
:-plugins-any(ANY SELECTOR)

This works just like all of the other prefixed -any- selectors in the sense that they allow you to say something like:

div span:-moz-any(.foo,.bar,.bat) .bit{ .... }

instead of what you are forced to do today without them....

div span .foo .bit .bit, 
div span .foo .bar .bit,
div span .foo .bat .bit{ .... }

of course, part of the problem is that you cannot realistically use them until the prefixing is removed or you would wind up repeating the whole rule, not just a bit of selector:

div span:-moz-any(.foo,.bar,.bat) .bit{ .... }
div span:-o-any(.foo,.bar,.bat) .bit{ .... }
div span:-webkit-any(.foo,.bar,.bat) .bit{ .... }
div span:-ms-any(.foo,.bar,.bat) .bit{ .... }

When will that happen? IE15? I dont know - but I dont want to wait to do useful things in modern browser either.

The second big difference is that you can use complex selectors with -plugins-any... Extended filters always count as a single argument (in fact, under the covers they are).. For example, the following is impossible with the currently implemented/proposed native versions:

div :-plugins-any(span .foo, div .bar, .foo .x .y) .z{ .... }

because they accept only a simple list just like some of the other pseudo-filters like :not Likewise, you can use :-plugins-any inside a :not to make that selector more capable than it is natively:

div .x:not( :-plugins-any(span .foo, div .bar) ) .z { .... }