Deprecate specificity?


#1

Specicifity causes huge problems when working on large projects. Approaches such as SMACSS, BEM, & OOCSS mitigate the problem somewhat, but it feels to me like a better long term solution would be to deprecate specicifity (with the exception of !important or inline styles) and rely purely on the source order for choosing which rule to apply.

I’m not sure what mechanism could be used to deliver this deprecation. Perhaps an attribute on <style> and <link> tags, ignored by older browsers. Or a new tag (<link> is a weird choice of tag for including styles anyway if you ask me). Or an accepts header to allow the server to send different styles to different browsers.


#2

Allow me to explore the issue and my initial thoughts.

This does cause code management issues in larger sites where multiple teams work on areas of the style and markup of a site; however I feel this is best managed by code review and testing.

I question however if by simplifying specificity would reduce the issues at hand. In a big organisation when different teams are completely fragmented from another their CSS might be pushed higher up the list of compiled CSS breaking all their styles.

This wouldn’t be an issue if CSS had some inherent dependency tree to manage order however I feel this would quickly become a requirement if specificity was dropped.

For example:

//Team one CSS
.component-name strong {
  color: blue;
}

...

//Team two css
strong {
  color: red;
}

Currently the ordering allows for the following thought process to styling all strong tags:

  • Add strong tag rule to CSS
  • Check results for styles
  • See that a library has set a more specific rule, either:
    • Replace the rules
    • Create more specific rules than the library
    • Modify HTML to add extra anchors around the library code (New classes, id’s or wrapping html)

The appeal is the no specificity process:

  • Append strong tag to end of CSS rules

However what I feel the first gives designers is an ability to add semantic meaning to the files rather than a fight for the most important CSS.

<div class="my-component">
  <h1>Heading</h1>
  <p>Text here</p>
</div>
<h1 class="super-important">Heading</h1>
.my-component  h1 {
  color: red;
}
h1.super-important {
  color: purple;
}
h1 {
  color: blue;
}

Rather than classifying the meaning of the h1 actually you are doing the reverse, meaning that developers won’t be promoted to add meaning. What the style based systems you mention give is adding in extra meaning to the HTML further classifying what the tags mean.

If anything I would drop !important as it causes a quick line of abuse to CSS files ending in a constant struggle to becoming the most important. Rather than actually fixing the specific case of HTML that you care about at the time, you rectify this by adding !important. When further changes are required there is no way to rectify the nest of !important that has been added to just add the styles that team needs. The same I feel applies to fighting to be the end of the CSS file.

That being said for utility classes like mentioned in the following article I agree important ‘could’ be the right solution here (However I prefer to ban it in CSS):

Deprecation issues

In terms of deprecation it is the same issue that plagues evolving JavaScript; Its not brilliant to evolve the language this way by deprecating features.

Worth reading: http://www.2ality.com/2014/12/one-javascript.html


#3

Also another reason I think this isn’t required is the future of web components will be solving the problems I believe you are trying to address here.

You mention using CSS approaches to solve specificity. However I think this is better solved by web components, shadow DOM and the related improvements to CSS given around this. All styles inserted within shadow DOM are then scoped.

Preview the following example (Works in Chrome): http://jsfiddle.net/qvgyt34g/3/

  <my-heading icon="user">
    My important heading
  </my-heading>

Could use the following template:

  <template id="myheadingtemplate">
    <div>
      <i class="icon"></i>
      <h1>
        <content></content>
      </h1>
      <a href="#" >#</a>
    </div>
    <style>
        h1 {display: inline-block;}
    </style>
  </template>

The following JavaScript would be used to define the component:

var myHeadingPrototype = Object.create(HTMLElement.prototype);

myHeadingPrototype.createdCallback = function() {
  var shadow = this.createShadowRoot();
  var template = document.querySelector('#myheadingtemplate');
  var clone = document.importNode(template.content, true);
  shadow.appendChild(clone);
};

var MyHeading = document.registerElement('my-heading', {prototype: myHeadingPrototype});

Would be the equivalent of writing something like:

    <div class="my-heading">
      <i class="icon"></i>
      <h1>
        <content></content>
      </h1>
      <a href="#" >#</a>
    </div>

With the CSS:

.my-heading h1 {display: inline-block;}

However the Shadow DOM variant allows nesting of many of the same components within each other without CSS colliding.

Further info on how this can be extended here: http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201/

From what I know there isn’t a way to import CSS currently into shadow DOM (link element is an inert in the spec) besides using @imports.

However once the browser support matures I suspect I will be combining JS, and CSS/LESS/SASS behind the scenes into one delivery via <link rel="import"s.

In the example I threw together above: http://jsfiddle.net/qvgyt34g/3/ this shows that in a short amount of code we soon will be able to abstract away code that we want to change less frequently. You can see also that we gain with reduced specificity on CSS selectors in the templates due to them being scoped.


#4

The way the web platform is expected to evolve precludes the idea of deprecation per se. Breaking changes are not tolerated and even non-standard things like Flash or weird proprietary IE extensions will still have corners of the internet that require them until the end of time.

Modern browsers are still expected to be able to read old documents and that includes ones which rely on particular specificity rankings to generate the final styling. Likewise, if we had the ability for a modern document to claim a particular specificity ranking, it’s styling would also change in old browsers. The latter approach is at least feasible in that it’s roughly what we did with “use strict”. However, in strict-mode JS, it’s unlikely that an otherwise strict-mode and legacy compatible program will fail if run on a non-strict mode browser.

With a no-specificity mode for CSS, you have to write your styling to have the same result in both cases, which increases the test matrix for cross-browser testing. The transition period will be unfavorable to progressive enhancement techniques other than ensuring that your stylesheet has all the same specificity selectors already.