Advanced Tutorial

Mobile Performance Optimization

Master advanced techniques for creating lightning-fast mobile experiences

90 min
Duration
Advanced
Level
4
Modules

Optimization Focus Areas

Key areas to focus on for mobile performance optimization

Touch & Interaction

Optimize for finger-based navigation

  • 44px minimum touch targets
  • Touch feedback animations
  • Gesture support
  • Scroll optimization

Network Adaptation

Efficient data usage and connectivity handling

  • Adaptive loading
  • Data compression
  • Offline strategies
  • Connection quality detection

Battery Efficiency

Minimize power consumption

  • Reduce animations
  • Optimize images
  • Lazy loading
  • Background task management

Performance Metrics

Monitor and optimize mobile-specific performance

  • First Input Delay
  • Time to Interactive
  • Memory usage
  • CPU efficiency

Implementation Guide

1

Touch-Optimized Interface

Design interfaces optimized for touch interaction

20 minutes
// Touch-optimized button component
export function TouchButton({ 
  children, 
  variant = 'primary',
  size = 'medium',
  ...props 
}: TouchButtonProps) {
  const sizeClasses = {
    small: 'min-h-[40px] px-4 py-2 text-sm',
    medium: 'min-h-[44px] px-6 py-3 text-base',
    large: 'min-h-[48px] px-8 py-4 text-lg'
  };

  const variantClasses = {
    primary: 'bg-blue-600 hover:bg-blue-700 text-white active:bg-blue-800',
    secondary: 'bg-gray-200 hover:bg-gray-300 text-gray-900 active:bg-gray-400'
  };

  return (
    <motion.button
      className={`
        ${sizeClasses[size]}
        ${variantClasses[variant]}
        rounded-lg font-semibold transition-all duration-150
        touch-manipulation select-none
        focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2
        active:scale-95
      `}
      whileTap={{ scale: 0.95 }}
      transition={{ type: 'spring', stiffness: 400, damping: 30 }}
      {...props}
    >
      {children}
    </motion.button>
  );
}

// Touch gesture hook
export function useTouch() {
  const [touchStart, setTouchStart] = useState<Touch | null>(null);
  const [touchEnd, setTouchEnd] = useState<Touch | null>(null);

  const onTouchStart = (e: React.TouchEvent) => {
    setTouchEnd(null);
    setTouchStart(e.targetTouches[0]);
  };

  const onTouchMove = (e: React.TouchEvent) => {
    setTouchEnd(e.targetTouches[0]);
  };

  const onTouchEnd = () => {
    if (!touchStart || !touchEnd) return;

    const distance = touchStart.clientX - touchEnd.clientX;
    const isLeftSwipe = distance > 50;
    const isRightSwipe = distance < -50;

    return { isLeftSwipe, isRightSwipe, distance };
  };

  return { onTouchStart, onTouchMove, onTouchEnd };
}
2

Network-Aware Loading

Adapt loading strategies based on network conditions

25 minutes
// Network-aware image loading
import { useState, useEffect } from 'react';

interface NetworkInfo {
  effectiveType: '2g' | '3g' | '4g' | 'slow-2g';
  downlink: number;
  saveData: boolean;
}

export function useNetworkStatus() {
  const [networkInfo, setNetworkInfo] = useState<NetworkInfo | null>(null);

  useEffect(() => {
    const updateNetworkInfo = () => {
      if ('connection' in navigator) {
        const connection = (navigator as any).connection;
        setNetworkInfo({
          effectiveType: connection.effectiveType,
          downlink: connection.downlink,
          saveData: connection.saveData
        });
      }
    };

    updateNetworkInfo();
    
    if ('connection' in navigator) {
      const connection = (navigator as any).connection;
      connection.addEventListener('change', updateNetworkInfo);
      
      return () => {
        connection.removeEventListener('change', updateNetworkInfo);
      };
    }
  }, []);

  return networkInfo;
}

// Adaptive image component
export function AdaptiveImage({ 
  src, 
  alt, 
  lowQualitySrc,
  ...props 
}: AdaptiveImageProps) {
  const networkInfo = useNetworkStatus();
  const [imageSrc, setImageSrc] = useState(lowQualitySrc || src);

  useEffect(() => {
    if (!networkInfo) {
      setImageSrc(src);
      return;
    }

    // Use low quality image on slow connections or data saver mode
    if (networkInfo.saveData || networkInfo.effectiveType === 'slow-2g' || networkInfo.effectiveType === '2g') {
      setImageSrc(lowQualitySrc || src);
    } else {
      setImageSrc(src);
    }
  }, [networkInfo, src, lowQualitySrc]);

  return (
    <img
      src={imageSrc}
      alt={alt}
      loading="lazy"
      decoding="async"
      {...props}
    />
  );
}

// Preload critical resources based on network
export function useAdaptivePreload() {
  const networkInfo = useNetworkStatus();

  const preloadResource = (url: string, as: 'image' | 'script' | 'style') => {
    if (!networkInfo) return;

    // Skip preloading on slow connections
    if (networkInfo.effectiveType === 'slow-2g' || networkInfo.effectiveType === '2g') {
      return;
    }

    const link = document.createElement('link');
    link.rel = 'preload';
    link.href = url;
    link.as = as;
    document.head.appendChild(link);
  };

  return { preloadResource };
}
3

Battery & Performance Optimization

Implement battery-efficient optimizations

30 minutes
// Battery-aware animations
export function useBatteryStatus() {
  const [batteryInfo, setBatteryInfo] = useState<{
    level: number;
    charging: boolean;
    chargingTime: number;
    dischargingTime: number;
  } | null>(null);

  useEffect(() => {
    const getBatteryInfo = async () => {
      if ('getBattery' in navigator) {
        const battery = await (navigator as any).getBattery();
        
        const updateBatteryInfo = () => {
          setBatteryInfo({
            level: battery.level,
            charging: battery.charging,
            chargingTime: battery.chargingTime,
            dischargingTime: battery.dischargingTime
          });
        };

        updateBatteryInfo();
        
        battery.addEventListener('chargingchange', updateBatteryInfo);
        battery.addEventListener('levelchange', updateBatteryInfo);
        
        return () => {
          battery.removeEventListener('chargingchange', updateBatteryInfo);
          battery.removeEventListener('levelchange', updateBatteryInfo);
        };
      }
    };

    getBatteryInfo();
  }, []);

  return batteryInfo;
}

// Power-efficient animation component
export function PowerEfficientAnimation({ 
  children, 
  animate = true,
  reduceMotion = false 
}) {
  const batteryInfo = useBatteryStatus();
  const prefersReducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)');

  const shouldAnimate = useMemo(() => {
    // Respect user preference
    if (prefersReducedMotion || reduceMotion) return false;
    
    // Disable animations on low battery
    if (batteryInfo && batteryInfo.level < 0.2 && !batteryInfo.charging) {
      return false;
    }
    
    return animate;
  }, [animate, batteryInfo, prefersReducedMotion, reduceMotion]);

  return (
    <motion.div
      animate={shouldAnimate ? { opacity: 1, y: 0 } : {}}
      initial={shouldAnimate ? { opacity: 0, y: 20 } : {}}
      transition={shouldAnimate ? { duration: 0.3 } : { duration: 0 }}
    >
      {children}
    </motion.div>
  );
}

// Memory-efficient list virtualization
export function VirtualizedList({ items, itemHeight = 50, containerHeight = 300 }) {
  const [startIndex, setStartIndex] = useState(0);
  const [endIndex, setEndIndex] = useState(0);

  const visibleCount = Math.ceil(containerHeight / itemHeight);
  const bufferSize = 5;

  const onScroll = (e: React.UIEvent<HTMLDivElement>) => {
    const scrollTop = e.currentTarget.scrollTop;
    const newStartIndex = Math.floor(scrollTop / itemHeight);
    const newEndIndex = Math.min(
      newStartIndex + visibleCount + bufferSize,
      items.length - 1
    );

    setStartIndex(Math.max(0, newStartIndex - bufferSize));
    setEndIndex(newEndIndex);
  };

  const visibleItems = items.slice(startIndex, endIndex + 1);

  return (
    <div 
      style={{ height: containerHeight, overflowY: 'auto' }}
      onScroll={onScroll}
    >
      <div style={{ height: startIndex * itemHeight }} />
      {visibleItems.map((item, index) => (
        <div 
          key={startIndex + index}
          style={{ height: itemHeight }}
          className="flex items-center px-4 border-b"
        >
          {item}
        </div>
      ))}
      <div style={{ height: (items.length - endIndex - 1) * itemHeight }} />
    </div>
  );
}
4

Mobile-Specific Performance Monitoring

Track and optimize mobile performance metrics

15 minutes
// Mobile performance monitoring
export class MobilePerformanceMonitor {
  private metrics: Map<string, number> = new Map();

  constructor() {
    this.setupObservers();
  }

  private setupObservers() {
    // Monitor Long Tasks (>50ms)
    if ('PerformanceObserver' in window) {
      const longTaskObserver = new PerformanceObserver((list) => {
        list.getEntries().forEach((entry) => {
          console.warn(`Long task detected: ${entry.duration}ms`);
          this.trackMetric('longTaskDuration', entry.duration);
        });
      });

      try {
        longTaskObserver.observe({ entryTypes: ['longtask'] });
      } catch (e) {
        console.warn('Long task monitoring not supported');
      }

      // Monitor Layout Shifts
      const clsObserver = new PerformanceObserver((list) => {
        let clsScore = 0;
        list.getEntries().forEach((entry) => {
          if (!(entry as any).hadRecentInput) {
            clsScore += (entry as any).value;
          }
        });
        this.trackMetric('cumulativeLayoutShift', clsScore);
      });

      try {
        clsObserver.observe({ entryTypes: ['layout-shift'] });
      } catch (e) {
        console.warn('CLS monitoring not supported');
      }
    }

    // Monitor memory usage (Chrome only)
    if ('memory' in performance) {
      setInterval(() => {
        const memInfo = (performance as any).memory;
        this.trackMetric('usedJSHeapSize', memInfo.usedJSHeapSize);
        this.trackMetric('totalJSHeapSize', memInfo.totalJSHeapSize);
      }, 30000);
    }
  }

  trackMetric(name: string, value: number) {
    this.metrics.set(name, value);
    
    // Send to analytics service
    if (typeof window !== 'undefined' && 'gtag' in window) {
      (window as any).gtag('event', 'mobile_performance', {
        metric_name: name,
        metric_value: value,
        user_agent: navigator.userAgent
      });
    }
  }

  getMetrics() {
    return Object.fromEntries(this.metrics);
  }

  // Detect device capabilities
  getDeviceInfo() {
    const connection = (navigator as any).connection;
    const deviceMemory = (navigator as any).deviceMemory;
    const hardwareConcurrency = navigator.hardwareConcurrency;

    return {
      connectionType: connection?.effectiveType,
      deviceMemory: deviceMemory || 'unknown',
      cpuCores: hardwareConcurrency,
      screenSize: {
        width: screen.width,
        height: screen.height,
        pixelRatio: window.devicePixelRatio
      },
      viewport: {
        width: window.innerWidth,
        height: window.innerHeight
      }
    };
  }
}

// Usage
export function usePerformanceMonitoring() {
  useEffect(() => {
    const monitor = new MobilePerformanceMonitor();

    // Log device info on mount
    console.log('Device Info:', monitor.getDeviceInfo());

    return () => {
      console.log('Performance Metrics:', monitor.getMetrics());
    };
  }, []);
}

Best Practices

Touch Interface Design

  • Minimum 44px touch targets
  • Clear visual feedback for interactions
  • Avoid hover states, use active states
  • Design for one-handed use

Performance Optimization

  • Optimize images for mobile screens
  • Use efficient CSS animations
  • Implement virtual scrolling for long lists
  • Minimize JavaScript bundle size

Network & Battery

  • Implement adaptive loading strategies
  • Use service workers for offline support
  • Respect data saver preferences
  • Monitor battery status for animations

Mobile Performance Checklist

Progress: 0 / 8