Skip to content

Define reactive CSS rules in Javascript or (preferably) Coffeescript.

Notifications You must be signed in to change notification settings

ccorcos/meteor-reactive-css

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Reactive CSS

This package allows you to define all your CSS rules in a Javascript or Coffeescript and with reactive bindings to Tracker-aware functions.

Check out the live demo. It demonstrates:

  • reactive-responsive deisgn: changes layout when window resizes
  • reactively updating color scheme
  • platform-specific css for Android vs iOS

Getting Started

meteor add ccorcos:reactive-css

The API is highly flexible so choose whatever syntax works best for you.

Basics

The easiest way to get started is by defining nested rules they way you are probably comfortable with in whatever CSS preprocessing language you use.

css
  '.page':
    '.nav':
      'height': '90px'
      'width': '100%'
    '.content':
      'paddingTop': '90px'
      'paddingBottom': '50px'
      'color': 'blue'
      '&:hover':
        'color': 'red'
    '.toolbar':
      'height': '50px'

The other way is more object oriented.

page = css('.page')

nav = page.child('.nav').height('90px').width('100%')

content = page.child('.content')
content.paddingTop('90px')
content.paddingBottom('20px')
content.color('blue')

hoveredContent = content.also(':hover')
hoveredContent.color('red')

toolbar = page.child('.toolbar').height('50px')

Every function returns this so you can chain them, or not.

Units

Units are handled in a few ways. For nested objects, it is sometimes convenient to leave everything as numbers so you can add and subtract them. Thus you can specify the unit by the postfix 2 letters in the CSS rule. For example:

navHeightpx = 90
toolbarHeightpx = 50
css
  '.page':
    '.nav':
      'heightpx': navHeightpx
      'widthpc': 100
    '.content':
      'paddingToppx': navHeightpx
      'paddingBottompx': toolbarHeightpx
      'color': 'blue'
      '&:hover':
        'color': 'red'
    '.toolbar':
      'heightpx': toolbarHeightpx

Valid postfixes are 'px', 'pc', 'vh', 'vw', and 'em'.

The object oriented way is to pass a second string for the units.

page = css('.page')

nav = page.child('.nav').height(navHeightpx, 'px').width(100, 'pc')

content = page.child('.content')
content.paddingTop(navHeightpx)
content.paddingBottom(toolbarHeightpx)
content.color('blue')

hoveredContent = content.also(':hover')
hoveredContent.color('red')

toolbar = page.child('.toolbar').height(toolbarHeightpx)

The defualt unit is 'px' so you don't necessarily have to specify it.

Reactivity

This package is "Tracker-aware". So if you pass a function, it will evaluate the function with Tracker.autorun. This allows you to reactively update CSS rules! Suppose you parameterize your whole app within a reactive dictionary:

styles = new ReactiveDict()
styles.set('primary', 'blue')
styles.set('background', 'white')
styles.set('navHeightpx', 90)
styles.set('toolbarHeightpx', 50)

Then for the nested object you could use:

css
  '.page':
    '.nav':
      'backgroundColor': -> styles.get('primary')
      'heightpx': -> styles.get('navHeightpx')
    '.content':
      'paddingToppx': -> styles.get('navHeightpx')
      'paddingBottompx': -> styles.get('toolbarHeightpx')
      'backgroundColor': -> styles.get('background')
    '.toolbar':
      'backgroundColor': -> styles.get('primary')
      'heightpx': -> styles.get('toolbarHeightpx')

The object oriented way is the same idea, only the units will be the first arguement as opposed to the second. This makes your coffeescript a lot nicer :)

page = css('.page')

nav = page
  .child '.nav'
  .height 'px', -> styles.get('navHeightpx')
  .backgroundColor -> styles.get('primary')

content = page
  .child '.content'
  .paddingTop 'px', -> styles.get('navHeightpx')
  .paddingBottom 'px', -> styles.get('toolbarHeightpx')
  .backgroundColor -> styles.get('background')

toolbar = page
  .child '.toolbar'
  .height 'px', -> styles.get('toolbarHeightpx')
  .backgroundColor -> styles.get('primary')

Mixins

This library is clearly incomplete and it would be concenient if you could extend it nicely. Mixins attach to the css object AND the css prototype. Here's how you define one:

css.mixin 'fullPage', ->
  position: 'absolute'
  top: 0
  bottom: 0
  left: 0
  right: 0

css.mixin 'boxSizing', (args...) ->
  obj = {}
  value = args.join(' ')
  obj['boxSizing'] = value
  obj["Webkit"+capitalize('boxSizing')] = value
  obj["Moz"+capitalize('boxSizing')] = value
  obj["Ms"+capitalize('boxSizing')] = value
  return obj

css.mixin 'borderRadius', (args...) ->
  obj = {}
  # args could be [10, 'em']
  value = args.join(' ')
  obj['borderRadius'] = value
  obj["Webkit"+capitalize('borderRadius')] = value
  obj["Moz"+capitalize('borderRadius')] = value
  obj["Ms"+capitalize('borderRadius')] = value
  return obj

This allows you to add vendor prefixes as you like as well as create convenient helpers which you could use in a few ways:

css '*': css.boxSizing('border-box')

css
  '.page': _.extend css.fullPage(),
    '.nav':
      'backgroundColor': -> styles.get('primary')
      'heightpx': -> styles.get('navHeightpx')

page = css('.page').fullPage()

Now, all that typing can be a pain, especially 'backgroundColor'. So there's an alias function to alias mixins.

css.alias('backgroundColor', 'bg')

Ahh... Much better. No help me expand this package! Or build a responsive framework using reactive window size! Create different styles easily whether on Android or iOS. Or, as in the demo, create a rotating color scheme for your app!

Pros and Cons

There is obviously going to be a tradeoff here. So lets enumerate them.

Pros

  • Create your CSS styles using a turing complete language you are familiar with.
  • Reactively update your CSS styles.

Cons

  • Browsers cannot cache your CSS stylesheets.
  • Tracker.autorun everywhere, but wait, you don't have to use it.

I think its worth it. I hate "battling the framework" when it comes to CSS.

To Do

  • tests
  • template-specific css using Template.name.css(...).
    • can we set inline styles using @find on created?
    • we also need to stop all the associated autorun methods

About

Define reactive CSS rules in Javascript or (preferably) Coffeescript.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published