[HN Gopher] You want enabling CSS selectors, not disabling ones ___________________________________________________________________ You want enabling CSS selectors, not disabling ones Author : AryanBeezadhur Score : 206 points Date : 2021-08-31 21:21 UTC (12 hours ago) (HTM) web link (css-tricks.com) (TXT) w3m dump (css-tricks.com) | jimkleiber wrote: | Hmm, I visited the site on my phone and it seemed to be glitching | out. A red background with white outlined large lettering | blinking on and off so quickly I couldn't decipher the text. | Looked like maybe a GA and some xxxxx after it. Viewing from an | iPhone X using the iOS 14.7.1 on Firefox. | | Anyone else seeing this? Or am I 1) crazy and/or 2) admitting to | having some crazy virus on my phone? | maccolgan wrote: | If it starts with GA and has random stuff after it, probably | related to Google Analytics | politician wrote: | Is there a language that compiles to CSS but excludes the decades | of cruft that have accumulated in CSS? Something that just | exposes a few key primitives and jettisons the rest even if that | means it doesn't handle some extreme edge cases? | lucb1e wrote: | I wonder if people would have the same sentiment if it had been | a newly introduced language that the major browsers overnight | agreed to all include as alternative to CSS. Now I feel like | CSS keeps getting more complicated, but if there was a shiny | new thing supported by all browsers, I would probably feel | different. | goto11 wrote: | What in particular do you consider cruft? The original | "standard flow" layout model is still very relevant for | document-like pages like Wikipedia even if more advanced layout | models have become available. In theory you can do everything | with absolute positioning (the only primitive you really need) | but it would be completely impractical. | extra88 wrote: | > decades of cruft that have accumulated in CSS | | Like what? | | I assume there's _some_ CSS that doesn 't have a use anymore | but thinking about layout, we don't need floats for page layout | but that was basically a hack, float is still useful for its | original purpose. | | Basically, the CSS spec isn't full of cruft but there are a lot | of CSS _practices_ that are no longer needed. | Brendinooo wrote: | Was just thinking about this the other day. Once aspect-ratio | gets Safari support, that will take away the need for the | height:0/padding-bottom: 66% thing, which is one of the last | hacky bits of CSS that I use regularly. Container queries | will fill another huge hole, but I don't polyfill/do hacky | things for that in the meantime. | | CSS really does do pretty much everything you need these | days. | ArchieMaclean wrote: | I think the hard part with this is that because CSS properties | are so context-dependent, the compiler would have to somehow | figure out a way to translate your simple property into the | correct one, without knowing how your HTML is structured. | | For example: | | .thing { topgap: 10 } | | .other { topgap: 10 } | | Would have to compile to different things if .thing was in a | flexbox and .other was in a grid or a box. Since a lot of HTML | is dynamically generated, we don't actually "know" this, and | specifying which to use yourself ahead of time defeats the | purpose, since you may as well just use the normal CSS | properties. This could however work with completely static | HTML. Maybe some JavaScript solution could hack on dynamic CSS | but I would be sceptical of accessibility and performance in | that case. | | In the precompiled case, unless all the CSS was outputted using | a very limited subset of CSS along with a large "base" CSS | file, I don't quite know how it would work. | | I hope somebody proves me wrong! | eyelidlessness wrote: | This is a case where build tools surprisingly shine. Example: | if you use Fela (CSS-in-JS atomic style library), but build | statically, it has all the context it needs to determine | optimal order of rules and which rules are actually in use... | but you can pipe the styles wherever you want at build time | and eliminate the runtime for anything static. | | (I use this on my site. It's suboptimal for build and could | use a mountain of refactor. But the source is up on my GH if | anyone's curious) | tenaciousDaniel wrote: | I've been in the process of designing exactly such a language. | It's nowhere near ready, but my goal is to create a design tool | that can edit this language either using a figma/sketch like | GUI or by editing the code directly. | avereveard wrote: | So what's the enabling fade/in equivalent? | jontro wrote: | I don't see why 0 should be treated as special value. Initial | should be used if meant to "disable" it. | | What if you want margin: 5px as the general rule and margin: 10px | on the last element. Is 10px a disabling selector? | cerved wrote: | I believe that's exactly the point. You don't set all to 5px | and then override using a special rule that says 0px for the | last. You exclude the last element from the 5px rule. | | There might be other rules, browser, user that should not over | the 5px rule | TimTheTinker wrote: | I disagree. If a 5px margin is the general rule, then I would | argue it's cleaner to apply it generally, and then apply the | 10px margin exceptions in separate rules. | | - When special cases are added or removed, the general rule | won't have to be adjusted, just code that handles the special | cases. | | - On the other hand, a single general rule that specifically | avoids application to multiple exceptional cases will be | pretty long and have multiple :not()s, thus reducing | readability and maintainability. | | Why burden the general rule with knowledge of its exceptions? | To me, doing so is a (small) violation of the principle of | separation of concerns. | mattwad wrote: | plus it's called "cascading style sheets". you're going | against the current if everything wants to be so specific. | This is one of my gripes with styled components.. it makes | it easy to forget the power of cascading rules! | TimTheTinker wrote: | ... but if you're nesting styled components, you'd better | not forget about the cascade :-) | leephillips wrote: | I think that forgetting the power of the cascade is part | of the point, maybe the main point. | TimTheTinker wrote: | For me, forgetting the cascade has nothing to do with it; | in my use cases, styled-components is all about: | | - eliminating the chance of colliding CSS class names | when composing multiple micro-clients together | | - simplifying builds, especially cascading builds | (library + client). It's nice when styles are covered | entirely by the JS build (no separate CSS/SCSS input or | output files or separate build pipelines). | | Yes, there are other complexities/problems that styled- | components adds (including the likelihood that devs | _will_ forget about the cascade)... so I wouldn 't | recommend it for every case. But it does have its place. | croes wrote: | As I understand it it's not about the value but that first a | rule is applied to all elements and then a new rule overwrites | the previous rule for some element, the last one in that | example. | | To quote the article referenced in the article: "I call this | technique disabling selector since the li:last-child selector | disables the previous selector's rule." | | So the 10px margin for the last element is a disabling | selector. | chrismorgan wrote: | > _Initial should be used if meant to "disable" it._ | | `initial` isn't any better than 0 for this sort of purpose. | `unset` and `revert` are _probably_ less bad; I'd tend to | choose `unset`. | [deleted] | oleganza wrote: | This reminds of an idea in math that proofs by construction are | better than proofs by contradiction. Or making artificial | grammars (e.g. PLs) with recursive descent parsers instead of | context-sensitive grammars with Turing-complete parsers. | | If you can build something step-by-step with a clear hierarchy | and easy to trace causes and effects, the result seems to be more | convincing/reliable than a process involving a bunch of logical | roundabouts. Of course, if that's at all possible for a problem | at hand. | leephillips wrote: | That's what made Paul Gordon complain after he read a proof by | David Hilbert, of his own conjecture, that "This is not | mathematics. This is theology." | ljm wrote: | I think CSS is approaching the point where it's equivalent to | assembly because it's impossible to keep up and write good CSS. | It's no longer easy to do it by hand which is why there is a | whole ecosystem of tooling that handles CSS. | | Not to mention that CSS is essentially platform-specific due to | differences between chrome, safari and firefox. | ericwood wrote: | What this article describes is no different than programming | patterns in more traditional languages. | | I legitimately can't think of anything that has made it more | difficult to write by hand in the last 15 or so years; if | anything it's never been easier! Building complex software | is...complex, and frameworks and tools in the CSS world are no | different than reaching for an MVC framework or ORM. | | There's minor quirks between browsers, but it's a far cry from | being platform-specific, and a huge improvement on the | incompatibilities of yore. | iratewizard wrote: | Mirroring this sentiment. CSS is fantastic now and they've | put a lot of careful attention into the new specifications. I | haven't run into a situation in years where I was unable to | lay something out the way I pictured it in my mock ups. We | used to have to do a lot of hacking just to get simple things | into layout in the mid to late 2000's. | extra88 wrote: | Some tooling is for managing the complexity caused by | complexity of the site/app. | | Some tooling is managing the complexity of managing component- | centered design (particularly scoping); it's a very positive | approach to design but it's not without its problems. | | Some tooling is to help developers avoid having to actually | learn the CSS language well and/or to force it into JavaScript. | | > CSS is essentially platform-specific due to differences | between chrome, safari and firefox. | | That's an exaggeration. Consistency of implementations between | browsers is better than its every been. There are still some | vendor-prefixed properties to care about, especially if one is | generous in one's support for older browsers, but that's | another reason CSS tooling exists, to write only standard CSS | and let the tool fill in the older variants. | chefandy wrote: | That's true for every language/format used on the front end. | | I do a lot of visual work as a designer/developer. If it | weren't for the obvious accessibility caveats such as basic | page structure, I'd be making at least 20% of the pages I code | in straight SVG. | | Edit: Maybe not HTML5 I guess... you can make anything | inscrutable if you try. | serverholic wrote: | If you're using react or another frontend framework then you | really don't need css selectors. Just make plain css classes and | dynamically append them to your components. So much simpler. | | We do this at my current job and it's honestly the easiest time | I've ever had with CSS. | extra88 wrote: | How do you solve the kind of problem the article is describing? | How do you have a margin on the bottom of every <Card> except | the last one? Is there a loop for cards with a conditional that | doesn't add the margin? I think the declarative language | solution they offer is better. | serverholic wrote: | Yeah just use the index of the card. For example: | | cards.map((card, i) => { const isLast = i === | cards.length - 1 const className = "card" + isLast | ? '' : 'card-margin' return <Card | className={className} /> | | )} | | The nice thing about this is you have a full programming | language at your fingertips. You could do something with | every even card, ever prime number card, etc. | extra88 wrote: | Just because you _can_ do everything in JavaScript doesn 't | mean you should. The equivalent CSS is a lot shorter and | more performant. | | > every prime number card | | You got me, CSS alone can't select only primes. | serverholic wrote: | The performance difference is negligible. If you add a | new card to the list then react is going to add/remove a | couple CSS classes. Completely negligible. | | Plus you're going to need this approach anyway if you | want to do any more advanced logic like maybe you have a | list of users and you want to color them based on some | status. | | With this method you have the above logic all in one | place and in one language. After having used traditional | CSS with selectors vs this method I really can't go back. | extra88 wrote: | You may need the .map() for styling based on status but | const isLast = i === cards.length - 1 const | className = "card" + isLast ? '' : 'card-margin' | | Seems funny to argue for JavaScript's simplicity while | using .map() and an anonymous callback function; a good | ol' for loop would make it more clear what's happening. | | > all in one place and in one language | | That seems like the real reason, keeping to one language. | | I think following the rule of least power [0], having | HTML semantics do what it's good at, CSS what its good | at, and JavaScript for the rest is best for robust and | performant outcomes. <Card | className={className} /> | | I only have a little experience with React and that was a | while ago, can you not have the Card typed as an Element | to use `Card.classList.add(className)`? | | [0] https://en.wikipedia.org/wiki/Rule_of_least_power | mst wrote: | > Seems funny to argue for JavaScript's simplicity while | using .map() and an anonymous callback function; a good | ol' for loop would make it more clear what's happening. | | When you're doing a side effect free transform of some | data, I find .map far clearer. | | A for loop would require .push type noise for that case | and so personally I'd find that noisier and harder to | skim read. | | Tastes vary, of course, but certainly it doesn't seem | funny to me at all. | 11235813213455 wrote: | you're missing parens: "card" + (isLast ? '' : 'card- | margin') // ternary has a very low precedence | https://developer.mozilla.org/en- | US/docs/Web/JavaScript/Refe... | | or `card ${isLast ? '' : 'card-margin'}` | poniko wrote: | yes but no .. seems like a weird rule that makes it harder to | understand and read. A flow of default, exception, exception is | easier to follow. And What if you have odd even, every third etc | etc .. | extra88 wrote: | > What if you have odd even, every third etc | | The solution is the same. `:nth-child(3n)` selects every third | so you add the :not(:last-of-child) to the end to prevent it | from being matched by the rule. .card:nth- | child(3n):not(:last-of-child) { /* styles for every | third card, not the last card */ } | | What's less clear to me is why `.card + .card` would be better | for applying a style to all but the first card than | `.card:not(:first-child)`. I think there are reasons for not | using `*:not(:first-child)` and preferring the "lobotomized | owl" `* + *` but my hunch is they don't apply when styling | classes. | matthoiland wrote: | Interesting way to think - we use additive color (RGB) on web so | why not additive styling? | | But in practice while creating interfaces, we're making broad | brush strokes, then accommodating exceptions, like :last-child. | | Also curious about how browsers prioritize the render stages - | does every style get applied sequentially (hence cascading), or | do pseudo selectors get applied later during the paint? | thaumasiotes wrote: | > Interesting way to think - we use additive color (RGB) on web | so why not additive styling? | | Sounds confused. I'm not sure what "additive styling" means, | but I'm sure it doesn't mean the same thing as "additive | color". "Kids like jelly beans, so why not lima beans?" | | The reason we use additive color on the web is that it reflects | the display technology, which is a bunch of independent light | emitters. The web has nothing to do with it, except that the | web is viewed on computers. | andrewmcwatters wrote: | Style calculations are typically done before rendering, but as | far as I know, there's nothing in the spec that dictates you | needing to do anything specific other than comply with the | output outlined. | emadabdulrahim wrote: | The best resource that will teach you systematic thinking and | give you a proper foundation for how to use CSS is https://every- | layout.dev/. [0] | | Really enjoyable read and it takes you through the thinking | process. | | [0] Not recommended for absolute beginners | nine_k wrote: | $69 for full access (one-time payment AFAICT). | | Must be worth it if web design is your profession. | asleepawake wrote: | Absolutely worth it. Top 3 books I've ever read on web design | emi2k01 wrote: | May I know what are the other two? I read Every Layout for | the past hour and it's good so I'd like to read something | else of similar quality in the future. | | Also, how did you come across those books? I just found out | about Every Layout in this thread. I'm not a web developer | so I don't know if it was advertised in a web dev forum or | what. | dairylee wrote: | Here are some other excellent resources from the authors | of Every Layout: | | https://inclusive-components.design/ | | https://cube.fyi/ | | https://briefs.video/ | emadabdulrahim wrote: | Imagine you charge $69 an hour as a developer. Learning the | proper way to think about building resilient CSS layout will | save you tens of hours throughout your career by building | things the right way from the beginning. | jordwest wrote: | This selector has saved me an inordinate amount of time hacking | together UIs quickly: .vertical-stack > | :not(:last-child) { margin-bottom: 8px } | | Just add the class to a parent and all the children will have | spaced between, but no spacing around the edges. It's then easy | to add padding to the parent: <div | class="vertical-stack"> <h1>Heading</h1> | <p>Paragraph</p> <p>Paragraph</p> </div> | have_faith wrote: | This is a bit easier these days with Grid. You can set grid- | template-columns: 1fr; and use gap: 20px; to control the | spacing which feels much more natural. You can then pad as you | like. | | edit: realise this is at the end of the article so you probably | already know this | evan_ wrote: | `gap` is available on Flexbox in most browsers since earlier | this year. | innocenat wrote: | Currently it's ~86% according to caniuse.com. I think it's | still a bit low to be used comfortably. | pdamoc wrote: | Good enough for vertical markets and admin/back-office | apps. | gempir wrote: | It doesn't work on iOS 13 only grid gap works | [deleted] | raihansaputra wrote: | Yeah I have a variation of this too. stack-y-<size> and | stack-h-<size> for horizontal spacing. This combined with Flex | makes a lot of layout implementations easy. | thorin1 wrote: | I am always using negative margins on container for this. | wruza wrote: | And then you can't nest one container into another, because | there is only one "margin" rule and they don't add up. You | start to wrap children into separate containers only to find | out that it breaks more and more "nice and simple css tricks" | you used before. Eventually you end up with half-broken | bootstrap/etc clone that even supports component design if | looked at from afar. After few weeks it starts to feel like | not using components at all would be much less of a | maintenance. Css "tricks" are full of these situational | traps. | eyelidlessness wrote: | If you want to keep doing this, it'll save you a whole lot of | heartache if you also wholesale prevent margin collapsing. In | fact, some people recommended that as a baseline default (I | personally find it great for layout but surprisingly mixed | for typography). | wruza wrote: | If only we had <sizer> (or display:sizer) element that | could expand, disappear on wrap and not count as a regular | child (sort of like a space in a text node)... But that | would be so '90s. | eyelidlessness wrote: | I really think CSS gap is going to cover most of these | needs. Adding decorative nodes to the DOM doesn't seem | like a good solution. | wruza wrote: | _decorative nodes to the DOM doesn't seem like a good | solution_ | | Why? You could add the same constraints to the sizer: | min, max, flex shrink/grow, put a line or any other shape | in it. It wouldn't even take a separate "display" mode, | just make :row-start, :row-end and :row-wrap | pseudoclasses to control collapsibility of regular divs | at the sides of a container (or whatever styling you | need, anything). Instead they feed us yet another | crippled special case with these gaps. | ximm wrote: | The downside of the enabling rule is that it has high | specificity. I often have that issue with links. But if you are | really strict about this and never overwrite styles anyway you do | not even need to think about specificity. | mewpmewp2 wrote: | It might be subjective, but I disagree, for me it would be easier | to reason, read and maintain the first way, preferably with scss, | so you nest the last child. Maybe it is because that's the | pattern I have most faced, though. | | And I think definitely avoid li + li. It wouldn't be immediately | obvious at all for me if I saw that, what the intention is. | extra88 wrote: | > I think definitely avoid li + li. It wouldn't be immediately | obvious at all for me if I saw that, what the intention is. | | Nothing unfamiliar is obvious. As with any language, get to | know the capabilities of CSS better and it will feel familiar. | The article is right that for spacing, the `gap` property on | the parent makes more sense but hasn't been around long enough, | we need some more older browsers to age out (especially when | used with Flexbox). | mewpmewp2 wrote: | Yeah, but it wouldn't be just me, point of writing readable | code is so that as many developers as fast as possible would | understand what is going on. So in this case I think using | the pattern that is most commonly used is the best thing to | do. | | I've done web for more than 7 years and I still immediately | wouldn't recognize why someone has used selectors in such | manner (li + li). Just obfuscates things IME. | dvaun wrote: | I found the linked article "Axiomatic CSS and Lobotomized Owls" | to be a decent read. I'm surprised that it hasn't been highly | upvoted in the past despite having many submissions to HN. | | Article: https://alistapart.com/article/axiomatic-css-and- | lobotomized... | | Prev. submissions: | https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que... | chrisweekly wrote: | While "Axiomatic CSS" per se has (unfortunately) not quite | (yet?) gone mainstream, its origins -- see https://every- | layout.dev -- are a profoundly excellent resource, and have | been highly influential. | dvaun wrote: | What a neat resource. Thanks for sharing! | leephillips wrote: | That site is black on white1, and has no other colors, | images, fancy borders, nor any other obvious "design"--and | yet it is remarkably pleasant to look at, even beautiful. The | site sells the authors' ideas; they obviously know something. | (Plus no doorslams, cookie warnings, or other annoyances. And | an RSS feed.) | | [1] Really very dark grey on very light grey. | juped wrote: | "and yet"? It's "and therefore". | | + The only problem is that the atrocious #fafafa on #050505 | is made a whole lot worse because there aren't a bunch of | even worse things distracting you from it. | chipotle_coyote wrote: | Okay, I'll bite. Why is #050505 on #FAFAFA (not the | reverse, as you stated) "atrocious"? Are we playing the | "anything less than #000000 on #FFFFFF is grey text on a | grey background and entirely unreadable" card? | extra88 wrote: | I don't understand their complaint either. Some people | have a hard time with absolute black on absolute white | (and/or vice versa) so easing up a little can be helpful. | It's a small difference, 19:52:1 vs. 21:1 contrast ratio. | I've seen advice to avoid exceeding 18:1 in large areas, | maybe #111 on #f9f9f9. | chipotle_coyote wrote: | We tend to focus only on the accessibility issues caused | by low contrast, but very high contrast also makes | reading more difficult, especially for people with | dyslexia -- and it's also more likely to cause eye strain | if it's a full-length article. | | At any rate, "it's okay for text not to be pure black and | backgrounds not to be pure white" has become my tiny hill | to die on. | dotancohen wrote: | How do you calculate the contrast ratio? | chipotle_coyote wrote: | I use the WebAIM contrast checker: | | https://webaim.org/resources/contrastchecker/ | | It's basically a measure of perceived brightness. The | actual formula involves calculating the relative | luminance of the background and foreground colors, where | luminance is a value from 0 (darkest) to 1 (lightest), | and using the formula | | (lighter_luminance + 0.05) / (darker_luminance + 0.05) | | So the highest possible contrast ratio in this system is | 21:1. | mobilemidget wrote: | thanks for the site link, did not have that as a entry on the | resource list myself :) | [deleted] | mninm wrote: | I was trying to figure out what font they are using and when | I was inspecting the page I found the comment below. I have | nothing in particular to say about it. I just thought it was | interesting. <!-- | ... s, . | .s ss, . .. .ss | 'SsSs, .. . .sSsS' | sSs'sSs, . . .sSs'sSs sSs | 'sSs, ... .sSs' sSs sS, | 'sSs, .sSs' .Ss 'Ss | 'sSs, .sSs' sS' ... sSs ' | .sSs' sSs ... . sSs | .sSs' .., sSs . . .. sS, | .sSs' . 'sSs, .Ss . .. .. . 'Ss | .Ss' . 'sSs. '' .. . . . | sSs ' . 'sSs, . . ... | .sS.'sSs . .. 'sSs, ... | .sSs' sS, ..... .Ss 'sSs, .sSs' | 'Ss . sS' 'sSs, .sSs' | sSs . sSs 'sSs, | .sSs'____________________________ sSs ______________'sSs, | .sSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS'.Ss | SSSSSSSSSSSSSSSSSSSSSs, ... | sS' sSs sSs | sSs sSs sS, .Ss | 'Ss sS' sSs sSs | sSsSs sSs | s YOU ARE YOUR OWN GOD. | YOU HAVE THE POWER TO CHANGE THE WORLD. | MAKE THE MOST OF IT. --> | rocqua wrote: | Pretty sure that is from the church of satan. Which is not | about worshiping satan but more humanist / atheist / there | is no god but you should still be a force for good. | | It's just that their imagery is intentionally quite jarring | to christians. To quote the satanists. It is not them who | believe in Satan, its the christians who believe in Satan. | BongoMcCat wrote: | As a European, I find it quite amusing that religion is | so central to american culture, that they even figured | out a way to make a christian version of atheism. | sings wrote: | I didn't really understand why the sibling selector was | introduced as a scoped version of the lobotomised owl, as if | that was the canonical implementation. The sibling selector has | always been underrated. | noman-land wrote: | It's an excellent article. I share it with people constantly. | bob229 wrote: | Stating the obvious much | sfink wrote: | I think rule-followed-by-exception is clearly superior because | it's more flexible and generalizes better to future additions. | | Except when it isn't superior. Like when the exception is pages | of code below the rule. | | Which means that precise (enabling) selectors are more robust | since you don't have to worry about future CSS additions (or even | whether to look for exceptions). | | Which means that in general, general rules don't work very well. | chrisweekly wrote: | Yeah, just like "in theory, there's no difference between | theory and practice; in practice, there is." | wruza wrote: | This stems from the incorrect (but popular) idiom of doing a | container's job by invading child properties. One can't make it | non-leaky neither to layout around, nor to a developer. These | gaps are ones of the parent, not of a child, and anything else | will leak. | kebman wrote: | I had a sore throat, so I made an "In A World" reading of this | web page. | math-dev wrote: | I wrote (what I hope) is a great read to CSS selectors, check it | out if you are keen for a nice intro to this important topic: | | https://ashok-khanna.medium.com/rounded-tables-an-elusive-dr... | paraph1n wrote: | > I think gap is where this is all headed in the long term. | | gap? Is this new? I've been waiting for years for CSS to finally | support something like that. Always thought it was weird that I | had to mess with margins (and last-child hacks) to get a proper | gap between items in a container. | btown wrote: | Yep! | | https://developer.mozilla.org/en-US/docs/Web/CSS/gap | | https://caniuse.com/?search=gap | seumars wrote: | It's part of CSS grid so in a way it's new, but CSS grid well | supported nowadays. | petepete wrote: | It's been made more general than just grid (it used to be | called grid-gap) and works with flexbox too. I don't know if | Safari supports it in flexbox yet and it's a pain to detect | with @supports because Safari _does_ support gap but in a | different context, but it works fine in Chrome and Firefox. | | Edit: just checked, Safari 14.1 added support for using gap | with Flexbox. | [deleted] ___________________________________________________________________ (page generated 2021-09-01 10:00 UTC)