For example: using “form > p or fieldset > p” would prevent authors from replacing a `p` with a `div` (a very strong possibility) without editing the style sheet.
It may be a strong possibility, but the W3C clearly states it should be a `p`, not a `div`, so it would be an undesirable change, wouldn’t it? There are relatively few ways to mark up a given thing well. Make it easy and clear to do the right thing, and harder to do the incorrect thing.
Since you mention HTML bloat, why not pointing out that using “[type=text]” instead of “.text-input” will lead to more selectors in the styles sheet (url, number, tel, email, etc.). A class being more generic can target different/more elements.
It can, but it doesn’t necessarily. No matter what system one uses, it’s up to prudent developers to manage bloat — and specificity, for that matter. It will go wrong if left unattended. BEM, for example, can quickly bloat both markup and styles with overly specific Blocks and Elements that are not reusable. Personally, I’ve found less bloat in both markup and CSS using these methods, but there is not methodology that absolves you from vigilance.
Defining things globally never worked out in the wild since a lot of the time we need to override the default styling for various reasons such as multiple states of a single form.
No one is saying you cannot override, or style for multiple states. You do, however, have much richer tools at your disposal for doing so than simple and arbitrary classes. You can, instead, use the actual attributes of the object. If it’s disabled, for example, then it is disabled. Adding a class marking it .disabled doesn’t change that or add anything to it.
TL;DR; Attribute selectors like [role=button] doesn’t have support in older browsers and that is the reason, why classes are still used as a main tool to style elements -> and it surely will do for another few years.
Agreed, but today the toolset is much improved. And it has been for awhile. You can safely use attribute selectors <a >in all major browsers, including IE8 and above</a>.
When you suddenly discover you need e.g. a button element that is unstyled/very differently styled, then you suddenly have to struggle with resetting styles.
There is no more struggle than if your starting point had been .button. But you will have defined what makes this button special in the first place.
Using html tags to apply visual styles can be restrictive, especially in larger (real life) systems.
A simple example would be a data entry page with a search option in the header. Two forms, matching markup, different visual styles. Applying styles to the ‘form’ creates a coupling between the semantics of the content and the visual presentation.
There’s no restriction. Using your example, I would suggest that the search form could (and should) be marked up with [role=search]. But to address the larger point of “what happens when a form is different”, I would say mark it up and style it as appropriate. At some point, markup alone will not be enough to differentiate. And ARIA will not not have the additional semantics you need. And your form will not follow any micro formats. On a long enough timeline, you will have a form that truly is different just because and is not different for any semantic, structural or standardized reason. And when that day comes, I would say by all means, create form.just-because and define your own internal standard. But I would suggest knowing and leveraging the established standards first.