15

what is the best/most efficient way of creating dynamic CSS with Rails. I am developing an admin area on a site, where I would like a user to be able to customize the style of their profiles(Colour mostly), which will also be saved.

Would you just embed ruby script in the css file? Would you need to change the file extension from css?

Thanks.

Matt
  • 2,730
  • 4
  • 28
  • 35

6 Answers6

25

In Rails 3.1, you can have your stylesheets pre-processed by erb.

Now let's say you have some dynamic styling called dynamic.css.scss.erb (the .erb at the end is important!) in app/assets/stylesheets. It will be processed by erb (and then by Sass), and as such can contain stuff like

.some_container {
    <% favorite_tags do |tag, color| %>
    .tag.<%= tag %=> {
        background-color: #<%= color %>;
    }
    <% end %>
}

You can include it like any stylesheet.

How dynamic should it be?

Note that it will be only processed once, though, so if the values changes, the stylesheet won't.

I don't think there is a super efficient way to do have it completely dynamic yet, but it is still possible to generate the CSS for all requests. With this caveat in mind, here's a helper for that in Rails 3.1:

  def style_tag(stylesheet)
    asset = YourApplication::Application.assets[stylesheet]
    clone = asset.class.new(asset.environment, asset.logical_path, asset.pathname, {})
    content_tag("STYLE", clone.body.html_safe, type:"text/css")
  end

Here's how to use it:

First, copy the above helper in app/helpers/application_helper.rb.

You can then include it in your page as follows:

<% content_for :head do %>
  <%= style_tag "dynamic.css" %>
<% end %>
The rest of your page.

Make sure that your layout uses the content :head. For example, your layout/application.html.erb could look like:

...
<HEAD>
  ....
  <%= yield :head %>
</HEAD>
...

I found this out thanks to this post.

Community
  • 1
  • 1
Marc-André Lafortune
  • 78,216
  • 16
  • 166
  • 166
2

You can use ERB with CSS, you just need to render css in the controller. However, for such a heavily requested resource, I do not recommend generating this every time. I would store the users stylesheet in memcached or redis, and recall from it when the page loads, rather than rerendering the file each time. When they update their style, you can expire the cache, just make sure it gets rebuilt when the page renders.

Preston Marshall
  • 1,185
  • 1
  • 8
  • 15
2

There has been a lot of development over the years, and I recently figured out how to do what this question is asking. And since it has been about 9-10 years since someone has answered this, I thought that I would put in my 2 cents.

As others have said, it is not good practice, and thus can not be done, to put ruby code directly into the CSS file as the CSS is precompiled and is not able to be dynamically changed within the file.... BUT, it can be dynamically changed outside the file!

I will need to give a quick synopsis of CSS variables in case future readers do not know how to use them.

CSS has the use of variables within its coding language to make it easier to change a lot of elements at one time. You put these variables at the top of the CSS file in a root section. Like this:

:root {
    --primary: #0061f2;
    --secondary: #6900c7;
}

Now, anytime you want to style an element one of those colors, you can simply put var(--variableName) like this:

.btn{
   color: var(--secondary);
   background-color: var(--primary);
}

.h1 {
   color: var(--primary);
}

You can see how it would then be much easier to change the variable in the root section and thus change all other instances within the CSS.

Now for the dynamic Ruby part.

In the <head> section of your application file (or in the case of this question the file that holds the template for the admin's dashboard), you will need to redeclare the CSS variables with your dynamic variables and mark them as important. For example, let's say that you allow your user to choose primary and secondary colors for their dashboard and they are stored in the user's profile called like: user.primary_color and user.secondary_color. You will need to add this to your <head> section:

<style>
  :root{
    --primary: <%= user.primary_color %> !important;
    --secondary: <%= user.secondary_color %> !important;
  }
</style>

This !important tag will override the variables found in the CSS file thus dynamically allowing the user to change the CSS and view of their dashboard and have it remain persistent (as the values are saved in their profile).

I hope that this helps future developers.

Happy Coding!

  • Very helpful, but do you know of any way to use this same approach but also work with SASS? For example, im wanting to do `lighten(var(--foo), 20%);`, but this is not possible. Any thoughts? – Tony Beninate Feb 10 '21 at 15:54
0

Currently there is a lot of options to generate dynamic css in rails.

You can use less css - is an extension to CSS with extra features.

Gem Less css for rails provides integration for Rails projects using the Less stylesheet language in the asset pipeline.

If you are using twitter bootstrap you may check this out less rails bootstrap.

Also you can use one more CSS extension language Sass for generating CSS. Here is a Saas rails gem.

Check out Dynamic CSS in Rails and Render Rails assets to string blog posts and article about Asset Pipeline

Related SO questions:

Community
  • 1
  • 1
angularrocks.com
  • 26,767
  • 13
  • 87
  • 104
  • Note that if you have any Database dependent logic within your less file, it won't deploy to Heroku. – Trip Mar 19 '14 at 18:16
0

I just built this for another site. I have a controller action and a view that pulls color values out of the database, then renders a customized CSS based on the current user's account. To optimize, I am using the built in Rails page caching, which stores a copy on disk and serves it as a static asset. Nice and fast.

Here's an example from the ERB code

#header { background: <%= @colors["Header Stripe Background"] %>; border: 1px solid <%= @colors["Header Stripe Border"] %>; }
#header h1 {color: <%= @colors["Headline Color"] %>; }
#header p a { background: <%= @colors["Control Link Background"] %>; color: <%= @colors["Control Links"] %>;}
#header p a:hover {background: <%= @colors["Control Link Hover"] %>; text-decoration:underline;}
Joshua
  • 5,336
  • 1
  • 28
  • 42
-1

This solution defines some constants in config/site_settings.rb, which can then be used throughout the Rails application, as well as for automatically generating the CSS files whenever the Rails app starts and the CSS input files have been modified..

http://unixgods.org/~tilo/Ruby/Using_Variables_in_CSS_Files_with_Ruby_on_Rails.html

Tilo
  • 33,354
  • 5
  • 79
  • 106
  • Seems like the link is dead. Instructions should typically be written directly into SO answers to avoid this. – beporter Oct 07 '21 at 17:42