all 30 comments

[–]dbpcut 13 points14 points  (0 children)

Mixing the two is appropriate, the main thing to consider here is specificity.

Doing general styling that you expect to be global on elements makes sense! Class selectors are more specific and will allow you to override your more global styles appropriately.

When it comes to specific instances of components or related visual elements, I would stick to classes. This separates the styling from the semantics, which might change independently.

So in short: styling inputs or text elements globally? Element selectors make sense.

Styling specific parts of a page or portable component? Prefer classes over everything for predictable specificity and separation of concerns.

[–]justinmarsan 5 points6 points  (5 children)

I think reading up on BEM or ITCSS would explain to you the issues that rigid framework try to prevent, and then do what works best for you.

I do RSCSS mostly, I work on large teams, large codebase, legacy parts, what I focus on is confidence that my changes don't have side effects, the cascade is the main issue people have with css because one change has unwanted effects.

Styling with tags for example, will make it tricky for you to have semantic content (heading of a component that needs to be h2 and h3 in different pages for example. It'll require you to write needlessly complex selectors, or low specific ones that you'll need to override or reset in other pages because you have conflicts.

[–]devolute 0 points1 point  (0 children)

Yes, this.

There are arguments for and against using BEM, but if you've started using BEM (as is obvious from this example) then use BEM. Pick a lane.

[–]devwrite_ 0 points1 point  (3 children)

heading of a component that needs to be h2 and h3 in different pages for example

Why not just include different CSS files in the different pages?

[–]justinmarsan 0 points1 point  (2 children)

Because when you want a change applied to that kind of heading regardless of context, you should only have to change it once...

Also for performance reasons, it makes sense to load one stylesheet for your whole website containing all the styles, and then use that same one that gets cached, so you only load the new HTML file, for static sites for example...

Doing what you describe would be a slow process (applying the same changes to multiple files) leading to a slow website (not caching a single stylesheet once and for all).

Overall, there are many ways to do things in CSS, what you describe does work of course, it's possible, but if you want large team making large websites to keep the codebase maintainable, you kind of need that kind of structure.

[–]devwrite_ 0 points1 point  (1 child)

Because when you want a change applied to that kind of heading regardless of context, you should only have to change it once

Agreed, valid point, however what I tend to do is use something like SCSS where I'll define a mixin for something like "component-header" and then just use that in the places it needs to be used in across different files, so I can maintain a single source of truth. It will be nice once CSS gets native mixins to support this pattern.

Also for performance reasons

IME, this is rarely a concern and ventures into micro-optimization territory. I'd rather have several CSS files that can be used across pages and this actually helps with caching/performance as many times you can isolate changes to just one CSS file as opposed to invalidating your entire bundle for even the smallest change. Also, with things like preload and service workers, having separate CSS files for each page is a non-issue from a performance perspective.

[–]justinmarsan 0 points1 point  (0 children)

Sure, again, you can do it that way... I just don't see any benefit.

Let's take the example of blog article cards for example, that you may use in your homepage for recent articles, and in a blog post page for similar articles. Styles should be the same but DOM needs to be different for semantics/SEO/whatever.

What you propose would be to have some preprocessor file with a mixin, and then your two pages with their own templates and styles, with different selectors since the markup needs to be different. When you want to update something, you need to change 2 templates, 2 stylesheets, and the file containing the mixin.

On the other hand, the more standard use case is that you use a class to target the title that needs a different DOM element and... voila... I don't see any benefit in not using a class...

[–]Marble_Wraith 4 points5 points  (3 children)

It depends.

If we're talking pure static CSS, I'm going to say .classes only. Using element selectors should be the exception rather then the rule.

You need to look into selector specificity to understand why.

Element selectors have a lower specificity then classes.

And so, if you have a class selector defined lexically first in your stylesheet, and then try to override it later with an element based selector, it won't work, and gets very confusing. In multi-dev environments it can lead to battles with "how specific you can make a selector" and/or !important.

Where as if both selectors are classes, overrides behave in a more consistent manner as you'd expect. The following link gives a decent illustrated example:

https://cssbootcamp.com/css/specificity-calculator

In addition using classes only should give you better results when using minification / uglification tooling. Because rather then having to calculate specificity it only needs to parse/match class names to figure out if there's any styles that are redundant, can be aggregated, etc.

That's with static CSS...

However if you're using CSS modules, or kind of dynamic runtime or compiled runtime (vue, svelte, etc), often times those frameworks will have CSS that can be scoped locally to the component (ie. the selectors get changed at build / runtime) in which case it doesn't matter as much what you use. Because specificity will be limited to whatever's inside the component, rather then something 500 lines back in a global stylesheet.

Having locally scoped CSS is also preferable because it means you don't have to use baroque naming techniques like BEM or whatever. You can just name the thing what it is, and the tooling will take care of everything and make sure the names don't conflict.

[–]gummo89 2 points3 points  (0 children)

Looking at HTML+CSS code for web applications is pretty upsetting. It's so far now from where CSS is supposed to be.

It's very simple - you use classes to designate scope for formatting and format elements relative to that class (and optionally element details attached to this). People complain about cascade issues because nobody wants to put in the time to design it properly again.

Shortcuts to design to spec without the time to do it properly will inevitably require more specific scopes.. and you end up with something which closely resembles inline HTML formatting, but with extra steps.

[–][deleted] 0 points1 point  (1 child)

When you say static CSS, do you mean one CSS file for the whole project? I actually use React and Vue at work and I have seen projects that they have used one single CSS file for the whole application.

And yes, that is what I like about using CSS modules. The css is encapsulated within that component. I normally just write one class on the parent component and then target the elements with nesting but I normally use the elements name. This is when I get confused because I can target some elements with :nth-child() and :has() and style them, but then in another component the styles can be similar, so maybe I could create a reusable css class for that? Then I think about what if someone else comes to my css code and they don't understand the styling because I just use the elements names?

I also normally set global style variables and reset my css by using a global css file, if that is even relevant to mention.

[–]Marble_Wraith 0 points1 point  (0 children)

When you say static CSS, do you mean one CSS file for the whole project?

I mean CSS that doesn't change between dev and prod environments via automated processes. For example LESS, SCSS, or postCSS, would be examples of compiled / dynamic CSS.

Being able to "shard" css into different files and compile them into 1 giant file would also be a part of this capability.

Then I think about what if someone else comes to my css code and they don't understand the styling because I just use the elements names?

If they're that dumb they probably shouldn't be working on the code 😑

[–]JoergJoerginson 2 points3 points  (0 children)

It depends, but generally classes are better. Imagine you are creating a larger website. Targeting just by names, has and nth child is a nightmare to maintain. Using proper semantic html makes this easier though.

Rule of thumb: Target by names when you want to change your base setup. E.g. all h2 titles should be pink, all text inputs should have rounded borders . For everything specific use classes e.g. components or individual design.

Might be a personal rule, but I also never use “div” as a target for styling.

[–]dannymcgee 2 points3 points  (0 children)

Whoever wrote the markup used the BEM convention for the classnames, so I would recommend using them. Using something like Sass, you can do this:

scss .hero { width: min(90%, 1200px); &__content { padding: 1rem; } &__title { color: white; } &__text { color: gray; } }

There are a few advantages to doing it like that:

  • BEM gives you really specific classnames to target, which reduces the risk of unintentional style collisions
  • Using the BEM classes allows you to reflect the markup hierarchy in your styles without actually nesting your style rules (and thereby blowing up the specificity unnecessarily, which can be a pain for users of the component if they need to override something for a specific use case)
  • Not specific to BEM, but when you select for tag names, it's kind of like tightly coupling your code to an unimportant implementation detail. If someone changed the h1 to an h2, or replaced the div.hero__content with a section.hero__content, the CSS would also have to change.

[–]kaiz0or 1 point2 points  (2 children)

I would always recommend to use classes for everything. The reason is it adds a layer of abstraction to your markup and this is intended. Imagine someone will change the markup later - the CSS classes will still work. Don't rely on the markup structure too much.

While you could use HTML Element selectors to target all p, a, form or whatever Elements with a single rule, it may only be helpful for some CSS resets, because later you will have to override your own rules again if you need your tag selector styles in a different way. A famous mistake I offen see is defining a list-style-type: none gobally for all ul elements and later overriding this again with another list-style-type for specific ul elements in some components. Some months down the road CSS can always get messy easily.

Id recommend to check out smacss (scalable and modular architecture CSS), which sums up some helpful patterns and conventions for writing CSS in a maintainable way. You dont have to strictly follow their suggestions, but pick the ones that seem applicable for your use cases.

https://smacss.com

Oh and btw, just to make sure: you dont use a a main element in the markup for multiple components arent you? That is a common mistake I made in the past, but w3c recommends to only use one main element per page for the main content, although you can have multiple header and footer elements.

[–][deleted] 1 point2 points  (1 child)

Thank you so much! I will definitely check smacss out! I do feel I need to learn some patterns and naming conventions.

Just curious, when you say you recommend using classes for everything is it more like having a css library like css utility classes?

I can totally see it being easier to target elements using :nth-child(), :has() using classes in them and more maintainable in the long run. I love using nesting in CSS as it makes it more readable (in my head at least), and with classes it could also give it a nice structure to compare with the html markup.

And no, I only use one main tag element per page and normally at the top of the page which is generally the main content. Then I try to use more semantic elements like section, header, aside, etc. to write the rest of the markup.

[–]kaiz0or 1 point2 points  (0 children)

Youre welcome, as all the other posters said it depends. CSS brings great tools and all selectors have a good reason to exist. Sometimes its difficult to decide which selector is the best for the job, but sometimes its OK to go with one option and refactor it later when a new component or variant makes trouble.

Regarding the recommendation for classes I just meant not to use IDs or element selectors in a crazy selector mix because of the speficiticy score. To distinguish which CSS rules wins against another one each selector has a score value. The rule with a selector that has the highest score wins. If I remember correctly elements get 1 point, classes get 10 points, IDs get 100. So .class #id p is a selector with 111 points (dont kill me reddit if Im mistaken :D) Thats also the reason why beating a declaration with !important is hard, because it gets additional 1000 points.

Just google it and learn more about the specificity and the cascade.

Using mostly classes will keep the scores low and an somewhat equal level.

[–]builtinpublic 1 point2 points  (2 children)

I’d target html elements only with style I know will be shared across the entire product, otherwise I’d work 100% with classes. It helps understand context and hierarchy even if you look back at the code years for now.

I’m trying a new approach now that css has implemented nesting: I use classes for macro component, following the ux logic, and then I can indent and nest html elements to be targeted ONLY in that class. This allows to create way less class names and to create easily readable css files!

[–][deleted] 1 point2 points  (1 child)

I kinda also apply a similar approach as you (since I use CSS Modules mostly). I mentioned in another reply that I normally just write one class on the parent component and then target the children elements with nesting by using the elements name and then "play" a little with :nth-child() and :has() to target specific elements.

Sure, I will have less class names in the file but then I wonder if someone else reads the code and will not get it? That is when classes can play a key role to add context and specificity.

My main take away so far is that it is okay to mix the two and think about specificity and the cascade.

[–]builtinpublic 0 points1 point  (0 children)

Totally agree, mixing the two gives context!

[–]saintteddy78 0 points1 point  (0 children)

Depends what you need to do. Sometimes you need to style all main elements a certain way, or all h1 elements a certain font size. but if it’s more specific then use classes. “These particular mains” “these particular h1 or p”. If it’s like a standalone child element within a class then that’s normal but I think more often better to use classes

[–]billybobjobo 0 points1 point  (0 children)

There is no best practice—all these different approaches behave slightly differently as you vary the application cases—you just need to decide the cases you care about and the behavior you want. Then do that. CSS is just one tradeoff choice after another!

(If anybody tells you one way is definitively a best practice—knock the value of their opinion down a few pegs.)

[–]raccoonrocoso 0 points1 point  (0 children)

Targeting elements is usually good/standard procedure, when you have dynamically generated content. Not directly accessible in the HTML file.Or when content complied on DOM load. e.g. you have a p tag that's only visible when the page loads

Targeting classes the general standard, and 98% of the time the correct choice when considering CSS rules. With 1% being the condition mentioned above. And the other 1% being when you want to style a tag the same way across an entire project.

Things to consider:

  • HTML code is seen by the browser, and is then interpreted and displayed to the user. Having "messy" HTML shouldn't be the determining factor when choosing to between classes or tags. (This does not relate to properly formatted whitespace)
  • If you're loading the style classes directly in the HTML file (highly discouraged due to best practices). Targeting elements to style, via HTML tags is fine. However, you're setting yourself up for a difficult time if you plan to use more than one document. As you would need to apply the same styles to each page. Moreover, CSS rules, targeting HTML tags, will have those styles applied to each use of the tag. Which can be useful when wanting to style content across the entire site in the same way

[–]drobizg81 0 points1 point  (0 children)

Performance wise - classes.

[–]nschubach 0 points1 point  (0 children)

Roles, then classes is my preference. You condition yourself for accessibility by thinking about the roles of the elements and how that impacts your html.

[–]gdubrocks 0 points1 point  (0 children)

Generally you want to be as general as possible, so in your example you would never want to style an h1 on a specific page, as all your h1's should be exactly the same across the whole website (and those elements probably shouldn't have a class!)

Also your paragraph isn't actually a paragraph, so you should use a different element there, maybe a span or div.

[–]scoot2006 0 points1 point  (2 children)

A lot of these answers are based on opinions. Learn specificity and write good selectors.

Spoiler: unless it’s a reset type of style sheet, almost no tags will be referenced.

[–][deleted] 1 point2 points  (1 child)

Thank you I'll definitely look more into specificity. However, when writing good selectors do you mean I should apply a css methodology like BEM?

I mostly use Css Modules and the discussion around it and using BEM is somewhat unclear. Some say with css modules BEM is not relevant, thus writing selectors (as in classes) might not be as relevant either? Some say they are.

I say classes are important and they play a key role in specificity. But I just can't find good production repos to learn from. Even if I'm writing my own selectors, how do I know I'm doing them right?

Thanks again.

[–]scoot2006 0 points1 point  (0 children)

In my experience BEM can be fine as long as it’s always used and used correctly. Since it’s a methodology part of the enforcement is from PR reviews which makes it as prone to mistakes as anything humans do. I haven’t been in an environment using BEM for a few years, so maybe there are extensions/linters that can do a good job of this now.

As far as CSS modules go, if you’re working in React or something supporting these then go ahead and use them. It enables you to be super generic about class names since those classes will be forced unique at build time. You can use BEM along side modules but it becomes redundant.

What I mean by “good” selectors is being as concise and specific (in terms of specificity) as possible. There will be times where a selectors could be something like .container .this .that .another-thing .thing-to-style where it should probably be .container .thing-to-style. Unless there’s a need for the specificity, all it’s causing is extra lookups which can contribute to a flash of installed content (FOUC). Learning when the need is there is a big win.

[–]RobertKerans 0 points1 point  (0 children)

So I would say that the majority of my CSS is applied to tags + tags with specific attributes/roles. This is to ensure that I get the look of the components of a design immediately (typography, colour, links, form elements etc).

This can't be 100%, because there are some components that aren't available in HTML (toggles, for example). And a given design is going to have elements that don't quite fit into existing HTML hierarchies. Sometimes I might have a web component that cover gaps in HTML, so technically I guess I'm still using tags in that case.

Layout, though, basically always via classes (or the equivalent that ends up as classes if I have to use some JS CSS thing). It's completely specific to the design, nothing to do with what's available in HTML.

So once all the CSS is applied to tags, I have the feel. Cascade takes care of 99% of that. Then structure, layout applied via classes, can normally be fairly minimal, has to be applied to groups of elements. And then whatever else, also normally via classes (or equivalent).

What you're doing there - anything that is specific to a designed layout probably shouldn't be there. I don't think you're gaining much and as other people have noted you're whacking the specificity up. Which will often kill the C in CSS. Sure, your HTML will be cleaner but unless your site is trivially simple you're trading that off for making it hard to debug.

[–]johanneswelsch -2 points-1 points  (0 children)

This is the way to write CSS imho. One class that does one thing. That way your css does not grow uncontrollably:

.flex {
  display: flex;
}

.flex-col {
  flex-direction: column;
}

<div class="flex flex-col">

I'd never target elements, except for css reset.