sodcalculator

10 Tech How-To

Vue JS Cross-Browser Compatibility Guide

Guide 10-12992 · Updated · Step by step

This guide walks through making Vue.js applications render and behave consistently across Chrome, Firefox, Safari, and Edge. You’ll learn about the main sources of cross-browser issues—JavaScript syntax, CSS features, and browser APIs—and how to address them with tooling and coding practices.

What You’ll Need

  • A Vue.js project (Vue 2 or Vue 3, created with Vue CLI or Vite)
  • Node.js and npm installed
  • Access to at least two different browsers for testing (e.g., Chrome and Safari)
  • Optional but helpful: a browser testing service like BrowserStack or LambdaTest, or virtual machines with different OS/browser combos

Step-by-Step

  1. Set up Browserslist configuration. Create a .browserslistrc file in your project root or add a browserslist key to package.json. This tells build tools which browsers you need to support. A common starting point is: last 2 versions, not dead, > 0.2%. This automatically influences how Babel transpiles your JavaScript and how Autoprefixer handles CSS.
  2. Configure Babel for your target browsers. If you’re using Vue CLI, Babel is already set up with @vue/babel-preset-app, which respects the Browserslist config. For Vite projects, add @vitejs/plugin-legacy to generate two bundles: one modern and one for older browsers. Install it with npm install -D @vitejs/plugin-legacy and add it to your vite.config.js plugins array.
  3. Add Autoprefixer for CSS. Most Vue projects use PostCSS. Ensure Autoprefixer is installed and configured to read your Browserslist. With Vue CLI it’s included by default. In a Vite project, add autoprefixer to your PostCSS config or use the postcss.config.js file. This automatically adds vendor prefixes for CSS properties like display: flex or user-select that older browsers need.
  4. Use modern JavaScript features with caution. Vue 3 itself uses ES2015+ features. If you need to support older browsers like IE11, Vue 3 is not an option—you’d need Vue 2 with the @vue/compat build. For most modern setups, features like optional chaining (?. ) and nullish coalescing (??) are fine after Babel transpiles them. Avoid using newer APIs like Array.prototype.at() or structuredClone without checking support or adding a polyfill.
  5. Add polyfills for missing browser APIs. Use core-js (already included with Vue CLI) or polyfill.io for things like Promise, fetch, IntersectionObserver, or ResizeObserver. In your main.js or entry file, import the specific polyfills you need, e.g., import 'core-js/stable' for all stable features or import 'core-js/es/promise' for just Promise.
  6. Test CSS features you rely on. Check caniuse.com for CSS Grid, Flexbox gap, position: sticky, and CSS variables. If you use a modern feature that’s unsupported in your target browsers, provide a fallback. For example, use display: block as a fallback before display: grid in your CSS.
  7. Handle browser-specific event quirks. Use Vue’s event modifiers (.stop, .prevent) instead of manually calling event.preventDefault() when possible. For keyboard events, use event.key instead of event.keyCode (deprecated). For touch events, consider using a library like Hammer.js if you need complex gesture support across devices.
  8. Test with real browsers. Run npm run serve and open your app in Chrome, Firefox, Safari, and Edge. Use the browser’s DevTools to check the console for errors and the Network tab for failed requests. Pay special attention to Safari, which often lags behind in support for newer JavaScript and CSS features.
  9. Use automated cross-browser testing. Integrate a tool like Cypress (with its cross-browser support) or Playwright into your CI pipeline. These can run your test suite against multiple browsers automatically. Start with a few critical user flows: navigation, form submission, and rendering key components.
  10. Check for layout inconsistencies. Different browsers have different default styles. Add a CSS reset or normalize.css at the start of your global styles. This ensures margins, padding, and font sizes are consistent. Also test with different font loading strategies—if you use web fonts, ensure font-display: swap is set to prevent invisible text.
  11. Verify responsive design in all browsers. Use DevTools device mode to simulate different screen sizes. Check that media queries work as expected. Safari and Chrome may handle viewport units (vh, vw) slightly differently, especially with dynamic toolbars on mobile—consider using 100dvh (dynamic viewport height) with a fallback to 100vh.
  12. Monitor for runtime errors. Use a service like Sentry to capture JavaScript errors from real users in different browsers. This helps you catch issues that only appear in specific environments. Look for patterns like errors that only occur in Safari or only on older Android WebView.

Common Mistakes

  • Assuming your dev browser is the baseline. If you only test in Chrome, you’ll miss Safari-specific issues.
  • Using CSS features without fallbacks. For example, using gap in Flexbox without checking Safari 14 and earlier support.
  • Ignoring the Browserslist config. If it’s missing, build tools default to a very broad or very narrow set, causing either bloat or missing transpilation.
  • Forgetting to test on actual mobile devices. Emulators don’t catch all issues with touch events, viewport sizing, or performance.
  • Over-polyfilling. Adding every polyfill available increases bundle size and can slow down your app. Only include what your target browsers actually lack.

Tips

  • Use the @vue/compiler-sfc with the compatConfig option if you need to support IE11—but seriously consider whether IE11 support is worth the effort.
  • Keep your Vue version and dependencies updated. Newer versions often include bug fixes for browser-specific issues.
  • Use CSS logical properties (margin-inline-start instead of margin-left) for better internationalization and consistency.
  • For animations, prefer CSS transitions over JavaScript-based animation libraries when possible—they’re more performant and consistent.
  • Test early and often. Don’t wait until the end of development to check other browsers.

Troubleshooting

Symptoms: Your app works in Chrome but breaks in Safari. Check the console for syntax errors. Safari often fails on newer JavaScript features that haven’t been transpiled. Verify your Babel config is actually transpiling for Safari—check your .browserslistrc includes last 2 Safari versions or similar. Also check for CSS features like aspect-ratio or backdrop-filter that may need prefixes or fallbacks.

Symptoms: CSS looks fine in Firefox but misaligned in Chrome. This is often a flexbox or grid issue. Use the browser’s DevTools to inspect the computed styles and see if any properties are being overridden. Check if you’re using min-width: auto on flex items—Chrome and Firefox handle this differently. Add min-width: 0 to flex children that contain text or images.

Symptoms: JavaScript errors in older browsers but not in modern ones. This points to missing polyfills or untranspiled syntax. Open the error message and look for the specific feature. Search for it on caniuse.com to see which browsers support it. Add the appropriate polyfill or rewrite the code to use a more widely supported approach.

Symptoms: Your app loads but is blank in one browser. Check the Network tab for failed requests—this could be a CORS issue or a missing file. Also check for JavaScript errors in the console. A blank screen often means a runtime error prevented Vue from mounting. Use a tool like vue-devtools to inspect the component tree.

Frequently Asked Questions

Do I really need to support older browsers like IE11?

For most consumer-facing apps, IE11 usage is below 1% globally. Unless your analytics show significant IE11 traffic, it’s usually not worth the effort. Vue 3 doesn’t support IE11 at all, so if you must support it, you’d need Vue 2.

What’s the difference between transpiling and polyfilling?

Transpiling converts modern syntax (like arrow functions) into older syntax (like function()). Polyfilling adds missing APIs (like Promise) that don’t exist in older browsers. You need both for full compatibility.

How do I know which browsers to support?

Check your analytics data to see what browsers your users actually use. If you don’t have analytics, a reasonable default is last 2 versions, not dead—this covers about 95% of users.

Can I use CSS Grid in my Vue app?

Yes, CSS Grid is supported in all modern browsers since 2020. If you need to support older browsers, provide a fallback layout using flexbox or floats, then override with @supports (display: grid).

What about Safari’s private mode and localStorage?

Safari’s private mode historically had a 7-day limit on localStorage and could throw errors. Use a wrapper that catches exceptions when accessing localStorage, and consider using in-memory storage as a fallback.

How do I handle different font rendering across browsers?

Fonts render slightly differently on Windows vs Mac vs Linux. Use a font stack that includes system fonts as fallbacks, and consider using font-display: swap to avoid invisible text while web fonts load.

Related

General steps for current mainstream versions; menus can differ by device and version. See the disclaimer or report an error.

More in this bed

The whole Tech How-To bed →