Vendor prefixes (-webkit-, -moz-, -ms-, -o-) were essential 10 years ago when CSS3 features shipped behind prefixes. Today most are dead weight — modern browsers support unprefixed versions and hand-written prefixes inflate bundles, get out of date, and cause maintenance noise. The fix is to stop writing prefixes by hand and let Autoprefixer add only the ones your target browsers actually need.
grep -rE "(-webkit-|-moz-|-ms-|-o-)" src/ --include="*.css" --include="*.scss" | wc -lTypical numbers: thousands of prefix usages in legacy codebases. After Autoprefixer migration: zero in source.
flex, transform, transition, border-radius, animation, gradients haven't been needed since 2016.
# .browserslistrc > 0.5% last 2 versions not dead not IE 11This targets browsers used by more than 0.5% of users globally, the last 2 versions of each, excluding browsers that no longer receive updates and explicitly excluding IE 11.
// package.json
{
"browserslist": [
"> 0.5%",
"last 2 versions",
"not dead",
"not IE 11"
]
}
Either location works. Pick one source of truth.
npx browserslistLists every browser version your config targets. Useful sanity check — make sure you're not excluding browsers your real users use, and not including ancient ones you don't need.
npm install --save-dev postcss autoprefixerConfigure PostCSS:
// postcss.config.js
module.exports = {
plugins: {
autoprefixer: {},
}
}
Now that Autoprefixer handles prefixes at build time, source CSS should be prefix-free.
/* BEFORE — hand-written prefixes */
.box {
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
-webkit-transition: transform 0.3s;
transition: transform 0.3s;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
/* AFTER — clean source CSS */
.box {
transform: translateY(0);
transition: transform 0.3s;
display: flex;
}
Autoprefixer adds back exactly what your target browsers need at build time. Source stays clean.
# Strip common dead prefixes from all CSS files (test on backup first!)
find src -name "*.css" -exec sed -i -E '
/-webkit-(transform|transition|border-radius|animation|box-shadow|user-select|appearance|backface-visibility|perspective)/d;
/-moz-(transform|transition|border-radius|animation|box-shadow|user-select|appearance)/d;
/-o-(transform|transition|animation)/d;
' {} +
Then rebuild and test. Anything broken means that prefix was actually still needed — restore it via Autoprefixer config.
cat dist/main.css | grep -E "(-webkit-|-moz-|-ms-)" | head -20You should see prefixes only on properties that still need them per your Browserslist.
Removing dead prefixes typically saves 10-20% of CSS bundle size on legacy codebases. Larger savings if you had heavy prefixing for old flexbox spec, multi-column, transitions.
Combined with PurgeCSS and code splitting (see the bundle size guide), the total CSS shipped drops dramatically.
caniuse-lite data. Outdated data means decisions based on old browser stats.
// In CI or as a periodic task npx browserslist@latest --update-dbOr set up a renovate/dependabot rule to update
caniuse-lite monthly.