Just...why

So, in the course of however long I’ve been on here, I’ve seen some things, man dark things(j/k). And been part of some heated debates. This is all well and good as its the nature of the beast to say “yeah but so and so told me such and suck so there” or my favorite " I read it somewhere buy some guy".

Well as I have pointed out I spend time at work teaching many things to developers. One of the things I have noticed recently in general is the lost art of CSS. I debated weather or not to even type this out but hey, take this with you or leave it, its cool, but I am going to share with you WHY I write some things the way I do.

First thing I want to point out is that I work in Sharepoint CMS(Its a monster, a bear, and other descriptive words as well), so a lot of thought has to go into "well they want it this way NOW, but they probably want it to be able to do(fill in weird business requirement here) later. Yeah, its part psychic BUT, if you take an approach thinking "wouldn’t it be cool if it could also do this, odds are you’ll find life easier when they eventually do… but moving on.

DISCLAIMER: I pulled some snippets from other threads, I am NOT tying to pint faults at anything, just using examples.

Lets take this example:

.navbar-header ul li {
  text-transform: uppercase;
}

So, whats wrong with this? Well to see the problem is to understand how the browser parses this information which is right to left. Meaning that the browser is saying “oh hey look, I have a style for list items, okay lets find ALL of the list items in a page. Oh wait, only the ones in un-ordered lists… okay… so lets re-check to make sure all the list items I should apply this style to are inside un-ordered lists by looking at every un-ordered list on the page. PHEW… okay… wait… they ALSO need to be inside a thing with a class of navbar-header??? DAMNIT, okay, recheck the page… AGAIN to make sure all the list items that are INSIDE an un-ordered list are ALSO inside a thing with a class of navbar-header. DONE”. Seems slightly non performant yes?

Solution? Give the li a class like “navbar-header-item” or some such. Now the browser will say “oh everything with the class of navbar-header-item gets this style and… DONE”.

I do work in Sass ( and frankly probably always will), so normally… lets take a button. In a reset sheet I would probably “blank it out”:

button : {
  background: transparent;
  border: 0;
  ...whatever else
}

then have a button specific style sheet:

.btn {
   ...default button settings
}

and then in the same style sheet have more specific styles:

.btn_red {
...styles specific to ONLY btn_red
}

and then markup:

<button class="btn btn_red>Oh hi Mark</button>

In this case, mr. browser, “oh I need to apply these red styles to this class, check, are they inside .btn class button?? check, DONE”.

So, why not just set button tag with styles? Well sometimes buttons need to look like buttons, sometimes they need to look like links. Also you might have to over-ride them in some instances which is something to try and avoid if possible. Another anti-pattern would be something like this:

button.btn {
   ...styles
}

Now the browser will parse any .btn class and STILL look if its part of a button, which is just un-needed work. Imagine if you have 20 buttons on a page but only ONE has the .btn class, The browser will still check to see if the class is part of a button, having to look at every button on the page, so the actual tag is irrelevant.

I tend to use the same technique with typography. Ill set classes fro all my heading ( such as .h2, .h3, whatever), that way if I have a heading that should SEMANTICALLY be an h3 but LOOKS like an h2, I can just apply the styles (I cant tell you how often I’ve seen bad markup due to styles for headings).

Anywho, there some stuff is, take it for what its worth, or don’t, lol.

1 Like

I have always advocated avoiding long chains of descendant selectors when a simple class name would do.

There is a thread here from about 10 years ago where we talk about the same things :slight_smile:

1 Like

I feel it’s always good to revisit these things as there’s a strong possibility some of what I typed became obsolete as I was typing it, lol… Such is the job.

2 Likes

Fully agree. People entering the industry now are getting so used to the high level abstractions like SASS and stuff like React, but fully lack the basis of what that’s actually compiled to, and therefore won’t see any possible pitfalls with what they’re doing. And if turns out that what they’ve built is really slow they’ll probably blame everything in sight - except for their tools. Their tools are awesome. Don’t touch their tools. People should just get faster devices, just like they have. What’s the problem?

3 Likes

Interesting.

Is there any kind of tool for CSS that could give you a metric as to how fast one selector is versus another? Kind of like JSPerf for CSS.

I recently came across this SitePoint article on a similar subject that ended with the conclusion:

To sum it up, you shouldn’t worry about selector performance, unless you really go overboard. While the topic was all the rage in 2012, browsers have gotten a lot faster and smarter since. Even Google doesn’t worry about it anymore. If you check out Google’s Page Speed Insights page, you won’t see the rule “Use efficient CSS selectors” which was removed in 2013.

Please don’t get me wrong. I’m all for understanding how the browser does things under the hood, and avoiding long chains of selectors makes your code easier to maintain. But nonetheless, I’d be interested to find out if writing:

.navbar-header ul li {
  text-transform: uppercase;
}

instead of:

li.header {
  text-transform: uppercase;
}

has any kind of real world impact.

2 Likes

I was recently working on the responsive mobile styles for the product I work for. Upon doing these we decided instead that it would be a better solution in our case to make a separate theme instead of making the mobile styles as part of responsive. This was because we wanted to keep the mobile styles when in a tablet, no matter the resolution, therefore responsive did not fit in well with what we wanted, and themes sounded like a more flexible and better solution. So after we had the responsive styles in place we decided to go for a stylesheet switch instead. As part of that work I was asked to profile the performance of both solutions (at plain sight the stylesheet switch seemed like a much more performant solution interestingly). I profiled the application in Chrome for both solutions at the point of media query and stylesheet switch respectively and the themes (stylesheet switching) solution was way more performant (4x at least) at the point of re-rendering and paint.

From then on I’m sold on the seeming fact that CSS can have a great impact on performance. Everyone knows how messy and unwieldy CSS can get in medium to large projects and the browser has to read and interpret every single rule in order to calculate the layout and paint the page.
We use LESS and I can see the great convenience in pre-processors however I can also see were we might be abusing them, like when we unnecessarily nest rules creating more specificity than we need. Also the more styles in the page the more effort the browser has to make to render, like when we have lots of media queries. Another architectural problem I often see in modern sites that use modern frameworks is that people tend to couple the styles with a component. IMHO this is the wrong approach and it leads to style repetition and chaos. To me styles should be completely de-coupled and ideally organised in themes.

Just my two cents :slight_smile:

2 Likes

Is the .btn class necessary? I would have included the defaults in with the button reset class.

Well, not really, but it is quite handy if you have multiple buttons, because you don’t need to undo all changes done in button in a secondary button that uses a lot of different styles.

Basically, instead of this:

button {
    border: 1px dashed green;
    color: blue;
    padding: 10px;
    font-style: italic;
}

.secondary {
    border: 0; // don't need a border here
    color: green;
    padding: 0; // don't need padding here
    font-style: normal; // don't want italics here
}

it would become this:

.primary {
    border: 1px dashed green;
    color: blue;
    padding: 10px;
    font-style: italic;
}

.secondary {
    color: green;
}

where .secondary does not need to undo a bunch of stuff that was set on button that it doesn’t need.

This gets worse over time, because imagine you were to add font-weight: bold; to button, you would then also need to change .secondary (and any other buttons …) to undo it there, but .secondary really had no reason to change, so the fact that you need to change the CSS there is smell that something is wrong.

1 Like

Very true ( we use Sass so I like to call it Sass abuse). We used …USED to have a lint rule that would disallow Sass nesting beyond 3, but we had to switch linters and that rule wasn’t available. But your ABSOLUTELY correct. We messed with the idea of Sheet switching, but went with critical css and a mobile first strategy as we didn’t want to maintain separate style sheets.

At first I was kinda dead set against this also, but there is something to be said for it in SOME cases. We looked at some components that appear only once on our site and associated the CSS for those to the component. It is kinda nice to know if the component isn’t on the page, the CSS for it wont render, but we do reserve that for one offs (our designers LOVE their one offs).

Exactly, and it also allows to tie that class to links for those times you want a link to look like a button. If the “defaults” were set directly to the button itself, you would have to repeat the same fro the a tag default styles and that’s not DRY.

I’m a firm believer in death by a thousand cuts. On a large project, any savings count and while Use efficient CSS selectors may have been removed, lighthouse has remove unused css… which is sort of unhelpful since it looks at only the css on the page. Also, not to pick nits:

That would style two different things. first one would style any li, inside a ul, inside an element with the class navbar-header. The second would apply styles to any li with the class header applied, so it doesn’t target the same thing. the li on the second (in this case) is redundant UNLESS you have a reusable class called header you use to style typography. But even in that case, if I had a reusable style that I wanted to be different for li, I’d probably write another class instead of reseting the original to meet the needs of the li.

Oh yeah, for sure. I’m just interested in if any performance gain is measurable. And if so, how.

Not necessarily.

That’s what I thought was doing :slight_smile:

1 Like

My bad then, its early and I didn’t comprehend exactly what you were trying to do. In that case the li isn’t really needed. As far as tools, yeah I dont know of any for css only performance testing.

1 Like

Chrome developer tools has a performance tab where you can record while you interact with a website. Once you finish recording it will show you how many milliseconds it took to complete each of many processes. In terms of styles of a page you would be interested to look at ‘Recalculate Style’, ‘Layout’ and ‘Paint’. You could profile how your media queries are affecting the layout by recording while resizing the page.

It is true that these kind of performance problems are rarely a problem, but they do also happen, and there are pages that are more layout intensive than others. When there are lots of things going on in a page, any optimisation is welcome and can make a website feel slick versus heavy.

Yes but this isn’t exactly a tool like jspref.

I…mostly agree with this thread, though the back of my head is saying “There comes some balance point at which CSS rule processing can’t outweigh HTML transfer time and overhead”. But I freely admit I have no grasp of scale for where that point would be.

IE, to go back to an initial example:

I agree. But there does come some point at which turning

<div class='navbar-header'>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
....

into

<div>
<ul>
<li class='navbar-item'>1</li>
<li class='navbar-item'>2</li>
<li class='navbar-item'>3</li>
....

becomes so weighty on HTML size that it overshadows the CSS processing time. Again, I have no concept or sense of where said balancing point is, or even if it’s practicable/worth consideration, but my head tells me there must be one somewhere.

2 Likes

I think they are different unrelated things, HTML quantity would affect initial page load whereas CSS and style recalculation would affect beyond that in how the page behaves while you interact with it.

1 Like

Surely the above is sloppy, grossly inefficient and very poor implementation of utilising the Cascading principles of CSS?

I’m not sure i’d call them unrelated, but I take the point; if your CSS is dynamic (or dynamically applied), then there would be more time spent on processing it. That said, if your page is static, then CSS processing time would be equivalent; except that transfer time for the HTML would make a page unreadable, instead of just un-styled.

1 Like

Um… no? Please explain why you think this would affect the cascade. In other words, please explain your not so nice verbiage as to why you think this is sloppy and inefficient when it comes to the Cascade, please.

I haven’t found any documentation on this. All browsers, a particular browser?

AFAIK a browser uses the HTTP content to build a DOM node tree. I do vaguely recall having seen documentation regarding whether the tree was built ancestor->children or child->ancestors but didn’t find it again after looking for it just now.

This is a beginning
https://developer.mozilla.org/en-US/docs/Learn/CSS/First_steps/How_CSS_works


4. The browser parses the fetched CSS, and sorts the different rules by their selector types into different “buckets”, e.g. element, class, ID, and so on. Based on the selectors it finds, it works out which rules should be applied to which nodes in the DOM, and attaches style to them as required (this intermediate step is called a render tree).
5. The render tree is laid out in the structure it should appear in after the rules have been applied to it.
6. The visual display of the page is shown on the screen (this stage is called painting).

I’ve not found any more about the “based on”, “works out” details. To me it seems intuitive to think “cascade” implies drilling down from the ancestor elements to the children elements. But that’s “attaches style” not “read selectors” and it certainly wouldn’t be the only time something was counter-intuitive to me.

My unsubstantiated gut feeling is that any differences in selector choice vs. any given selectors relation to the DOM is relatively insignificant and that the major bottleneck is not getting to the “render tree” but the paint - perhaps most noticeable when there is a repaint.

Right to left information is out there. A simple Google search should do it. Also the Cascade definition doesn’t measure up to what many think, boy did I get schooled on that when I started out. Again I recommend a google on the subject for I am way to tired to type that out.