Hacker News new | past | comments | ask | show | jobs | submit login
[flagged] CSS Classes Considered Harmful (keithcirkel.co.uk)
100 points by fanf2 3 months ago | hide | past | favorite | 119 comments



The problem is the modern webs hyper focus on appearance over content. Content first, style second.

I still say that the answer is just semantic HTML/CSS. You're coming at the problem from the wrong direction naming things for how you want them to appear. Name them for what they are. Write the HTML agnostic to how it's intended to appear, and then just use CSS as a tool to style the already existing document.

SCSS and extending placeholder[1] selectors makes this insanely easy and viable. You can write your "how things appear" classes as placeholder classes, and then simply extend those from your "what they are" classes. Super easy to keep organized.

1. https://naxoc.net/2014/01/28/placeholder-selectors-in-sass/


Time and again, people argue as if everyone was just trying to style their blog. HTML isn't only used for documents that roughly look like a printed page, but also for actual web applications. Applications don't map too well onto HTML, and while the pedants are hung up on separating content from appearance, the rest of us is busy working on actual software.

If nobody "does it right", maybe right is just wrong?


> If nobody "does it right", maybe right is just wrong?

It is certainly possible. However, what I have seen in the industry is that there are very few real CSS experts among people who are "busy working on actual software". Few people who have thought deeply about their methodology, the problems that it solves, and the problems that it introduces. And, on the contrary, there are too many people who either regard html/css as a playground for juniors, or are too happy to copy what other people are doing. In such context, it is very difficult to have a well-informed discussion about what is "right", and what is "wrong".


I'm curious, why would you say "applications don't map too well onto HTML"?


Most of the heavy lifting of modern web applications is still on "userland" JavaScript frameworks instead of the browser, because lots of dynamic interactions can't really be modelled with HTML alone. For example, consider creating a dropdown menu to select a contact, displayed with an avatar, name, and email as a subtitle. Doing that right—so it is accessible to screenreaders, has dynamic completions fetched from a server, adjusts to different output devices—is not only quite complex on its own, but also requires reinvention of several things, like an input field with a custom select box. Support for modal dialogs just became widely available two years ago. Two way data bindings between dynamic state and HTML elements still requires complex Javascript code. Drag and drop is a pain. Input elements haven't really caught up to the last twenty years. And while HTML does provide capabilities to register custom elements, they don't really catch on for a reason.

I will say HTML is flexible enough to be used for just about anything, but it certainly is better suited for text documents than web applications.


The OpenUI folks have been doing the angel's work of upstreaming various core components. And doing a great job. Popover & dialog are both coming along nicely. https://open-ui.org/

For a while it was all left to appdevs to build a UI toolkit out of basic HTML but OpenUI really has been driving the standard forwards.


Why would you need a custom selectbox in the example you provided? Because you could use the menu element with the popup API and AJAX if I understand your example correctly.

On a sidenote, do you know about HTMX? If so, what do you think about it?


The popover API is pretty much brand new. Sure, that would probably work. That misses my point, however; lots of basic building blocks of modern UIs users expect are missing from browsers today (or on the popover case, yesterday) and need to be added manually.

HTMX is the same story—it's what HTML could be, but isn't, unless monkey-patched in userland.


Yes it's still and always evolving and we need less and less of the heavy JS frameworks to produce interfaces. HTMX is way lighter than React, for instance. And from what I know, it's enough for many, many app use cases.


> Applications don't map too well onto HTML

I'm not sure if I totally agree with this take, but if it's true that's a great reason to not build web applications. If the medium isn't right for the use case, why force it?


Because it's the only ubiquitous, actual multi-platform delivery channel we have. Web browsers are available on pretty much any device in the hands of users right now. And while HTML doesn't map too well, it is certainly good enough—there are simply no viable alternatives anyway, so people are going to use what is available.


Do you think it would be as good of a delivery channel if browsers focus more on features needed to build applications rather than to view documents?

In my experience, application-specific features are really what made the modern web complex and bloated. Building applicstion frameworks and operating systems is insanely difficult, much more so than building a standard document format and rendering protocol.

Can the web be used for applications? Absolutely. But my argument would be that it almost never should be. Native applications will always handle that better, and though there isn't a great cross platform solution for applications today we'd be better off building that than shoehorning that usecase into the web.


But that just doesn't match the way people use the web, like it or not. Building native applications just isn't worth it for many businesses: You need to adhere to compliance and security, different platforms and operating system versions, keep track of different system APIs, handle a giant matrix of build targets, prepare and maintain installation guides with possibly required client SDKs and dependencies, employ specialists for every platform... it's an extremely wide field.

Compare to the web: A single platform to build for. A single API to keep track of. A sandboxed runtime environment with zero dependencies, available on virtually every client system. A way to communicate with your servers that works, even in tightly guarded networks. A giant amount of documentation, available developers, and resources.

In an ideal world, I'd like to see native applications for everything. In the world we have, constraints prohibit that. So for better or worse, the web has to be mended into the universal application runtime environment we use it as.


I thought that exact thought a while back, so I decided to fill in one of the gaps in my application arsenal by building a native application that does nothing but display a grid of images quickly. It's a gallery app.

After trying to make the most basic version of this app I can imagine, here's my takeaway on desktop application development: it sucks. Badly. Displaying a grid of images in a webapp is a few lines of javascript and a few lines of html. In most native application development systems I've seen, it's 20 lines of code just to open the window.

To be fair, the web makes easy things easy and hard things impossible, whereas native desktop applications make easy things hard and hard things possible. But, I definitely see now why most developers prefer to build things in electron.


What's an easier/better way to style an app then? It sure isn't easier with QT (unless you use QSS or QML, both of which are inspired by how you'd build an app on the web).


Easier and better really need context. For me, styling a UI in CSS is easier than manually coding a UI for an iOS app. The visual UI builder in VS Code is pretty damn nice though, and I find that easier than CSS for complex UI.

If I need to do anything related to complex state changes, animations, page navigations, etc I'd also much rather use a native applications built with that scenario in mind. There are a ton of things we simply can't do with CSS - we're starting to see experimental features for simple page animations but they're very limited and manual. I worked on the Windows Phone UI framework back in the day, that was over a decade ago now and the kinds of navigation animations you could do with a few properties and flags was light years ahead of web page transitions today.


It's a great delivery channel.


Yes, we should bend over to serve HTML. It is "the medium" that dictates what we should and should not do /s


> Applications don't map too well onto HTML

In what way do you mean this? HTML doesn't have the elements required for apps? Or declarative, XML-ish markup doesn't work well for apps?


Think about it like this: In the beginnings of Web 2.0 people used tables for their layouts. The experience was abysmal, but it worked and allowed quite sophisticated layouts, remnants of which you can still find sometimes today. HTML has changed since then, and lots of things have improved, but its roots undeniably lie in marking up text documents, not applications.

I think that mostly shows in the awkwardness of transferring user interface widgets over. Stuff like popover, modals, combo boxes, toggles, drag and drop, sticky elements, etc. have either just recently become possible or require manual efforts to get right. And that, in my opinion, is an effect of shoehorning application primitives into a document environment.


There are very few "web applications" that wouldn't have been better off as a form.


> I still say that the answer is just semantic HTML/CSS. You're coming at the problem from the wrong direction naming things for how you want them to appear. Name them for what they are. Write the HTML agnostic to how it's intended to appear, and then just use CSS as a tool to style the already existing document.

I would love to do that, but it's simply not practical, at least not without CSS hacks that are hard to reason about.

---

A few reasons (non-exhaustive list):

In general, the separation of HTML and CSS is theoretical, not practical. They are tightly coupled descriptions of your overall layout, which is why there are so many incomplete attempts to manage the resulting complexity (see: this article).

HTML is not just content. It complects content plus layout. If you separate content from layout you get something like XML+XSLT, not HTML.

HTML is a strict tree structure and CSS can only query it in two directions: "down" and "next". A lot of layout and styling concerns are graph relationships. You need to adorn things _up_ the tree (in the form of nodes/attributes/classes etc.) in order to give enough context for layout and styling down the tree. And in some cases that doesn't work either.

Many CSS properties describe styling relationships between nodes. For example flex and grid make no sense in isolation. This couples the structure of your HTML with its styling in a profound way.

Some HTML tags don't represent their structure well, for example: <dl>, <dt>, <dd>. The natural way of thinking of these elements, laying them out and styling them, is to group each <dt> and <dd> together.

---

I agree half-way with you though. It's often useful to generate _just_ the "semantic" content at first: just use the tags and structure you need to lay out the structure of your content in a meaningful way. But as soon as you start caring about design, you will have to add tags, attributes classes etc. that are only there to serve styling.


Some thoughts on reasons above:

With recent display roles (like grid, flex, contents, etc.) the HTML needed exclusively for layout problems is really minimized if not completely nonexistent.

With `:has()` you can query "up" and "previous".

Some structure in your HTML is absolutely necessary, yes. But I'm not sure it is a problem. Data, content and states have structure.

Classes and attributes should be used for styling purposes, yes. Namespacing and linting can do most of the heavy work of keeping things tidy.


> With recent display roles (like grid, flex, contents, etc.) the HTML needed exclusively for layout problems is really minimized if not completely nonexistent.

I'm not talking strictly about _problems_ but about requirements/relationships. Flex/grid describe parent/child relationships between elements. They inherently couple styling with structure, so that you are sometimes forced to introduce tags for stylistic grouping.

> With `:has()` you can query "up" and "previous".

:has() is a lookahead.

Please correct me if I'm mistaken: But there are no selector rules that you can put on an element which looks up or at previous siblings that I know of.

The only CSS features that query up/previous are @media and @container rules.


You may have to group elements, yes. But generally speaking, they already are grouped in some logical sense. And you can do a lot now with grid, without having to wrap child elements in containers. It's not absolutely separated but to great degree it is (in my experience at the very least).

And yes, you can select previous elements with :has(). Here is an article about it: https://tobiasahlin.com/blog/previous-sibling-css-has/


Thank you that's a very useful article!


My pleasure!


> the separation of HTML and CSS is theoretical, not practical.

Yes

> HTML is not just content. It complects content plus layout

No. One broad and now to a great degree complete goal of CSS has been: "regardless of HTML markup order, we can present these elements to the user in whatever order we want."


> CSS can only query it in two directions: "down" and "next".

:has() has entered the chat.


:has() is a lookahead. See my other comment.


> Write the HTML agnostic to how it's intended to appear, and then just use CSS as a tool to style the already existing document.

But it's not possible to write HTML agnostic to how it's intended to appear, in the general sense. That's the issue with CSS. This whole thing about separating content and styling is carried too far leading to very bad UI architectures.

Stuff like colors and fonts can be separated from content. Stuff like positioning, hierarchy, etc. cannot be meaningfully separated from content in many cases, and trying to do so is the root of UI evil.

This is why the component approach is so powerful. By combining content (with its implied style) with explicit styling in an integrated package, large UI trees become composable and easier to reason about.

But many devs still don't grasp this, and continue to fantasize about pure content that can exist totally separate from presentation, a pipe dream.


You can use structural HTML and CSS inside components as their content is already structured and should not change on whim. Same for the first "master" layout layer.

Applying styles with "form" classes like card still is semantic too!


> The problem is the modern webs hyper focus on appearance over content. Content first, style second.

That's not "the web", that's "most humans"


It's the classic "internet as a means to share information" versus "internet as a means to make money" distinction.

Clear, correct, semantic HTML is important to people who want information to be shared as effectively as possible, who want collecting and processing information to be done easily, and who value correctness.

People trying to make a product don't give a rat's ass about correctness. They don't care if the button is actually a span with some weird inline CSS rules, they just want the blue "buy now" button to be front and center.

Semantic CSS is correct and it's the theory behind web browsing, but priorities have shifted. The web has moved away as a method to share information and has become a method for making apps and interactive experiences. There's no business incentive for correct HTML and CSS, only for the buttons that make money to render correctly.


Aren't there inherent advantages to correct and semantic code, advantages like performance, simplicity, understandability, expressivity, that could/should benefit the business?


Those advantages don't appear on metrics and therefore don't exist. If the benefit to the business is in two years and isn't measurable, the benefit it would bring will be misattributed to whoever happens to be around afterwards using it


That depends on context though. Sure, in a company driving for profits those metrics almost certainly won't exist. If the project is focused on end user experience, though, they would.

Accessibility is one area I've seen an overlap. It is still rare, but I have been on a couple teams where accessibility was a metric and it largely lead to better DOM structure and semantic HTML.


Quite true, unfortunately. But I think there are benefits that can be "feeled" almost instantly. I think problem is one of focus.

Lots of team leads don't focus on these solutions and their benefits but rather on the most recent technologies and their own benefits while ignoring (or accepting as inevitable) their costs. The longer you look in that direction, the harder it gets to see what you are missing or could get by looking elsewhere.


There are advantages for the society, for the rest of humanity, but usually not advantages for the short term bottom line of the business.


> Name them for what they are.

I've kept hearing (and believing) this for 20 years but never seen a project where it's actually enforced. It seems like one of those things that doesn't work in practice and that come with very few benefits compared to the overhead it creates. Every time I redesign something I throw out both HTML and CSS anyway.


Whenever I have seen code like that, it’s awful. “Name them what they are” becomes “name them after their content”, which is the opposite of separation of concerns.


Is `my-card` not a declaration of what something is (supposed to be)? The attributes are then encapsulating the state of the thing e.g. "is-loading", "size", etc. And the style then naturally follows, becoming a function of state e.g. "large loading indicator".

The extend selector solves the problem of one style definition inheriting styles from another style definition, but the author is trying to solve the problem of how styles are mapped to stateful elements. It's the mapping process that introduces the combinatorial problems of class names.


`.my-card` is semantic, but `.big` is presentational/visual. You could maintain the semantics with rules like:

    .my-card { width: normal; }
    .homepage .my-card { width: bigger; }
    .sidebar .my-card { width: smaller; }
(where 'normal', 'bigger', and 'smaller" should be replaced with real values).

BEM suggested state labels (e.g. `.my-card__loading`). I'm on the fence about those vs `.my-card.loading`. The class-based syntax seems shorter than either BEM-style or attribute selectors, and thus I prefer it. You might get a bit more rigour from the more longer-form methods, but I'm not convinced the energy isn't better spent training your team to be more careful.

Shared code, CSS toolkits, shareable widgets present bigger challenges... the thing is that none of the tools suggested actually fix the problems. Your code can still break 3rd party code and vice-versa because of the global nature of CSS.

Specificity needs management, but so do type systems and class hierarchies. Stop pretending the cascade and global namespace don't exist and just do the work.


.big is what it really is, big. Inventing a new name for it like emphasized, enlarged or attention-grabbing is just unnecessary pedantry.

Naming things what they are and then styling with how they must look like creates an additional linguistic layer in an already csessed up system.

“What things are” must become component names, not a part of markup. If there’s no reason to componentize a chunk, it doesn’t get a name (and vice versa).


It's only visually big. To a blind person, it doesn't matter what size it is. It's big to fulfil some layout concern, and the layout concern is there to fulfil some attention or intent concern.

And also, I didn't say one should use `.emphasised`. I said to change the size based on the container: `.hero .card {}` would be big but `.articles .card {}` would be normal sized. `.card`s are always just cards; their context makes them different variations.

"But `.hero` is just another way of saying big, or emphasised"... Not really. A `.hero` is "the focus of the page. EVERYTHING (`.card`, `button`, `.btn`, `q` etc) inside `.hero` might all be big, or bold, or a contrasting colour, or surrounded by extra negative space, or in italic, or a mixture of those. Back when there were going to be aural style sheets [0], you'd have a way to specify alternate modality presentations using the same class names. It doesn't always make sense that something is aurally louder when it's visually bigger.

`.big` is not "what things are". `.big` is "how do we express what that thing is in this situation".

[0]: https://www.w3.org/Style/CSS/Speech/speech.html


The problem is that you are trying to use a document markup language to create an user interface including designing and styling the controls themselves.

Also computers were not black and white in the 90s.


> I still say that the answer is just semantic HTML/CSS

It's literally impossible to implement because humans just don't function like that. I'm sorry.

The answer for discoverability on the Internet was not semantic URLs or even link directories, it was the search engines.


SCSS in general is a very good preprocessor for writing any amount of CSS when you're designing more than a single webpage.

It's a very nice wrapper around CSS that make CSS feel so much less archaic to use. Do use SCSS though, not the weird SASS syntax which differs just a bit too much from CSS to be useful.


Rather, developer convenience over users.


I don't understand how "<div class="Card" data-size="big"></div>" is better than just <div class="Card big">, then using a .card.big selector?

The article just says "but this can cause specificity issues, which can create problems further down the line" to move the same thing into attributes rather than just use the thing for what it was designed for there has to be a good reason.


They key difference is that an attribute can only appear once on an element, and consequently only have one of its variants present. Classes can present multiple variants at once.

At a surface level `<div class="Card" data-size="big">` isn't really any better `<div class="Card big">`. But `<div class="Card" data-size="big" data-size="small">` is not valid HTML - the second attribute is discarded. While `<div class="Card big small">` has no such contract, and as such is valid HTML and the CSS is unlikely to account for it, perhaps doing surprising things.


This is what BEM solves. You do not have class="Card big" but class="Card Card_big". And if you care about modifier conflicts you may always define a rule .Card_big.Card_small { /* whatever makes sense */ } and not rely on a random application of attributes.


It's not and that's the reason why the author doesn't address it in their article. It's just bad faith.

Especially with CSS pre-processors (because they make writing that syntax in the CSS file super easy) which basically everyone is using, ".card.card-big" is the obviously right solution.

It is easy to read, specific, doesn't risk collisions, doesn't risk adding broken styles if you forgot the "card" class on the element, etc. It addresses all the negatives outlined in the "BEM is not the solution" section of the article.

The only "argument" that still sticks against this one is that "it's verbose", but not once in my career have I seen a __good__ software engineer discard a perfect solution because "it's verbose".


As this article argues, problem with CSS Classes is that a CSS Class can be applied to _any_ element where custom properties will be scoped to the elements that the CSS was meant to be used for.


Custom properties can be applied to any element as well. You can constrain the effects of either to only the elements they should affect in your CSS rules.


> Custom properties can be applied to any element as well.

Well, no, they can't. That's the point the article is making.

Classes can compose arbitrarily, i.e. class="size-small size-big"

Whereas data-size="small big", while valid syntax, would not be styled by a rule targeting elem[data-size="small"]


JSX is the answer: "<Card big />"


I don’t like the proposed method but I’m glad to see thoughts a little outside the main lines of utility CSS vs Module isolation vs naming conventions like BEM.

One bad consequence of the custom element name convention is that the outer layer of a component then has no semantic meaning and accessibility has to be fully implemented by the developer, which requires a lot of knowledge and effort compared to using correct semantic HTML.

Inaccessible code is a real business risk and making all components generic elements with no affordances for screen readers would not help. It’s a pity the article doesn’t consider this at all as its recommended patterns would lead to some needlessly bad experiences.


You can tell custom elements what they are using the „is“ attribute or by extending the appropriate HTMLElement class if you define the custom element via JS.


That seems like quite a hoop/footgun if you are only having devs do this for CSS reasons.


Sounds like a call to return to the days of <P ALIGN="LEFT">.

I occasionally use attribute selectors - really useful when you have crazy requirements like "Here's a table with rows having generated data-index attributes. Make the background of each[0] prime-indexed row blueish".

For other uses classes are quite simply shorter.

Also, if I have to write a lot of CSS then either:

-The stakeholders insist on an "unique look", in which case kill me.

-I'm making a component framework of sorts. If it's an internal project, also kill me.

[0] well, not "each". Just the first 100 or so. Users don't read long lists anyway.


I mean, Tailwind already is that with extra steps.


There's big performance downside replacing classes with attributes at least when using javascript query selectors.

Browsers have special data structures for id and class search optimizations.

Matching attributes scans through the dom top down.


Isn’t this mostly moving the namespacing problem from classes to tags and attributes? It’s not something I mind, but since the other potential solutions were dismissed as flawed for similar reasons, I’m not sure why the solution presented in the post is better than the other solutions.

That criticism aside, I learned something new about CSS today, and the dynamic attribute based values is something I’d like to play around with to see if I like it. I also appreciate the enumeration of different strategies, that is something I can reference in a conversation with a colleague even if my conclusion is different from that of the author. Thanks for sharing.


This gives big bikeshedding vibes. I always liked the idea of semantic markup, but humans are messy and complex and we will always find ways to bring that chaos to utopian systems. Classes and IDs work fine most of the time. Documenting your styles is good practice. Using BEM or Tailwind has the benefit of adhering to a system and base classes that others can make sense of without much effort. CSS is OK. Our energies are better spent on more important things.


Tailwind solves this but not in the way you think!

The rise of React and SSG/SSR means there is a world where the classes are React components and the attributes are props.

Even for static pages, for DX you can use the same tooling as you are used to for dynamic pages. And something like NextJS can generate the static html.

And this makes even more sense for dynamic stuff like date pickers.

In this world you use utility classes because tags are too granular and components are the logical unit.

But if you are hand crafting the html then tailwind might be more of a pain. I am a bit undecided on that. I still have a soft spot for CSS Zen Garden.


> Our energies are better spent on more important things.

This is true about most things in tech though, yes?


> Conceptually you could think of these as classical inheritance (so class Card extends Div) - inherit the semantics and base styles of div while making a re-usable style for a Card class.

You could, but you’d be wrong. The CSS selector specificity algorithm has nothing in common with OO inheritance, and classes are only one of many equivalent ways to interact with that algorithm.


All these examples of "scaling CSS" tends to end with "don't write CSS".

Relying on HTML attributes to describe presentation could have its neat uses, but suggesting it as a new generic paradigm that everybody should jump on regardless of problem space is not the way to go. HTML is not the escape hatch out of CSS.

The main issue is that it's just not better than a class soup of Tailwind classes. It maybe a bit more readable, but if you stuff a DIV with endless `data-junk` then it will be just as bloated as the rest of these specifications if used without care and if you avoid writing CSS it will be pretty bloated.


> HTML is not the escape hatch out of CSS

If anything, CSS is kind of an escape hatch out of HTML/SGML attributes which were specifically introduced for attaching any meaningful info to text nodes not displayed as such to the reader. This is especially evident if you compare the enormous amount of extensions and added non-type-checked ad-hoc syntax to CSS with the relative lack of HTML evolution. The only reason appears to be that HTML was organisationally locked in a W3C process for such a long time, while CSS could be easily extended.

Attributes are used for rendering details all the time with the original concept of markup. The idea that you need a special syntax and separate item-value space that's neither here nor there, like CSS is, when organising item-value assignments is the entire point of attributes and even hard-code a vague structure/presentation dichotomy that's then up for interpretation for like 30 years is beyond absurd. SGML, from before 1986, can already assign attributes (so called link attributes) based on context-dependent rules much like CSS.


Good job everyone. We're almost back there again. Twenty years later, 2026 will be the year of semantic CSS, though I guess it will have a new, cool name. Complete Stylesheets or something I dunno I'm not in marketing.


> Twenty years later, 2026 will be the year of semantic CSS

Alas, people are too deep in tailwind for that :-(


Wow I like this solution a lot, and I’m sad that it’s presented after a million paragraphs of ranting and a terrible title.

The tl;dr is: if you use custom element names (instead of “.Card”) and attributes (instead of “.Card—size-big”), things get very clear and you lose many downsides of other approaches (such as name clashes and unmaintainable soup):

So write HTML like this:

    <my-card data-size="big"></my-card>
And CSS like this:

    my-card { /* ... */ }
    my-card[data-size=big] { width: 100%; }
    my-card[data-size=medium] { width: 50%; }
    my-card[data-size=small] { width: 25%; }
Personally I think this idea is really great. I’m not sure yet that I prefer it over Tailwind in all situations, but it seems obviously better than eg BEM, CSS Modules, inline styles, styled-components and all those other approaches. I really love the idea, it feels like a “woa why didn’t I realize this before” kind of thing.

EDIT: Thinking on this a bit, I’m not sure I’d replace every single div with a custom element like the author suggests, I think a div-with-a-class works just as well and is easier to grok for other readers of the code cause everybody knows how a div works. Readers don’t have to figure out whether it’s a defined custom element (ie a JS class) or just a CSS level thing, etc.

But the idea of using attributes instead of .my-thing—-level-3 is genius in my book. It means you only ever need one class per element at most. No more concatenating long className props, no more repetitive prefixing, it’s scoped by definition, etc. Also all the logic in the HTML rendering code is nicely siloed:

    <div 
      className="my-thing"
      data-level={someFunc(props.foo)}
      data-size={props.size ?? "big"}
      etc
    >
So much nicer than some nested classname object hack!


I didn't know I could just create my own tags in HTML. I assume this makes it harder for accessibility technologies to understand the page?


Obviously if there is a semantic tag, you should use it. But if not, a custom tag is not worse than a <div>.


I'm out of touch, I guess. Can I just use any tags with ordinary HTML? Is it correct HTML?


Yep. The standard promises that new standard tags will never contain a dash, so if your custom tag does contain a dash, it can’t ever clash with future new browser features.


The "data" prefix, followed by whatever you want, has been formalised for quite some time. The DOM provides a "dataset" property.


That's for attributes, not tags, no?


Yes, attributes. The property is on the element.


You can use any tag name with a hyphen, IIRC.


Yes, though I personally don't use it, a weird fear of colliding with obscure existing or new tags down the line. But technically, name spacing them with a prefix should cover that.


Link to the CSS Values 5 specification, where it describes how HTML attribute names can be referenced in CSS properties.

6.4. Attribute References: the attr() function

https://drafts.csswg.org/css-values-5/

With the ability to specify attribute types, including dimension units, and to provide a default value - it does look like a new way to connect HTML to CSS beyond the limitations of classes.

---

> The data- prefix can be a little unwieldy but it allows for the widest compatibility with tools and frameworks. Using attributes without some kind of namespace can be a little dangerous, as you risk clobbering HTML's global attributes, but as long as your attribute name has a dash it should be quite safe.

I wonder if this last part is true. For custom elements, since they're required to have a dash, I imagine future HTML tags are guaranteed to not contain a dash. But for attributes..

Are all future HTML global attributes guaranteed to not include a dash?

Maybe the author means, as long as your custom attribute has a name with unique prefix, it should be "quite safe".


While it hasn't been expressly resolved by the HTML working group to not propose new attributes with dashes, and while I don't speak for everyone in the HTML working group, I would assert that many members would object to a proposed attribute that included a dash (including myself).

There is also a proposal in the works to allow web developers to define custom attributes - much like custom elements - which would likely follow the same or similar rules around dashes, at which point I imagine the HTML spec would guarantee that no dashes would be used in "built in" attributes.

New attributes have been proposed that reasonably _could_ have had a dash, for example `popovertargetaction`, but instead they were compounded to one word precisely to cave out this path.


Very interesting to know, thank you.

There are template languages that extend the HTML syntax but render to valid HTML, and I imagine this kind of guarantee of future naming scheme is important to ensure the extended syntax does not have the potential to conflict with new attributes added to the HTML specs.

> proposal in the works to allow web developers to define custom attributes

Looks like this is it:

Proposal: Custom attributes for all elements, enhancements for more complex use cases

https://github.com/WICG/webcomponents/issues/1029

Searching for "dash" does bring up a thread of discussion around whether to require dashes or not.

---

I wonder if starting the custom attribute with a dash is allowed or not. Searching around, I see colon ":" and underscore "_" are OK, but dash "-" or period "." is only allowed after the first character.

> Any namespace-less attribute that is relevant to the element's functioning, as determined by the element's author, may be specified on an autonomous custom element, so long as the attribute name is XML-compatible and contains no ASCII upper alphas.

https://html.spec.whatwg.org/multipage/custom-elements.html#...

XML-compatible attribute name:

  NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
  NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
  Name ::= NameStartChar (NameChar)*
https://www.w3.org/TR/xml/#NT-NameStartChar


Oh I didn't realize I was speaking to the author of the article! I enjoyed it very much, it was thought-provoking, educational, and made me wonder about new ways of integrating HTML and CSS beyond classes.

One aspect of Tailwind that I'm not satisfied with is editor integration, in particular linting, hints, autocomplete. There are editor extensions for this, but it feels too cramped working inside the `class` value, a single space-separated string.

Custom elements and attributes could enable a better editing experience, for example autocomplete suggestions can be specific to attribute name; or if the attribute is known to have a color as value, the editor can provide a color picker to fill in the value.


Thank you for providing the detail I was scant on.


Clearly the best solution is just to write styles inline, because classes are evil and attributes are just classes with a hat.


How is using markup filled with data-attributes better than "messy" atomic CSS? I don't see how this is an improvement over simply using classes. Maybe it's just me.


Atomic CSS requires a class for every CSS property you wish to set, at each breakpoint, each active/hover/focus state, each color scheme you support, etc. With data-attributes one could specify that the element is a primary, full-width, large button and all the properties that make that happen live in the stylesheet.


The author seems to be under the impression that classes didn't exist before OO. Of course they have always been used to describe broad groups of things and in that context their use in CSS is perfectly consistent.


This is just class names with extra steps and more syntax, it's a downgrade, not an improvement.


If you're not Dijkstra then you're considered harmful if you steal his valor in your title.


https://meyerweb.com/eric/comment/chech.html

“Considered Harmful Essays Considered Harmful”.



The only exception may be "Eval is evil," which is generally true and requires a high bar for using safely.


I could be wrong, but I reckon I read somewhere that the "considered harmful" was added in review by Niklaus Wirth, who, at the time, was editor for CACM.


A snowclone is not "stolen valor", it's a completely normal part of modern writing.

Especially considering that Dijkstra didn't even coin the phrase himself.


It's a stretch at best to call "Considered Harmful" in this context a snowcone.


I mean, this could've been called "CSS Considered harmful". Also suggesting the use of attributes to mix state with style is... quite the bold strategy.

What if the same component is used multiple times in a page with a slightly different appearance and same behaviour? Do you keep adding more attributes? You're gonna end up rebuilding Tailwind, but using an even more opaque syntax.


In the CSS that we have today, they are still probably the least shitty solution in most cases.

attr() for things that aren't content isn't really supported and manually doing [data-gap="1"] {} [data-gap="2"] {} and so on sucks for various reasons. Attributes like [card-size="big"] look good, but unlike classes, they don't get autocompleted so you always have to remember the magic strings (ugh) and errors don't get caught by static analysis.

It's not just the class attribute that's harmful legacy garbage, but the core design of CSS. But we're stuck with it.


I've been building websites for over 20 years and I've come back to frontend after a few years out of the industry recently, horrified to see what developers are doing with current trend tailwindcss trend, but understand why you'd want it. I pity whoever picks up those legacy projects

I thought about using custom tags before for components (not web components, which have a few gotchas) but it came down to SEO. If there were more certainty on the impact of custom tag on SEO I'd already be doing this.


we really need a separation between documents and applications.

for documents - css classes & BEM are more than adequate.

for applications - we seem to have short memories. why not learn from what complex UI frameworks used in industry do e.g desktop frameworks case in point - https://doc.qt.io/qt-6/stylesheet-reference.html#background-...


Lots to dismiss in this, but I was pretty impressed by the bit about psuedo selectors! I had no idea this could be done, and it's pretty awesome! Can't think of when I would use it, given that you have to publish your implementation details for it to be useful (even if you only publish them for your internal team). But for personal projects, or well-moduled projects, I might reach for that little trick in the future.


For the curious, here is a set of "simple" rules for CSS authoring that, coupled with linting (through Stylelint, for instance) can address a lot (most?) of the issues raised in the article and the comments:

https://ecss.info/en/

Interested in what you may think about these rules and the principles behind them.

PS: still a work in progress!


This is impressive and an easy read, well done. Regardless, the fact that so many rules are needed to write good, safe, efficient CSS indicates to me at least a disconnect with the technology and how people want to use it. Indeed, just a casual look around the world of CSS tooling reinforces my opinion. CSS has such an odd mix of declarative-feeling design but with occasional "hacks" to get some imperative-like behaviors that more than once in my career I've thrown in the towel and just reached for a bit of JS to get the result I needed.

Sorry a bit rant-y.


CSS was not meant to be used by programmers but by designers... so yeah there's a disconnect there. But that does not mean programmers cannot use it the way it was intended to instead of making it, at great cost, like what they would have wanted it to be from the beginning!

Also, wouldn't you say that there are also many rules and guiding principles necessary to write good javascript? Genuinely curious here.


CSS is like a wooden spoon.

Conclusion: you are overcomplicating things. This ain't rocket science. CSS is dead simple, only you making it complicated.


The title is made by a person with very bad taste: Dijkstra would have given a different name to the title had he got a chance to return to past and his attitude to person writing articles about CSS would probably have been despising largely.


I expected to hate this article but ended up finding it interesting. The author didn't convince me but I thought they had style interesting points.


The author's solution mixes style declarations (i.e. centering text) into HTML, which surely goes against the spirit of CSS?

    .Card[data-align=center] { text-align: center; }
Filling HTML with data-* style attributes would intertwine layout and content in a single file, meaning we're no longer able to use CSS to flexibly re-style the content.


It looks like you didn't read all the way to the end, and custom data attributes can be for whatever you desire. Presently a lot of people are putting style information right in class names so this distinction you're speaking about isn't present now and developers are already violating it in a big way. The solution in the article is at least using tag names, attributes, and attribute values in ways they're meant to be used. There's a warning about abusing class names in the CSS spec that reads like this:

    Note: Because CSS gives considerable power to the "class" attribute, authors could conceivably design their own "document language" based on elements with almost no associated presentation (such as div and span in HTML) and assigning style information through the "class" attribute. Authors should avoid this practice since the structural elements of a document language often have recognized and accepted meanings and author-defined classes may not.
https://www.w3.org/TR/selectors-4/#example-f9c08b5b


don't write css in the class attribute, write the css in a custom attribute. even better, implement a custom element, that uses custom attributes! how totally brilliant, absolute genius, what a visionary!


I complete disagree with this statement that lacks evidence and it just want to duplicate functionality:

"At first blush a utility class system might seem like a boon to a design system, but when applied to the markup we quickly see the problems: being unable to represent components easily in markup leads to a design system looking for other solutions such as providing markup with attached class names to represent a component - which usually results in the design system implementing components across a multitude of frameworks."

In this era of component frameworks, looking at HTML and its classes is the least of our problems. Our real challenge is to build an additional architecture on both the component side and the CSS side. Additionally, both components and CSS can have (or end up with) more than just styles; they can include behavior, animation, and effects, which adds complexity, making the entire project difficult to memorize, scale, and maintain. OOCSS projects often result in unmaintainable code, with developers ending up with large CSS files and creating more specific classes to implement new features. FCSS (Functional CSS, or Atomic CSS as exemplified here) solves this problem by separating concerns and removing the mental load from the equation.

The problem with Atomic CSS, Tailwind and others I just the syntax. It takes time to master Tailwind toolset of classes. At first it may seems easy and intuitive but it’s deceiving. FCSS has natural language https://www.fcss.club/syntax and it’s hundreds of times more intuitive.

The only real issue of FCSS or Tailwind is achieve inheritance only using CSS inheritance model. Let me give you an example:

.color—blue { … }\ .color—red { … }

<div class=“color—red color—blue”>text</div>

In this situation, you might expect the text to be blue, but it will actually be red due to inheritance weight. This issue can be resolved on the component side easily with JavaScript https://www.fcss.club/customization, providing a more controlled solution.

“There are a plethora of other issues with the Utility CSS methodology, and with it a plethora of articles. If you consider this a suitable solution, I'd encourage you to invest time researching the pitfalls, but I don't want to spend too long on this."

I’ve been reading dozens of articles regarding the atomic approach and I didn’t find any phletora of issues. The only thing I found was a bunch of arguments in favour of OOCSS, all of them listed here. https://www.minid.net/2019/8/12/in-defense-of-functional-css


Just use web components, and use trie attributes instead.


"Scaling class selectors" is a false problem: actually, classes and pseudo-classes "increase the granularity of control over elements" (which are much closer analogues of classes in the OOP sense than CSS classes) better than in 1997 because useful new selectors and pseudoclasses have accumulated over the years.

Class selectors (and everything else) become weak, as should be expected, with monkeys ("With mutually exclusive classes like Big and Small, it is possible for elements to apply both classes at once") working with no actual design ("parameterise Card to take a size option which is either Big Medium or Small, a rounded boolean, and an align option which is either Left, Right, or Center").


It's unfortunate how many people misunderstand CSS today and how web applications should be structured.

Articles like this make me sad.


> Now your design system team is tasked (or burdens other engineering teams) with orchestrating all of this tooling.

Design system team? I'd like to have that problem.


No. I mean data-no=jose




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: