CSSModules
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
andcss_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.