Styling - a big challenge these days

And yes, of course I used badgeStyle to override it. I just meant that out of the box, it’s wonky looking and causes breakage.

“no one has bothered” didn’t come across as matter-of-fact. It suggests a lack of effort. Subscribe to the project to follow all the activity, and you’ll see just to see how much work the 3 guys put in day after day.

Hai Nguyen who original created Material-UI (but is less involved now) started a project allow custom builds. https://github.com/hai-cea/mui-custom-builder Your theme builder could complement that nicely.

Now back to your scheduled discussion. :grin:

Bottlenecks. The rendering engine parses through the HTML DOM tree, and does a lookup on each class to figure out what the necessary styling is. The CSS is in-memory, the lookup only takes half a millisecond; but as the size of the app grows, it can eventually take hundreds of milliseconds.

There’s maybe three different levels of optimization worth thinking about. For sake of discussion, call them ‘matrix optimized’, ‘optimized’, and non-optimized.

CSS has a half-dozen attributes that are strongly optimized with direct GPU matrix functions… as I recall, they’re transform3d(), translate(), and the transition, animate, and the opacity attributes. Using any of those will hook into the GPU matrix rendering functions, and provide GPU optimized functionality.

However, between the strongly optimized GPU functionality of transform3d() and the non-optimized functionality of HTML and CSS, there’s a middle ground. And that involves ditching the CSS parsing system, which bottlenecks the default performance of CSS.

Example: Say it takes 1 millisecond for the GPU to parse an image and display it as a background image. But it takes 10ms to parse the DOM and another 10ms to parse the 20k lines of Bootstrap styles. It’s taking your app 20ms to render; which is 20x more than what the GPU needs to render the image to screen.

Now assume that you’ve got some expensive animation function that’s hooked up to a reactive variable. Maybe an image carousel that takes 300ms to fade an image in; a DOM that takes 20ms to parse; and 30k of CSS files that takes another 30ms to parse. All of a sudden, you’re well past the 36ms limit that the eye can detect (because 27.5 fps is required to visualize motion), and you start noticing flicker in animation redraws.

How do you optimize this?

Well, by getting rid of the CSS parsing system, you can take your 60ms application refresh, and squeeze it back down to 31ms… 30 ms to parse the DOM, and the 1ms for the GPU to draw the image. And you’re back under the threshold that the human eye can detect; and animation is smooth again.

So… all that it to describe a sort of minimal-optimization that naturally occurs when you get rid of the CSS subsystem. The GPU has a refresh rate maybe 10x faster than the CSS’s refresh rate. Both are well below the threshold of the human eye to detect; so most people feel that the accessibility and convenience that CSS provides is worth the 10x performance penalty it imposes. But when you start making animation-heavy sites that are reactive and real-time; sometimes the DOM parsing and CSS lookup starts to add up as the site becomes bigger, and they start bottlenecking.

Ditching the CSS subsystem and accessing the GPU directly is exactly what Famo.us was all about; and is the underlying reason of why React performs so well on web and can support mobile device. Squeezing out 60fps which gives you that butter-smooth native-like feeling requires getting your render refresh below 16ms. So, most people going for 60fps and native-quality response use some technology that ditches the CSS parsing, meaning they have to find strategies for inline styling or direct GPU management from the javascript.

9 Likes

What the videos by Steve Newcomb from Famo.us in the “Audit Your CSS” section of the Animations article above. He does an excellent job of explaining what’s going on with the CSS subsystem and getting 60fps from a web browser.

Thanks, but I meant this phrase specifically:

use inline styles (with Blaze/React helpers) for layout and animation effects; they will be GPU optimized if they’re not attached to CSS classes

Which I understand as: Some css properties will only be accelerated if they are defined inline. But afaik the origin of a css property doesn’t have an influence on whether it can be GPU accelerated or not.

But this has too be parsed only once? Of course, everytime you add to the DOM tree, it will need to infer the right properties, but if your css rules are not too complex (not too deep nesting, use only fast selectors), I believe there’s a case to be made for using classes. As in: the win in reusability is higher than the small performance loss.

Actually, I never really liked the famo.us approach, since it put each and every node of their render tree on a gpu accelerated layer, even when it was not necessary. This gave immense memory pressure.

1 Like

What I’m left with in this conversation is that style frameworks try to do too much. In other words, there’s a lack of separation of concerns. Each framework kind of wants to be its own ecosystem, but that leaves me with a lot of either-or choices.

I want more of UI architecture. Something that is easy to extend and hack on. I’m still investigating the possibilities.

Hey whoa, watch the misquote! :slight_smile: It was dcworldwilde who said that.

Over a month later now…

What are people using lately on new projects? I’m using inline styles with Radium, though I’m considering just moving towards using BEM and putting SCSS files alongside the JS files. But I’m feeling really indecisive about the whole thing.

1 Like

Just had to add my 0.02 since this is the first time I’m seeing this thread. Wow, all that css-in-js feels like so much overengineering. Might just be me, and yes a lot might still be wrong with css, but what’s the point :slight_smile: The only thing I can think of as an advantage is maintainability. But is that really worth the effort?

Performance wise, in my experience, it makes no difference at all. Just watch out with the properties you’re handling and boom… native experience. Or am I missing the point here?

Check this out:

it looks really good, this is exactly what I was looking for.

4 Likes

I’m doing a single SCSS file for each component. Every component has a class on its top level element which is the top level selector in the SCSS file. The style files are named the same as each component and reside in the same directory.

I have some global / library *.sass files that are imported at the top of each component e.g.

@import '{}/client/scss/main';

This way they’re automatically imported by fourseven:scss and I don’t have to maintain a file that does all the imports for me.

2 Likes

That’s actually how I use it myself and how I envisioned it to be used when I rewrote fourseven:scss it to support cross package imports

3 Likes

I have used @timfletcher’s approach to much success. The problem with inline styles is they CANNOT be overriden by any style sheet. So it’s much better to have a default style scoped with intelligent class names (perhaps package and component names as class names at the top of your scss file). This way that style can be overriden when needed by a consuming component and the sub component remains blissfully unaware that the override exists. When no override is in place, default styling inherent to the component is used.

This has allowed me to write extremely modular code and in no instance do I have to look into the scss file of the other module to know what’s going on, I just bring it in and add any overrides that might be necessary to that specific instance.

Please do not propogate the very outdated practice of inline styles. Components with inline styles are hell on other developers trying to use them!

4 Likes

Yes, I believe by definition inline styles can’t be overridden. You need some kind of a system/framework to manage styling if you’re using inline styles. Any language/technology can be used in the wrong way where you will end up with a mess.

But I think inherently JS is superior to CSS as a way to manage styling. CSS has been a mess, which is the reason why people have invented endless systems, workarounds, preprocessors, etc. to make CSS more palatable.

I’m sure part of it is a matter of preference. I came from a backend development background, so I never had to learn much CSS. So learning css, less, scss is a big investment, with little return, and I think this will never be as clear to me as using JS. If I look at twbs/bootstrap code, it makes no sense to me. But looking at some, Rebass, code, it’s very clear.

Simply saying “inline styles are bad” as a universal truth is missing the point of this discussion. Inline styles are just a tool that can be used effectively or poorly.

2 Likes

You just agreed with my actual point, but then missed what I really said.

Inline styles are not automatically bad. What is bad is only inline styles (an important distinction).

You describe css as being super complicated, but that just means you are doing it wrong. Give your component a unique class (I usually use package-name-component-name) and hang all of your style code off of that class. Now specificity isn’t a problem, and neither is collision with other styles. More importantly, the contents of that file are just the inline styles you were using. Voila! Simple, easy to reason. Meteor will combine your hundred (or more) css files and all will be well!

But just so I am clear, let me give some examples of legitimate use of inline style based on state that I have personally used:

  • Carousel slider, inline style left. Other rules (such as position relative) in CSS. Also, inline style transition which is added and removed based on whether I’m animating a snap into position.
  • Position on screen of a draggable widget. Once it’s snapped into place in a list I remove this.
  • Color of an option picker for custom ordering anything with multiple colors.

These are times when state based inline style makes 100% sense and should be used. Thing is, it should be used exceedingly sparingly. In all of these cases, related styles were still in the CSS.

I use Sass, but you are not required to, obviously. Withe Meteor’s minification, you can literally have hundreds or even thousands of small style sheets attached to your individual components and you don’t have to reason through all of the other stuff if you don’t want to.

3 Likes

You just agreed with my actual point, but then missed what I really said.

I’m sure CSS is a totally adequate tool, especially if you use it in the right ways, like giving each component a unique class, avoiding global CSS.

My point is that managing styles in JS, the way Rebass does it, is ALSO totally valid. It’s my preference because it doesn’t require learning a whole new language.

Rebass does not provide a way for another developer to come along and use that component elsewhere with different styling. The styling is still all inline and therefore can’t be overriden except by overriding the actual javascript (or the rebass source file). That extensibility is exactly what CSS is made for.

I have two major sites (which because my company is pretty secretive I’m not at liberty to share). They have all of the same code, in fact they share a git repository. Their only difference? CSS. That difference is easy to override on each site. Using Rebass I’d have to have hooks into all of my styling to allow me to override everything. This is not the right way to do things.

All inline is just plain bad, and if you can’t see this point, then all I can do is wait until you are burned by it.

I can’t think of any single valid argument why this would be ok, except the fact that (mostly backend?) some developers can’t work with CSS and try and think of something new :slightly_smiling: (ignoring the fact, that smart people developed CSS in itself, and most things are there for a reason :wink: ).

Take note though, that if you prefer this way, that’s totally fine. But let’s not kid ourselves by stating that it’s equally as good as native CSS.

1 Like

Ok, it sounds like you can’t see how this would be “good” or “ok” to do, but this sounds like simply your judgement and preference. It might be worth keeping an open mind to new ways of doing things.

Frameworks like famo.us (also React) already bypassed big part of HTML and CSS layout engine for higher performance. The point is, don’t be too quick to judge, what didn’t make sense yesterday, may be a good idea today or tomorrow.

I disagree, you can use React for inheritance of components (not inheritance in a classical OOP sense, but functional “inheritance”). For example look at this:
https://github.com/jxnblk/rebass/blob/master/src/ButtonOutline.js

It’s just a different way of doing it than with CSS.

And thanks for sharing your story, interesting, I’m sure it’s working very well for you.