Opinionated CSS Defaults
work in progressPrompted by Declan Chidlow’s My Opinionated CSS Reset, which in turn made me revisit Andy Bell’s A (more) Modern CSS Reset, Manuel Matuzović’s uaplus.css and others.
*,
*::before,
*::after {
box-sizing: border-box;
}Despite some folks being critical, I still think this is a decent default.
:root {
/* modular scale-ish; cf. https://www.modularscale.com/?1.5 */
--spacing: 0.5rem;
--spacing-sm1: calc(var(--spacing) * 0.667);
--spacing-sm2: calc(var(--spacing) * 0.444);
--spacing-sm3: calc(var(--spacing) * 0.296);
--spacing-lg1: calc(var(--spacing) * 1.5);
--spacing-lg2: calc(var(--spacing) * 2.25);
--spacing-lg3: calc(var(--spacing) * 3.375);
--animation-duration: 200ms;
}There’s no particular reason to use :root over html for custom properties;
it’s just a habit.
img {
display: block;
max-width: 100%;
height: auto;
}button,
summary {
cursor: pointer;
}textarea:not([rows]) {
min-height: 8lh;
}Typography
body {
font-family: system-ui, sans-serif;
line-height: 1.5;
/* prevent font-size inflation; cf.
https://kilianvalkhof.com/2022/css-html/your-css-reset-needs-text-size-adjust-probably/ */
-moz-text-size-adjust: none;
-webkit-text-size-adjust: none;
text-size-adjust: none;
/* disable macOS's default subpixel antialiasing for consistency across
platforms; cf. https://dbushell.com/2024/11/05/webkit-font-smoothing/ */
-webkit-font-smoothing: antialiased;
}We want form elements to assume the respective base font:
input,
textarea,
select,
button {
font-family: inherit;
font-size: inherit;
}Links
a {
text-underline-offset: 0.15lh; /* XXX: magic value */
@media (prefers-reduced-motion: no-preference) {
transition-property: text-underline-offset, text-decoration-color;
transition-duration: var(--animation-duration);
}
&:not(:focus, :hover, :active) {
text-underline-offset: 0.1lh; /* XXX: magic value */
/* XXX: a11y might be impacted by insufficient color contrast */
text-decoration-color: color-mix(in srgb, currentColor, transparent 50%);
}
}Utilities
.nonvisual:not(:focus, :active) {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
white-space: nowrap;
clip-path: inset(50%);
}.stack > * {
margin-block: 0;
& + * {
margin-block-start: var(--spacing);
}
}