Hacker News new | ask | show | jobs
by danShumway 2562 days ago
I work as a web developer for an enterprise-level software company.

Experimented a bit with CSS-in-JS, which is designed to get rid of this separation, and I found it to ultimately be harder to maintain than SCSS. This process was also what got me hooked on BEM after being initially pretty skeptical about whether it had any real value.

I now believe that BEM would meet the needs of most teams, with the exception of a few massive software houses like Facebook. And most companies don't fall into the Facebook category, even if they think they do.

I've also taken some time to reflect on older companies I've worked for, particularly some work I did at Oracle, which was for a reasonably large team spread across several continents. I think BEM would have been good enough for us there as well.

I would propose the following test: Is your front end in a monorepo? If so, BEM is probably good enough to solve any problems with scope and style conflicts. If your code can fit in a monorepo, I think its unlikely you will ever have a legitimate reason to duplicate a component name in multiple places.

Take it or leave it, just my experience, I'm sure other people would advocate different things. But it's by no means a settled debate, different people/orgs have come to different conclusions. It's just that one side writes a lot more blog posts.

10 comments

BEM seems to be "Block Element Modifier"[1] if anybody wonders.

[1]: http://getbem.com/introduction/

I have the opposite experience. I’m in a React team that was doing BEM via Sass for a few years. Almost two years ago, we moved to Styled Components. The only real difference is that Styled Components automates

* naming of classes

* creating components whose sole purpose is styling

* eliminating unused stylesheets

It’s not like we became any less strict about specificity or used inline styles any more or less than we did with BEM. I find the differences to be purely logistical. Styled Components simply automates a lot of the grunt work and allows us to focus on more important things.

I'm with you... Also, with theme context(s) it's easy enough to re-use theme values while keeping actual component styling with the component and in isolation... you remove a component, and the styling goes with it.

I've found it much easier to not have left over or unused cruft with component styling JSS/StyledComponents etc.

I've never loved CSS-in-JS, but I do love CSS modules, which allows you to use proper CSS, while solving the biggest flaw in CSS - its global nature.

We import shared styles for typography, color, and some layout basics, but each component gets its own CSS file.

Used to be a hardcore Sass lover, and CSS modules took a small amount of getting used to, but worth it in the long run.

Do you use Sass with CSS Modules? I've found it to be an excellent pairing. I put shared styles/variables (like colours) in top-level Sass partials that individual component styles can import if they need them.

The only part I dislike about CSS Modules is having to use camelCased class names, or string references (styles['class-name']), which always feel awkward. I prefer kebab-case for CSS because it's a lot more flexible (more word separators: "-", "--", "_", "__", etc.), but I'm sure I'll adapt.

Agree with this smaller pain point in the vast peace of mind that CSS Modules bring.

I try to simplify as much as possible to a single word and repeat them a lot since there’s no collision, so you can usually expect a .container, .items, .item in most components, all top level but SASS helping with other annoyances like pseudo selectors, parents and nesting where it makes sense.

You just have to remind yourself that you aren’t writing css class names, even though it looks like css class names you’re picking js identifiers. Once I made peace with that it got a lot easier to write camelCase class names- and even switch back to kebab-case when necessary.
I have two problems with BEM -

1. naming rules almost always lead to verbose inelegant names that humans would not really use at some point. (I said almost to ward off a war)

2. The part of CSS that I am generally better at than most developers is specifically in understanding the cascade. BEM, in order to help the people who are not good at the part that I am good at, pretty much makes it impossible to use what I am good at. I feel like I'm being Harrison Bergeroned every time I use BEM. But also the names I have to give things rankle.

I'm not a fan of BEM, I think it neuters one of the strongest parts of CSS
I agree on the "inelegant" and "verbose", but the tradeoff is that every block became "obvious", so manteinance is much much easier than ever before.
As a front-end dev working on the web for roughly twenty years, I concur. I was late to the game with BEM and initially bristled since it goes against patterns I thought were working for me. Plus, it's not exactly terse. But, it won me over. I also agree with your comments on CSS-in-JS ... in practical terms, I feel BEM, properly executed, can handle the CSS portion of a large majority of projects.
I always stuck BEM in the same category as other more dogmatic software approaches -- nice in theory, but not particularly practical for everyday development.

Then I tried in a practical, everyday development setting and found out I was just wrong :)

Despite trying using it a few times I've never seen the appeal in BEM, it's just bringing excessive and redundant verbosity to CSS class names as well as introducing unnecessary complexity in maintenance (e.g. if you change a class's name you need to also need to apply the change to any derivative class names)
The appeal of BEM is that it offers module scoping through naming convention (because we had no other way to do it). And it stops you accidentally styling something you didn't intent to. If you have a .box with a .title inside and you write some css like .box .title { color: red; } You're telling the browser to find any title in box and make it red. But that's not what you wanted to do, you wanted to style box titles, not anything that happens to be in box with a .title, there could be sub-components with titles that you don't want to target. So instead you could write .box > .container > .left-panel > .title and maybe you've been explicit enough to get your intentions across, or you could write .box__title, which only titles scoped to box will contain if conventions are followed. This will also target the title no matter how you refactor the markup inside of box, if the title moves from the left panel to the right etc.

In the hundreds of projects I've used it on it has only make maintenance easier and intentions much more clear. Having a flatter css structure is much easier to work with too. The classes do look ugly though, and was a point of contention when I first looked at it. It was the same when I first saw JSX in React too. I hope a native scoped css solution becomes commonplace so we can avoid having to use a naming convention to achieve the same thing.

Sorry I meant I don't see the appeal in contrast to using CSS in JS solutions, BEM clearly offers better separation of concerns compared to traditional CSS, but this problem is already solved when using CSS in JS, because you explicitly import the styles you want to apply to an element, having to line up class names in your CSS and DOM is a non-issue as the classnames are autogenerated
Show us a pastebin of your compiled CSS. I can tell you from now your CSS is bloated with the uncountable properties and classes that repeat the same fixes and structures. You can program functional CSS and get better in way.
My experience has been that the extremely minor performance benefits of functional CSS are not worth the extra time and energy you will spend on a multi-person team trying to mitigate duplicated class names and conflicting CSS functions.

You're welcome to disagree of course, I held a somewhat similar view to you until I tried BEM in a production setting.

And of course, different products call for differing methodologies. I haven't yet switched my personal blog over to BEM, for example.

I did many BEM projects. The idea behind Functional CSS is precisely that: let entire teams work without having to deal with naming. The project becames ultra-maintainable with the best legacy support.

My experience and all the data I've gathered about performance, even coding the equivalent in UCSS was shocking: 400% render speed improvement. 600% loading resources improvements and radical painting speed. To set you in context: one corporate website from a bank, had an average of 230kb resource loading, we lowered it to 33ms. 650ms rendering, we lowered to 90ms. Painting speed avged 90ms, we lowered to 12ms. If you plan things properly, you can radically improve the speed.

It's true that UCSS doesn't make that much sense for very small websites. Although you will render close to a plain HTML doc for sure. It makes sense when you need to repeat and componetize many things. There's when you gain true power. For example, in our tests, we made another equivalent 590kb uncompressed CSS file to 32kb total code need in UCSS. Compressed was about 12kb against 190kb compressed file. That's how you make great improvements.

I've discovered functional CSS some months ago, and I don't think I'll ever look back. Building everything with simple classes makes it easy to keep things consistent, appearance concerns live firmly in the style layer, and once patterns of classes used together start to appear, I can break the rules a little with SCSS and make classes like "button" ("ps ts cap rc2 box1") for the shorthand convenience.
Once you add all of those classes, it's nearly impossible to add a developer who isn't used to it. It's also really hard for me to read. Tailwind / bootstrap etc - is a total deal breaker for me. I'll just get a different client. https://www.browserlondon.com/blog/2019/06/10/functional-css... I just can't imagine not writing CSS like this: https://maintainablecss.com/chapters/introduction
Specially if you work with reactive HTMl, like VUE or React. It's a win. Even with old MVC frameworks you can work confortably and have inmeasurable performance and development speed. The CSS becomes so easy to read, mantain. Changing things is way faster. Back then I needed to watch so many things to do the job. That's why I lost my OO CSS bias.
But does bloated CSS matter?

If a human isn't going to read the CSS and the computer handles it without performance problem, I say no.

Those are of course two quite important ifs!

It matters.

First, not all users need your huge CSS file, in terms of downloading. Specially when they're on mobile phones and cache is crap.

A ~9000 rules CSS file will load and become COSSM slower than one that has 1000 or 10. It is linear increment. Make a test to see it for yourself.

A bloated CSS is more network time. Therefore, slower loading.

A bloated CSS will contain slower selectors, therefore slower rendering time and painting speed.

When you count all these things, you will see radical speed performance.

Maybe. You need to measure these things and get a feel for the actual performance impact to make informed decisions.

Rule 1 of performance: Your intuitions are not reliable.

Upthread, this commenter did post specific measurements from production projects.
Does download size matter? Why bother with compression or minification?

https://jakearchibald.com/2019/f1-perf/

No. No way. If you're CSS is a problem - then you are doing something really really wrong.
I agree. While I'm in theory in favour of alternatives to CSS, my experience with css-in-jss using the React Material-UI framework has been pretty painful.

Definitely worse than my usual approach of writing some LessCSS and trying to be quite specific.

CSS is decent enough for overall theming, but quite bad for actually laying things out.

I think CSS's cascading and inheritance are bad design choices for most of the things that people actually use CSS for.

The alternatives need to do better. Or, I need to find out which alternatives are already better.

I’ve been using BEM for about a week now and my first impression is that the readability of my code has improved a lot. It’s only a small project though.
What made CSS in js harder for you?
So obviously, all of this is just opinion me.

To start with, the only good way to do CSS in JS is to use a library that compiles your styles at runtime and inserts them into the document under a style tag. If you're not doing that, you lose the ability to use pseudo-elements and pseudo-selectors like hover. Probably 95% of the time, using CSS will be easier than setting up an event system to monitor all of this stuff yourself.

React's default tutorials will almost always tell you to pass styles manually into components, and ironically this reintroduces a lot of the problems with cascade that we're trying to avoid, because it's very easy to apply multiple styles in the wrong order or forget that some style is getting overridden. It can also make it very difficult to figure out where styles are coming from in code. So definitely don't follow that advice -- at the very least use a runtime compiler that doesn't spit out any inline styles.

There are plenty of libraries that will handle runtime compilation, but many of them come with performance costs. Enterprise software has a reputation of being slow, for good reason -- it usually is slow, because it's framework heavy and handles weird edge cases, and it's developed by multiple people over multiple years. I worry about performance more at work than I do on personal projects.

Aside from performance, I was finding that it was irritating to track class prefixes for dynamically compiled styles. One advantage of BEM is that it's really, really easy to debug. You always know exactly where a style is coming from, you always know where in code to find it, and you always know what class to use in the (hopefully rare) case that you need to hack together some selectors someplace in your code.

On the ecosystem side of things, there are a number of tiny annoyances if you're using React -- Webpack can handle live style updates if you're compiling a stylesheet. If you're compiling your CSS in Javascript though, Webpack can only reload the entire page. I found this made iteration and design a lot slower. Maybe there's some setting someplace to fix that behavior, but I couldn't find it and I didn't want to waste the time trying to build my own solution.

Finally, on a personal level, I was finding that putting my CSS in the same file as my component logic was making it very hard to organize everything and quickly grep sections of the code. This is probably personal preference for a lot of people, but I've found that disorganization is one of the biggest risks for large applications. Everyone tells me that you can still keep your JS-styles in a single file, and people will be good, and they won't split it across multiple sections of code or files -- I don't think that reflects the reality of most software development. I want the people I'm working with (and myself) to fall into a "pit of success" where organization is concerned.

Putting all of that together, the biggest thing was that I was messing around with all of this technology, finding that it was not as tightly integrated or as seamless as everyone said it was, was spending a lot of time debugging stuff, and I asked myself -- why?

IMO the biggest problems to solve with external CSS is style cascade, it's conflicting class names, it's selectors that apply across multiple components. BEM solves all of these problems for most codebases I've encountered, and doesn't require any extra libraries or frameworks. I hate debugging third-party code, and I can count on one hand the number of third-party libraries I've used on the web that I've never needed to debug. So a solution that solves all of the problems we face at work without introducing edge-case behaviors or extra dependencies is nearly always the right choice to make.

There is a rare case where you want to make your own custom CSS behavior that can only be handled through Javascript, but this is usually a bad idea because of performance concerns, and it's usually better to handle that as a separate, global polyfill anyway.

Thanks for taking the time to share all of this. Definitely something for me to review a few times and think about.

For me the argument for was: maintaining a component tree and a style tree is a non-start. Too much for me to keep sense of.

But admittedly I didnt think too much further than that.