Skip to content

Instantly share code, notes, and snippets.

@zspecza
Last active December 17, 2022 21:01

Revisions

  1. zspecza revised this gist Jan 28, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion css-preprocessor-spec.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # CSS Preprocessor Micro-Specification <img src='http://dogesay.com/such%20spec'>
    # CSS Preprocessor Micro-Specification <img src='http://dogesay.com/such%20spec///very%20features'>

    ## Introduction

  2. zspecza revised this gist Jan 28, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion css-preprocessor-spec.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # CSS Preprocessor Micro-Specification
    # CSS Preprocessor Micro-Specification <img src='http://dogesay.com/such%20spec'>

    ## Introduction

  3. zspecza created this gist Jan 28, 2014.
    163 changes: 163 additions & 0 deletions css-preprocessor-spec.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,163 @@
    # CSS Preprocessor Micro-Specification

    ## Introduction

    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.

    ## First off, the basic features:

    Pretty much everything the 3 leading pre-processors offer in terms of:

    1. Variables
    2. Comments
    3. Mixins
    4. Functions
    5. Conditionals
    6. Logic Operators
    7. Arithmetic Operators
    8. Built-in functions
    9. Color operations
    10. Property lookup (like in Stylus)
    11. Nesting
    12. Embedded Media Queries
    13. @extend
    14. Placeholder selectors
    15. Block Mixins
    16. @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.

    ## Property lookup improvements

    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
    ```

    ## Handy shortcuts in selectors

    What is a pre-processor if not DRY?

    1. Optional child selector:

    ```
    .a > .b? > .c {}
    ```

    compiles to:

    ```
    .a > .c, .a > .b > .c {}
    ```

    2. Multiple Children:

    ```
    #long-selector > .child > (.grandchild, .other-grandchild) {
    // code
    }
    ```

    compiles to:

    ```
    #long-selector > .child > .grandchild,
    #long-selector > .child > .other-grandchild {
    // code
    }
    ```

    ## Mixin Improvements

    1. Mixins should be able to detect the use of other mixins within the same selector:

    ```
    if (selector.mixins.clearfix() is true) {}
    ```

    2. 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) {}
    ```

    ## Extras

    1. 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 {
    }
    ```

    2. ability to overwrite parent properties using the same syntax as property lookup

    ```
    .selector {
    @color(1, 1): red
    }
    ```

    3. 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));
    }
    ```

    4. 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?