My favourite 3 lines of CSS
andy-bell.co.uk
andy-bell.co.uk
Because the syntax looks somewhat like the function notation in math, and a variation of it is also present in many programming languages, often functional, but also Java since version 8. It's quite widespread and not very bizarre / specific to JS.
You'd have mentioned tagged templates [1], I'd have to bow.
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
It counts, because it makes it familiar to many people.
Had JS introduced this syntax without it being anywhere else I would be completely with you: it would just be weird and unnecessarily complicated.
I find this syntax very clear too (though I still prefer function () { ... } for most functions). It has the merit to make some code using small functions, often somewhat functional, lighter to read. But this is a matter of taste, of course.
Having said that, I also knew what it did immediately upon reading it, and I am not a CSS expert. One you know a little bit about selectors, then you should be able to decode this one rather easily.
I still can’t remember how to horizontally and vertically center an element but CGPT sure can.
This isn't to say those hacks were good, mind you - just that their existence was never really a problem insofar as ability to understand them if you dealt with it once.
I'm not worried.
> The spec is already huge, the selectors are hard to read and google, the interplay between various features is devilishly complex.
Actually things are getting less complex due the fact we don't need to use all of the hacks, work-arounds and polyfills that were once just what pretty much every web developer did not that long ago. And of course, the original sin of the misuse of HTML tables for layout.
Sure, it wasn't fun to deal with new specs coming out while trying to maintain existing code and attempting to understand when (or if) we can use the new stuff. Sometimes is was like trying to fly a plane while the plane is being retrofitted with new features.
The irony: many of the techniques described in the article is how we should have been doing things for along time. Hayden's article [1], which is the basis for this, was published nearly 10 years ago—these concepts aren't new.
[1]: https://alistapart.com/article/axiomatic-css-and-lobotomized...
Hardly a sin - there were no alternatives at the time (1996 - 1998) if you wanted a tabular or grid layout.
The first edition of Zeldman’s seminal book Designing with Web Standards [1] was released in 2003; two additional editions were released in 2007 and 2009.
[1]: https://en.wikipedia.org/wiki/Designing_with_Web_Standards
Many of the newer CSS features prevent you using JavaScript to achieve the same thing, which is better as it results in better performance and easier to understand code.
I would rather have newer standardised selectors than see the same pattern re-implemented with JS differently in every codebase.
And let's face it… to understand the example code you only need understand what > + * do in CSS
Using intrinsic sizing, and the sorts of approaches Andy Bell suggests reduces the volume of CSS enormously and can often get rid of media queries and huge numbers of selectors that get repeated across viewport sizes
I'd really encourage you to watch this talk by Andy https://www.youtube.com/watch?v=5uhIiI9Ld5M
If you know your basic CSS selectors `.stack > * + *` is very easy to understand. I didn't know `* - *` was sometimes referred to as "lobotomized owl selector" but it doesn't matter, `>`, `*` and `+` are all basic selectors that everyone working with CSS should know from the top of their head. None of these are "clever". If you can't read `.stack > * + *`, you don't know CSS selectors. I'd even argue if you don't use mostly `>` instead of ` ` (space selector) your stylesheets are probably unmaintainable.
CSS hacks were a shit show 10 years ago because of browser compatibility, but the thing presented here is not a hack, it's just a useful rule.
I had the same thought with Regex before learning it. Now I can read it like css selectors, and you'll notice that the complex patterns are that way because they have to cover dynamic situations (using ranges, lookbehind/lookahead, etc).
.stack > * + * {
margin-block-start: 1.5rem;
}
I got it immediately because I think I've been doing something similar for a while. I identified the problem it solves. I understand that if you haven't encountered the situation, it's probably hard to decipher.It reads like: apply a top margin to all direct children that are not the first one.
I write it like this:
.stack > :not(:first-child) {
margin-top: 1.5rem;
}
I probably should start using -block-start. I'll keep my selector though I think.I didn't know about the default value parameter of --var, I'll probably use it too.
margin-block-* and margin-inline-* (versus margin-{top,right,bottom,left}) are more generic and take into account the writing-mode, direction, and text-orientation.
https://developer.mozilla.org/en-US/docs/Web/CSS/margin-inli...
Notably, for instance, if you want to support both rtl and ltr languages, margin-inline-start (instead of margin-left) will behave correctly and put the margin at the correct side.
If you ask me, it's a step towards specifying/conveying the intent and not hard-coding the look.
* + * is 0,0,0.
:not(:first-child) is 0,1,0.
:where(:not(:first-child)) would take it back to 0,0,0.
So do I, I am somehow wired to think "* is going to be very bad for performance because now the rendering engine will need to apply this bunch of rules to any and every element on earth, which might not be only overkill, but which also might have undesirable side effect."
It might not really apply here but the feeling is present.
https://www.reddit.com/r/web_design/comments/5u6e7b/comment/...
Other browsers might see different results, especially Firefox which has a very fast / efficient CSS engine.
ps: a difference of 43 ms for one page load would be huge indeed. By comparison, a frame in a 30 fps video is 33 ms.
With all the recent criticism of tailwind, css-in-js, and other bloated frameworks I truly feel like 90% of projects could get away with a handful of sensible global styles or "classless css" and then aggressive use of components with scoped styles. You hardly ever need anything else
/* lobotomized owl typography*/Your approach, redefining all the properties per class, echoes avoiding using parent+subclass relationships in OO style code. Sometimes you benefit from the generalisation of a class hierarchy, sometimes you don’t. A hard rule in either direction gets in everyone's way.
The "C" is an attempt to make it easy to have a mixture of generic rules that apply across the whole page/site, and specific rules for alternatives and edge cases. CSS and particularly the C make it really easy to say:
button { border-radius: 20%; background-colour: teal; color: white; }
button.cta { background-colour: blue; colour: yellow; }
What's wrong with that? How would you do it otherwise? In a way that generalises to any HTML or XML element? Without changing HTML or XML? It's essentially a syntactic formulation of multiple inheritance. I accept that multiple inheritance is frowned upon and difficult, but it's not without precedent or practicality.
Does the designer really want such a specific edge case to an edge case? Can they explain or justify it according to the design patterns they laid down? Why are we using such a general ".container" to specify a ".button", and whilst we're at it why do we have a "button" AND a ".button". Our codebase was going off the rails long before we reached this (admittedly scary-looking) selector. There was a better way to do what we're doing, several iterations ago, and people who cared about the ux+information design and the CSS should have caught it sooner. Go back to them and fix the problem there rather than let this horrible selector pass code review.
We wouldn't stand for this in the TS/JS codebase. Why do we put up with it in the CSS?
To be honest, I was never on board with the "classes everywhere" approach. IDs are fine when they identify a single item on the page. We lost something when we stopped using the language as it was designed.
Also a lot of it comes down to the original plan to have semantic HTML, which ultimately failed. But we rarely talk about whether semantic CSS is possible, I think the assumption is that it is. But IMO it's not practical because of the poor specificity controls. That's something I'd do different, add in a manual specificity level (like how z-index has manual weights).
> the original plan to have semantic HTML, which ultimately failed
I feel that browser developers still build browsers with this in mind. You can see this expressed in the default ARIA roles, for example. I feel that developers of large web apps are the ones who aren't thinking about the semantics the right way and who think semantic HTML has failed. It didn't, they gave up trying to use it. Most of us think only in terms of using JS to render anonymous boxes, rather than about outputting an implementation of an underlying information design. Browsers and HTML still supports that very well. We're wrapping all the conceptual design up into JS and components, and treating the HTML + CSS as some kind of dumb output... when in fact that's the browser's job, and it hides that dumb render from us on purpose. If you use your web framework to output an expressive information design, the browser will render it just fine and more of your code will make sense (IMO).
I don't think you gain much from allowing manual specificity. No-one finds managing z-indexes easy. In fact, I think manual specificity would accentuate the problems we already have. You can fix most z-index issues by not using it, because the stacking is mostly handled already for you by the browser. Imagine trying to find the "specificity 203" in your codebase, or to establish a pattern for which disparate Thing A on the page is the same specificity as a Thing B. It'd be harder than the current system, I"m sure.
I develop things at work similarly to you. JSS where every component has its own style, but you have a common `theme` file so that you can reuse the common styles via a library.
But I have a certain romantic feeling about… what if we could do 90%+ of our styling using these global-per-page rules, and overriding when necessary. The simplicity is really appealing
These various CSS states would be much better expressed as named properties of React components. That way there would be explicit branches instead of allowing the CSS selector engine to do some implicit insanity.
To be fair, this is the first time I see this but I immediately got it. So might not be as hard / innovative for no reason. I believe someone working often with CSS should be able to parse *+*, and if not, take the time it takes once to understand it. It's nothing that implicit.
Anyway please please don't pull off a React to avoid CSS, just comment your CSS instead, or find a clearer way to write it if you prefer (:not(:first-child)).
This styles documents (puts margins on paragraphs), we don't want an app for this. And even for a React app, we have a nice language to style stuff at our disposal that our browsers are incredibly efficient at evaluating, I don't think reinventing CSS in React is a good thing.
React will die before CSS anyway.
By no means am I an expert, but I thoroughly enjoy writing CSS using techniques they teach in the book. Somehow, it helps me to think of CSS as a constraint programming system. Combinators are that --- layout constraint directives.
Architecturally, I really like the choice of pulling apart CSS in terms of structural definitions (Stack, Box, Switcher etc.), style definitions (applied to leaf nodes as far as possible), and global rules, ratios, and units (e.g. modular scale).
I think the system composes beautifully and lets me do a lot with a very small set of core definitions.
My personal site uses those techniques: https://www.evalapply.org/static/css/style.css
edit: formatting
*, *::before, *::after{
box-sizing: border-box;
overflow-wrap: break-word;
}Firstly, it’s too general. Most boxes don’t care which sizing model is being applied. I have found that I want explicit control more often. To be fair, I learned web development when I had no choice but to work with both models so I don’t find the switching much of a burden.
Second, I’ve seen * { box-sizing: border-box; } cause whole areas of the screen to disappear due to a bug in Chrome. This was years ago, so those bugs have probably been fixed, but it was such a significant problem to the layout and caused by such a generally applied rule, that it’s put me off.
I learned CSS with the W3C / standard box model, in a time where we had to deal with the buggy IE behavior which was essentially box-sizing: border-box. Now, we have the choice of specifying which box model to use and is seems many people prefer box-sizing: border-box. I'm definitely used to the standard/default one more but odds are someone overridden this.
I don't know which one is better but now we have two existing box models, and depending on the project you work on, the default one depends on what was decided when starting it. It's weird, before it was depending on the browser in use, not the project :-)
I'm not sure how this interacts with libraries / components you import that might not expect such a global setting. I guess you have to be very defensive about this when writing a component. And it seems the expectation is that the component writer should be defensive rather than the website / app builder be careful not to break stuff with global rules. Which is also weird to me.
The spirit of the cascading styles was that you could style and customize everything and that stuff you import would adapt to your styling, but we are rejecting this idea by going out of our ways fool-proofing everything and making nothing customizable. I understand why (it's hard to support everything and ensure no breakage), but this still feels backwards to me.
We were begging for these features for years and it was a nightmare waiting for enough browser support.
[1]: https://alistapart.com/article/axiomatic-css-and-lobotomized...
I think I'd probably opt to buy into flexbox/grids and gap for greenfields projects, but I do appreciate the notion of flow axioms and styling the space between adjacent items.
It helps avoid bleeding issues of space which used to require :last-child / :first-child / :only-child overrides.
...but that's exactly how a sound design system SHOULD work. Structural components (containers etc) SHOULD be in complete control of child distribution. I simply cannot imagine what a nightmare having to manage margin at an atomic component level for everything would be instead of just spelling out a few container components for them all to live in.
Furthermore the resistance to using the two display types that utilise the gap property (flex + grid) is absolutely bizarre. No sane person would avoid these tools as web dev without them is messy and utterly maddening, so this resistance makes no sense at all.
> The author's arguments against gap
I don't think it's a argument against gap. It's that this technique is advantageous in some situations. It is stated later on that grid is his choice for bespoke layouts.
> what a nightmare having to manage margin at an atomic component level for everything would be instead of just spelling out a few container components
This is the essence of the technique. Specifying `* + *` allows controlling the layout of adjacent elements, rather than an atomic element. I think this would all make more sense after reading some of the precedent material: https://alistapart.com/article/axiomatic-css-and-lobotomized.... (It's actually pretty succinct, so rehashing it here wouldn't add anything.)
When I was younger I also had a phase where I liked to do things like these because I could. Nowadays I do things in a way that doesn't waste my own (or other people's) time by being too clever
border box, flex, the trick to make a square with ::before and content/padding 100%
A person which values their sanity would not write this in CSS.
@tailwind base;
@tailwind components;
@tailwind utilities; :)