Fix Safari/iPhone performance issues - remove 300ms click delay

- Added touch-action: manipulation CSS to eliminate 300ms tap delay
- Optimized service worker to skip cross-origin requests
- Updated viewport settings to prevent iOS delays
- Added format-detection meta tag
- Enabled Next.js performance optimizations
- Created comprehensive performance fix documentation
This commit is contained in:
2025-12-03 20:54:55 +00:00
parent bfe49e7211
commit 509de75e1a
5 changed files with 196 additions and 3 deletions

168
SAFARI_PERFORMANCE_FIX.md Normal file
View File

@@ -0,0 +1,168 @@
# Safari/iPhone Performance Optimization
## Issues Fixed
### 1. 300ms Click Delay (Primary Issue)
**Problem**: Safari on iOS has a historical 300ms delay on click events to detect double-tap-to-zoom gestures.
**Solutions Applied**:
- Added `touch-action: manipulation` CSS to all interactive elements (buttons, links, inputs)
- Added `format-detection` meta tag to disable automatic phone number detection
- Updated viewport to allow user scaling (prevents iOS from adding delays)
- Added explicit touch-action rules in globals.css
### 2. Service Worker Overhead
**Problem**: Service worker was intercepting all fetch requests, including cross-origin requests, adding latency.
**Solutions Applied**:
- Added check to skip cross-origin requests in service worker
- Service worker now only handles same-origin requests
- Reduced unnecessary cache lookups
### 3. Touch Interaction Optimization
**Problem**: Missing touch-specific CSS optimizations for iOS Safari.
**Solutions Applied**:
- Added `-webkit-touch-callout: none` to prevent context menu delays
- Added `touch-action: manipulation` to prevent double-tap zoom delays
- Optimized tap highlight colors
### 4. Next.js Configuration
**Problem**: Missing performance optimizations in Next.js config.
**Solutions Applied**:
- Enabled `reactStrictMode` for better development debugging
- Enabled `optimizeFonts` for faster font loading
- Already had compression and minification enabled
## Testing the Fixes
### On iPhone Safari:
1. Clear Safari cache: Settings > Safari > Clear History and Website Data
2. Close all Safari tabs
3. Reopen the app
4. Test clicking on list cards and navigation links
5. Should feel instant now (no 300ms delay)
### Expected Results:
- Links should respond immediately to taps
- No delay between tap and navigation
- Smooth, native-app-like feel
- Faster page transitions
## Additional Recommendations
### If Still Experiencing Slowness:
1. **Check Network Speed**
- Open Safari Developer Tools on Mac (Develop > [Your iPhone])
- Check Network tab for slow requests
- Look for large bundle sizes or slow API calls
2. **Disable Service Worker Temporarily**
- Comment out `<ServiceWorkerRegistration />` in layout.tsx
- Test if performance improves
- If yes, service worker needs further optimization
3. **Check for Memory Issues**
- Close other Safari tabs
- Restart iPhone
- Check if other apps are using memory
4. **Verify Build Optimization**
```bash
npm run build
npm start
```
- Test production build (much faster than dev mode)
5. **Enable Safari Debug Console**
- Settings > Safari > Advanced > Web Inspector
- Connect iPhone to Mac
- Safari > Develop > [Your iPhone] > [Your Site]
- Check for JavaScript errors or warnings
## Performance Metrics to Monitor
### Good Performance Targets:
- **First Contentful Paint (FCP)**: < 1.8s
- **Time to Interactive (TTI)**: < 3.8s
- **Total Blocking Time (TBT)**: < 300ms
- **Cumulative Layout Shift (CLS)**: < 0.1
- **Largest Contentful Paint (LCP)**: < 2.5s
### Measure with Lighthouse:
```bash
# Install Lighthouse CLI
npm install -g lighthouse
# Run audit (with iPhone user agent)
lighthouse https://your-app-url --preset=perf --emulated-form-factor=mobile
```
## Changes Made
### Files Modified:
1. `app/layout.tsx` - Updated viewport and meta tags
2. `app/globals.css` - Added touch-action CSS rules
3. `next.config.js` - Added performance optimizations
4. `public/sw.js` - Optimized fetch event handler
### Key CSS Addition:
```css
/* Remove 300ms click delay on iOS Safari */
a, button, input, select, textarea {
touch-action: manipulation;
}
```
This single CSS rule is the most important fix for the click delay issue.
## Rollback Instructions
If these changes cause issues:
1. **Revert viewport changes**:
```typescript
maximumScale: 1,
userScalable: false,
```
2. **Remove touch-action CSS**:
- Remove the touch-action rules from globals.css
3. **Revert service worker**:
- Remove the cross-origin check in sw.js
## Further Optimization Ideas
If you need even better performance:
1. **Implement Route Prefetching**:
- Next.js Link components prefetch by default
- Ensure prefetch is not disabled
2. **Code Splitting**:
- Use dynamic imports for heavy components
- Lazy load modals and forms
3. **Image Optimization**:
- Use Next.js Image component
- Implement lazy loading for images
4. **Reduce JavaScript Bundle Size**:
- Analyze bundle with `npm run build`
- Remove unused dependencies
- Use tree-shaking
5. **Implement Virtual Scrolling**:
- For long lists of items
- Use react-window or react-virtual
## Support
If issues persist after these fixes:
1. Check browser console for errors
2. Test on different iOS versions
3. Compare with other devices
4. Profile with Safari Web Inspector

View File

@@ -104,4 +104,19 @@ mark {
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
user-select: none; user-select: none;
} }
/* Remove 300ms click delay on iOS Safari */
a, button, input, select, textarea {
touch-action: manipulation;
}
/* Optimize for touch interactions */
* {
-webkit-touch-callout: none;
}
/* Prevent double-tap zoom on interactive elements */
button, a, input[type="button"], input[type="submit"] {
touch-action: manipulation;
}
} }

View File

@@ -34,8 +34,8 @@ export const metadata: Metadata = {
export const viewport: Viewport = { export const viewport: Viewport = {
width: 'device-width', width: 'device-width',
initialScale: 1, initialScale: 1,
maximumScale: 1, maximumScale: 5,
userScalable: false, userScalable: true,
viewportFit: 'cover', viewportFit: 'cover',
themeColor: '#3B82F6', themeColor: '#3B82F6',
} }
@@ -66,7 +66,8 @@ export default function RootLayout({
<meta name="theme-color" content="#3B82F6" /> <meta name="theme-color" content="#3B82F6" />
<meta name="background-color" content="#ffffff" /> <meta name="background-color" content="#ffffff" />
{/* iOS Splash Screens - Optional but recommended */} {/* iOS Performance Optimizations */}
<meta name="format-detection" content="telephone=no" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
</head> </head>
<body className="bg-gray-50 min-h-screen"> <body className="bg-gray-50 min-h-screen">

View File

@@ -16,6 +16,10 @@ const nextConfig = {
productionBrowserSourceMaps: false, productionBrowserSourceMaps: false,
trailingSlash: false, trailingSlash: false,
poweredByHeader: false, poweredByHeader: false,
// Optimize for mobile Safari
reactStrictMode: true,
// Enable optimized font loading
optimizeFonts: true,
} }
module.exports = nextConfig module.exports = nextConfig

View File

@@ -60,6 +60,11 @@ self.addEventListener('fetch', (event) => {
if (!url.protocol.startsWith('http')) { if (!url.protocol.startsWith('http')) {
return; return;
} }
// Skip cross-origin requests for performance
if (url.origin !== self.location.origin) {
return;
}
// Handle authentication-related requests // Handle authentication-related requests
if (isAuthRequest(url)) { if (isAuthRequest(url)) {