P.S. I don't think you'll have the abstraction abilities of code.
It's definitely not as powerful as code abstraction, but we are trying to build clean and maintainable framework. What issues do you see?
This is true for basic html too. You could create a bullet list by adding a div with a class for the container and arbitrarily located divs with classes indicating that they're list items related to the container, and then use complicated CSS to pull it all together into a visual representation of a bullet list. Or, you could use a ul element for the container with direct child li elements for the items. Your visual style relies on the DOM structure, but overall it's a cleaner solution.
In your scenario, I'd use a list element (<ul> or <ol>, according to the nature of the data) with a class (e.g. .my-list) and list item elements also with a class if needed (<li> with e.g. .my-list__item). No complications here. If somewhere along the way someone wanted to to a navigation area with exactly the same styles but with a different mark-up (anchors inside a <nav>), you could reuse or extend those classes to a <nav> element for the container and <a> elements for items. That's another "level" of DOM independence.
The point I was trying to make was that at a component level, your CSS classes are usually going to depend on a particular hierarchy in the DOM elements that the classes are applied to, or they won't work correctly. How much of a dependency you have is a tradeoff; you can design your framework to minimize the dependency, but you're likely to create a more complicated framework in exchange.
Not quite exactly. My solution doesn't require list items to be child elements of the list. Bootstrap's "list item" needs (by definition/rule) to be a "direct" descendant - a child element of a given type (a selector with "> li") of the list. They have classes for lists, and then style the list items via element and "descendancy" (i.e. .my-list > li).
If somewhere along the way you decide/are asked to change the mark-up in order to have an element for grouping list items (so, you'd have elements between the list and list items ), Bootstrap's way of creating rules wouldn't work anymore - list items wouldn't be child elements of the list, despite you wanting to keep the styling in them. Independently of how you solved this in the mark-up, if your rule was like Bootstrap's .my-list > li, then it wouldn't work anymore because list-items wouldn't be "direct" descendants of .my-list.
This might seem minor or unusual, but I assure it's not - this is the kind of changes in structure that happen very frequently and make DOM-tied CSS fail. And bear in mind the Tetris effect on this: your less-than-experienced team member might solve this with yet another rule, but a even more specific one (.my-list > .group > li) which will yield harder to maintain CSS (this rule is very specific; it would need even more specific rules to be overridden when necessary). If your development rule was "no DOM tying; just use classes), the problem of escalating specificity would've also been avoided.
> The point I was trying to make was that at a component level, your CSS classes are usually going to depend on a particular hierarchy in the DOM elements that the classes are applied to, or they won't work correctly. How much of a dependency you have is a tradeoff; you can design your framework to minimize the dependency, but you're likely to create a more complicated framework in exchange.
I understand your point, but I don't agree with the notion that "but you're likely to create a more complicated framework in exchange" by minimizing the dependency on the DOM. You're likely, definitely, to create a more verbose CSS framework, with a way bigger amount of classes. But I don't think this is the same as complicated; it's more verbose, it may require you to write more code[1], but I think it's very predictable and easier to follow by team members with different expertise levels.
P.S. Also, bear in mind that BEM-like solutions also have hierarchy. Elements which belong to blocks. They just don't depend on a specific hierarchy on the DOM; DOM hierarchy is independent of styling hierarchy.
[1] I'd argue it will make you write more code in the beginning. Traditional DOM-tied styling will eventually catch-up and the code you have to write to overwrite "over-specific" selectors and similar issues will grow bigger.
https://github.com/twbs/bootstrap/tree/v4-dev/scss
I don't know if reading the source code is enough, but if you try incorporating it in projects, it's easier to see how well SCSS works in practice. I really enjoy how Bootstrap sets up conventions for typography and other variables:
https://github.com/twbs/bootstrap/blob/v4-dev/scss/_variable...
https://github.com/twbs/bootstrap/blob/v4-dev/scss/_type.scs...
There's global variables for serif, sans-serif, and mono...When prototyping a site, I sometimes change my mind over whether or not to use serif or sans-serif...with SCSS, it's a matter of just switching $font-family-base to either $font-family-serif or $font-family-sans-serif:
$font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, font-family-sans-serifs-serif !default;
$font-family-serif: Georgia, "Times New Roman", Times, serif !default;
$font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace !default;
$font-family-base: $font-family-sans-serif !default;
I usually set a $font-family-headings variable if I decide to use a third font for headings. All font-family names are set in this file and I never have to refer to them explicitly in any of my other CSS.The elegance of setting a base font size and then having h1-h6 be multiples of that number is also a delightful convenience. And this is just the bare minimum of ways that SCSS can aid in composability...though to be honest...besides variables and the ability to nest definitions within each other...I don't habitually use all of the other really nice features, yet.