I understand why people hate Tailwind, but it largely solved this problem for me.
I understand why people hate Tailwind, but it largely solved this problem for me.
CSS is about rules, selectors and cascading, hence Css.
Abstractions matter, and using procedural programming abstractions on a declarative styling language only gets in your way.
Writing CSS is not programming.
It's just not one based on states, mutability, and variables. Even the things that use the `var` keyword are constants, not variables.
(But then, don't read that as being against scoped rules. The fact that all rules are global to the document is bad. We can emulate scopes with specific selectors, but that's the kind of thing a language is supposed to help with.)
Constants which you can redefine/shadow in scopes, and change the values of at runtime via JS.
They seem like variables to me.
No, you can't. You can set a new value and reevaluate everything.
elem.style.setProperty(‘—var-name’, newValue);
… will set a new value for the “constant”. The element will rerender with the new value. You can animate/automate these changes and the element will continue to rerebder with the updated value.To me, that justifies the name “variable” from the perspective of the CSS.
We've heard that one before, haven't we? HTML was supposed to be a declarative language, not a vanilla programming one. And look where we are... the biggest mess of a programming language the world has ever seen.
What's the wisdom of randomly inserting cutesy "declarative" bits in a world infused with programming-oriented infrastructure... It doesn't make any sense.
Granted, when you add CSS to the mix, HTML+CSS is programming if you get fancy about it.
HTML5 doesn't refer specifically to HTML, rather it's "HTML + JavaScript + CSS". There's hardly a website nowadays that can be used without JS.
By using the name HTML5 as an umbrella name for a programming language API plus some declarative bits, the W3C tacitly admitted that the declarative push has been a mistake - I explained "why" in my previous comment.
The fact is, JavaScript is ubiquitous in web programing and the web is unthinkable without it, it's so pervasive on the front end that it's been repurposed for backend use precisely because it makes a lot of sense to use one programming language for one project. Pure HTML is unsuitable for backend use and it sticks like a sore thumb in the front end.
Younger developers are likely missing on the history of the entire web endeavor but in order to get a feel for it, I'd recommend to focus on practical meaning rather than on trivial semantics.
The big point I was driving at is this: The damage has been done, instead of a clean rendering API we've got this hybrid monstrosity which locked us to a couple / triple browser rendering engines which, due to cutesy BS, are complex beyond comprehension, beyond security analysis or normal competition. This is what an obsession with fancy names leads to.
It's our fault we pack all the rules in one file and ship it to all our pages.
"Shadowing" is on purpose it's the cascading part of the cascading style sheets. There are rules around which rule has priority read about selector specificity.
Where do you see CSS being global mutable state?
There are solutions/workarounds to this. First following a convention like BEM, then enforcing that at build time (CSS Modules), and now (potentially, i haven't checked in with it) the language supports @scope.
You can do this in TypeScript and Ruby too.
on edit: a downvote on that, really. because I don't think class names are anything like a variable!
Give your element a class. Now show me the CSS that styles it. Good luck because it can be literally anywhere.
Absolutely the worst kind of variable.
One very obvious example is browser defaults.
You literally have no idea what they are. You can override them, but not until you find a list so you know what to override.
Did you know the default browser margin for body is 8px?
Insane.
Frankly I tend to find analogies not very useful, I don't think my analogy of CSS as a db is very good, but as bad as it is I feel it makes some sense as opposed to talk about classes as if they were global mutable variables.
I will take my analogy slightly farther.
I will say the browser ships with a DB system called CSS, and a toy DB called BrowserDefaults implemented in CSS, the same way MS Access used to ship with Northwind. The especially sucky thing about this system is that when you want to create your own DB you have to extend BrowserDefaults. This is why a lot of specific DBs have what are called resets that basically delete all of the BrowserDefaults setup so it is not messing with your DB.
The browser also ships with two languages with the ability to query CSS, one is JavaScript and that is a pretty straightforward language it can read and write to CSS using an API called the CSSOM. The other query language is a tree based query language called HTML (actually there is also another tree based language called XML in there but nobody talks about that anymore, let's just say it works almost the same as HTML only when you use it, it automatically clears all the data out of the base BrowserDefaults DB)
(We can see what I mean about analogies suck right about here)
This tree based query language is crazy as shit! Because it is not just a query language but also has some weird transformational capabilities.
And also the thing that is weird is that the HTML query language can be changed by the JavaScript language!
Let's look at an example
Let's suppose we have a tree structure like this
<div class="one"></div>
<div class="two"></div>
and the JavaScript holds a tree fragment <span class="myspan">text</span>
and the CSS says
.myspan { color: green; } .one span { color: red }
.two span { color: black }
the JavaScript reading that fragment css properties will see that "color" = "green"
but placing it inside of the parts of the HTML tree gives different values for the color property. Some people will mistakenly claim at this point that the is mutation of the global state but that is obviously incorrect. The CSS state has not been mutated at all, what the HTML query has done essentially is run a transformation and output an object, the CSS state remains unchanged because JavaScript can use the CSSOM to query what the data in the myspan class is.
JavaScript can mutate the value of the CSS classes, but HTML cannot. HTML essentially copies all the classes, runs a transformation, and outputs the result.
This is actually a pretty interesting situation, I don't feel that there is any similar architecture anywhere. I don't feel it really fits with DSSL or Latex (because of how JavaScript works with HTML)
Now although I don't feel that I have ever really had the problems that other people of undoubtedly superior programming ability seem to have with this, I can see how this unique and somewhat accidentally arrived at architecture can be irritating to people.
Note - when I say I don't have any problems I mean sure, I can create bugs with this, I can find bugs impacting me with this, but I've never really had long running hard to resolve bugs due to CSS/HTML. Bugs that are generally hard to resolve I find are in the JS stack.
Going back to the browser defaults thing - again not really a good example of either of our analogies, more an example of how every programming language has its idiosyncratic and stupid things you just have to learn about it and keep in mind or they will bite you on the ass.
on edit: obviously I am not making any claims as to internal implementations in browsers and how they do it, I am just discussing the external experience of these languages working together and how to think about them.
.one span {color: red}
.one span {color: purple}
inside of a CSS file.
Again I don't think I could consider that as mutating state.
This is mutating state
let color = "red";
if (x} { color = "purple"; }
because it mutates the variable value at run time based on something else.
The variable at different parts of the program have different values.
If you read .one span with the CSSOM in the above example it will always return color: purple.
That is not a mutated value, that is poorly written code that has been compiled down.
JS with CSSOM can read what the value .myspan, .one span and .two span all are.
because this is the point where CSS breaks down as a db holding properties, it is here that it is instructions for the HTML language on how it is to run transformations.
It ought to be possible to compose HTML documents the way Ted Nelson wanted to compose documents in Xanadu, it's a PITA to do because the classes are all in the same namespace although now we have Shadow DOM to manage this and you can even do it without JS with Declarative Shadow DOM.
It's a source of stress to add a class to the system with a simple, short and readable name and have to worry it is used someplace else. There is BEM but I despite it (not simple, not short, not readable)
I work on a React application that uses more than one plain-CSS framework and also Emotion and some other JS frameworks that generate more CSS properties. These are all leaky abstractions so if you aren't happy with the defaults the way I am with my boostrap-based RSS reader, you have to understand the abstractions of the framework and still understand the underlying CSS. Probably the worst time was when I had to get an application to run inside the Shadow DOM and vendorize some components to patch them accordingly.
One saving grace is that that LLMs are good at both coding CSS and answering questions about how it works.
That is the whole point of CSS classes: re-use. A CSS class is not meant to be used in only one very specific place. For that, you can select an element's ID or an elements HTML path, to style just that one thing.
2. Custom properties can be scoped to a particular part of the DOM [1].
3. @function has shipped Chrome; custom properties defined inside of an `at` function are local custom properties. So are the parameters.
4. Local properties stay local unless the outside explicitly references them (which it can't without knowing they exist)
[1] Limit the reach of your selectors with the CSS @scope at-rule -- https://developer.chrome.com/docs/css-ui/at-scope
It's like saying Rego[1] should just be done in a procedural language when in fact it also wouldn't be useful in that context.
Tailwind is built on top of CSS. It is basically a library of hundreds of tiny "global", documented CSS classes.