GithubHelp home page GithubHelp logo

jonhmchan / descartes Goto Github PK

View Code? Open in Web Editor NEW
443.0 443.0 21.0 2.58 MB

Descartes | Write CSS in JavaScript

Home Page: https://descartes.io/slides

License: MIT License

JavaScript 31.96% HTML 33.48% CSS 34.56%
css javascript

descartes's People

Contributors

e154 avatar jonhmchan avatar prayagverma avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

descartes's Issues

Virtual DOM Compatibility

Descartes looks like a great way to handle CSS. It would be really great if it could work with virtual DOM API's like: Inferno, Snabbdom, Virtual-DOM and others. Working with Decartes in Cycle.js would be especially awesome!

Hard to remember name

It took me days to find your site and I couldn't find it anywhere on Google search with lot of combination of "Javascript" and "CSS". On the last resort, I found HNAPP site that manage to find and I stil can't remember the name easily.
http://hnapp.com/?q=score%3E50%20css%20javascript

For the sake of getting enough exposure without difficulty to recall the name and pronunciation. You might want to change https://descartes.io to Carter or anything that is meaningful.

Create full extension library support

Extensions should be:

  • JavaScript classes
  • Private attributes that describe the library, modifiable at construction
  • Value methods that produce computed values for properties (shorthand for rgba(), modular font-sizes, etc.)
  • Mixins that produce rulesets to be passed as mixins. Methods are prefixed with _
  • A .transform that manipulates the style tree before it is rendered by Descartes. Should take in the style tree as an argument and return a new style tree. This allows for custom rules, rule prefixing, etc.

I've had an initial attempt with Plato.js - you can see that within the src for what this might look like.

iOS does not render styles correctly

img_0647

This happens to me on iOS 8.

Error in console:

TypeError: undefined is not a function (evaluating 'Object.assign')
rowplato.js:43
(anonymous function)styles.js:1:588

Non-JS fallback

If a web page's styles are all set by Descartes, what happens when JavaScript is disabled? Does the user just see unstyled text?

It seems to me that static styles could be generated server-side as a fallback for browsers that do not (or cannot) have JavaScript turned on.

Not JSON

Really cool experiment, I tried to do the same the other way around; inserting scripts into CSS. However, I have something to note. This is not JSON:

new Descartes({
  "html": {
    "margin": 0,
    "padding": 0,
    "body": {
      "margin": 0,
      "padding": 0,
      "section": {
        "max-width": "800px"
      }
    }
  }
})

It's just a javascript object (also noted as literal object). It'd be JSON if it was all a big string, but in this way it's just an object. See one explanation and [another](http://stackoverflow.com/a/2904181/938236 %28reason 3%29).

Implement the cascade for nested rules using &

Right now, the library insists that any rules that have a high priority (furthest from the root) overwrite any styles that are applied to the node from lower priority rules. In other words, cascading does not work by default:

{
    "h1": {
        "color": "red",
        "font-size": 36
    },
    "body": {
        "h1": {
            "color": "blue"
        }
    }
}

results in

<h1 style="color: blue;">

This is (currently) thought to be by-design. Descartes insists that we be explicit about our styles to avoid the complexity of our stylesheets as applications grow. Cascading can be done in a more controlled way by using mixins. It forces reused styles - especially for base elements - to be defined in a mixin and abstracted out. As the application scales, reusable code can get bundled together in a neat way:

var _h1 = {"color": "red", "font-size": 36}

{
    "h1": {
        "_mixins": [_h1]
    },
    "body": {
        "h1": {
            "_mixins": [_h1],
            "color": "blue"
        }
    }
}

<h1 style="color: blue; font-size: 36px;">

However, there are some instances where this lack of cascade is problematic. Especially in the case of appended classes and psuedo-selectors:

"a": {
    "text-decoration": "none",
    "&.dark": {
        "color": "#333"
    }
}

We expect a.dark to inherit the text-decoration: none rule from its parent, but because it is nested within the element, it is ignored. Using mixins in this case seems unnecessary, and forces the developer to be too explicit at the element and class level.

Proposed Solution

Implement the cascade for rulesets that use the & in its selector, such that it inherits the rules of its parent as a mixin. If there's a chain of &-prefixed selector rulesets, the rules should cascade from the root to its grandchildren. This should result in cascading such that rules in a lower priority that conflict with the current ruleset will get overwritten.

Handling multiple style trees

A very common practice is to split styles into multiple files, typically so that certain parts are reusable throughout a site (like grids, fonts, etc.) and others are more specific in scope (styles for a specific page). There's currently no way for Descartes to handle multiple style trees at once, or to have some concept of merging multiple trees so that it cascades predictably. Currently, end users would have to merge the style trees on their own, then pass it into the constructor.

The approach we probably want to take is to have helper functions that merge multiple style trees into a single style tree with the correct prioritization.

Here's the specification we could take:

  • A method called merge that takes two arguments: tree and target
  • tree is typically the smaller style tree that is to be merged into the target tree.
  • target should sensibly default to the Descartes style tree stored in this.tree and initialized in the constructor. This allows for styles to be added to a Descartes instance incrementally.
  • The method should return a merged style tree with the correct prioritization (probably recursively). Given two trees, A and B, The resulting tree should be the same: merge(A, B) === merge(B, A)

Bind listeners to specific rules

Currently, listeners affect the entire ruleset of a selector. For example, if you wanted to have every h1 tag have a random opacity every time you clicked it, it would like this:

h1 {
    _listeners: [this, click],
    opacity: function(_) {
        return Math.random()
    }
}

which in jQuery would be equivalent to:

$("h1").each(function() {
    var _this = $(this);
    _this.click(function() {
        _this.css("opacity", Math.random());
    })
})

This works well for very small examples like those above, but this becomes problematic if there are multiple event bindings and many, many rules that don't need to be computed:

h1 {
    _listeners: [[this, click], [window, resize],
    color: "red",
    "font-weight": 300,
    opacity: function(_) {
        return Math.random()
    },
    "font-size": function(_) {
        return (window.innerWidth >= 800) ? "2.0em" : "1.5em";
    }
}

In the above example, opacity changes when either the h1 is clicked or if the window is resized. Chances are, this second event binding is intended to just change the font-size based on what is being used in the function, and vice-versa. There's no way to specify specific rulesets with specific event listeners. Descartes also reapplies static rules like the font-weight and color rules event when there is no change. It also makes it unclear how to set the default value of opacity or font-size on the initial load.

The proposed solution is to refactor the declaration of event listeners as a new property prefixed with a symbol like $ with the value as the ruleset to be computed upon the event firing. You should also be able to set a default that will be applied on initial load, with the function firing if there is no explicit default specified:

h1 { // No more `_listeners` arrays!
    color: "red",
    "font-weight": 300,
    opacity: 1.0,
    "$this.click": {
        opacity: function(_) { // Does not fire on initial load, since `opacity` is specified already
            return Math.random()
        }
    },
    "$window.resize": {
        "font-size": function(_) { // Fires on initial load, since there is no default `font-size` default
            return (window.innerWidth >= 800) ? "2.0em" : "1.5em";
        }
    }
}

Improve Performance

This is currently the achilles heel in using this library in a production environment. CSS (and the Less, and Sass that can generate it) get all the advantages of being optimized for the browser. Using just JavaScript here means Descartes can't exploit any of those optimizations: how can we improve the performance here? Here are a few ideas and considerations:

  • Generate a stylesheet. Descartes could generate CSS just like other preprocessors so that basic styles can be cached, served, and rendered. The major issue is making sure that Descartes could accurately do so because of dynamic values: since it uses inline styling and actually does style calculation at the node level, it's more specific than traditional CSS would be.
  • Fine tune the code. This should happen anyways, but I have a comparatively naive understanding of JavaScript performance where others in the OS community could really contribute. The library is highly recursive, requires a lot of O(n) run throughs multiple times, and doesn't take full advantage of some of JavaScript's concurrency or caching capability. The more ideas, the better.
  • Eat the cost. Maybe I'm overthinking this? What is really the cost of speed here? Is the flexibility provided by the library to do event-based, highly context-based, and largely cascade free styling worth the cost of performance? In Less and Sass (which also have similar JS libraries that compute style at load time) the cost is not justified because it's mainly used for debugging or development agility, but they do not provide many of the features that Descartes does with DOM-based styling, better computation, and dynamic values. Is there enough in Descartes to tip the scale?

Want to hear people's thoughts.

Using web workers

Related to #26

Currently, Descartes does not take advantage of web workers to increase the performance of the library. I think the vast majority of what Descartes does should be done in background threads.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.