Blog

Thoughts from my daily grind

Lighten or Darken a CSS Colour in Ruby on Rails

Posted by Ziyan Junaideen |Published: 13 April 2021 |Category: Ruby on Rails
Default Upload |

Lightning or darkening a given color is a common requirement in user interface development. For example we will have a button with a box-shadow property that is darker than the button background-color. Most of such styles will go bundled with the the primary stylesheets. It also comes handy to have ways to dynamically generate CSS in cases of user configurable themes. Here are few ways you can lighten and darken a given HEX color in Ruby.

Note: While HEX is sued as an example, you can use any color definition in y understanding.

Static Usage - Stylesheets

If your needs are static and it doesn't change by any user configuration (ie: styles stored in a database) you can use the Sass lighten and darken helpers.

Ex: app/assets/stylesheets/themes/default.sass

$default-color: #4f99a6

.btn
  .btn-defeault
    background-color: $default-color
    box-shadow: 0 3px 0 darken($default-color, 15%) 

Dynamic Usage - Views & Helpers

There are times when we need to dynamically generate styles. For example assume a SaaS web application. It would need to allow its tenants to custom choose backgrounds, button colors, alert styles etc. In such cases we can't rely on compiled assets as they are compiled deploy time. Instead we need to generate them on the fly. As a result if you are doing this, it would be good to keep in mind to cache to save compute in repeated requests.

Saas in Haml Views

HAML supports inclusion of Sass styles in views. It also supports ruby variable interpolation. As a result you can inject Ruby variables easily in to Saas blocks effortlessly.

Ex: app/views/layouts/tenant.html.haml

sass:
$default-color: #{current_tenent.theme.colors.default}

.btn
  .btn-defeault
    background-color: $default-color
    box-shadow: 0 3px 0 darken($default-color, 15%) 

Slim

Unfortunately the way Slim integration with Saas works, it doesn't support injecting variables. How ever it does support variable injection in markdown, textile and rdoc. Hopefully they will support it in the future.

The approach I take in projects with Slim templates is different. It is...

  1. Have an ERB template to generate the necessary Sass (ex: app/layouts/tenant/_theme.erb)
  2. A helper method to render the template and covert it to CSS

Ex ERB template app/views/layouts/tenant/_theme.erb

$default-color: <%= theme.colors.default %>

.btn
  .btn-default
    background-color: $default-color
    box-shadow: 0 3px 0 darken($default-color, 15%)

Ex Helper method

def render_tenant_theme
  sass = render 'layouts/tenant/theme', theme: current_tenant.theme_data
  SassC::Engine.new(sass, syntax: :sass).render
end

Plain Ruby

If for some reason you don't like to use views, you can use Ruby to calculate darkened and lightened colours. You don't need any fancy code as Ruby color gem does most of the heavy lifting for you.

Check the Github Repo to know all its options. Its easy to follow and documented.

  def darken(html_code, percentage = 85)
    Color::RGB
      .from_html(html_code)
      .darken_by(percentage)
      .html
  end

Conclusion

This article is in response to the article Lighten or darken a hexademical color in Ruby on Rails by Joel Friedlaender. The article is almost 10 years old and i find junior developers still referring it and making PRs reinventing the wheel. When I checked out why, it turns out that it comes as the first result when you search for some thing like ruby color darken.

I took some time to write an article with the hope of updating the topic to make it more relevant to today. If you a better way, I would like to know your thoughts. Leave a comment or send me an e-mail. If you have already written a post I can link it to this page.

Tags
About the Author

Ziyan Junaideen -

Ziyan is an expert Ruby on Rails web developer with 8 years of experience specializing in SaaS applications. He spends his free time he writes blogs, drawing on his iPad, shoots photos.

Comments