Skip to content

Commit a3043cb

Browse files
committed
Update article content
1 parent 6c4809d commit a3043cb

File tree

2 files changed

+34
-28
lines changed

2 files changed

+34
-28
lines changed

app/content/pages/articles/how-to-render-css-dynamically-in-rails.html.mdrb

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,9 @@ tags:
1717

1818
Let‘s talk about how to render CSS dynamically with Ruby on Rails.
1919

20-
Most of the time, you might think of CSS as a static asset. But sometimes you want _dynamic_ CSS. Maybe end user preferences, results of an A/B test, or some organizational data in the system should determine what styles to present.
20+
Most of the time, you might think of CSS as a static asset. But sometimes you want _dynamic_ CSS. Maybe end-user preferences, results of an A/B test, or some organizational data in the system should determine what styles to present.
2121

22-
In this post, we‘ll talk about some techniques and considerations to accomplish this in Rails.
23-
24-
In my [previous article](/articles/color-schemes-with-ruby-on-rails), I used Hotwire to let you, the reader, preview and safe different color schemes for this site. As a recap, here‘s a slim demo so you can see how it works:
22+
In this post, we‘ll talk about some techniques and considerations to accomplish this in Rails. In my [previous article](/articles/color-schemes-with-ruby-on-rails), I used Hotwire to let you, the reader, preview and safe different color schemes for this site. As a recap, here‘s a slim demo so you can see how it works:
2523

2624
<%= turbo_frame_tag "color-scheme-preview", src: preview_settings_color_scheme_path(custom_color_scheme_params), class: "grid-cols-12 lg:grid-cols-12 m-bs-m" %>
2725
<noscript>
@@ -30,11 +28,11 @@ JavaScript not enabled? Go to the <%= link_to "color scheme demo", settings_colo
3028

3129
## ERB isn‘t just for HTML
3230

33-
The color scheme preview relies on embedded Ruby to render CSS into a `<style>` on the server.
31+
The color scheme preview relies on Ruby embedded in HTML templates on the server to render CSS into a `<style>` tag.
3432

3533
While most of your CSS likely should be rendered in a bundled CSS file (or files), like `application.css`, it may make sense for small bits of custom CSS to be rendered inline in HTML. Your static CSS files will be served from your web server or likely a Content Delivery Network (CDN) depending on your application setup, which skips your Rails application logic.
3634

37-
When you make a color scheme selection, a request is issued to update the Color Scheme preview. The endpoint returns an HTML response with a [Turbo Frame](https://turbo.hotwired.dev/handbook/frames) containing a `<style>` tag. Hotwire swaps out the portion containing the Turbo Frame including the new styles. As an example, here‘s part of the HTML response when you select **Blue Chill**:
35+
That‘s true for most of the CSS in Joy of Rails too. But, to make the the color scheme preview, I‘ve mixed in some dynamic CSS into the Hotwire interaction. When you make a color scheme selection, a request is issued to update the color scheme preview. The endpoint returns an HTML response with a [Turbo Frame](https://turbo.hotwired.dev/handbook/frames) containing a `<style>` tag. Hotwire swaps out the portion containing the Turbo Frame including the new styles. As an example, here‘s part of the HTML response when you select **Blue Chill**:
3836

3937
```html
4038
<html>
@@ -79,13 +77,13 @@ When you make a color scheme selection, a request is issued to update the Color
7977
</html>
8078
```
8179

82-
As you can see, the color scheme for Joy of Rails is built on [CSS Variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties). Using CSS variables for dynamic CSS isn‘t required but sure makes the job of updating CSS easier. We can set values of CSS variables to new values by rendering new CSS or by JavaScript manipulation; this makes CSS variables an ideal choice for dynamic CSS techniques like those described in this article.
80+
As you can see, the color scheme for Joy of Rails is built on [CSS Variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties). Using CSS variables for dynamic CSS isn‘t required but sure makes the job of updating page styles easier. We can set values of CSS variables to new values by rendering new CSS or by JavaScript manipulation; this makes CSS variables an ideal choice for dynamic CSS techniques like those described in this article.
8381

8482
The partial that renders CSS in the HTML response looks something like this:
8583

86-
<%= render CodeBlock::AppFile.new("app/views/application/theme/\_color.html.erb", language: "erb") %>
84+
<%= render CodeBlock::AppFile.new("app/views/application/theme/\_color.html.erb", language: "erb", revision: "9852f2ccf65401848c19a6eabd1eb74fca49c789") %>
8785

88-
The controller helper methods `custom_color_scheme?` looks for the presence of a color scheme id in `params` or the `session` and `find_color_scheme` makes the database query if needed.
86+
The controller helper method `custom_color_scheme?` looks for the presence of a color scheme id in `params` or the `session` and `find_color_scheme` makes a database query to find a `ColorScheme` record if needed.
8987

9088
`ColorSchemes::Css` is a simple [Phlex](https://www.phlex.fun/) component but it could easily be rendered in an ERB partial. Here‘s what it looks like:
9189

@@ -97,7 +95,7 @@ The key point here is that we can use logic in Rails templates or components for
9795

9896
## Controller actions aren’t just for HTML either
9997

100-
Rails controllers can do more than just HTML. In fact, Rails controller actions support 36 MIME types by default (as of Rails 7.1).
98+
Rails controllers can do more than just HTML. In fact, Rails controller actions support over thirty [MIME types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) by default (as of Rails 7.1).
10199

102100
```ruby
103101
$ bin/rails s
@@ -143,36 +141,38 @@ Here’s the code for the `iframe`:
143141

144142
Behold: dynamic css from a controller action!
145143

146-
And we can use this endpoint in a stylesheet `<link>` tag just like any other static CSS URL:
144+
We can use this endpoint in a stylesheet `<link>` tag just like any other static CSS URL:
147145

148146
```html
149147
<%= stylesheet_link_tag color_scheme_path(@color_scheme, format: :css) %>
150148
```
151149

152-
A downside of moving our dynamic CSS to a separate controller action is that it requires an additional HTTP request. This might not be a big deal. But, for that same reason, we might also be able to take advantage of Rails conditional GET features to instruct HTTP proxies to cache the request if it hasn’t been modified:
153-
154-
<%= render CodeBlock::AppFile.new("app/controllers/color_schemes_controller.rb", lines: [1, 8..19], language: "ruby", revision: "c6f970e6c95787ab66c75f9d230734710084c9d2") %>
155-
156-
Note the use of the `stale?` method here. This method will calculate a value for `Etag` or `Last-Modified` response headers and set the status to `304 Not Modified` if request headers match and the server doesn’t need to render anything.
150+
A downside of moving our dynamic CSS to a separate controller action is that it requires an additional HTTP request. This could be an issue for a highly interactive user experience. But on the other hand, using a separate request allows you to take advantage of Rails [conditional GET features](https://guides.rubyonrails.org/v3.2/caching_with_rails.html#conditional-get-support)
157151

158152
> Conditional GETs are a feature of the HTTP specification that provide a way for web servers to tell browsers that the response to a GET request hasn't changed since the last request and can be safely pulled from the browser cache.
159153
>
160154
> [Source: Rails guides](https://guides.rubyonrails.org/caching_with_rails.html#conditional-get-support)
161155

162-
Using conditional GETs can help speed up the performance of such requests and lighten the workload on your Rails server.
156+
Below, I‘ve modified the `ColorSchemesController#show` to use the `stale?` method to enable conditional GET:
157+
158+
<%= render CodeBlock::AppFile.new("app/controllers/color_schemes_controller.rb", lines: [1, 8..19], language: "ruby", revision: "c6f970e6c95787ab66c75f9d230734710084c9d2") %>
159+
160+
This method will calculate a value for `Etag` or `Last-Modified` response headers and set the status to `304 Not Modified` if request headers match and the server doesn’t need to render anything.
161+
162+
In short, dynamic CSS combined with a conditional GET allows you to leverage put Ruby logic behind your stylesheet link tags in a performant manner.
163163

164164
## Recap
165165

166-
Rendering CSS inline
166+
Rails provides us with all sorts of [sharp knives](https://rubyonrails.org/doctrine#provide-sharp-knives) especially it comes to dynamic rendering in various formats, like CSS.
167+
168+
We can allow for real-time style changes based on user preferences or application state to enable user- or context-specific styling—like [custom color schemes](/settings/color_schemes) for your application.
167169

168-
- Extra request isn‘t needed
169-
- More difficult to take advantage of long-lived caching
170+
We can render CSS in `<style>` tags using embedded Ruby. This approach works well for small bits of CSS and may save bandwidth and latency without having to make additional HTTP requests
170171

171-
Rendering CSS in a controller
172+
Rendering CSS in a controller isn‘t as crazy as it sounds. This approach offers flexibility and is primed for HTTP caching through conditional GET support in Rails.
173+
174+
---
172175

173-
- Extra request isn‘t needed
174-
- More difficult to take advantage of long-lived caching
176+
Did you find this article helpful? How are you doing dynamic CSS? Let me know on [Twitter](https://x.com/rossta), [Mastodon](https://ruby.social/@rossta), or [send me an email](mailto:[email protected]). You can check out the [source code for Joy of Rails on Github](https://github.com/joyofrails/joyofrails.com). And... you can [subscribe](#newsletter-signup) to my newsletter to get notified of new content.
175177

176-
Flexibility: Allows for real-time style changes based on user preferences or application state.
177-
Customization: Enables user-specific or context-specific styling.
178-
Performance: Can reduce the overall CSS payload by serving only necessary styles.
178+
Until next time, have fun!

app/views/settings/color_schemes/preview_view.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,14 @@ def view_template
6262
end
6363
div(class: "outside") { reset_button }
6464
else
65-
markdown do
66-
"The site default is **#{@color_scheme.display_name}**."
65+
if preserving?
66+
markdown do
67+
"You have saved **#{@color_scheme.display_name}** as your personal color scheme."
68+
end
69+
else
70+
markdown do
71+
"The site default color scheme is **#{@color_scheme.display_name}**."
72+
end
6773
end
6874

6975
render ColorSchemes::Swatches.new(color_scheme: @settings.color_scheme)

0 commit comments

Comments
 (0)