Skip to content

rmosolgo/css_modules

Repository files navigation

CSSModules

Build Status Gem Version

An alternative to "magic string" classnames in Sass or SCSS.

Thanks to Fatih Kadir Akın for his post, "How I Implemented CSS Modules in Ruby on Rails, Easily", which led the way on this idea!

Usage

Add modules to stylesheets

Your .sass or .scss stylesheets can define modules with :module(module_name):

:module(events) {
  .header {
    font-style: bold;
  }

  .link:visited {
    color: purple;
  }

  #footer {
    font-size: 0.8em;
  }
}

Sass requires an extra \:

\:module(events)
  .header
    font-style: bold

Put modulized names into HTML

To access the contents of a module in a view, you must include the helpers in your controller:

class EventsController < ApplicationController
  helper CSSModules::ViewHelper
end

(To use the view helper everywhere, include it in ApplicationController.)

Then, in your view, you can access the module & its contents by name:

<!-- access by module + identifier -->
<h1 id="<%= css_module("events", "main_header") %>">
  Events
</h1>

<!-- block helper -->
<% css_module("events") do |events_module| %>
  <div id="<%= events_module.selector("footer") %>">
    <%= link_to "Home", "/", class: events_module.selector("link") %>
    © My company
  </div>
<% end %>

Extra classes

You can also provide multiple, space-separated class names and/or extra class names to join without a module:

# Apply "events" to "image-wrapper" and "image", then add "pull-left" without modification
css_module("events", "image-wrapper image", "pull-left")
#=> "events_123_image-wrapper events_123_image pull-left

Null module

If you pass nil as the module name, no transformation is applied to the selectors.

css_module(nil, "media-row")
# => "media-row"
css_module(nil) do |styles|
  styles.selector("image image--main", "pull-left")
  # => "image image--main pull-left"
end

Use modulized names in JavaScript

In JavaScript, you can include a helper to access module styles:

//= require css_module

// Module + identifier
var headerClass = CSSModule("events", "header")
$("." + headerClass).text() // => "Events"

// Or module helper function
var eventsModule = CSSModule("events")

function header() {
  var headerClass = eventsModule("header")
  return (
    <h1 className={headerClass}>Events</h1>
  )
}

Extra classes

You can also provide multiple, space-separated class names and/or extra class names to add without a module:

// Apply "events" to "image-wrapper" and "image", then add "pull-left" without modification
CSSModule("events", "image-wrapper image", "pull-left")
// "events_123_image-wrapper events_123_image pull-left"

Null module

If you pass null as the module name, CSSModule will make no transformation:

CSSModule(null, "item")
// => "item"

var cssModule = CSSModule(null)
cssModule("item")
// => item

Installation

Add this line to your application's Gemfile:

gem 'css_modules'

And then execute:

$ bundle

Or install it yourself as:

$ gem install css_modules

Implementation notes

  • The gem outputs shorter names when Rails.env.production?
  • Module names are hashed in Ruby and JS, see transform.rb and css_module.js for the hash function

TODO

  • Dead code warning for Development env:
    • Warn when not all styles are used?
    • Sprockets require CSS to JS? require_styles ?
  • Support plain .css
  • Check for hash collisions in development
  • Fix sprockets cache: a new version of this gem should expire an old cache

License

MIT.

About

Local CSS rules for sass, Rails views and JS

Resources

License

Stars

Watchers

Forks

Packages

No packages published