Halvor William Sanden

Separating concerns with complex CSS selectors

Separating concerns #

I recently used CSS has() to show and hide buttons based on the content of a sibling of the parent. I considered using two classes to refer to one element; one to style a container and another one to check for content inside it. Using them separately, we can change the styling class name without affecting the other. That’s the rationale behind separating classes for JS and CSS, where the two are in different files and doing completely different things. I’m sure most interface developers have broken JS functionality when editing CSS. But would it be a similar risk when both are in CSS?

Higher risk across languages #

Some bugs can be avoided by remembering to use global search. All instances appear as long as we write them in the same manner – at least in CSS, where the name is always the same. In JS, we can interpolate; the name can be split and combined with variables. If I search for elements__class-name, the JS can be elements__class-[var]; it doesn’t show up, is left out and breaks. I avoid CSS classes in JS unless I’m editing class lists.

The risk is lower within CSS because the cases might be fewer and different.

Too close to be different #

In most projects, the chance is low of having many complex selectors. And if there are, it might signify that something should be structurally different or rendered differently.

There is a point in the codebase where names referring to the same thing do not benefit from being different, regardless of what they contain. CSS and JS are always separated somehow, but related CSS is usually within the same file. We can be more confusing than helpful when we use different names for the same element within just a few lines.

Layout and style #

It can make sense to have different class names for the same element when working with name properties in CSS grid, where one pertains to layout and the other to everything else. It allows us to work with the layout in one part of the CSS and keep the rest elsewhere, even in separate files.

In these cases, we can, for example, have a class named form-toolbar for styling, and to select the same element in the layout CSS, we can add something like pagelayout__form-toolbar that defines it from the perspective of the layout and its parent element.

Every element is both its own thing and a child of its parent.

Picking the form of separation is up to the project and dependent on its complexity. That’s the nice thing about being in control of our code; we can and should write it with the project in mind, not religiously following a recommended practice.