30 8 / 2012

Integrating Prefixr with Rails asset pipeline

Prefixr is cool online service created by Jeffrey Way for adding vendor prefixes to your css. It has nice and simple API to let you integrate it into your workflow. Here is how you can integrate it with Rails asset pipeline.

Just create prefixr.rb file inside config/initializers folder with following content:

require 'uri'
require 'net/http'

class PrefixrPostprocessor < ::Tilt::Template
  def prepare
  end

  def evaluate(context, locals, &block)
    uri = URI.parse "http://prefixr.com/api/index.php"
    Net::HTTP.post_form(uri, { css: data }).body
  end
end

Rails.application.assets.register_postprocessor 'text/css', PrefixrPostprocessor

It defines and registers postprocessor for text/css files. Now, every css file served through rails will be automatically prefixr’d! This will work even if you use sass or less!

The downside of this approach is that it will slow down the development because it will need to make HTTP request to prefixr.com API every time the css file is requested by browser. I wish that there is ruby version of prefixr service as a gem that I could just use directly inside PrefixrPostprocessor. That would be just awesome! Who knows.. maybe I just make one!

25 4 / 2012

Simple HTML5 details polyfill

Although there are many HTML5 <details> polyfills already available, I didn’t like the complexity behind them. Here is how you can create your own from scratch in just few lines of css and js.

The idea was to put as much “logic” as possible in the stylesheet itself. It should hide/show the content based on the presence of open attribute. Here is the sass file:

.no-details details {
  > * {
    position: absolute;
    visibility: hidden;
  }

  > summary, &[open] > * {
    position: static;
    visibility: visible;
  }


  > summary {
    display: block;
    &:before {
      content: "►";
      padding-right: 5px;
      font-size: 11px;
    }
  }

  &[open] > summary:before {
    content:"▼"
  }
}

All children of details tag (except summary) will be by default hidden. If details element has open attribute set, its content will be shown. We could use css :not selector to simplify the css a whole lot, but it is only supported by IE9+, and I’d like polyfill to target IE8+.

And here is the coffeescript:

jQuery ->
  return if Modernizr.details

  $(document).on 'click', 'summary', (event) ->
    $summary = $(this)
    $details = $summary.parent()

    if $details.attr('open')
      $details.removeAttr('open')
    else
      $details.attr('open', 'open')

It simply toggles the open attribute when user clicks on summary. Its as simple as that.

01 4 / 2012

Tagging the HTML tag

Before rails asset pipeline was introduced, I was loading bunch of separate css and js files on every page. Depending on my needs, I would load different set of assets. For example, when I am on the articles/index path, I loaded articles.css and articles.js files (among default ones).

Asset pipeline changed things (for better, of course). Now, all assets are bundled into single application.css and application.js files. This approach was good for a lot of reasons including less requests made to the server (load once, use everywhere) and higher compression rate (when using gzip) all resulting in faster page loads and better ux.


I like to keep things organized. When styling specific page, I want to be very explicit on what I’m styling. Likewise, when writing a script, I want to be very specific when that script should run. Thats why I decided to tag every page in a way that I can reference that info within my css and js files.

In past I tried to do this with html classes, but html5 data- attributes now seem like a way to go.

The idea is to have this:

<html data-controller="articles" data-action="index">
    ...
</html>

This is very easy to achieve by creating custom rails helper method:

module ApplicationHelper
  def html_tag(attributes = {})
    attributes[:data] ||= {}
    attributes[:data][:controller] = controller_name
    attributes[:data][:action] = action_name
    tag(:html, attributes, true)
  end
end

And in the application.html.erb layout file, we simply include

<!DOCTYPE html>
<%= html_tag lang: 'en' %>
  <head>...</head>
  <body>...</body>
</html>

Although a bit controversial, I prefer to generate only <html> opening tag with html_tag method in order to avoid wrapping entire layout file in a block.

Now, if we want to set #content’s background color to yellow only for the articles/index page, we could do this:

html[data-controller=articles][data-action=index] {
  #content { background-color: yellow; }
}

Likewise, we could do this in our coffeescript:

jQuery ($) ->
  return unless $('html').data('controller') == 'articles'
  alert "Welcome to Articles controller"

We can easily add javascript page detection helper method to our App module to simplify this process. It can look something like this:

@App =
  data: (name) -> $('html').data(name)
  controller: -> @data('controller')
  action: -> @data('action')
  path: ->
    p = []
    p.push @controller()
    p.push @action()
    "/" + p.join("/")
  onPath: ->
    for arg in arguments
      return true if @path() == arg
    false

We can rewrite the previous script:

jQuery ($) ->
  return unless App.onPath '/articles/index'
  alert "Welcome to Articles controller, index action"

We can store whatever we like in these attributes. I store vars like module name, current environment, current user’s id and even the public api keys (e.g. for google maps).