This is a conceptual specification for what could/would/should be the preprocessor to end all preprocessors. Unfortunately, it is just that - a specification. I had made quite a few attempts to create a CSS preprocessor, but I am far too inexperienced with advanced programming to succeed at this task. I got as far as the scanner and half of a half-working tokenizer before proceeding to pull my hair out. So I gave up, and decided just to list the proposed features here for reference. Perhaps these will make their way into existing pre-processors, or even inspire the birth of a new one.
Pretty much everything the 3 leading pre-processors offer in terms of:
- Variables
- Comments
- Mixins
- Functions
- Conditionals
- Logic Operators
- Arithmetic Operators
- Built-in functions
- Color operations
- Property lookup (like in Stylus)
- Nesting
- Embedded Media Queries
- @extend
- Placeholder selectors
- Block Mixins
- @import'ing
Basically, the general rule is that if it exists in at least one of the 3 major CSS preprocessors, it should exist here. Also, every feature should work everywhere, no matter where it is in the context of the code. Variables should be easily usable inside media queries, and dynamic @importing based on the truthfulness of a variable should work.
Stylus offers a feature called property lookup - it is used inside a selector and "bubbles" up all the way to the root until it finds that it exists - which allows you to get the value of properties from a parent context, for example - if I want to change text colour on a button between black/white depending on the color of the background:
.parent
background-color: black
.button
color: light(@background-color) ? black : white
An improvement would be the ability to specify just how far to bubble up using a 0-based index and an optional number of selectors to pick from (imagine this second value as bubbling down rather than up):
@property // bubble to root
@property(0) // only the current selector
@property(1) // only the current selector or it's parent
@property(1, 1) // only the parent selector
What is a pre-processor if not DRY?
-
Optional child selector:
.a > .b? > .c {}
compiles to:
.a > .c, .a > .b > .c {}
-
Multiple Children:
#long-selector > .child > (.grandchild, .other-grandchild) { // code }
compiles to:
#long-selector > .child > .grandchild, #long-selector > .child > .other-grandchild { // code }
-
Mixins should be able to detect the use of other mixins within the same selector:
if (selector.mixins.clearfix() is true) {}
-
a @has directive that allows mixins and functions to inspect any selector at the current point of execution:
if (body @has color: blue) {} or if (.user-avatar @has border-radius) {}
-
ability to define a property on an element from within an entirely different element:
.selector { if (condition) { define .other-selector { property: value } } }
compiles to:
.selector { } .other-selector { }
-
ability to overwrite parent properties using the same syntax as property lookup
.selector { @color(1, 1): red }
-
BIF to remove all declarations associated with a selector for use in mixins e.g.
.selector { remove-declarations(); }
or a specific declaration:
.selector { remove-declarations(@color(1), @font-size(1)); }
-
An events system to monitor variables for changes/redefinition and execute code when it happens:
variable = 'red' .selector color: variable mixin() mixin() @change variable define .selector color: variable variable = 'blue'
You may be thinking "Why would this be useful?" - I'll tell you. Let's say you have a mixin that relies on a settings variable being true. Now, let's assume that mixin overrides something depending on if the setting is true. There's no way the user interacts with this mixin, it's simply there to override something else depending on the truthfulness of a value encountered before it's execution.
What if the user decides to change the setting outside of a conventional settings file? Your override mixin is broken, that's what happens. But with a @change event - the mixin can listen for changes and re-call itself after the change. Nifty, huh?
Hi! I'm currently doing my own css preprocessor (https://github.com/mauro-balades/aurora.css). I love some of the ideas you mentioned and I was wondering if you would we cool with me taking inspirations from these.