Scope and precedence of CSS definitions?

I (a Rails newbie) am trying to understand how CSS works in Rails,
relying
on guidance from Configuring Rails Applications — Ruby on Rails Guides. I’m
getting some surprising, perplexing, and unwelcome results, regarding
how
the CSS settings cascade to different views.

To follow the story, see numbered screen shots at
https://drive.google.com/file/d/0B-thboqjuKZTeVI3R0tPbGhPVjQ/view?usp=sharing
:

  1. Here’s the legend for all the screen shots: This app has two models,
    users and toys. The views and other Rails objects for both models have
    been generated using scaffold. On each screen, the top window shows
    scaffolds.scss; below that on the left is users.scss; at the right of
    that
    is toys.scss; at lower left is the users object list; and at lower right
    is
    the toys object list. This screen shows the unmodified versions of all
    this. The screen backgrounds are both white, following the CSS in
    scaffolds.scss. Thru all these screens, the variable to watch is the
    background color.

  2. I modified (and saved) users.scss to make a yellow background, and I
    refreshed the pages at the bottom. Here came the first surprise: I
    expected the users background to turn yellow and the toys background to
    remain white. In other words, I assumed that the scope of the
    users.scss
    setting would be just the users pages, and that the toys pages would
    continue to inherit the (unmodified) white background from
    scaffolds.scss.

  3. I modified (and saved) toys.scss to make a yellow background, and I
    refreshed the pages at the bottom. I was hoping that the toys screen
    would
    turn green and the users screen would stay yellow. Nothing changed. So
    it
    seems that the users CSS overrides the toys CSS, tho I have no idea how
    this precedence got established.

  4. THis is further confirmed when I change the users CSS, and it applies
    to
    both.

  5. When I remove the users CSS color specification, both screens now
    follow
    the toys CSS. This too is weird; why doesn’t one or both of these
    screens
    inherit the scaffold.scss setting?

6-7. A couple more experiments confirm that (a) If the CSS attribute
for
any model is set, that setting applies to all models in the application
(rather than just to that model); and (b) among the models in an app,
there
is some kind of precedence ordering that determines which model’s
setting
of a given CSS attribute applies to all models.

Clearly, there is a bug here. Whether the bug is in in the machinery of
Rails or in my understanding of it, I can’t tell. What I would like to
know is, how (or where) to set CSS attributes so they apply to the
displays
of just one model.

~ Thanks, Ken

On Friday, June 5, 2015, kenatsun [email protected] wrote:

of just one model.

The default setup is that all of your CSS is loaded all the time. While
it
might seem wasteful to load CSS that isn’t needed on a given page, the
rationale is that this allows the browser to load a single CSS file on
first visit that is then cached for subsequent pages.

In development the CSS files are fetched individually but the result is
the
same. There is nothing that says that the styles from users.scss should
only apply to pages rendered by the users controller, nor is there an
inheritance chain. If you want these things, you must set them up
yourself,
for example by setting a class on some appropriate element of the DOM
based
on the current controller and then changing the selectors in your CSS
files

In the presence of conflicting CSS directives the browser picks the most
specific one (eg #foo .title is more selective than just .title) - see
Specificity - CSS: Cascading Style Sheets | MDN for
example.

Fred

Thanks Fred ~

My follow-up questions are inserted below your comments (which I have
indented).

~ Ken

There is nothing that says that the styles from users.scss should only
apply to pages rendered by the users controller, nor is there an
inheritance chain.

There *does *seem to be a de facto inheritance chain (or precedence
ordering) among my three .scss files (in descending order of
precedence,
the chain is users.scss, toys,scss, scaffold.scss) - that is, if I add
a
style to any of these, it trumps those later in the chain; if I remove a
style, it exposes the one following it in the chain.

What I don’t understand is how this particular chain got established,
and
why. In other words, why are there separate *scaffold.scss, users.scss,
**toys.scss,
*and other *.scss *files in the standard generated Rails
setup? Why not just one .scss file for all application-wide styles?

And if I want a particular style sheet to be scoped to something less
than
the whole app, where do I put it or references to it?

I just noticed this in the application.css file. It seems to speak to
these questions, but I don’t understand it:

  • You’re free to add application-wide styles to this file and they’ll
    appear at the bottom of the
  • compiled file so the styles you add here take precedence over styles
    defined in any styles
  • defined in the other CSS/SCSS files in this directory. It is
    generally
    better to create a new
  • file per style scope.

On Jun 5, 2015, at 1:17 PM, kenatsun [email protected] wrote:

Why not just one .scss file for all application-wide styles?

FYI, that is a perfectly legitimate, and common, way to do things. But
it’s also perfectly legitimate, and common, to have some styles specific
to certain kinds of data. Really just depends on what’s a better fit for
your application design…


Scott R.
[email protected]
http://www.elevated-dev.com/
https://www.linkedin.com/in/scottribe/
(303) 722-0567 voice

~ Ken

What I don’t understand is how this particular chain got established,
and

why. In other words, why are there separate *scaffold.scss, users.scss,
**toys.scss,
*and other *.scss *files in the standard generated Rails
setup? Why not just one .scss file for all application-wide styles?

Inheritance is the wrong way to think about it: there is a single flat
namespace, conflicts are resolved by specificity as described in the
document linked earlier. The behaviour you observe simply means that
(for
example) the styles you’ve added/removed to users.css had higher
specificity to the ones in the other stylesheets. If there is a tie on
specificity of a selector then the last selector ones. Which files
selectors are in doesn’t matter, other than it having some influence on
which occurrence of a selector is last.

And if I want a particular style sheet to be scoped to something less
than

better to create a new

  • file per style scope.

It’s trying to discourage you from adding straight to application.css -
it
creates clutter. You can setup an entirely separate manifest (I’ve
commonly
see applications have a separate admin.css) and then change
stylesheet_link_tag to load that css file instead of application.css for
some pages. Most of the time you just want to make the selectors
specific
enough that they only apply to content on the relevant pages.

For example if the body elements on all the pages rendered by the users
controlled have class “users” then a selector of the form

body.users h1 {

}

would only affect h1 tags on pages from that controller (the application
layout is a good place to enforce this sort of thing)

Fred

On Monday, June 8, 2015 at 6:29:12 AM UTC-4, Frederick C. wrote:

body.users h1 {

}

would only affect h1 tags on pages from that controller (the application
layout is a good place to enforce this sort of thing)

Thanks Fred ~

The stylesheet_link_tag is the new news to me (remember, I’m a newbie!),
and it sounds like that’s the way to apply different stylesheets to
different pages. Also, I just discovered the
Layouts and Rendering in Rails — Ruby on Rails Guides guide, which I
should have read before I even raised this question.

~ Ken