Why selecting by ID is not recommended in CSS? [closed]
Asked Answered
T

6

28

In CSS Lint, they don't recommend using an id for selecting elements. I trust CSS Lint because it written by smart people who know CSS very good and in depth. But I want to know what are reasons of this? Why is selecting with an id not a good thing?

Tilley answered 10/11, 2011 at 18:35 Comment(0)
E
29

CSSLint gives a guide to why they make their recommendations:

IDs shouldn't be used in selectors because these rules are too tightly coupled with the HTML and have no possibility of reuse. It's much preferred to use classes in selectors and then apply a class to an element in the page. Additionally, IDs impact your specificity and can lead to specificity wars.

(From Disallow IDs in selectors.)

Basically, if you structure your code to use classes rather than IDs, your code can be more general and reusable, which is generally a good thing. Furthermore, specificity is a hard thing to get your head around, and can cause bugs that are hard to find, so if you omit ID selectors, you're less likely to have conflicting rules resolved in unexpected ways.

Enigmatic answered 10/11, 2011 at 18:38 Comment(7)
Seems like its a by user preference. I think it depends on what you're styling, and maybe somebody uses the same general IDs for their page formatting divs.W
CSS lint is horse-hockey.Choir
Is it possible to just separate the reusable and specific styles in different stylesheets? The specific styles will reside inside site.css and the general styles will be in styles.css for example.Dockhand
@Dockhand If that suits your site, go for it. CSS Lint and such sites provide interesting good practice, but their implementation should often have a pinch of salt!Enigmatic
I hate to disagree completelly, specially when developing self contained components.Fettling
@Fettling I disagree with that. That imposes a "once per page" rule on your components, which is unlikely to be something you really want. A better option going into the future is shadow DOM.Enigmatic
That's exactly what I meant. Either using CSS3 variables as parameters, or using less/sass to emulate a web-component. The main idea remains for future and present. Keep the component styles withing it self, but allow to be styled differently via parameters. BTW I hope this discussion comes handy to someone :)Fettling
A
30

I disagree with the idea of never using IDs for selecting elements, however I do understand the reasoning.

Oftentimes developers will use a very high specificity selector when the general form will suffice:

#foo #bar #baz .something a {
    text-decoration: underline;
}

is probably better written as

.something a {
     text-decoration: underline;
}

Additionally, writing styles like:

#foo-1,
#foo-2,
#foo-3,
#foo-4 {
    color: #F00;
}

are better written as:

.foo {
    color: #F00;
}

Where I differ from CSSLint involves structural IDs that are reused.

I often mark up pages with this structure:

<div id="page">
    <div id="page-inner">
        <header id="header">
            <div id="header-inner"></div>
        </header>
        <nav id="nav">
            <div id="nav-inner"></div>
        </nav>
        <div id="wrapper">
            <div id="wrapper-inner">
                <div id="content">
                    <div id="content-inner">
                        <article></article>
                        ...
                    </div>
                </div>
                <div id="sidebar">
                    <div id="sidebar-inner">
                        <div class="module"></div>
                        ...
                    </div>
                </div>
            </div>
        </div>
        <footer id="footer">
            <div id="footer-inner"></div>
        </footer>
    </div>
</div>

And because I know that structure is consistent, I don't mind using #page, #header, #nav, #wrapper, #content, #sidebar, and #footer in my css for sweeping region-specific styles. These styles are tightly coupled to this particular structure, which makes them less reusable; because I reuse the structure, they are reusable. The important thing to remember is that using an ID in a selector is very specific, and should be used sparingly.


A few words on specificity:

Generally speaking, one should use the lowest possible specificity selector that makes the correct selection:

If you're targeting all <a> elements, then it makes sense to use a.
If you're targeting all <a> elements within <div class="foo">, then it makes sense to use .foo a.
If you're targeting all <a> elements within <div id="bar">, then it makes sense to use #bar a. However, you could use a lower specificity selector. [id="bar"] a has the same specificity as .foo a, which means that you can still target specific elements by ID without creating selectors with unnecessarily high specificity.

I do not generally recommend using [id="XXXX"] selectors for selecting on the [id] attribute, because it's verbose and may cause confusion. I do recommend using [data-id="XXXX"] selectors for selecting based on custom [data-*] attributes to more closely relate styles to the current state of DOM nodes.

Acaudal answered 10/11, 2011 at 18:50 Comment(0)
E
29

CSSLint gives a guide to why they make their recommendations:

IDs shouldn't be used in selectors because these rules are too tightly coupled with the HTML and have no possibility of reuse. It's much preferred to use classes in selectors and then apply a class to an element in the page. Additionally, IDs impact your specificity and can lead to specificity wars.

(From Disallow IDs in selectors.)

Basically, if you structure your code to use classes rather than IDs, your code can be more general and reusable, which is generally a good thing. Furthermore, specificity is a hard thing to get your head around, and can cause bugs that are hard to find, so if you omit ID selectors, you're less likely to have conflicting rules resolved in unexpected ways.

Enigmatic answered 10/11, 2011 at 18:38 Comment(7)
Seems like its a by user preference. I think it depends on what you're styling, and maybe somebody uses the same general IDs for their page formatting divs.W
CSS lint is horse-hockey.Choir
Is it possible to just separate the reusable and specific styles in different stylesheets? The specific styles will reside inside site.css and the general styles will be in styles.css for example.Dockhand
@Dockhand If that suits your site, go for it. CSS Lint and such sites provide interesting good practice, but their implementation should often have a pinch of salt!Enigmatic
I hate to disagree completelly, specially when developing self contained components.Fettling
@Fettling I disagree with that. That imposes a "once per page" rule on your components, which is unlikely to be something you really want. A better option going into the future is shadow DOM.Enigmatic
That's exactly what I meant. Either using CSS3 variables as parameters, or using less/sass to emulate a web-component. The main idea remains for future and present. Keep the component styles withing it self, but allow to be styled differently via parameters. BTW I hope this discussion comes handy to someone :)Fettling
C
23

First of all:

CSS Lint, like JS lint is an opinion disguised as validation, not an authority.

I've been at this for five years. I've worked on very large retail sites, at interactive agencies, as a solo contractor, and am currently at a SaaS firm.

The idea that IDs are unequivocally bad, IMO is only an idea you could arrive at if your CSS-fu when it comes to dealing with teams wasn't that great to begin with.

Good, flexible CSS, IMO, follows the following general best practices:

  • Always move from general to specific. Font-family and most-common font-size for general body text for instance, should only ever be declared in one place. As you move up to selectors that more typically involve use of classes, you'll start to override font-size. When it comes time to apply a mostly unused font-family to a very specific subset of HTML, that's when it makes sense to use an ID on a container to hit the elements getting the body text variation.

  • The more generally applied a property is, the easier it should be to override and you shouldn't ever be worried about overwriting your most general properties by accident. This for instance, body#some_id div, is an incredibly bad selector to use for that reason. At the 2nd-ish tier (there are 3...ish) where you're typically dealing more with bundles of commonly re-used elements tied to classed containers, it should be a little harder to overwrite those properties by accident. 'By accident' happens more frequently, IMO, when you've got piles of multiple-class selectors all over the place. In the last tier, you should be dealing not with re-usable elements but overrides for highly specific sections of a document. Using an ID in these circumstances is an ideal practice, not a bad one but IDs are best used sparingly and only for the specific properties of the elements in the item container that the ID actually needs to change.

  • The more specific a selector is, the harder it should be to break it by accident. By specific, I don't just mean IDs on the element. I mean an ID'd container element that sits close to the element you're actually targeting. Intentionally overriding, however, should always involve minimal effort, which is where IDs actually help rather than hinder you (see example below). If you ever find yourself in a position of "running out of IDs, classes, and tags" I recommend violence (at least imaginary violence). But seriously, somebody deserves to be hit.

  • Avoid lengthy selector lists: you should start to feel like you're 'doing it wrong' any time you regularly use 4+ selectors values for a declaration. I would not count > as a tag/value when tallying since using that wisely is an excellent practice for both maintainability and performance.

  • Avoid Specificity Arms Races: You know the guy. The "don't mess with my stuff" rookie who decided the best way to cover his butt was use every tag, selector and ID he could starting with the body. Don't hire that guy or spank him until he stops. But even on more forward-looking teams, arms races can still start innocently enough if you don't (sparingly) add more weight to selectors in places where it makes sense to.

The minimalist approach in particular is huge. The more you rely on HTML placement to avoid needing CSS in the first place, the better. The better job you've done at distributing the most general styles globally, the less you have to worry about in more specific contexts. The more pinpoint-targeted and concise highly specific property overrides are, the easier they are to manage in the long haul. And this is where the blanket non-ID policy is stupid IMO.

What's more practical and straightforward to override?

This:

body .main-content .side-bar .sub-nav > ul > li > button

Or this?

#sub-nav button

If you generally work solo or only do small projects to keep up the appearance of doing web dev for a living while making your real money at speaking engagements, the upper one might seem silly and unlikely to you but when you work with a team and you're following a class-only policy, and you just got burned for not using high enough specificity recently, it would be very easy to start adding more and more classes and tags to your stuff (just to avoid trouble on a short deadline - you'll change it back later of course), resulting in a gargantuan unpredictable convoluted mess in your CSS files.

So: Try to never use more than one ID and only for properties that are local to a container that doesn't contain other containers. Try to never use more than one or two classes. Avoid classes and IDs that target elements from on-high (the containers they represent are many many ancestor nodes above). More than 3-4 tags is probably too much in most cases until it's time for some maintenance or training/spanking of rookies. And follow the boyscout rule. Zap those importants and obviously overly specific selectors as you go when it's safe to.

But stick with rules of thumb rather than CSS "laws" and make sure you evaluate these ideas in the light of experience. Don't trust anybody or any tool that spouts blanket statements like "never use IDs" for something with as many variables as a CSS layout scenario can have. That's just noob kool-aid as far as I'm concerned and the authors responsible should know better by now if they want to claim to be experts at it.

Choir answered 24/8, 2012 at 3:9 Comment(7)
Yes, yes, yes, yes and yes. Did I miss a yes?Corruptible
You should never have a rule that looks like body .main-content .side-bar .sub-nav > ul > li > button anyway. By keeping your depth of applicability to 2 levels, by not styling using ID's or elements, you're left with very little specificity wars. Are there exceptions to this? Yup. But if you actually organize your selectors, that type of garbage selector would never happen.Fantasize
@ScottSilvi Of course you shouldn't. That's a cautionary tale but I've seen people do that and if they aren't made to understand CSS with more nuance they'll do it a lot faster armed only with the understanding that "IDs are bad." Thinking in terms of components is useful. So is document context so you don't have to redefine variant classes for simple section-specific overrides. For unique section overrides, IDs make sense. Used well or used poorly, specificity is a tool, not the enemy. Excess quantity of selectors and thoughtless and/or panicking/ignorant devs are always the enemy.Choir
I want to like this answer, and I agree with a lot of the points. It can be boiled down to "know CSS specificity and use it properly". I mostly fall in line with @ScottSilvi though - by having standards like he mentions, there is almost no place where you need EITHER of IDs or super specific class/element structures to write good CSS. IDs are like the baseball bat of specificity, they just clobber things and will most often lead to higher specificity than necessary.Rupee
IDs are the baseball bat or classes are the hammer for every nail? When specificity hurts, it's usually because somebody's been hitting baseballs with hammers and nails with a baseball bat. IDs can help you write less CSS and hooks for CSS, giving the person trying to understand your layout less to look at and fewer places to look. There is no blended component scheme or CSS hate crime inflicted on us by Twitter that trumps the value of that 99% of the time, IMO.Choir
I haven't found a single compelling reason to use an ID since I started using modern JS/SCSS frameworks about 4 years ago. If you're abiding by the faintest notion of modularity and are semantically naming your components, you really don't need IDs any more, at all. The notion that something will be special enough that you need to address it directly, is, frankly, a bit silly at this point.Slum
People keep talking about IDs like the label's going to be #second_div or #a_tag_named_kevin. How about #overlay_container? When you see that as a class are you as certain that's probably the unique-per-page popup container that swaps content on every page of the web app? Which is more semantically appropriate and gives me more information about what that element's likely role in the layout is? How much more certainty can I have about intent and likely scope of layout impact if I want to change #overlay_container > .standard_headline vs. the class version in a large app I'm new to?Choir
J
4

Their argument is mentioned by lonesomeday in their answer, that it tightly couples it to the HTML and doesn't allow for reuse.

I could make an argument, that there are cases where you don't want a style to be used by anything other than a single element, so specifying it on an id selector would make sense.

It's all going to come down to personal preference. This isn't some hard and fast rule that you have to adhere to, it appears to be the thinking of the CSS Lint team, not a rule that causes errors or anything.

Jaworski answered 10/11, 2011 at 18:42 Comment(0)
P
3

A big issue comes in when you are managing a lot of CSS or large websites. IDs by definition are not reusable. But you also get into issues with specificity. You get into nasty race conditions with styles when you start changing specificity. IDs have more specificity then classes, but inline styles have more than IDs. Inline styles have more specificity than external style sheets. By using classes you standardize how styles are applied to your elements making things more predictable. This tends to ease development, especially when working with multiple people.

Physoclistous answered 15/3, 2012 at 14:8 Comment(6)
Specificity is a tool, not the enemy. Selector bloat is the enemy.Choir
@ErikReppen The question was why are IDs not recommended for CSS selectors and it is my argument that they are not reusable and they tend to create difficult to manage race conditions. Specificity is not a tool it is how CSS works. Selector bloat is a bad thing. It makes CSS hard to manage and slows browser rendering. Specificity is a reason why I think IDs are not good CSS selectors in general while selector bloat is outside the scope of this question.Physoclistous
On any site with multiple layouts, IDs are re-usable. Layouts often have common elements that will only get used once per page. A modal dialog box or global navigation for instance. There's no reason not to hit unique attributes of those containers with an ID when needed to override properties set by classes. Using IDs well and sparingly will reduce bloat. IMO, the critical thing is to not add specificity weight to elements needlessly and to manage the orders of magnitude that having one of a kind (tag, class, ID) such that it helps keep the number of selectors down.Choir
@ErikReppen First you say that IDs are reusable then go on to say that there are elements which are only used once per page. If elements are only used once they are unique and by definition not reusable. I was not suggesting that IDs not be used, I was presenting a possible reason why CSSLint may not like them. I was also not suggesting that greater specificity be used, that is a recipe for disaster. As for IDs reducing bloat, the presentations I've seen on this topic have it that well designed classes reduce bloat. Presentations of OOCSS by Nichole Sullivan are what I'm referencing.Physoclistous
Specificity is useful for sure, but excessive specificity leads to repetition. There becomes a tight coupling between the HTML and the CSS when you start binding CSS to IDs. It takes CSS markup away from intent-driven markup and in most cases isn't dramatically better from a maintainability and separation of concerns perspective than inlining your CSS in style attributes. Like all things, there are exceptions, but since ID-based CSS can only ever target a single element, they are few.Plead
@Physoclistous I meant reusable across your app for components that will be unique per-page but reused in a variety of layouts. You can make CSS about components or about layers. I advocate making it about both as appropriate. If you go 100% layers, it's hard to read/maintain. If you go 100% components you're repeating stuff all over the place, making it much more difficult/messy to re-theme a site. IDs are a layer thing. To override in a specific context only, not to hang an entire set of properties on.Choir
H
0

COMPONENTS: if you write reusable component e.g. table with id (e.g. <div id="data">) then if you put two tables into one document then you will get INVALID html.

Halpin answered 12/4, 2019 at 14:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.