modern-normalize
modern-normalize copied to clipboard
Consider a version without forcing box-sizing
Counter to the common trend, it is not always 'awesome' or 'FTW'. It wreaks havoc with expectations stemming from normal browser defaults, which makes it harder to integrate into existing properties and makes it harder to integrate anything created by third parties that are not operating off of the same opinionated principle.
It's also a total pain in the ass to selectively undo with override rules, as it's reapplied on every element. At the very least you could use box-sizing: inherit
I'd think, which makes it at least somewhat easier to selectively cut this awesomely annoying behavior out?
Really, Chris Coyier has improved the code that is currently being used in modern-normalize.css
back in 2014.
Instead of
*, *::before, *::after {
box-sizing: border-box;
}
we really
should be getting this:
html {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}
I can't explain better than Chris, so please take the time to read his reasoning why this is a much better version: https://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/
Even Paul Irish, who in 2012 came up with the code you're currently delivering, has agreed and edited his original article to reflect the improvement: https://www.paulirish.com/2012/box-sizing-border-box-ftw/
I've created a PR for this improvement. https://github.com/sindresorhus/modern-normalize/pull/56
This is also an option, but I dont think its always the better one.
In most cases I want box-sizing:border-box
.
But there is also the situation that I want content-box
for a certain element, but not inherited to the contained elements.
Both have advantages and disadvantages, for me not inheriting is the better solution.
@nuxodin Both have advantages and disadvantages, for me not inheriting is the better solution.
Even when inheriting, your use-case can still be supported. Just reset back to border-box on the direct children.
Personally, I would just pre-process whatever form of box-sizing normalization is present in a normalization sheet and rip it out, because after having run up against problems with it numerous times, I've come to believe it to be a theoretical ideal but a fallacy in practice...
The current version was intentional: https://github.com/sindresorhus/modern-normalize/pull/37
// @jamiebuilds
Yeah, I think the advice in css-tricks is only better if you only consider one pattern of building UIs.
Compare these two snippets:
Islands of widgets:
<widget-one/>
<widget-two/>
<widget-three/>
Trees of components:
<component-one/>
<compontent-two>
<component-three/>
</component-two>
Both of these have their place on the web, and really almost every webpage will be a mix of both of these in different places. So given the goals of a generic reset/normalize stylesheet, they should both be considered.
The idea behind applying box-sizing: inherit
to every element is that it creates a simpler mental model when marking an entire sub-tree as box-sizing: content-box
.
That's great if you're only considering the "islands of widgets" pattern, but then it shifts the burden onto the "trees of components" pattern. And you start getting snippets like this:
component {
box-sizing: content-box;
}
component::before, component::after, component > * {
box-sizing: border-box;
}
So really we just have a tradeoff here, if we make it easier for "islands of widgets" we make it harder for "trees of components", if we make it easier for "trees of components" we make it harder for "islands of widgets".
So the question becomes: Which is the easier mental model for people to apply in the real world?
*, ::before, ::after { box-sizing: border-box; }
Developer: "I want to make this entire tree
content-box
sized because that's what its expecting"widget, widget *, widget ::before, widget ::after { box-sizing: content-box; }
That's it, they are done.
<component-one> <component-two> <component-three/> </component-two> <component-four/> </component-one>
:root { box-sizing: border-box; } *, ::before, ::after { box-sizing: inherit; }
Developer 1: "I want my component to be sized with
content-box
"component-one { box-sizing: content-box; }
Developer 2: "Wait why does my component suddenly look wrong. Oh its inheriting
content-box
now, I guess I need to reset my component, and I'll make sure nothing inheritscontent-box
again":component-two, component-two *, component-two ::before, component-two ::after { box-sizing: border-box; }
Developer 3: "Wait why does my component suddenly look wrong. Oh someone added a higher specificity selector overriding my
content-box
. I'll just add!important
compontent-three { box-sizing: content-box !important; }
Developer 4: "Wait..."
I've seen all of this chaos play out all because Developer 1 forgot to reset the styles back to border-box
for <component-one/>
's children. I've also seen it play out that Developer 1 reset the styles incorrectly and broke the inherit
behavior for everyone.
Overall, I think a generic reset/normalize stylesheet is better off pushing the burden on "islands of widgets" because a lot less can go wrong there.
@jamiebuilds That's it, they are done.
You're conveniently leaving out the case where .widget
nests something else which needs box-sizing:border-box
and which is styled using best-practice short class-only selectors, e.g.
<div class="widget">
<div class="nested-widget"></div>
</div>
*, ::before, ::after {
box-sizing: border-box;
}
.widget, .widget *, .widget ::before, .widget ::after {
box-sizing: content-box;
}
.nested-widget {
box-sizing: border-box;
}
That will break and will require the site author to pinpoint target their own dedicated CSS rules with higher specificity to fix it. Moreover; it may require the site author to do so, each and every time the nested widget structure changes and those changes may be out of their control if they are dynamically including a third party widget from another web origin not under their control.
This is the reason both implementations of 'border-box all the things' are flawed, btw. And the reason a version without it should exist.
which is styled using best-practice short class-only selectors
That problem is only difficult because you decided that this was a best practice. Maybe re-evaluate that.
That problem is only difficult because you decided that this was a best practice. Maybe re-evaluate that.
Oh yes; let's force site authors to needlessly write higher-specificity selectors to cater to the whims of forcing non-default behavior on box-sizing. And then let's cover up that mess by saying those site authors should re-evaluate their position on the practice of managing selector specificity to keep it low.
Now there's a clear-cut case of "I reject your reality and substitute my own."
With css variables you could have the advantages of both variants, but maybe that's too mutch overhead.
html {
--box-sizing:border-box;
}
*, ::before, ::after {
box-sizing: var(--box-sizing);
}
.elementNeedsContentBox { /* but does not inherit */
box-sizing: content-box;
}
.widget {
--box-sizing: content-box; /* will inherited */
}
.nested-widget {
--box-sizing: border-box; /* will inherited */
}