If you embed "big" in the HTML, how do you go from mobile to desktop? Maybe that button should be "big" on desktop, but only slightly bigger than normal on mobile. If you specify its _role_ rather than its presentation, it becomes very easy to override the style in CSS with @media selectors.
PS: BTW, <button class="buy">...</button>, no <div> needed.
In my experience the lower level classes increase flexibility, maintainability, and sanity of your css. It's what allows bootstrap to be such a powerful tool for so many products.
Using a conceptually high-level naming scheme won't scale very well as your team and site grows. Eventually someone will say, I need a large rounded button, I can use the .buy class for this contact form. Or perhaps your team is very disciplined but ends up with 10-15 different ways of specifying large rounded buttons.
You'll potentially end up where .buy makes sense in two different contexts which will then increase the complexity of your css:
button.buy {...}
h1.buy {...}
Having .button .button-rounded .button-large helps you keep your css simple allows it to be remixed and reused in ways you haven't planned for yet.
Not to say semantic classes are wrong, I like them, but I have yet to see a system for it that doesn't break down after a certain size for a project/team.
I've started combining both approaches, with help from SASS's '@extend' directive.
What I mean is, I have a section of my CSS for defining all of those simple, modular classes like 'button' and 'button-rounded' (I start with bootstrap for most of these and then add more as I need them), with the idea that I'll reuse these over and over.
BUT, these never get used in the HTML directly. Instead, I have a second section of my CSS which contains definitions for those high-level, one-time-use rules. So, for instance:
// Low-level CSS (don't nest anything or it breaks @extend)
.button { // basic button... }
.button-large { // large button... }
.button-rounded { // rounded button }
.button-primary { // blue button }
.button-warning { // red button }
// High-level CSS (avoid nesting, but sometimes it is okay)
#buy_page .buy_button {
@extend .button;
@extend .button-large;
@extend .button-primary;
}
#settings_page .deactivate_button {
@extend .button;
@extend .button-rounded;
@extend .button-warning;
}
The big rule for the HTML is that I can only use IDs and classes from the high-level CSS, and should really only have one class/id per element. For the most part the high-level selectors are 1:1 with the markup, but things like widgets/components it's okay to reuse them on multiple pages.
The major exception here is the CSS for actually laying out pages. I don't use a class-based grid system. Instead, I map <section> tags to rows and <header>/<article>/<aside> tags to columns. The grid behavior is defined using Susy[1], and for specific pages I can modify the standard layout pattern if necessary.
The result of all of this is CSS that is easy to navigate. The low-level CSS is highly reusable, and the high-level CSS is structurally similar to page content, yet keeps the presentation information entirely out of the HTML. It also sometimes results in very long selectors, but that's actually not an issue performance-wise and has yet to cause me any issues.
If all classes are basically strictly scoped, encapsulated components, targeted in the CSS via parent chains, then you won't have this problem, and you won't fall into the trap you describe.
For example, rather than having .buy, it would be named something like .NavigationBar_buy (ie., following a ComponentName_child naming convention) and it would be declared in NavigationBar.scss and look like something like:
The really nice thing about the mixin approach is that you will be able to trace all usage. After all, a huge problem with CSS is class rot (where you don't know which classes are actually being used by the app) and class leakage (where classes are used for unrelated things in surprising ways that break if you modify it not knowing about the potential side-effects). Whereas in a component/mixin system, the dependencies are crystal clear: if a mixin isn't used in the stylesheet, you know it's not used by the page, and similarly, you know exactly which classes map to which components. You may get some rot, but zero leakage, and the rot is carefully contained. The only downside is increased HTML/CSS size.
Class-based CSS doesn't scale to large teams, in my opinion. A strictly enforced design manual might do it, but I don't think most companies can work that way.
Yeah I'll second this. You can also use the @extend directive to make selector definitions inheritable (kinda), in the case where 'rounded' and 'large' do have to be classes.
.buy {
@extend .large;
@extend .rounded;
}
I should never have to use .large and .rounded in my HTML directly, but I might use both a 'buy' and a more specific 'buy-special-case' which itself @extends 'buy'.
This looks a promising approach to the chaos that is writing reusable and maintainable CSS. I wonder about performance though, especially on mobile. Will this perform as good as regular class-written CSS, even if you have >2000 loc CSS files?
Attribute selectors have the worst performance of any selector. Coupling that with the =~ operator is even more cause for concern. This is why classes and id exist.
Actually, I spoke to soon. Since selector engines work right to left, this would first narrow down the list of elements to all the spans in the document. Assuming thats a fairly small percentage of the overall tags in the document, this selector runs at .0023 ms on my MBP w/ 8 GB or RAM.
Sa'll good.
Edit: For the record, bGriz edited his comment, making my comment invalid.
Not a chance, browsers can optimise lookup for ids and classes (or even elements by name) because they have spec-defined semantics, and they can be preprocessed based on those semantics (e.g. used to key maps). Custom attributes have arbitrary semantics, so they can't be fit into such a static structure.
Technically nothing prevents browsers from inferring specific behaviors from the way a custom attribute is used, and dynamically generate shortcuts (e.g. key objects by attribute name, value or computed value), but I doubt any existing browser does so, so you get a "universal selector" behavior: every element of the DOM has to be scanned and processed to apply the rule.
And it's not exactly an easy problem, it's essentially equivalent to auto-generating (and tearing down, since elements, attributes and CSS rules can be added and removed on the fly) database indexes except you've got way less usage to rely on (for cost/benefit estimations), and way less usage time to recoup your investment.
I imagine if it is optimized, using data attributes will be the most likely route. There's probably already benefits (and thus it may already be done) to cache which elements have specific data attributes set. Combining that with a lazy indexing of values of matching attribute selector rules on elements with matching data elements on first match may yield non-horrible performance.
I imagine data attributes are already optimized in some respects (probably not as selectors though), since their intended usage is slightly different than other attributes. I only contend that if any type of attributes are likely to receive special treatment in the future (besides those already designated as so, such as id and class), data attributes may be a likely candidate. Then again, due to the lack of constraint on the value of the data tags, that would make future optimizations much harder (which may have been your point).
Maybe just using class-* as a namespace would be best, both from a point of clearly identifying intent and not conflicting with any current valid html attributes (AFAIK).
Right. Then the question is: does it matter enough in performance that the user might notice it? If it's just a few ms i would be willing to trade that for better maintainability of the CSS. Or maybe you could use some kind of preprocessor that would translate the attributes to regular ids/classnames.
Performance of long CSS files isn't really the (major) concern —its how many _elements_ are being traversed (size of the dom) that really effects CSS-selector performance.
Looks like tal:attributes to me. That was a terrible idea before, and its a terrible idea now.
Honestly, what problem is this actually solving?
You have .foo, .foo--bar, .foo--extra, and you're concerned the style tags are what... not pretty enough? Too hard to visually parse? Too complex when you're building a large css framework?
I really don't understand the problem.
...but having worked with tal, I can hands down say I hate the custom attribute syntax; it scatters the style into multiple locations and makes it unclear what parts are data and what parts are presentation.
I thought we all agreed that:
<font color="red"> Its 1998! Hi! </font>
Was a bad thing. (and that was fifteen years ago... lessons from the past or whatever...)
This is a terrible misinterpretation of the article. It's not even tangentially related to hard-coding styles into HTML. Attribute models retain the ability to abstract style away from the HTML. Take the example used in the article, am-Button. Using the AM approach, you retain the ability to update the font-color, size, base styling in one place in a separate block of code (css, scss, whatevs). The styles are by no means scattered into multiple locations.
Certainly having a custom attribute that bundles multiple styles is novel.
...but having single attributes for color, font size and base styling is what attribute styles in early html were.
I think its disingenuous to suggest this is fundamentally different because these are custom style attributes (am-font) instead of hard coded style attributes (color).
The point is that presentation and data should be distinct in markup, and this use of custom attributes muddles things.
I can easily imagine some css framework providing css attribute classes that get used just like the old html style attributes, with all the same markup clutter and maintenance issues.
oh, want to change a style? now you have to change the markup attribute instead of the style sheet <--- this is why multiple display classes (btn--big) and custom attributes are fundamentally an anti-pattern.
Markup should be tagged with meaning attributes (btn--buy) and the styling done via stylesheets.
Well, the problem with having foo and foo--bar but not both is that contextual overrides become a problem. Having both of them solves that but clutters things up.
This is a technique to better express your styling intent through markup. Instead of <div class="x x-y z"> you have <div x="y" z> - two namespaces instead of one.
It's trying to ease the problems surrounding contextual overrides.
Having color="red" and other inline styles is a bad design pattern, but AM only superficially resembles it in that it uses attributes. Whether you give an element the attribute of class="nav" or just am-nav, it's accomplishing the same thing: defining that it's a "nav" element for purposes of styling.
Not to be insulting but… are you unable to read text? Because the problem (which has nothing to do with visual clutter and has to do with modularity and contextual overrides) is explained from the third section "Contextual overrides".
You can definitely do this, though I think "data-am-" is better to avoid conflicts. React ignores unexpected attributes at the moment, but can't forever with Custom Elements (since it can't know what valid attributes for new elements are).
I wouldn't completely assume react is going to give on that. In React you can create any custom properties you want to because it's just JS. The problem is how to interop with Web Components and from what I've seen nobody is really interested (rightfully so) in that
Absolutely! The prefix is optional (but recommended). If you're comfortable with data attributes (or, they're required for some reason), thats cool too.
There's nothing technically wrong with this, but one could make the argument that once a project expands beyond a single developer, you have a greater chance of namespace collisions with vague class names like `.large`. Eventually someone will come along and make a `.large` class for headlines that will make your buttons have 36pt labels.
Edit: I have a suspicion that most attempts at "semantic" CSS are a symptom of a slightly OCD designer wanting to write pretty markup, which is, in my opinion, probably the last thing you should be optimizing for productivity.
You can't guarantee that someone won't add a 'top-level' class name in the future that matches one of your 'modifier' class names. It's essentially the same argument as saying that global variables are OK because no one will ever have a global variable with the same name as yours.
I've heard people complain about this approach because if you tried to refactor, someone could have written class = "large rounded btn" in one place and "btn rounded large" in another, making finding all the variations more cumbersome.
That doesn't mean it's a bad approach, but that is one concern I've heard about it.
Edit: Oh never mind, I now realize that you're saying it's harder to find markup that uses a specific combination of classes. That's probably true, sorry.
I've gone full BEM on a recent project of mine, and it's been a godsend. Name our block elements by function, take advantage of SASS's abbreviated BEM syntax, reuse actual presentation styles with mixins, and use helpers within our templates to vastly minimize BEM's noisiness in the markup we work with. The modifiers are also great for capturing variations.
AM strikes me as clever, but I can't see it replacing class-based styling. At best, with some extensions, it might be a slightly more abbreviated way to write BEM, but decent tooling can do that for you anyway.
I agree that this approach solves a problem. But using custom data attributes for styling is just not as easy as using classes and I do not think I'll ever use such approach.
`class="btn btn-large"` was sufficient for all the projects that I've seen so far. I'm honestly curious about the scale of the applications requiring such measures (there were some other attempts IIRC) and whether they "work".
On a side note, the name sounds funny in Turkish but I guess that's a minor concern.
I really like this approach, but I think the thing that is currently missing is preprocessor/build support. The primary use case for this would be large-scale web applications -- it's probably overkill for anything else. Unfortunately, for large apps, the performance hit of using ~= is unacceptable. However, most large apps use some kind of build system - grunt, gulp, make, etc, and writing a task to convert these into old-fashioned CSS class names as part of the build seems entirely doable.
These selectors are evaluated globally, checked against to EVERY NODE in the DOM. You might as well write
*[am-Button]
just to hammer home to the reader that performance is going to be a problem with this selector approach on any complex DOM.
If I recall, CSS performance can roughly be gauged by the key selector (right most thingy on the selector) like this:
* inline styles = fastest (ok, this doesn't have a selector, but it evaluates fast!)
* id = fastest-ish
* class = fast
* tagname = slower
* any/everything else evaluated like global = super slowest
I hacked together a markdown editor with previews. To allow the user to change how an image was displayed they could put space separated options in the alt text values of the syntax.
eg. 
Aside & max500px were then picked up the CSS using the images alt attribute as the selectors.
Isn't
plus a bit of SASS enough and more correct?If you embed "big" in the HTML, how do you go from mobile to desktop? Maybe that button should be "big" on desktop, but only slightly bigger than normal on mobile. If you specify its _role_ rather than its presentation, it becomes very easy to override the style in CSS with @media selectors.
PS: BTW, <button class="buy">...</button>, no <div> needed.