6 ms·
AM – Attribute Modules for CSS
- huskyr 12y agoThis 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?
- goldenkey 12y agoAttribute 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.
- batbomb 12y agoI'm not sure, but from the post it's actually ~=. The =~ variant is used in Perl and Bash as a regex matching operator.
- ratbeard 12y agoNo, :nth-last-child(n) has the worst performance of any selector.
- bGriz 12y agospan:nth-last-of-type(2n+1):not(div) > span ? Edit: I reversed my edits to maintain proper history.
- ratbeard 12y agoYea, thats slower for sure.
- ratbeard 12y agoActually, 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. Edit (2): Thanks!
- bGriz 12y agoDefinitely fact.
- germanforblack 12y agoPerformance 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.
- ricardobeat 12y agoAfter a certain point the number of selectors does affect parsing time and selector matching time, in a very significant way. Performance has improved a bit since this post but it's still relevant: http://perfectionkills.com/profiling-css-for-fun-and-profit-optimization-notes/ http://perfectionkills.com/profiling-css-for-fun-and-profit-...
- masklinn 12y agoNot 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.
- huskyr 12y agoRight. 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.
- kbenson 12y agoI 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.
- masklinn 12y agoUsing data attributes is even less likely to ever be optimised as data attributes exist specifically to store browser-opaque programmatic content.
- 12y ago
- egeozcan 12y ago`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.
- taylorlapeyre 12y agoVery interesting approach. One small peeve: this method will not allow you to use Sass/LESS nesting.
- masklinn 12y agowhy wouldn't it? Attribute selectors are just selectors. [foo] { color: blue; background-color: pink; .bar .baz { [qux~="ok"] { color: red; } } } compiles to [foo] { color: blue; background-color: pink; } [foo] .bar .baz [qux~="ok"] { color: red; } as I'd expect.
- taylorlapeyre 12y agoOh, lovely! I must have been mistaken then.
- wildpeaks 12y agoYou may prefer the regular "data-" prefix (https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Usin...) to "am-", especially if you want to be compatible with React.
- geelen 12y agoYou 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). We've got an open discussion on this point, if you want to contribute there: https://github.com/amcss/attribute-module-specification/issues/4 https://github.com/amcss/attribute-module-specification/issu...
- wildpeaks 12y ago"data-am-" would be a good choice indeed :)
- germanforblack 12y agoAbsolutely! The prefix is optional (but recommended). If you're comfortable with data attributes (or, they're required for some reason), thats cool too.
- jlongster 12y agoI 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
- _lce0 12y agointeresting approach! any real web/app using this technique?
- germanforblack 12y agoRight now, the AM site, Glen's site and am-grid. This is the first time we've shared what we've been working on.
- CatsoCatsoCatso 12y agoI 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. It was a terrible hack but it worked.
- bensmithett 12y agoWe're using it for a basic responsive grid on some Envato Market pages: https://themeforest.net/make_money/become_an_author https://themeforest.net/make_money/become_an_author
- deleted 12y ago[deleted]
- shadowmint 12y agoLooks 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...)
- geelen 12y agoWell, 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.
- shadowmint 12y agoSo its to avoid human readable visual clutter? ...by having obscure custom attributes? That seems extremely close to having size="big" and color="red" from html4. How is this not just going back to a known bad design pattern?
- masklinn 12y agoNot 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".
- deleted 12y ago[deleted]
- 12y ago
- u124556 12y agoWhat's the problem with `class="btn large rounded"` and then in css: .btn {} .btn.large {} .btn.rounded {} .btn.large.rounded {}
- hliyan 12y agoOr rely on semantic classes?
- u124556 12y agoYes, I was just following the example on the site but something like .btn.important would be even better.
- morley 12y agoI think they're trying to telegraph that "large" is describing a state specific to buttons.
- bsimpson 12y agoI'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.
- tobr 12y agoNot sure what you mean - order of classes don't have any effect with regular css .class selectors. http://jsfiddle.net/n1a9Lew5/ http://jsfiddle.net/n1a9Lew5/ 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.
- pault 12y agoThere'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.
- o_____________o 12y agoThis will be horribly slow for DOM-heavy projects.
- gioele 12y agoWhy should "rounded" and "large" be classes? Isn't <div class="button buy">...</div> plus a bit of SASS .buy { @include big; @include rounded; } 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.
- Smudge 12y agoYeah 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'.
- jdcantrell 12y agoIn 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.
- Smudge 12y agoI'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. [1]: http://susy.oddbird.net/ http://susy.oddbird.net/
- grumblestumble 12y agoI 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.
- demircancelebi 12y agoI 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.
- amccloud 12y agoWhat is the performance of an attribute selector?
- EdSharkey 12y agoThese 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
- acjohnson55 12y agoI'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.