I’ve sometimes wondered why CSS isn’t more dynamic.
Take, for example, the styles applied to the sub-menu on the services page of this site. To achieve the highlighting of the current service, I combine a Rails view and CSS as follows:
<div id="<%= @current_service.name %>"> <div id="secondaryNav"> <ul> <% @services.each do |service| %> <li class="<%= service.name %>"><%= link_to service.heading, service_path(service) %></li> <% end %> </ul> </div> </div>
#agileweb #secondaryNav .agileweb a, #java #secondaryNav .java a, #coaching #secondaryNav .coaching a, #mentoring #secondaryNav .mentoring a, #overview #secondaryNav .overview a, #advice #secondaryNav .advice a { color: #99CC00; text-decoration: underline; }
That does the trick nicely until I decide to add a new service. Wouldn’t it be nice to have that CSS regenerated dynamically whenever I create, update or delete a service?
Enter a new Ruby module:
# lib/dynamic_css.rb module DynamicCss def generate_services_nav_links_css return if RAILS_ENV == "test" FileUtils.cd File.expand_path("public/stylesheets", RAILS_ROOT) File.open("servicesnav.css", "w") do |out| service_names = [] services = Service.find :all services.each { |s| service_names << s.name } service_names.each_with_index do |name, i| out.print "##{name} #secondaryNav .#{name} a" if i + 1 < service_names.size out.puts "," else out.puts " {" end end out.puts " color: #99CC00;" out.puts " text-decoration: underline;" out.puts "}" end end end
Then a small adjustment to invoke the css regeneration via a filter in my admin services controller:
class Admin::ServicesController < AdminLayoutController include DynamicCss after_filter :generate_services_nav_links_css, :only => [:create, :update, :destroy] # remainder of controller end
Lastly, to ensure that the servicesnav.css file exists by the time one of the public services pages is requested:
# config/initializers/services_nav_css.rb include DynamicCss generate_services_nav_links_css
Admittedly this is a specific case, but this example shows that it is relatively straightforward to dynamically generate CSS within a Rails app if required.
Previous post: Code Syntax Highlighting
More recently: OSDC 2008 Earlybird registration closing this Friday
© 2023 Keith Pitty, all rights reserved.
Comments
“Selected” isn’t a very semantic class name though. I’d rather have a few lines extra CSS. Saves sometimes having to make changes to your view code when you want to make changes to your styles. It also keeps the markup from becoming to presentationy (new word..).
Posted by: Dylan 1 day later
Ah, Charles. Now that I have formatted your comment so that it displays properly, allow me to congratulate you on two counts. Firstly on being the first reader to comment on this blog. And, secondly, for pointing out a simpler solution that should have been blindingly obvious to me. Oh well, the sense of having contributed something worthwhile was fun while it lasted.
Posted by: Keith Pitty about 3 hours later
Surely having the template spit out
if current_service == service is a simpler solution all round? About 25 fewer lines of code and one less artifact/server roundtrip in order to load the page.
Posted by: Charles Miller about 1 hour later
Comments are closed for this post.