Hacker News new | ask | show | jobs
by ahoge 4621 days ago
> Some CSS framework methodologists suggest that using IDs is a bad idea. The reasoning behind this is that IDs carry such a higher specificity [...]

No, the primary reason is that IDs prevent reuse.

If you want to build a library of reusable components, IDs are obviously not what you want.

As the person who writes these components, you do not care how often one of these components is used. From your point of view, it only matters if it's used at least once. If it isn't, you can throw it away.

Secondly, if you use IDs which were added for JavaScript or fragment links, you'll introduce some coupling which really shouldn't be there.

Same thing with JavaScript. If you need a class, you should add a prefixed one (e.g. "js-foo"). Obviously, classes like that should never appear in your stylesheet.

Nothing of this has anything to do with cargo cults. There is an actual reason behind every rule.

3 comments

"No, the primary reason is that IDs prevent reuse."

The fact that they cannot be reused in a single page is what makes IDs so useful.

There are benefits of IDs others mentioned, but for me properly used IDs make CSS so much clearer. An ID in CSS code is a flag saying: "custom-crafted for this part of the page only, not to be reused", or "non-modular code".

Unlike a class, an ID informs me with 100% certainty that if modified, it will not affect other instances on the page, because there are none. It's hard to overestimate the value of such information, especially when working on older or someone else's code.

>The fact that [IDs] cannot be reused in a single page is what makes IDs so useful.

This isn't enforced by browsers. They will happily render all elements with the same ID and apply the same styles to all of them.

This kind of thing really isn't useful. If you accidentally put the logo twice on the page, it will be clearly visible. It virtually never happens and when it does it isn't hard to track down.

This "just once" property of IDs really doesn't add anything useful.

>Unlike a class, an ID informs me with 100% certainty that if modified, it will not affect other instances on the page, because there are none.

If I modify one of my building blocks, I know that every instance of it will now look like this.

Consistency is awesome.

>This isn't enforced by browsers. They will happily render all elements with the same ID and apply the same styles to all of them.

We live in post-xhtml times, browsers will try to make sense and render all sorts of bad code.

>If you accidentally put the logo twice on the page, it will be clearly visible. It virtually never happens and when it does it isn't hard to track down.

You're assuming the visual difference in applied style is always clearly visible, like a repeated logo. No, it's often not, not until someone changes something in a class and the change is populated everywhere the class was reused. An ID is a guarantee it was not reused, or at the very least serves as a "do not reuse" sign.

Edit: formatting

Right, so what's the problem if it looks fine?

The only problem is that you used an ID.

>"do not reuse"

Why not? If someone wants to reuse something, they probably have a good reason. Why would you get in their way? You won't gain anything from doing that.

> If I modify one of my building blocks, I know that every instance of it will now look like this.

But that's based on your own system, which may be non-obvious to other developers. The rules of valid HTML dictate the situation in which you will encounter a given ID, so this communicates something to every developer who sees IDs used in a given selector. To me that's tremendously valuable, and far more useful than trying to graft additional meanings onto parts of a single classname.

Whether that system is BEM, OOCSS, SMACSS or some other syntax, this kind of naming convention isn't a native part of CSS.

> But that's based on your own system, which may be non-obvious to other developers.

Yes, conventions are like that. You have to read the docs.

> [...] this kind of naming convention isn't a native part of CSS.

That's true for naming conventions in general.

Well, this stuff was added for a reason. If you know the rules, the SCSS and markup becomes way easier to navigate. Additionally, there are now many properties which can be automatically verified.

It adds structure which wouldn't be there otherwise.

> No, the primary reason is that IDs prevent reuse.

Reuse of what, exactly? Selectors? Properties? My assertion is that if you need to re-use properties a lot then you should make use of a preprocessor framework and then use a combination of mixins or extends. Re-use of selectors is an unnecessary artefact of how OOCSS (and similar) suggest you should write your code.

> If you want to build a library of reusable components, IDs are obviously not what you want.

If you're building components that could end up on any page entirely outside of your control, I agree. But: horses for courses. It still has valid uses, and avoiding it entirely isn't necessary.

> Secondly, if you use IDs which were added for JavaScript or fragment links, you'll introduce some coupling which really shouldn't be there.

You're looking at this backwards: IDs exist for many purposes, not just CSS. Selecting elements by ID in JavaScript, or using a fragment identifier to link to within a page are just two other examples of how they can be used, and not considering the other purposes of the attribute is part of the problem (see also ‘CSS classes’).

> Same thing with JavaScript. If you need a class, you should add a prefixed one (e.g. "js-foo").

How does the developer benefit from writing the classname like this? Why is a prefixed classname any more informative to you than a selector that tells you a little about the context in which the element appears? I've actually come around to the view that if you're using this class to select on any other criterion than the semantic purpose of the element is wrong, and it would be more appropriate to use a data attribute to contain the hooks for additional behaviour.

>Reuse of what, exactly? Selectors? Properties?

Building blocks or legos. You create a library of these and then you just use them.

Soon, you reach a point where implementing new features/views doesn't require any new CSS. You just use what's already there.

As a result, the total number of rules is kept at a minimum, which helps with performance and also with maintenance.

>If you're building components that could end up on any page entirely outside of your control, I agree.

Well, I don't write every template/view/whatever.

>How does the developer benefit from writing the classname like this?

If you change the JS, you can freely add/remove those "js-" classes.

If you change the structure of the markup, those classes will warn you ahead of time of potential issues. They will also give you something for grepping.

Also, using those classes on the CSS side can be easily identified by tools.

Basically, it's just a naming convention which tells you something about the purpose of this particular class. In languages like Java, C#, etc. you also use naming conventions to communicate something useful. In CSS, I do the same thing. There is UpperCaseCamelCase, lowerCaseCamelCase, _withLeadingUnderscore, and x-prefixed. All of these things mean something specific.

Apart from reset/normalization and base styles, everything is written in the same mechanical style. This makes the code really easy to navigate. It's very organized.

> Basically, it's just a naming convention which tells you something about the purpose of this particular class. In languages like Java, C#, etc. you also use naming conventions to communicate something useful. In CSS, I do the same thing. There is UpperCaseCamelCase, lowerCaseCamelCase, _withLeadingUnderscore, and x-prefixed. All of these things mean something specific.

What does those four styles mean then, respectively? I'm curious.

Subtree root node, descendent, modifier, and not CSS.

A modifier changes one or several aspects to make it more suitable for a different purpose.

You can stick subtrees into the leafs of other substrees. There is no overlap or interweaving.

So, if you look at some node, you just travel the tree up until you hit the first UpperCaseCamelCase class. That's the structure this node belongs to. It's also the name of the partial.

E.g. this is the "bricks/_Pagination.scss" partial:

  /// Simple pagination for search results and similar things.
  ///
  /// <div class="Pagination">
  ///     <a href="#" class="active">1</a>
  ///     <a href="#">2</a>
  ///     <a href="#">3</a>
  ///     <a href="#">4</a>
  /// </div>

  .Pagination {
  	@include TopMargin;
  	text-align: center;
  	font-size: 0;
  	& > a {
  		background: lighten($lightBlue, 12.5%);
  		color: #fff;
  		display: inline-block;
  		width: $gap;
  		padding: $gapTiny 0;
  		text-decoration: none;
  		margin-left: $gapTiny;
  		font-size: $rootFontSize;
  		&.active {
  			background: $lightBlue;
  			cursor: default;
  		}
  		&:hover {
  			background: $lightBlue;
  		}
  		&:first-child {
  			margin-left: 0;
  		}
  	}
  }
The generated docs: http://i.imgur.com/YFbhWjj.png

If there are any modifiers, a preview (with one line description) will be generated for each of them.

Apart from the reset/normalization and base styles, everything looks like that.

You have an accessibility issue in your example markup. Having links adjacent to each other without either non-linked readable characters, or an appropriate markup structure leads to screen readers reading out the numbers 1 2 3 4 in a "linked" tone, and it is impossible to distinguish that from a single link containing all four numbers.

That's why the web development best practice here is to mark up a list of links with a list. And before we had web standards people used to separate adjacent links with the | character, so at least screen readers would have the numbers read out in a link voice, and the 'bar' read out in a non-linked voice.

If your intention is to create reusable components, then it's essential that you're not introducing accessibility issues by default.

There's a second accessibility issue with the pagination. Why is the active page a link? What does it link to, considering that you are already in the view that should be that page. That feels like a link that does nothing. For a generic pagination, this feels like another accessibility issue to trip up developers.

Also, there's the obvious anti-pattern of using # as the href, instead of an actual URL. That leads to developers assuming that everything is handled with JavaScript. It's easy to fix in documentation, by putting in realistic looking URLs in there.

Good examples of documentation are ones that demonstrate good practice, and not encourage bad habits.

I know, good documentation is not easy. That's why we have to be careful of falling into these sorts of pitfalls. Especially when developers have no choice but to rely on documentation being correct.

> If your intention is to create reusable components [...]

This isn't like Bootstrap, mind you. It's a set of building blocks for one particular website.

> Also, there's the obvious anti-pattern of using # as the href, instead of an actual URL.

It's about the structure of the markup. "#" is used as no-op href for dummy links. "data:," is used as no-op src for dummy images.

I think most of the advocates for OOCSS would agree with you that preprocessors make them better. But the principles they're proposing are made better by preprocessors, they're not invalidated by them. Preprocessors let you get the benefits of reusable components without polluting the DOM with classnames. Which is better than plain OOCSS in most cases. But OOCSS allows you to have those reusable component benefits without tying you into a specific preprocessor (or any at all), and that is a benefit as well, even if you personally don't think its worth the semantic tradeoff.

Basically

OOCSS with preprocessor => reusable components + minimum DOM impact

OOCSS without preprocessors => reusable component + potentially messy DOM

CSS without OOCSS => potentially clean DOM + potentially non-reusable CSS

> Nothing of this has anything to do with cargo cults. There is an actual reason behind every rule.

There may be reasons, but I find there is often a lack of understanding about the context in which that rule was developed, and the compromises that were made. A developer not understanding why things must be done in a certain way, but doing it anyway sounds pretty cargo-culty to me.

Well, that's the definition of a cargo cult. Following some rules without actually knowing why.

If you use IDs because some person on the internet said "Use IDs, for the love of God", you're cargo-culting.

Thing is, I know why I follow these rules. I'm the one who wrote them and refined them over the course of several years. I made informed decisions based on 13+ years of experience of which I spent the last 4 writing ecommerce related frontend code for dozens of websites.

This stuff is never done. It's always based on my current knowledge/experience and the limitations of the current boat-anchor version of IE.

Nowadays, my code is more maintainable, I can actually do some sort of "refactoring", and the total amount of selectors is very close to the optimum.

Anyhow, not using IDs makes writing CSS easier. Even if you don't understand the reasons/mechanics behind it.