[{"data":1,"prerenderedAt":147},["ShallowReactive",2],{"guide-mobile-image-optimization":3},{"slug":4,"category":5,"publishDate":6,"lastModified":6,"readingTime":7,"seo":8,"languages":15,"content":120},"mobile-image-optimization","mobile","2023-11-12","8 min read",{"keywords":9,"priority":14},[10,11,12,13],"mobile image optimization","responsive images","mobile performance","image optimization mobile","medium",{"en":16,"zh":20,"zh-tw":24,"ja":28,"ko":32,"id":36,"vi":40,"th":44,"ru":48,"pt":52,"es":56,"de":60,"fr":64,"it":68,"nl":72,"sv":76,"no":80,"da":84,"fi":88,"el":92,"pl":96,"cs":100,"ro":104,"sl":108,"tr":112,"hu":116},{"title":17,"description":18,"metaKeywords":19},"Mobile Image Optimization: Best Practices for Mobile Devices","Optimize images for mobile devices and improve mobile user experience. Learn responsive image techniques and mobile-specific compression strategies.","mobile image optimization, responsive images, mobile performance, image optimization mobile, mobile web optimization",{"title":21,"description":22,"metaKeywords":23},"移动端图片优化：移动设备的最佳实践","为移动设备优化图像并改善移动用户体验。学习响应式图像技术和移动端专用压缩策略。","移动端图片优化, 响应式图像, 移动性能, 移动图像优化, 移动网页优化",{"title":25,"description":26,"metaKeywords":27},"移動端圖片優化：移動設備的最佳實踐","為移動設備優化圖像並改善移動用戶體驗。學習響應式圖像技術和移動端專用壓縮策略。","移動端圖片優化, 響應式圖像, 移動性能, 移動圖像優化, 移動網頁優化",{"title":29,"description":30,"metaKeywords":31},"モバイル画像最適化：モバイルデバイスのベストプラクティス","モバイルデバイス向けに画像を最適化し、モバイルユーザーエクスペリエンスを向上させます。レスポンシブ画像技術とモバイル専用圧縮戦略を学びます。","モバイル画像最適化, レスポンシブ画像, モバイル性能, モバイル画像最適化, モバイルウェブ最適化",{"title":33,"description":34,"metaKeywords":35},"모바일 이미지 최적화: 모바일 기기를 위한 모범 사례","모바일 기기용 이미지를 최적화하고 모바일 사용자 경험을 개선하세요. 반응형 이미지 기술과 모바일 전용 압축 전략을 배우세요.","모바일 이미지 최적화, 반응형 이미지, 모바일 성능, 모바일 이미지 최적화, 모바일 웹 최적화",{"title":37,"description":38,"metaKeywords":39},"Optimasi Gambar Mobile: Praktik Terbaik untuk Perangkat Mobile","Optimalkan gambar untuk perangkat mobile dan tingkatkan pengalaman pengguna mobile. Pelajari teknik gambar responsif dan strategi kompresi khusus mobile.","optimasi gambar mobile, gambar responsif, performa mobile, optimasi gambar mobile, optimasi web mobile",{"title":41,"description":42,"metaKeywords":43},"Tối Ưu Hóa Hình Ảnh Di Động: Phương Pháp Hay Nhất cho Thiết Bị Di Động","Tối ưu hóa hình ảnh cho thiết bị di động và cải thiện trải nghiệm người dùng di động. Học các kỹ thuật hình ảnh đáp ứng và chiến lược nén đặc biệt cho di động.","tối ưu hóa hình ảnh di động, hình ảnh đáp ứng, hiệu suất di động, tối ưu hóa hình ảnh di động, tối ưu hóa web di động",{"title":45,"description":46,"metaKeywords":47},"การเพิ่มประสิทธิภาพภาพสำหรับมือถือ: แนวทางปฏิบัติที่ดีที่สุดสำหรับอุปกรณ์มือถือ","เพิ่มประสิทธิภาพภาพสำหรับอุปกรณ์มือถือและปรับปรุงประสบการณ์ผู้ใช้มือถือ เรียนรู้เทคนิคภาพที่ตอบสนองและกลยุทธ์การบีบอัดเฉพาะมือถือ","การเพิ่มประสิทธิภาพภาพมือถือ, ภาพที่ตอบสนอง, ประสิทธิภาพมือถือ, การเพิ่มประสิทธิภาพภาพมือถือ, การเพิ่มประสิทธิภาพเว็บมือถือ",{"title":49,"description":50,"metaKeywords":51},"Оптимизация изображений для мобильных устройств: лучшие практики","Оптимизируйте изображения для мобильных устройств и улучшите пользовательский опыт на мобильных устройствах. Изучите техники адаптивных изображений и специфические для мобильных устройств стратегии сжатия.","оптимизация изображений для мобильных устройств, адаптивные изображения, производительность мобильных устройств, оптимизация изображений мобильных, оптимизация мобильного веба",{"title":53,"description":54,"metaKeywords":55},"Otimização de Imagem Mobile: Melhores Práticas para Dispositivos Móveis","Otimize imagens para dispositivos móveis e melhore a experiência do usuário móvel. Aprenda técnicas de imagens responsivas e estratégias de compressão específicas para mobile.","otimização imagem mobile, imagens responsivas, performance mobile, otimização imagem mobile, otimização web mobile",{"title":57,"description":58,"metaKeywords":59},"Optimización de Imagen Móvil: Mejores Prácticas para Dispositivos Móviles","Optimiza imágenes para dispositivos móviles y mejora la experiencia del usuario móvil. Aprende técnicas de imágenes responsivas y estrategias de compresión específicas para móvil.","optimización imagen móvil, imágenes responsivas, rendimiento móvil, optimización imagen móvil, optimización web móvil",{"title":61,"description":62,"metaKeywords":63},"Mobile Bildoptimierung: Best Practices für Mobilgeräte","Optimieren Sie Bilder für Mobilgeräte und verbessern Sie die mobile Benutzererfahrung. Lernen Sie responsive Bildtechniken und mobilspezifische Kompressionsstrategien.","mobile Bildoptimierung, responsive Bilder, mobile Leistung, mobile Bildoptimierung, mobile Web-Optimierung",{"title":65,"description":66,"metaKeywords":67},"Optimisation d'Image Mobile: Meilleures Pratiques pour Appareils Mobiles","Optimisez les images pour appareils mobiles et améliorez l'expérience utilisateur mobile. Apprenez les techniques d'images responsives et les stratégies de compression spécifiques au mobile.","optimisation image mobile, images responsives, performance mobile, optimisation image mobile, optimisation web mobile",{"title":69,"description":70,"metaKeywords":71},"Ottimizzazione Immagine Mobile: Migliori Pratiche per Dispositivi Mobili","Ottimizza immagini per dispositivi mobili e migliora l'esperienza utente mobile. Impara tecniche immagini responsive e strategie compressione specifiche mobile.","ottimizzazione immagine mobile, immagini responsive, prestazioni mobile, ottimizzazione immagine mobile, ottimizzazione web mobile",{"title":73,"description":74,"metaKeywords":75},"Mobiele Beeldoptimalisatie: Beste Praktijken voor Mobiele Apparaten","Optimaliseer beelden voor mobiele apparaten en verbeter de mobiele gebruikerservaring. Leer responsieve beeldtechnieken en mobiel-specifieke compressiestrategieën.","mobiele beeldoptimalisatie, responsieve beelden, mobiele prestaties, mobiele beeldoptimalisatie, mobiele weboptimalisatie",{"title":77,"description":78,"metaKeywords":79},"Mobil Bildoptimering: Bästa Praxis för Mobila Enheter","Optimera bilder för mobila enheter och förbättra mobil användarupplevelse. Lär dig responsiva bildtekniker och mobilspecifika kompressionsstrategier.","mobil bildoptimering, responsiva bilder, mobil prestanda, mobil bildoptimering, mobil webboptimering",{"title":81,"description":82,"metaKeywords":83},"Mobil Bildeoptimalisering: Beste Praksis for Mobile Enheter","Optimaliser bilder for mobile enheter og forbedre mobil brukeropplevelse. Lær responsive bildetekniker og mobilspesifikke kompressjonsstrategier.","mobil bildeoptimalisering, responsive bilder, mobil ytelse, mobil bildeoptimalisering, mobil webboptimalisering",{"title":85,"description":86,"metaKeywords":87},"Mobil Billedoptimering: Bedste Praksis for Mobile Enheder","Optimer billeder til mobile enheder og forbedr mobil brugeroplevelse. Lær responsive billedteknikker og mobilspecifikke kompressionsstrategier.","mobil billedoptimering, responsive billeder, mobil ydeevne, mobil billedoptimering, mobil weboptimering",{"title":89,"description":90,"metaKeywords":91},"Mobiili Kuvan Optimointi: Parhaat Käytännöt Mobiililaitteille","Optimoi kuvat mobiililaitteille ja paranna mobiili käyttökokemusta. Opi responsiivisia kuvatekniikoita ja mobiilikohtaisia pakkausstrategioita.","mobiili kuvan optimointi, responsiiviset kuvat, mobiili suorituskyky, mobiili kuvan optimointi, mobiili web-optimointi",{"title":93,"description":94,"metaKeywords":95},"Βελτιστοποίηση Εικόνας για Κινητά: Καλύτερες Πρακτικές για Κινητές Συσκευές","Βελτιστοποιήστε εικόνες για κινητές συσκευές και βελτιώστε την κινητή εμπειρία χρήστη. Μάθετε τεχνικές responsive εικόνων και στρατηγικές συμπίεσης ειδικά για κινητά.","βελτιστοποίηση εικόνας κινητών, responsive εικόνες, απόδοση κινητών, βελτιστοποίηση εικόνας κινητών, βελτιστοποίηση κινητού ιστού",{"title":97,"description":98,"metaKeywords":99},"Optymalizacja Obrazów Mobilnych: Najlepsze Praktyki dla Urządzeń Mobilnych","Optymalizuj obrazy dla urządzeń mobilnych i popraw doświadczenie użytkowników mobilnych. Naucz się technik responsywnych obrazów i strategii kompresji specyficznych dla urządzeń mobilnych.","optymalizacja obrazów mobilnych, obrazy responsywne, wydajność mobilna, optymalizacja obrazów mobilnych, optymalizacja mobilnego internetu",{"title":101,"description":102,"metaKeywords":103},"Optimalizace Mobilních Obrázků: Nejlepší Postupy pro Mobilní Zařízení","Optimalizujte obrázky pro mobilní zařízení a zlepšete mobilní uživatelský zážitek. Naučte se techniky responzivních obrázků a strategie komprese specifické pro mobilní zařízení.","optimalizace mobilních obrázků, responzivní obrázky, mobilní výkon, optimalizace mobilních obrázků, optimalizace mobilního webu",{"title":105,"description":106,"metaKeywords":107},"Optimizarea Imaginilor Mobile: Cele Mai Bune Practici pentru Dispozitive Mobile","Optimizează imaginile pentru dispozitive mobile și îmbunătățește experiența utilizatorului mobil. Învață tehnici de imagini responsive și strategii de compresie specifice mobilului.","optimizare imagini mobile, imagini responsive, performanță mobilă, optimizare imagini mobile, optimizare web mobil",{"title":109,"description":110,"metaKeywords":111},"Optimizacija Mobilnih Slik: Najboljše Prakse za Mobilne Naprave","Optimizirajte slike za mobilne naprave in izboljšajte mobilno uporabniško izkušnjo. Naučite se tehnik odzivnih slik in strategij stiskanja, specifičnih za mobilne naprave.","optimizacija mobilnih slik, odzivne slike, mobilna zmogljivost, optimizacija mobilnih slik, optimizacija mobilnega spleta",{"title":113,"description":114,"metaKeywords":115},"Mobil Görüntü Optimizasyonu: Mobil Cihazlar için En İyi Uygulamalar","Mobil cihazlar için görüntüleri optimize edin ve mobil kullanıcı deneyimini iyileştirin. Responsive görüntü tekniklerini ve mobil özel sıkıştırma stratejilerini öğrenin.","mobil görüntü optimizasyonu, responsive görüntüler, mobil performans, mobil görüntü optimizasyonu, mobil web optimizasyonu",{"title":117,"description":118,"metaKeywords":119},"Mobil Kép Optimalizálás: Legjobb Gyakorlatok Mobil Eszközökhöz","Optimalizálja a képeket mobil eszközökre és javítsa a mobil felhasználói élményt. Tanuljon meg reszponzív képtechnikákat és mobil-specifikus tömörítési stratégiákat.","mobil kép optimalizálás, reszponzív képek, mobil teljesítmény, mobil kép optimalizálás, mobil web optimalizálás",{"zh":121,"zh-tw":122,"zh-cn":121,"en":123,"ja":124,"ko":125,"de":126,"fr":127,"es":128,"it":129,"pt":130,"ru":131,"nl":132,"pl":133,"cs":134,"hu":135,"th":136,"vi":137,"id":138,"tr":139,"sv":140,"da":141,"fi":142,"ro":143,"el":144,"sl":145,"no":146},"# 移动端图片优化：性能终极指南\r\n\r\n如今，移动设备占全球网页流量的 60% 以上。移动端图片优化对于用户体验、性能和业务成功至关重要。移动用户面临带宽有限、屏幕尺寸多样、电池消耗等独特挑战。本指南涵盖了移动端图片优化的高级策略、技术和工具。\r\n\r\n## 为什么移动端图片优化很重要\r\n\r\n### 对移动性能的影响\r\n\r\n移动端优化直接影响核心指标：\r\n- **页面加载速度**：图片通常占页面体积的 50–70%\r\n- **用户参与度**：53% 的移动用户会在页面加载超过 3 秒时离开\r\n- **电池消耗**：图片加载不高效会加速电池消耗\r\n- **流量消耗**：对流量有限的用户尤为重要\r\n- **SEO 排名**：Google 移动优先索引重视移动端性能\r\n\r\n### 移动端的独特挑战\r\n\r\n移动环境有其独特的优化难题：\r\n- **多变的网络环境**：从慢速 2G 到高速 5G\r\n- **算力有限**：移动 CPU 性能远低于桌面\r\n- **内存受限**：移动设备 RAM 较小\r\n- **屏幕多样性**：数百种尺寸和像素密度\r\n- **触控交互**：与桌面不同的交互方式\r\n\r\n## 理解移动端显示特性\r\n\r\n### 屏幕像素密度与 DPR\r\n\r\nDevice Pixel Ratio（DPR）影响图片需求：\r\n\r\n```javascript\r\n// 检查 device pixel ratio\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// 计算最佳图片尺寸\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// 使用示例\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`最佳尺寸: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### 常见移动屏幕配置\r\n\r\n**主流屏幕分辨率：**\r\n- iPhone 14/15：390x844 点（1179x2556 像素，3x DPR）\r\n- iPhone 14/15 Plus：428x926 点（1284x2778 像素，3x DPR）\r\n- Samsung Galaxy S24：412x915 点（1344x2992 像素，3.25x DPR）\r\n- Google Pixel 8：384x854 点（1080x2400 像素，2.8125x DPR）\r\n\r\n## 基于网络的图片优化\r\n\r\n### 按连接类型分发\r\n\r\n根据网络速度调整图片质量：\r\n\r\n```javascript\r\n// 网络感知图片加载器\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // 默认\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // 分类网络质量\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// 使用示例\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## 响应式图片用法\r\n\r\n### 移动端 picture 元素\r\n\r\n高级响应式图片用法：\r\n\r\n```html\r\n\u003C!-- 完整响应式图片设置 -->\r\n\u003Cpicture>\r\n    \u003C!-- 高分辨率移动屏（2x-3x DPR） -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- 标准移动屏（1x-2x DPR） -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG 兜底 -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- 最终兜底 -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"描述性 alt 文本\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## 渐进式加载策略\r\n\r\n### 移动端懒加载（Lazy Loading）\r\n\r\n高效实现移动端懒加载：\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // 支持 Intersection Observer 则使用\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // 距 viewport 50px 时加载\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// 初始化懒加载器\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## 移动端专用格式优化\r\n\r\n### 格式选择算法\r\n\r\n根据移动设备能力选择最优格式：\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // 始终支持\r\n            png: true   // 始终支持\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // 慢速/省流量优先小文件\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // 照片优先新格式高压缩\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## 电池与整体性能优化\r\n\r\n### 节能型图片处理\r\n\r\n减少移动端图片处理时的 CPU 占用：\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // 如有可能检测电池状态\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // 根据设备能力调整并发数\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // 低性能设备谨慎\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // 电量低且未充电时降低并发\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Core Web Vitals 优化\r\n\r\n### 优化 Largest Contentful Paint (LCP)\r\n\r\n优化移动端 LCP：\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // 找出首屏图片优先加载\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // 高优先级加载\r\n            img.loading = 'eager';\r\n            \r\n            // 可能为 LCP 则预加载\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### 防止 Cumulative Layout Shift (CLS)\r\n\r\n防止移动端布局跳动：\r\n\r\n```css\r\n/* 防 CLS 的宽高比容器 */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* 骨架屏防 CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## 测试与监控\r\n\r\n### 移动端图片性能测试\r\n\r\n全面测试移动端图片性能：\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // 监控图片加载性能\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('考虑进一步压缩图片');\r\n            recommendations.push('大图使用 progressive JPEG');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// 初始化性能测试器\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## 总结\r\n\r\n移动端图片优化是一项多维挑战，需要理解网络环境、设备能力、用户行为和性能指标。成功取决于采用能适应移动端实际限制并带来最佳视觉体验的策略。\r\n\r\n移动端图片优化要点：\r\n\r\n1. **网络感知**：根据速度和流量限制调整质量和加载策略\r\n2. **设备适配**：考虑屏幕密度、算力和电池\r\n3. **聚焦性能**：优先 Core Web Vitals 和用户体验指标\r\n4. **渐进优化**：从基础到高级分层优化\r\n5. **持续监控**：定期测试和监控以保持优化\r\n\r\n随着 5G、更强算力和新图片格式等移动技术发展，持续更新优化技术和兼容性对于卓越的移动体验至关重要。\r\n\r\n移动端图片优化的未来在于智能系统，能根据用户环境、设备能力和网络条件自动适配，在各种限制下实现最佳画质。\r\n","# 行動端圖片最佳化：效能終極指南\r\n\r\n現今行動裝置已佔全球網頁流量超過 60%。行動端圖片最佳化對於用戶體驗、效能與商業成功至關重要。行動用戶面臨頻寬有限、螢幕尺寸多樣、電池消耗等獨特挑戰。本指南涵蓋行動端圖片最佳化的進階策略、技術與工具。\r\n\r\n## 為什麼行動端圖片最佳化很重要\r\n\r\n### 對行動效能的影響\r\n\r\n行動端最佳化直接影響核心指標：\r\n- **頁面載入速度**：圖片通常佔頁面體積的 50–70%\r\n- **用戶參與度**：53% 的行動用戶會在頁面載入超過 3 秒時離開\r\n- **電池消耗**：圖片載入效率低會加速電池消耗\r\n- **流量消耗**：對流量有限的用戶尤其重要\r\n- **SEO 排名**：Google 行動優先索引重視行動端效能\r\n\r\n### 行動端的獨特挑戰\r\n\r\n行動環境有其獨特的最佳化難題：\r\n- **多變的網路環境**：從慢速 2G 到高速 5G\r\n- **運算能力有限**：行動 CPU 效能遠低於桌面\r\n- **記憶體受限**：行動裝置 RAM 較小\r\n- **螢幕多樣性**：數百種尺寸與像素密度\r\n- **觸控互動**：與桌面不同的互動方式\r\n\r\n## 理解行動端顯示特性\r\n\r\n### 螢幕像素密度與 DPR\r\n\r\nDevice Pixel Ratio（DPR）影響圖片需求：\r\n\r\n```javascript\r\n// 檢查 device pixel ratio\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// 計算最佳圖片尺寸\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// 使用範例\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`最佳尺寸: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### 常見行動螢幕配置\r\n\r\n**主流螢幕解析度：**\r\n- iPhone 14/15：390x844 點（1179x2556 像素，3x DPR）\r\n- iPhone 14/15 Plus：428x926 點（1284x2778 像素，3x DPR）\r\n- Samsung Galaxy S24：412x915 點（1344x2992 像素，3.25x DPR）\r\n- Google Pixel 8：384x854 點（1080x2400 像素，2.8125x DPR）\r\n\r\n## 基於網路的圖片最佳化\r\n\r\n### 依連線類型分發\r\n\r\n根據網路速度調整圖片品質：\r\n\r\n```javascript\r\n// 網路感知圖片載入器\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // 預設\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // 分類網路品質\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// 使用範例\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## 響應式圖片用法\r\n\r\n### 行動端 picture 元素\r\n\r\n進階響應式圖片用法：\r\n\r\n```html\r\n\u003C!-- 完整響應式圖片設定 -->\r\n\u003Cpicture>\r\n    \u003C!-- 高解析度行動螢幕（2x-3x DPR） -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- 標準行動螢幕（1x-2x DPR） -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG 備援 -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- 最終備援 -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"描述性 alt 文字\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## 漸進式載入策略\r\n\r\n### 行動端 Lazy Loading\r\n\r\n高效實現行動端 lazy loading：\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // 支援 Intersection Observer 則使用\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // 距 viewport 50px 時載入\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// 初始化 lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## 行動端專用格式最佳化\r\n\r\n### 格式選擇演算法\r\n\r\n根據行動裝置能力選擇最適格式：\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // 永遠支援\r\n            png: true   // 永遠支援\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // 慢速/省流量優先小檔案\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // 照片優先新格式高壓縮\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## 電池與整體效能最佳化\r\n\r\n### 節能型圖片處理\r\n\r\n減少行動端圖片處理時的 CPU 使用：\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // 如可偵測電池狀態則偵測\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // 根據裝置能力調整並行數\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // 低效能裝置謹慎\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // 電量低且未充電時降低並行數\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Core Web Vitals 最佳化\r\n\r\n### 最佳化 Largest Contentful Paint (LCP)\r\n\r\n最佳化行動端 LCP：\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // 找出首屏圖片優先載入\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // 高優先級載入\r\n            img.loading = 'eager';\r\n            \r\n            // 可能為 LCP 則預載入\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### 防止 Cumulative Layout Shift (CLS)\r\n\r\n防止行動端版面跳動：\r\n\r\n```css\r\n/* 防 CLS 的寬高比容器 */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* 骨架屏防 CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## 測試與監控\r\n\r\n### 行動端圖片效能測試\r\n\r\n全面測試行動端圖片效能：\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // 監控圖片載入效能\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('考慮進一步壓縮圖片');\r\n            recommendations.push('大圖使用 progressive JPEG');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// 初始化效能測試器\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## 總結\r\n\r\n行動端圖片最佳化是一項多維挑戰，需要理解網路環境、裝置能力、用戶行為與效能指標。成功取決於採用能適應行動端實際限制並帶來最佳視覺體驗的策略。\r\n\r\n行動端圖片最佳化重點：\r\n\r\n1. **網路感知**：根據速度與流量限制調整品質與載入策略\r\n2. **裝置適配**：考慮螢幕密度、運算能力與電池\r\n3. **聚焦效能**：優先 Core Web Vitals 與用戶體驗指標\r\n4. **漸進最佳化**：從基礎到進階分層最佳化\r\n5. **持續監控**：定期測試與監控以維持最佳化\r\n\r\n隨著 5G、更強運算力與新圖片格式等行動技術發展，持續更新最佳化技術與相容性對卓越行動體驗至關重要。\r\n\r\n行動端圖片最佳化的未來在於智慧系統，能根據用戶環境、裝置能力與網路條件自動適配，在各種限制下實現最佳畫質。\r\n","# Mobile Image Optimization: Complete Performance Guide\r\n\r\nMobile devices now account for over 60% of global web traffic, making mobile image optimization crucial for user experience, performance, and business success. Mobile users face unique challenges including limited bandwidth, varying screen sizes, and battery consumption concerns. This comprehensive guide covers advanced strategies, techniques, and tools specifically designed for optimizing images for mobile devices.\r\n\r\n## Why Mobile Image Optimization is Critical\r\n\r\n### Mobile Performance Impact\r\n\r\nMobile optimization directly affects key metrics:\r\n- **Page Load Speed**: Images typically account for 50-70% of page weight\r\n- **User Engagement**: 53% of mobile users abandon sites that take longer than 3 seconds to load\r\n- **Battery Consumption**: Inefficient image loading drains battery faster\r\n- **Data Usage**: Important for users with limited data plans\r\n- **SEO Rankings**: Google's mobile-first indexing prioritizes mobile performance\r\n\r\n### Mobile-Specific Challenges\r\n\r\nThe mobile environment presents unique optimization challenges:\r\n- **Variable Network Conditions**: From slow 2G to fast 5G connections\r\n- **Limited Processing Power**: Mobile CPUs are less capable than desktop CPUs\r\n- **Memory Constraints**: Mobile devices have limited RAM\r\n- **Screen Diversity**: Hundreds of different screen sizes and densities\r\n- **Touch Interface**: Different interaction patterns than desktop\r\n\r\n## Understanding Mobile Display Characteristics\r\n\r\n### Screen Density and DPR\r\n\r\nDevice Pixel Ratio (DPR) affects image requirements:\r\n\r\n```javascript\r\n// Detect device pixel ratio\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Calculate optimal image size\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Usage example\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Optimal size: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Common Mobile Screen Configurations\r\n\r\n**Popular Mobile Resolutions**:\r\n- iPhone 14/15: 390x844 points (1179x2556 pixels, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 points (1284x2778 pixels, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 points (1344x2992 pixels, 3.25x DPR)\r\n- Google Pixel 8: 384x854 points (1080x2400 pixels, 2.8125x DPR)\r\n\r\n## Network-Aware Image Optimization\r\n\r\n### Connection-Based Delivery\r\n\r\nAdjust image quality based on connection speed:\r\n\r\n```javascript\r\n// Network-aware image loading\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Default assumption\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Categorize network quality\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Usage\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Responsive Image Implementation\r\n\r\n### Mobile Picture Element\r\n\r\nAdvanced responsive image implementation:\r\n\r\n```html\r\n\u003C!-- Comprehensive responsive image setup -->\r\n\u003Cpicture>\r\n    \u003C!-- High-resolution mobile displays (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Standard mobile displays (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG fallbacks -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Final fallback -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Descriptive alt text\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Progressive Loading Strategies\r\n\r\n### Mobile-Optimized Lazy Loading\r\n\r\nImplement efficient lazy loading for mobile:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Use intersection observer if available\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Start loading 50px before entering viewport\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Initialize lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Mobile-Specific Format Optimization\r\n\r\n### Format Selection Algorithm\r\n\r\nChoose optimal format based on mobile capabilities:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Always supported\r\n            png: true   // Always supported\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // For slow connections or data saving, prefer smaller files\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // For photos, prefer modern formats with good compression\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Battery and Performance Optimization\r\n\r\n### CPU-Efficient Image Processing\r\n\r\nMinimize mobile CPU usage during image operations:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Monitor battery status if available\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Adapt concurrency based on device capabilities\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Conservative approach for lower-end devices\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Reduce processing intensity on low battery\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Core Web Vitals Optimization\r\n\r\n### Largest Contentful Paint (LCP) Optimization\r\n\r\nOptimize LCP for mobile devices:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Identify above-fold images and prioritize them\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Add high priority loading\r\n            img.loading = 'eager';\r\n            \r\n            // Preload if it's likely to be LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Cumulative Layout Shift (CLS) Prevention\r\n\r\nPrevent layout shifts on mobile:\r\n\r\n```css\r\n/* Aspect ratio containers to prevent CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading to prevent CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Testing and Monitoring\r\n\r\n### Mobile Performance Testing\r\n\r\nComprehensive mobile image performance testing:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Monitor image loading performance\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Consider more aggressive image compression');\r\n            recommendations.push('Implement progressive JPEG for large images');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Initialize performance tester\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Conclusion\r\n\r\nMobile image optimization is a multifaceted challenge that requires understanding network conditions, device capabilities, user behavior, and performance metrics. Success depends on implementing adaptive strategies that respond to real-world mobile constraints while delivering the best possible visual experience.\r\n\r\nKey takeaways for mobile image optimization:\r\n\r\n1. **Network Awareness**: Adapt image quality and loading strategies based on connection speed and data constraints\r\n2. **Device Adaptation**: Consider screen density, processing power, and battery life in optimization decisions\r\n3. **Performance-First Approach**: Prioritize Core Web Vitals and user experience metrics\r\n4. **Progressive Enhancement**: Layer optimizations from basic functionality to advanced features\r\n5. **Continuous Monitoring**: Regular testing and performance monitoring ensure ongoing optimization\r\n\r\nAs mobile technology continues to evolve, including 5G networks, improved processing power, and new image formats, staying current with optimization techniques while maintaining backward compatibility is essential for delivering exceptional mobile experiences.\r\n\r\nThe future of mobile image optimization lies in intelligent, adaptive systems that automatically adjust to user environment, device capabilities, and network conditions while maintaining the highest possible visual quality within those constraints.\r\n\r\n","# モバイル画像最適化：完全パフォーマンスガイド\r\n\r\nモバイルデバイスは現在、世界のウェブトラフィックの60％以上を占めており、モバイル画像の最適化はユーザー体験、パフォーマンス、ビジネスの成功にとって極めて重要です。モバイルユーザーは、帯域幅の制限、画面サイズの多様性、バッテリー消費など、独自の課題に直面しています。本ガイドでは、モバイルデバイス向け画像最適化のための高度な戦略、技術、ツールを包括的に解説します。\r\n\r\n## なぜモバイル画像最適化が重要なのか\r\n\r\n### モバイルパフォーマンスへの影響\r\n\r\nモバイル最適化は主要な指標に直接影響します：\r\n- **ページ読み込み速度**：画像はページ重量の50～70％を占めることが多い\r\n- **ユーザーエンゲージメント**：モバイルユーザーの53％は3秒以上かかるサイトを離脱する\r\n- **バッテリー消費**：非効率な画像読み込みはバッテリーを早く消耗させる\r\n- **データ使用量**：データプランが限られているユーザーにとって重要\r\n- **SEO順位**：Googleのモバイルファーストインデックスはモバイルパフォーマンスを重視\r\n\r\n### モバイル特有の課題\r\n\r\nモバイル環境には独自の最適化課題があります：\r\n- **ネットワーク状況の変動**：遅い2Gから高速5Gまで\r\n- **処理能力の制限**：モバイルCPUはデスクトップより非力\r\n- **メモリ制約**：モバイルデバイスはRAMが限られている\r\n- **画面の多様性**：数百種類の画面サイズと密度\r\n- **タッチインターフェース**：デスクトップとは異なる操作パターン\r\n\r\n## モバイル表示特性の理解\r\n\r\n### 画面密度とDPR\r\n\r\nデバイスピクセル比（DPR）は画像要件に影響します：\r\n\r\n```javascript\r\n// デバイスピクセル比を取得\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// 最適な画像サイズを計算\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// 使用例\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`最適サイズ: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### 一般的なモバイル画面構成\r\n\r\n**人気のモバイル解像度：**\r\n- iPhone 14/15：390x844ポイント（1179x2556ピクセル、3x DPR）\r\n- iPhone 14/15 Plus：428x926ポイント（1284x2778ピクセル、3x DPR）\r\n- Samsung Galaxy S24：412x915ポイント（1344x2992ピクセル、3.25x DPR）\r\n- Google Pixel 8：384x854ポイント（1080x2400ピクセル、2.8125x DPR）\r\n\r\n## ネットワーク対応画像最適化\r\n\r\n### 接続状況に応じた配信\r\n\r\n接続速度に応じて画像品質を調整：\r\n\r\n```javascript\r\n// ネットワーク対応画像ローダー\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // デフォルト\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // ネットワーク品質を分類\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// 使用例\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## レスポンシブ画像の実装\r\n\r\n### モバイル向けpicture要素\r\n\r\n高度なレスポンシブ画像実装：\r\n\r\n```html\r\n\u003C!-- 完全なレスポンシブ画像設定 -->\r\n\u003Cpicture>\r\n    \u003C!-- 高解像度モバイルディスプレイ（2x-3x DPR） -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- 標準モバイルディスプレイ（1x-2x DPR） -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEGフォールバック -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- 最終フォールバック -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"説明的なaltテキスト\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## プログレッシブローディング戦略\r\n\r\n### モバイル最適化レイジーローディング\r\n\r\nモバイル向け効率的なレイジーローディングの実装：\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Intersection Observerが利用可能なら使用\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // ビューポートに入る50px前から読み込み開始\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// レイジーローダー初期化\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## モバイル特有のフォーマット最適化\r\n\r\n### フォーマット選択アルゴリズム\r\n\r\nモバイルの機能に応じて最適なフォーマットを選択：\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // 常にサポート\r\n            png: true   // 常にサポート\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // 低速回線やデータ節約時は小さいファイルを優先\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // 写真には圧縮率の高い最新フォーマットを優先\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## バッテリーとパフォーマンスの最適化\r\n\r\n### CPU効率の良い画像処理\r\n\r\n画像処理時のモバイルCPU使用を最小限に：\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // バッテリー状態を監視（可能な場合）\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // デバイス性能に応じて同時処理数を調整\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // 低スペック端末には保守的に\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // バッテリー残量が少ない場合は処理を抑制\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Core Web Vitals最適化\r\n\r\n### Largest Contentful Paint（LCP）の最適化\r\n\r\nモバイル向けLCP最適化：\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // ファーストビュー内画像を特定し優先的に読み込む\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // 高優先度で読み込み\r\n            img.loading = 'eager';\r\n            \r\n            // LCPになりそうな画像はプリロード\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Cumulative Layout Shift（CLS）防止\r\n\r\nモバイルでのレイアウトシフトを防ぐ：\r\n\r\n```css\r\n/* CLS防止のためのアスペクト比コンテナ */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loadingでCLS防止 */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## テストとモニタリング\r\n\r\n### モバイル画像パフォーマンステスト\r\n\r\nモバイル画像のパフォーマンスを包括的にテスト：\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // 画像読み込みパフォーマンスを監視\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('より積極的な画像圧縮を検討してください');\r\n            recommendations.push('大きな画像にはプログレッシブJPEGを実装してください');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// パフォーマンステスター初期化\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## まとめ\r\n\r\nモバイル画像最適化は、ネットワーク状況、デバイス性能、ユーザー行動、パフォーマンス指標の理解が必要な多面的な課題です。成功の鍵は、現実のモバイル制約に対応しつつ、最良のビジュアル体験を提供する適応的な戦略の実装にあります。\r\n\r\nモバイル画像最適化のポイント：\r\n\r\n1. **ネットワーク認識**：接続速度やデータ制約に応じて画像品質や読み込み戦略を調整\r\n2. **デバイス適応**：画面密度、処理能力、バッテリー寿命を考慮\r\n3. **パフォーマンス重視**：Core Web Vitalsやユーザー体験指標を優先\r\n4. **プログレッシブエンハンスメント**：基本機能から高度な機能まで段階的に最適化\r\n5. **継続的なモニタリング**：定期的なテストとパフォーマンス監視で最適化を維持\r\n\r\n5Gや新しい画像フォーマットなど、モバイル技術が進化し続ける中、最先端の最適化技術を維持しつつ後方互換性も確保することが、優れたモバイル体験の提供に不可欠です。\r\n\r\n今後のモバイル画像最適化は、ユーザー環境・デバイス性能・ネットワーク状況に自動適応し、制約内で最高のビジュアル品質を維持するインテリジェントなシステムに委ねられます。\r\n","# 모바일 이미지 최적화: 완벽한 성능 가이드\r\n\r\n모바일 기기는 이제 전 세계 웹 트래픽의 60% 이상을 차지하며, 모바일 이미지 최적화는 사용자 경험, 성능, 비즈니스 성공에 매우 중요합니다. 모바일 사용자는 제한된 대역폭, 다양한 화면 크기, 배터리 소모 등 고유한 과제에 직면합니다. 이 종합 가이드는 모바일 기기용 이미지 최적화를 위해 설계된 고급 전략, 기술, 도구를 다룹니다.\r\n\r\n## 모바일 이미지 최적화가 중요한 이유\r\n\r\n### 모바일 성능에 미치는 영향\r\n\r\n모바일 최적화는 주요 지표에 직접적인 영향을 미칩니다:\r\n- **페이지 로드 속도**: 이미지는 일반적으로 페이지 무게의 50~70%를 차지함\r\n- **사용자 참여**: 모바일 사용자의 53%는 3초 이상 걸리는 사이트를 이탈함\r\n- **배터리 소모**: 비효율적인 이미지 로딩은 배터리를 더 빨리 소모시킴\r\n- **데이터 사용량**: 데이터 요금제가 제한된 사용자에게 중요함\r\n- **SEO 순위**: 구글의 모바일 우선 인덱싱은 모바일 성능을 우선시함\r\n\r\n### 모바일 특화 과제\r\n\r\n모바일 환경은 고유한 최적화 과제를 제공합니다:\r\n- **가변 네트워크 환경**: 느린 2G부터 빠른 5G까지\r\n- **제한된 처리 성능**: 모바일 CPU는 데스크톱보다 성능이 낮음\r\n- **메모리 제약**: 모바일 기기는 RAM이 제한적임\r\n- **화면 다양성**: 수백 가지의 화면 크기와 밀도\r\n- **터치 인터페이스**: 데스크톱과 다른 상호작용 패턴\r\n\r\n## 모바일 디스플레이 특성 이해\r\n\r\n### 화면 밀도와 DPR\r\n\r\n디바이스 픽셀 비율(DPR)은 이미지 요구사항에 영향을 미칩니다:\r\n\r\n```javascript\r\n// 디바이스 픽셀 비율 감지\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// 최적 이미지 크기 계산\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// 사용 예시\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`최적 크기: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### 일반적인 모바일 화면 구성\r\n\r\n**인기 모바일 해상도:**\r\n- iPhone 14/15: 390x844 포인트(1179x2556 픽셀, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 포인트(1284x2778 픽셀, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 포인트(1344x2992 픽셀, 3.25x DPR)\r\n- Google Pixel 8: 384x854 포인트(1080x2400 픽셀, 2.8125x DPR)\r\n\r\n## 네트워크 인식 이미지 최적화\r\n\r\n### 연결 기반 이미지 제공\r\n\r\n연결 속도에 따라 이미지 품질 조정:\r\n\r\n```javascript\r\n// 네트워크 인식 이미지 로더\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // 기본값\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // 네트워크 품질 분류\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// 사용 예시\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## 반응형 이미지 구현\r\n\r\n### 모바일용 picture 요소\r\n\r\n고급 반응형 이미지 구현:\r\n\r\n```html\r\n\u003C!-- 완전한 반응형 이미지 설정 -->\r\n\u003Cpicture>\r\n    \u003C!-- 고해상도 모바일 디스플레이(2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- 표준 모바일 디스플레이(1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG 대체 -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- 최종 대체 -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"설명적 대체 텍스트\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## 점진적 로딩 전략\r\n\r\n### 모바일 최적화 지연 로딩\r\n\r\n모바일에 효율적인 지연 로딩 구현:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Intersection Observer 사용 가능 시 활용\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // 뷰포트 진입 50px 전에 로딩 시작\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// 지연 로더 초기화\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## 모바일 특화 포맷 최적화\r\n\r\n### 포맷 선택 알고리즘\r\n\r\n모바일 기기 성능에 따라 최적 포맷 선택:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // 항상 지원\r\n            png: true   // 항상 지원\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // 느린 연결 또는 데이터 절약 시 작은 파일 우선\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // 사진에는 최신 포맷 우선\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## 배터리 및 성능 최적화\r\n\r\n### CPU 효율적 이미지 처리\r\n\r\n이미지 작업 시 모바일 CPU 사용 최소화:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // 배터리 상태 감시(가능한 경우)\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // 기기 성능에 따라 동시 처리 수 조정\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // 저사양 기기는 보수적으로\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // 배터리 부족 시 처리 강도 감소\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Core Web Vitals 최적화\r\n\r\n### Largest Contentful Paint(LCP) 최적화\r\n\r\n모바일 기기용 LCP 최적화:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // 화면 상단 이미지 식별 및 우선 처리\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // 높은 우선순위 로딩\r\n            img.loading = 'eager';\r\n            \r\n            // LCP 가능성 높으면 프리로드\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Cumulative Layout Shift(CLS) 방지\r\n\r\n모바일에서 레이아웃 이동 방지:\r\n\r\n```css\r\n/* CLS 방지를 위한 종횡비 컨테이너 */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading으로 CLS 방지 */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## 테스트 및 모니터링\r\n\r\n### 모바일 이미지 성능 테스트\r\n\r\n모바일 이미지 성능 종합 테스트:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // 이미지 로딩 성능 모니터링\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('더 강력한 이미지 압축을 고려하세요');\r\n            recommendations.push('큰 이미지는 프로그레시브 JPEG를 적용하세요');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// 성능 테스터 초기화\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## 결론\r\n\r\n모바일 이미지 최적화는 네트워크 환경, 기기 성능, 사용자 행동, 성능 지표에 대한 이해가 필요한 다면적 과제입니다. 성공의 핵심은 실제 모바일 제약에 대응하면서 최고의 시각적 경험을 제공하는 적응형 전략 구현에 있습니다.\r\n\r\n모바일 이미지 최적화 핵심 요약:\r\n\r\n1. **네트워크 인식**: 연결 속도와 데이터 제약에 따라 이미지 품질 및 로딩 전략 조정\r\n2. **기기 적응**: 화면 밀도, 처리 성능, 배터리 수명 고려\r\n3. **성능 우선 접근**: Core Web Vitals 및 사용자 경험 지표 우선\r\n4. **점진적 개선**: 기본 기능부터 고급 기능까지 단계별 최적화\r\n5. **지속적 모니터링**: 정기적인 테스트와 성능 모니터링으로 최적화 유지\r\n\r\n5G, 향상된 처리 성능, 새로운 이미지 포맷 등 모바일 기술이 계속 발전함에 따라, 최신 최적화 기술을 유지하면서도 하위 호환성을 확보하는 것이 탁월한 모바일 경험 제공의 핵심입니다.\r\n\r\n미래의 모바일 이미지 최적화는 사용자 환경, 기기 성능, 네트워크 상황에 자동으로 적응하며, 그 제약 내에서 최고의 시각적 품질을 유지하는 지능형 시스템에 달려 있습니다.\r\n","# Mobile Bildoptimierung: Umfassender Performance-Guide\r\n\r\nMobile Endgeräte machen mittlerweile über 60 % des weltweiten Web-Traffics aus, weshalb die Bildoptimierung für Mobilgeräte entscheidend für Nutzererlebnis, Performance und Geschäftserfolg ist. Mobile Nutzer stehen vor besonderen Herausforderungen wie begrenzter Bandbreite, unterschiedlichen Bildschirmgrößen und Akkulaufzeit. Dieser umfassende Leitfaden behandelt fortgeschrittene Strategien, Techniken und Tools, die speziell für die Optimierung von Bildern auf Mobilgeräten entwickelt wurden.\r\n\r\n## Warum mobile Bildoptimierung entscheidend ist\r\n\r\n### Einfluss auf die mobile Performance\r\n\r\nMobile Optimierung wirkt sich direkt auf wichtige Kennzahlen aus:\r\n- **Seitenladegeschwindigkeit**: Bilder machen typischerweise 50–70 % des Seitengewichts aus\r\n- **Nutzerinteraktion**: 53 % der mobilen Nutzer verlassen Seiten, die länger als 3 Sekunden laden\r\n- **Akkulaufzeit**: Ineffizientes Laden von Bildern entlädt den Akku schneller\r\n- **Datenverbrauch**: Wichtig für Nutzer mit begrenztem Datenvolumen\r\n- **SEO-Rankings**: Googles Mobile-First-Indexierung priorisiert mobile Performance\r\n\r\n### Mobile-spezifische Herausforderungen\r\n\r\nDas mobile Umfeld stellt besondere Optimierungsherausforderungen dar:\r\n- **Variable Netzwerkbedingungen**: Von langsamem 2G bis schnellem 5G\r\n- **Begrenzte Rechenleistung**: Mobile CPUs sind weniger leistungsfähig als Desktop-CPUs\r\n- **Speicherbeschränkungen**: Mobile Geräte haben begrenzten RAM\r\n- **Bildschirmvielfalt**: Hunderte verschiedene Bildschirmgrößen und -dichten\r\n- **Touch-Interface**: Andere Interaktionsmuster als am Desktop\r\n\r\n## Verständnis mobiler Anzeigeeigenschaften\r\n\r\n### Pixeldichte und DPR\r\n\r\nDas Device Pixel Ratio (DPR) beeinflusst die Bildanforderungen:\r\n\r\n```javascript\r\n// Gerätepixelverhältnis ermitteln\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Optimale Bildgröße berechnen\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Anwendungsbeispiel\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Optimale Größe: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Gängige mobile Bildschirmkonfigurationen\r\n\r\n**Beliebte mobile Auflösungen:**\r\n- iPhone 14/15: 390x844 Punkte (1179x2556 Pixel, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 Punkte (1284x2778 Pixel, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 Punkte (1344x2992 Pixel, 3.25x DPR)\r\n- Google Pixel 8: 384x854 Punkte (1080x2400 Pixel, 2.8125x DPR)\r\n\r\n## Netzwerkbewusste Bildoptimierung\r\n\r\n### Verbindungsbasierte Auslieferung\r\n\r\nPasse die Bildqualität an die Verbindungsgeschwindigkeit an:\r\n\r\n```javascript\r\n// Netzwerkbewusstes Bildladen\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Standardannahme\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Netzqualität kategorisieren\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Verwendung\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Responsive Bildimplementierung\r\n\r\n### \u003Cpicture>-Element für Mobilgeräte\r\n\r\nFortgeschrittene responsive Bildimplementierung:\r\n\r\n```html\r\n\u003C!-- Umfassende responsive Bildkonfiguration -->\r\n\u003Cpicture>\r\n    \u003C!-- Hochauflösende Mobilgeräte (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Standard-Mobilgeräte (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG-Fallbacks -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Letztes Fallback -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Beschreibender Alt-Text\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Progressive Lade-Strategien\r\n\r\n### Mobil-optimiertes Lazy Loading\r\n\r\nEffizientes Lazy Loading für Mobilgeräte implementieren:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Intersection Observer verwenden, falls verfügbar\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // 50px vor dem Viewport laden\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Lazy Loader initialisieren\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Mobile-spezifische Formatoptimierung\r\n\r\n### Format-Auswahl-Algorithmus\r\n\r\nWähle das optimale Format basierend auf den Fähigkeiten des Mobilgeräts:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Immer unterstützt\r\n            png: true   // Immer unterstützt\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Für langsame Verbindungen oder Datensparmodus kleinere Dateien bevorzugen\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Für Fotos moderne Formate mit guter Kompression bevorzugen\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Akku- und Performance-Optimierung\r\n\r\n### CPU-effiziente Bildverarbeitung\r\n\r\nMinimiere die CPU-Auslastung bei Bildoperationen auf Mobilgeräten:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Akkustatus überwachen, falls verfügbar\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Parallelität an Gerätefähigkeiten anpassen\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Konservativer Ansatz für schwächere Geräte\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Bei niedrigem Akkustand Intensität reduzieren\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Core Web Vitals-Optimierung\r\n\r\n### Largest Contentful Paint (LCP) Optimierung\r\n\r\nOptimiere LCP für Mobilgeräte:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Bilder im sichtbaren Bereich identifizieren und priorisieren\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Hochpriorisiertes Laden\r\n            img.loading = 'eager';\r\n            \r\n            // Preload, wenn wahrscheinlich LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Cumulative Layout Shift (CLS) verhindern\r\n\r\nVerhindere Layoutverschiebungen auf Mobilgeräten:\r\n\r\n```css\r\n/* Aspect-Ratio-Container zur CLS-Prävention */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton Loading zur CLS-Prävention */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Testen und Monitoring\r\n\r\n### Mobile Performance-Tests für Bilder\r\n\r\nUmfassende Tests der Bildperformance auf Mobilgeräten:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Überwache Bildladeperformance\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Erwägen Sie eine aggressivere Bildkomprimierung');\r\n            recommendations.push('Implementieren Sie progressive JPEGs für große Bilder');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Performance-Tester initialisieren\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Fazit\r\n\r\nDie mobile Bildoptimierung ist eine vielschichtige Herausforderung, die das Verständnis von Netzwerkbedingungen, Gerätefähigkeiten, Nutzerverhalten und Performance-Metriken erfordert. Der Erfolg hängt von der Implementierung adaptiver Strategien ab, die auf reale mobile Einschränkungen reagieren und gleichzeitig das bestmögliche visuelle Erlebnis bieten.\r\n\r\nWichtige Erkenntnisse für die mobile Bildoptimierung:\r\n\r\n1. **Netzwerkbewusstsein**: Passe Bildqualität und Lade-Strategien an Verbindungsgeschwindigkeit und Datenbeschränkungen an\r\n2. **Geräteanpassung**: Berücksichtige Pixeldichte, Rechenleistung und Akkulaufzeit bei Optimierungsentscheidungen\r\n3. **Performance-First-Ansatz**: Priorisiere Core Web Vitals und Nutzererlebnis-Metriken\r\n4. **Progressive Verbesserung**: Optimiere schrittweise von Basisfunktionalität bis zu fortgeschrittenen Features\r\n5. **Kontinuierliches Monitoring**: Regelmäßige Tests und Performanceüberwachung sichern fortlaufende Optimierung\r\n\r\nMit der Weiterentwicklung der mobilen Technologie, einschließlich 5G, verbesserter Rechenleistung und neuer Bildformate, ist es essenziell, mit Optimierungstechniken Schritt zu halten und gleichzeitig die Abwärtskompatibilität zu wahren, um herausragende mobile Erlebnisse zu bieten.\r\n\r\nDie Zukunft der mobilen Bildoptimierung liegt in intelligenten, adaptiven Systemen, die sich automatisch an die Nutzerumgebung, Gerätefähigkeiten und Netzwerkbedingungen anpassen und dabei die höchstmögliche visuelle Qualität innerhalb dieser Grenzen gewährleisten.\r\n","# Optimisation des images mobiles : Guide complet de performance\r\n\r\nLes appareils mobiles représentent désormais plus de 60 % du trafic web mondial, rendant l'optimisation des images mobiles cruciale pour l'expérience utilisateur, la performance et le succès commercial. Les utilisateurs mobiles font face à des défis uniques, notamment la bande passante limitée, la diversité des tailles d'écran et la consommation de batterie. Ce guide complet couvre des stratégies avancées, des techniques et des outils spécifiquement conçus pour optimiser les images sur les appareils mobiles.\r\n\r\n## Pourquoi l'optimisation des images mobiles est-elle cruciale ?\r\n\r\n### Impact sur la performance mobile\r\n\r\nL'optimisation mobile affecte directement des indicateurs clés :\r\n- **Vitesse de chargement des pages** : Les images représentent généralement 50 à 70 % du poids d'une page\r\n- **Engagement utilisateur** : 53 % des utilisateurs mobiles quittent les sites qui mettent plus de 3 secondes à charger\r\n- **Consommation de batterie** : Un chargement inefficace des images épuise la batterie plus rapidement\r\n- **Utilisation des données** : Important pour les utilisateurs avec des forfaits limités\r\n- **Classement SEO** : L'indexation mobile-first de Google privilégie la performance mobile\r\n\r\n### Défis spécifiques au mobile\r\n\r\nL'environnement mobile présente des défis d'optimisation uniques :\r\n- **Conditions réseau variables** : Du 2G lent au 5G rapide\r\n- **Puissance de traitement limitée** : Les CPU mobiles sont moins puissants que ceux des ordinateurs de bureau\r\n- **Contraintes de mémoire** : Les appareils mobiles ont une RAM limitée\r\n- **Diversité des écrans** : Des centaines de tailles et densités d'écran différentes\r\n- **Interface tactile** : Des schémas d'interaction différents du desktop\r\n\r\n## Comprendre les caractéristiques d'affichage mobile\r\n\r\n### Densité d'écran et DPR\r\n\r\nLe Device Pixel Ratio (DPR) affecte les besoins en images :\r\n\r\n```javascript\r\n// Détecter le ratio de pixels de l'appareil\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Calculer la taille optimale de l'image\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Exemple d'utilisation\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Taille optimale : ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Configurations d'écran mobile courantes\r\n\r\n**Résolutions mobiles populaires :**\r\n- iPhone 14/15 : 390x844 points (1179x2556 pixels, 3x DPR)\r\n- iPhone 14/15 Plus : 428x926 points (1284x2778 pixels, 3x DPR)\r\n- Samsung Galaxy S24 : 412x915 points (1344x2992 pixels, 3.25x DPR)\r\n- Google Pixel 8 : 384x854 points (1080x2400 pixels, 2.8125x DPR)\r\n\r\n## Optimisation des images selon le réseau\r\n\r\n### Livraison basée sur la connexion\r\n\r\nAjustez la qualité de l'image selon la vitesse de connexion :\r\n\r\n```javascript\r\n// Chargement d'images adapté au réseau\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Hypothèse par défaut\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Catégoriser la qualité du réseau\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Utilisation\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Mise en œuvre d'images responsives\r\n\r\n### Élément picture pour mobile\r\n\r\nImplémentation avancée d'images responsives :\r\n\r\n```html\r\n\u003C!-- Configuration complète d'image responsive -->\r\n\u003Cpicture>\r\n    \u003C!-- Écrans mobiles haute résolution (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Écrans mobiles standards (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Fallback JPEG -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Fallback final -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Texte alternatif descriptif\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Stratégies de chargement progressif\r\n\r\n### Lazy loading optimisé pour mobile\r\n\r\nImplémentez un lazy loading efficace pour mobile :\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Utilisez intersection observer si disponible\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Commence à charger 50px avant d'entrer dans le viewport\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Initialiser le lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Optimisation du format spécifique au mobile\r\n\r\n### Algorithme de sélection du format\r\n\r\nChoisissez le format optimal selon les capacités du mobile :\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Toujours supporté\r\n            png: true   // Toujours supporté\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Pour les connexions lentes ou l'économie de données, privilégiez les fichiers plus petits\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Pour les photos, privilégiez les formats modernes avec une bonne compression\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Optimisation de la batterie et des performances\r\n\r\n### Traitement d'image efficace pour le CPU\r\n\r\nMinimisez l'utilisation du CPU mobile lors des opérations sur les images :\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Surveillez l'état de la batterie si disponible\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Adaptez la concurrence selon les capacités de l'appareil\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Approche conservatrice pour les appareils d'entrée de gamme\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Réduisez l'intensité du traitement en cas de batterie faible\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Optimisation des Core Web Vitals\r\n\r\n### Optimisation du Largest Contentful Paint (LCP)\r\n\r\nOptimisez le LCP pour les appareils mobiles :\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Identifiez les images au-dessus de la ligne de flottaison et priorisez-les\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Ajoutez un chargement prioritaire\r\n            img.loading = 'eager';\r\n            \r\n            // Préchargez si c'est probablement le LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Prévention du Cumulative Layout Shift (CLS)\r\n\r\nÉvitez les décalages de mise en page sur mobile :\r\n\r\n```css\r\n/* Conteneurs à ratio d'aspect pour éviter le CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Chargement skeleton pour éviter le CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Tests et surveillance\r\n\r\n### Tests de performance des images mobiles\r\n\r\nTests complets de performance des images sur mobile :\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Surveillez la performance de chargement des images\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Envisagez une compression d'image plus agressive');\r\n            recommendations.push('Implémentez le JPEG progressif pour les grandes images');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Initialiser le testeur de performance\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Conclusion\r\n\r\nL'optimisation des images mobiles est un défi complexe qui nécessite de comprendre les conditions réseau, les capacités des appareils, le comportement des utilisateurs et les métriques de performance. Le succès dépend de la mise en œuvre de stratégies adaptatives qui répondent aux contraintes réelles du mobile tout en offrant la meilleure expérience visuelle possible.\r\n\r\nPoints clés pour l'optimisation des images mobiles :\r\n\r\n1. **Conscience du réseau** : Adaptez la qualité des images et les stratégies de chargement selon la vitesse de connexion et les contraintes de données\r\n2. **Adaptation à l'appareil** : Prenez en compte la densité d'écran, la puissance de traitement et la batterie dans les décisions d'optimisation\r\n3. **Approche axée sur la performance** : Priorisez les Core Web Vitals et les métriques d'expérience utilisateur\r\n4. **Amélioration progressive** : Superposez les optimisations de la fonctionnalité de base aux fonctionnalités avancées\r\n5. **Surveillance continue** : Des tests et une surveillance réguliers garantissent une optimisation continue\r\n\r\nÀ mesure que la technologie mobile évolue, y compris les réseaux 5G, la puissance de traitement accrue et les nouveaux formats d'image, il est essentiel de rester à jour sur les techniques d'optimisation tout en maintenant la compatibilité ascendante pour offrir des expériences mobiles exceptionnelles.\r\n\r\nL'avenir de l'optimisation des images mobiles réside dans des systèmes intelligents et adaptatifs qui s'ajustent automatiquement à l'environnement utilisateur, aux capacités de l'appareil et aux conditions réseau, tout en maintenant la meilleure qualité visuelle possible dans ces contraintes.\r\n","# Optimización de imágenes móviles: Guía completa de rendimiento\r\n\r\nLos dispositivos móviles representan ahora más del 60% del tráfico web global, lo que hace que la optimización de imágenes móviles sea crucial para la experiencia del usuario, el rendimiento y el éxito empresarial. Los usuarios móviles enfrentan desafíos únicos, como ancho de banda limitado, tamaños de pantalla variables y preocupaciones sobre el consumo de batería. Esta guía integral cubre estrategias avanzadas, técnicas y herramientas diseñadas específicamente para optimizar imágenes en dispositivos móviles.\r\n\r\n## Por qué la optimización de imágenes móviles es crítica\r\n\r\n### Impacto en el rendimiento móvil\r\n\r\nLa optimización móvil afecta directamente a métricas clave:\r\n- **Velocidad de carga de la página**: Las imágenes suelen representar el 50-70% del peso de la página\r\n- **Engagement del usuario**: El 53% de los usuarios móviles abandonan sitios que tardan más de 3 segundos en cargar\r\n- **Consumo de batería**: La carga ineficiente de imágenes agota la batería más rápido\r\n- **Uso de datos**: Importante para usuarios con planes de datos limitados\r\n- **Posicionamiento SEO**: La indexación mobile-first de Google prioriza el rendimiento móvil\r\n\r\n### Desafíos específicos de móviles\r\n\r\nEl entorno móvil presenta desafíos únicos de optimización:\r\n- **Condiciones de red variables**: Desde conexiones 2G lentas hasta 5G rápidas\r\n- **Potencia de procesamiento limitada**: Las CPU móviles son menos potentes que las de escritorio\r\n- **Restricciones de memoria**: Los dispositivos móviles tienen RAM limitada\r\n- **Diversidad de pantallas**: Cientos de tamaños y densidades de pantalla diferentes\r\n- **Interfaz táctil**: Patrones de interacción diferentes a los de escritorio\r\n\r\n## Comprendiendo las características de visualización móvil\r\n\r\n### Densidad de pantalla y DPR\r\n\r\nEl Device Pixel Ratio (DPR) afecta los requisitos de imagen:\r\n\r\n```javascript\r\n// Detectar el ratio de píxeles del dispositivo\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Calcular el tamaño óptimo de imagen\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Ejemplo de uso\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Tamaño óptimo: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Configuraciones comunes de pantalla móvil\r\n\r\n**Resoluciones móviles populares:**\r\n- iPhone 14/15: 390x844 puntos (1179x2556 píxeles, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 puntos (1284x2778 píxeles, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 puntos (1344x2992 píxeles, 3.25x DPR)\r\n- Google Pixel 8: 384x854 puntos (1080x2400 píxeles, 2.8125x DPR)\r\n\r\n## Optimización de imágenes según la red\r\n\r\n### Entrega basada en la conexión\r\n\r\nAjusta la calidad de la imagen según la velocidad de conexión:\r\n\r\n```javascript\r\n// Carga de imágenes consciente de la red\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Suposición por defecto\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Categorizar la calidad de la red\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Uso\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Implementación de imágenes responsivas\r\n\r\n### Elemento picture para móviles\r\n\r\nImplementación avanzada de imágenes responsivas:\r\n\r\n```html\r\n\u003C!-- Configuración completa de imagen responsiva -->\r\n\u003Cpicture>\r\n    \u003C!-- Pantallas móviles de alta resolución (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Pantallas móviles estándar (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG de respaldo -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Respaldo final -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Texto alternativo descriptivo\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Estrategias de carga progresiva\r\n\r\n### Lazy loading optimizado para móviles\r\n\r\nImplementa lazy loading eficiente para móviles:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Usa intersection observer si está disponible\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Comienza a cargar 50px antes de entrar en el viewport\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Inicializar lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Optimización de formato específica para móviles\r\n\r\n### Algoritmo de selección de formato\r\n\r\nElige el formato óptimo según las capacidades del móvil:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Siempre soportado\r\n            png: true   // Siempre soportado\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Para conexiones lentas o ahorro de datos, prefiere archivos más pequeños\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Para fotos, prefiere formatos modernos con buena compresión\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Optimización de batería y rendimiento\r\n\r\n### Procesamiento de imágenes eficiente en CPU\r\n\r\nMinimiza el uso de CPU móvil durante operaciones con imágenes:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Monitorea el estado de la batería si está disponible\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Adapta la concurrencia según las capacidades del dispositivo\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Enfoque conservador para dispositivos de gama baja\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Reduce la intensidad de procesamiento con batería baja\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Optimización de Core Web Vitals\r\n\r\n### Optimización de Largest Contentful Paint (LCP)\r\n\r\nOptimiza el LCP para dispositivos móviles:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Identifica imágenes above the fold y dales prioridad\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Añade carga de alta prioridad\r\n            img.loading = 'eager';\r\n            \r\n            // Preload si es probable que sea LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Prevención de Cumulative Layout Shift (CLS)\r\n\r\nEvita cambios de diseño en móviles:\r\n\r\n```css\r\n/* Contenedores de relación de aspecto para evitar CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading para evitar CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Pruebas y monitorización\r\n\r\n### Pruebas de rendimiento de imágenes móviles\r\n\r\nPruebas integrales de rendimiento de imágenes en móviles:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Monitoriza el rendimiento de carga de imágenes\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Considera una compresión de imágenes más agresiva');\r\n            recommendations.push('Implementa JPEG progresivo para imágenes grandes');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Inicializar el tester de rendimiento\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Conclusión\r\n\r\nLa optimización de imágenes móviles es un reto multifacético que requiere comprender las condiciones de red, las capacidades del dispositivo, el comportamiento del usuario y las métricas de rendimiento. El éxito depende de implementar estrategias adaptativas que respondan a las limitaciones reales de los móviles y ofrezcan la mejor experiencia visual posible.\r\n\r\nPuntos clave para la optimización de imágenes móviles:\r\n\r\n1. **Conciencia de red**: Adapta la calidad de imagen y las estrategias de carga según la velocidad de conexión y las restricciones de datos\r\n2. **Adaptación al dispositivo**: Considera la densidad de pantalla, la potencia de procesamiento y la batería en las decisiones de optimización\r\n3. **Enfoque en el rendimiento**: Prioriza Core Web Vitals y métricas de experiencia de usuario\r\n4. **Mejora progresiva**: Aplica optimizaciones desde la funcionalidad básica hasta las características avanzadas\r\n5. **Monitorización continua**: Las pruebas y monitorización regulares aseguran una optimización continua\r\n\r\nA medida que la tecnología móvil evoluciona, incluidas las redes 5G, la mayor potencia de procesamiento y los nuevos formatos de imagen, es esencial mantenerse actualizado con las técnicas de optimización y mantener la compatibilidad hacia atrás para ofrecer experiencias móviles excepcionales.\r\n\r\nEl futuro de la optimización de imágenes móviles reside en sistemas inteligentes y adaptativos que se ajustan automáticamente al entorno del usuario, las capacidades del dispositivo y las condiciones de red, manteniendo la mayor calidad visual posible dentro de esas limitaciones.\r\n","# Ottimizzazione delle immagini per dispositivi mobili: Guida completa alle prestazioni\r\n\r\nI dispositivi mobili rappresentano ormai oltre il 60% del traffico web globale, rendendo l'ottimizzazione delle immagini per mobile cruciale per l'esperienza utente, le prestazioni e il successo aziendale. Gli utenti mobili affrontano sfide uniche come larghezza di banda limitata, dimensioni dello schermo variabili e consumo della batteria. Questa guida completa copre strategie avanzate, tecniche e strumenti specificamente progettati per ottimizzare le immagini sui dispositivi mobili.\r\n\r\n## Perché l'ottimizzazione delle immagini per mobile è fondamentale\r\n\r\n### Impatto sulle prestazioni mobile\r\n\r\nL'ottimizzazione mobile influisce direttamente su metriche chiave:\r\n- **Velocità di caricamento della pagina**: Le immagini rappresentano tipicamente il 50-70% del peso della pagina\r\n- **Coinvolgimento dell'utente**: Il 53% degli utenti mobile abbandona i siti che impiegano più di 3 secondi a caricarsi\r\n- **Consumo della batteria**: Il caricamento inefficiente delle immagini scarica la batteria più rapidamente\r\n- **Utilizzo dei dati**: Importante per chi ha piani dati limitati\r\n- **Posizionamento SEO**: L'indicizzazione mobile-first di Google dà priorità alle prestazioni mobile\r\n\r\n### Sfide specifiche del mobile\r\n\r\nL'ambiente mobile presenta sfide di ottimizzazione uniche:\r\n- **Condizioni di rete variabili**: Da connessioni 2G lente a 5G veloci\r\n- **Potenza di elaborazione limitata**: Le CPU mobile sono meno potenti di quelle desktop\r\n- **Vincoli di memoria**: I dispositivi mobili hanno RAM limitata\r\n- **Diversità di schermi**: Centinaia di dimensioni e densità di schermo diverse\r\n- **Interfaccia touch**: Schemi di interazione diversi rispetto al desktop\r\n\r\n## Comprendere le caratteristiche di visualizzazione mobile\r\n\r\n### Densità dello schermo e DPR\r\n\r\nIl Device Pixel Ratio (DPR) influisce sui requisiti delle immagini:\r\n\r\n```javascript\r\n// Rileva il device pixel ratio\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Calcola la dimensione ottimale dell'immagine\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Esempio d'uso\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Dimensione ottimale: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Configurazioni comuni di schermi mobile\r\n\r\n**Risoluzioni mobile popolari:**\r\n- iPhone 14/15: 390x844 punti (1179x2556 pixel, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 punti (1284x2778 pixel, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 punti (1344x2992 pixel, 3.25x DPR)\r\n- Google Pixel 8: 384x854 punti (1080x2400 pixel, 2.8125x DPR)\r\n\r\n## Ottimizzazione delle immagini in base alla rete\r\n\r\n### Consegna basata sulla connessione\r\n\r\nAdatta la qualità delle immagini in base alla velocità di connessione:\r\n\r\n```javascript\r\n// Caricamento immagini consapevole della rete\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Assunzione predefinita\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Categorizza la qualità della rete\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Utilizzo\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Implementazione di immagini responsive\r\n\r\n### Elemento picture per mobile\r\n\r\nImplementazione avanzata di immagini responsive:\r\n\r\n```html\r\n\u003C!-- Configurazione completa di immagini responsive -->\r\n\u003Cpicture>\r\n    \u003C!-- Display mobile ad alta risoluzione (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Display mobile standard (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Fallback JPEG -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Fallback finale -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Testo alternativo descrittivo\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Strategie di caricamento progressivo\r\n\r\n### Lazy loading ottimizzato per mobile\r\n\r\nImplementa un lazy loading efficiente per mobile:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Usa intersection observer se disponibile\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Inizia il caricamento 50px prima di entrare nel viewport\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Inizializza il lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Ottimizzazione del formato specifica per mobile\r\n\r\n### Algoritmo di selezione del formato\r\n\r\nScegli il formato ottimale in base alle capacità del dispositivo mobile:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Sempre supportato\r\n            png: true   // Sempre supportato\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Per connessioni lente o risparmio dati, preferisci file più piccoli\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Per le foto, preferisci formati moderni con buona compressione\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Ottimizzazione della batteria e delle prestazioni\r\n\r\n### Elaborazione immagini efficiente per la CPU\r\n\r\nMinimizza l'uso della CPU mobile durante le operazioni sulle immagini:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Monitora lo stato della batteria se disponibile\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Adatta la concorrenza in base alle capacità del dispositivo\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Approccio conservativo per dispositivi di fascia bassa\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Riduci l'intensità di elaborazione con batteria scarica\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Ottimizzazione dei Core Web Vitals\r\n\r\n### Ottimizzazione del Largest Contentful Paint (LCP)\r\n\r\nOttimizza il LCP per i dispositivi mobili:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Identifica le immagini above the fold e priorizzale\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Aggiungi caricamento ad alta priorità\r\n            img.loading = 'eager';\r\n            \r\n            // Precarica se probabilmente è LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Prevenzione del Cumulative Layout Shift (CLS)\r\n\r\nPrevieni gli spostamenti di layout su mobile:\r\n\r\n```css\r\n/* Contenitori con rapporto d'aspetto per prevenire il CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading per prevenire il CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Test e monitoraggio\r\n\r\n### Test delle prestazioni delle immagini mobile\r\n\r\nTest completi delle prestazioni delle immagini su mobile:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Monitora le prestazioni di caricamento delle immagini\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Considera una compressione delle immagini più aggressiva');\r\n            recommendations.push('Implementa JPEG progressivo per immagini di grandi dimensioni');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Inizializza il tester delle prestazioni\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Conclusione\r\n\r\nL'ottimizzazione delle immagini per dispositivi mobili è una sfida sfaccettata che richiede la comprensione delle condizioni di rete, delle capacità dei dispositivi, del comportamento degli utenti e delle metriche di prestazione. Il successo dipende d'implementazione di strategie adattive che rispondano ai vincoli reali del mobile offrendo la migliore esperienza visiva possibile.\r\n\r\nPunti chiave per l'ottimizzazione delle immagini mobile:\r\n\r\n1. **Consapevolezza della rete**: Adatta la qualità delle immagini e le strategie di caricamento in base alla velocità di connessione e ai limiti di dati\r\n2. **Adattamento al dispositivo**: Considera la densità dello schermo, la potenza di elaborazione e la batteria nelle decisioni di ottimizzazione\r\n3. **Approccio orientato alle prestazioni**: Dai priorità ai Core Web Vitals e alle metriche di esperienza utente\r\n4. **Miglioramento progressivo**: Sovrapponi le ottimizzazioni dalla funzionalità di base alle funzionalità avanzate\r\n5. **Monitoraggio continuo**: Test e monitoraggio regolari garantiscono un'ottimizzazione continua\r\n\r\nCon l'evoluzione della tecnologia mobile, incluse le reti 5G, la maggiore potenza di elaborazione e i nuovi formati di immagine, è essenziale rimanere aggiornati sulle tecniche di ottimizzazione mantenendo la compatibilità all'indietro per offrire esperienze mobile eccezionali.\r\n\r\nIl futuro dell'ottimizzazione delle immagini mobile risiede in sistemi intelligenti e adattivi che si adattano automaticamente all'ambiente utente, alle capacità del dispositivo e alle condizioni di rete, mantenendo la migliore qualità visiva possibile entro tali vincoli.\r\n","# Otimização de Imagens para Mobile: Guia Completo de Performance\r\n\r\nDispositivos móveis já representam mais de 60% do tráfego web global, tornando a otimização de imagens para mobile fundamental para a experiência do usuário, performance e sucesso do negócio. Usuários móveis enfrentam desafios únicos como banda limitada, diversidade de tamanhos de tela e consumo de bateria. Este guia abrangente cobre estratégias, técnicas e ferramentas avançadas para otimização de imagens em dispositivos móveis.\r\n\r\n## Por que a Otimização de Imagens para Mobile é Importante\r\n\r\n### Impacto na Performance Mobile\r\n\r\nA otimização mobile afeta diretamente métricas essenciais:\r\n- **Velocidade de carregamento da página**: imagens frequentemente representam 50–70% do peso da página\r\n- **Engajamento do usuário**: 53% dos usuários móveis abandonam sites que demoram mais de 3 segundos para carregar\r\n- **Consumo de bateria**: carregamento ineficiente de imagens consome mais bateria\r\n- **Uso de dados**: importante para usuários com planos de dados limitados\r\n- **Ranking SEO**: o mobile-first index do Google prioriza performance mobile\r\n\r\n### Desafios Específicos do Mobile\r\n\r\nO ambiente mobile traz desafios únicos de otimização:\r\n- **Condições de rede variáveis**: de 2G lento a 5G rápido\r\n- **Poder de processamento limitado**: CPUs móveis são menos potentes que desktops\r\n- **Limitações de memória**: dispositivos móveis têm RAM limitada\r\n- **Diversidade de telas**: centenas de tamanhos e densidades de tela\r\n- **Interface touch**: padrões de interação diferentes do desktop\r\n\r\n## Entendendo as Características de Exibição Mobile\r\n\r\n### Densidade de Tela e DPR\r\n\r\nA Device Pixel Ratio (DPR) afeta os requisitos de imagem:\r\n\r\n```javascript\r\n// Detectar device pixel ratio\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Calcular tamanho ideal da imagem\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Exemplo de uso\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Tamanho ideal: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Configurações Comuns de Telas Mobile\r\n\r\n**Resoluções populares de dispositivos móveis:**\r\n- iPhone 14/15: 390x844 pontos (1179x2556 px, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 pontos (1284x2778 px, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 pontos (1344x2992 px, 3.25x DPR)\r\n- Google Pixel 8: 384x854 pontos (1080x2400 px, 2.8125x DPR)\r\n\r\n## Otimização de Imagens Sensível à Rede\r\n\r\n### Entrega Baseada na Conexão\r\n\r\nAjuste a qualidade da imagem conforme a velocidade da conexão:\r\n\r\n```javascript\r\n// Loader de imagem sensível à rede\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Padrão\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Classificar qualidade da rede\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Exemplo de uso\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Implementação de Imagens Responsivas\r\n\r\n### Elemento picture para Mobile\r\n\r\nImplementação avançada de imagens responsivas:\r\n\r\n```html\r\n\u003C!-- Configuração completa de imagem responsiva -->\r\n\u003Cpicture>\r\n    \u003C!-- Telas móveis de alta resolução (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Telas móveis padrão (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Fallback JPEG -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Fallback final -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Texto alternativo descritivo\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Estratégias de Carregamento Progressivo\r\n\r\n### Lazy Loading Otimizado para Mobile\r\n\r\nImplemente lazy loading eficiente para mobile:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Usar Intersection Observer se disponível\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Começa a carregar 50px antes de entrar na viewport\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Inicializar lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Otimização de Formato Específica para Mobile\r\n\r\n### Algoritmo de Seleção de Formato\r\n\r\nEscolha o formato ideal conforme as capacidades do mobile:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Sempre suportado\r\n            png: true   // Sempre suportado\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Para conexões lentas ou economia de dados, priorize arquivos menores\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Para fotos, priorize formatos modernos com boa compressão\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Otimização de Bateria e Performance\r\n\r\n### Processamento de Imagem Eficiente em CPU\r\n\r\nMinimize o uso de CPU em operações de imagem no mobile:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Monitorar status da bateria se possível\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Ajustar concorrência conforme capacidade do dispositivo\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Para dispositivos de baixa performance, seja conservador\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Reduzir intensidade se bateria estiver baixa\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Otimização de Core Web Vitals\r\n\r\n### Otimização do Largest Contentful Paint (LCP)\r\n\r\nOtimize o LCP para mobile:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Identificar imagens acima da dobra e priorizar\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Carregar com alta prioridade\r\n            img.loading = 'eager';\r\n            \r\n            // Preload se for provável LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Prevenção de Cumulative Layout Shift (CLS)\r\n\r\nEvite deslocamento de layout em mobile:\r\n\r\n```css\r\n/* Containers de proporção para evitar CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading para evitar CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Testes e Monitoramento\r\n\r\n### Teste de Performance de Imagens Mobile\r\n\r\nTeste abrangente de performance de imagens mobile:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Monitorar performance de carregamento de imagens\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Considere compressão de imagem mais agressiva');\r\n            recommendations.push('Implemente JPEG progressivo para imagens grandes');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Inicializar testador de performance\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Conclusão\r\n\r\nA otimização de imagens para mobile é um desafio multifacetado que exige compreensão das condições de rede, capacidades do dispositivo, comportamento do usuário e métricas de performance. O sucesso depende da implementação de estratégias adaptativas que respondam às limitações reais do mobile, proporcionando a melhor experiência visual possível.\r\n\r\nResumo dos pontos-chave:\r\n\r\n1. **Consciência de rede**: ajuste qualidade e estratégia de carregamento conforme velocidade e restrições de dados\r\n2. **Adaptação ao dispositivo**: considere densidade de tela, poder de processamento e bateria\r\n3. **Foco em performance**: priorize Core Web Vitals e métricas de experiência do usuário\r\n4. **Aprimoramento progressivo**: otimize em camadas, do básico ao avançado\r\n5. **Monitoramento contínuo**: teste e monitore regularmente para manter a otimização\r\n\r\nCom a evolução do 5G, maior poder de processamento e novos formatos de imagem, é essencial manter-se atualizado com as técnicas de otimização e garantir compatibilidade retroativa para uma experiência mobile excelente.\r\n\r\nO futuro da otimização de imagens mobile está em sistemas inteligentes e adaptativos que se ajustam automaticamente ao ambiente do usuário, capacidades do dispositivo e condições de rede, mantendo a melhor qualidade visual possível dentro dessas limitações.\r\n","# Оптимизация изображений для мобильных устройств: Полное руководство по производительности\r\n\r\nМобильные устройства сейчас обеспечивают более 60% мирового веб-трафика, поэтому оптимизация изображений для мобильных критически важна для пользовательского опыта, производительности и успеха бизнеса. Мобильные пользователи сталкиваются с уникальными проблемами: ограниченная пропускная способность, разнообразие размеров экранов, расход батареи. Это подробное руководство охватывает продвинутые стратегии, техники и инструменты для оптимизации изображений на мобильных устройствах.\r\n\r\n## Почему оптимизация изображений для мобильных важна\r\n\r\n### Влияние на производительность мобильных устройств\r\n\r\nМобильная оптимизация напрямую влияет на ключевые метрики:\r\n- **Скорость загрузки страницы**: изображения часто составляют 50–70% веса страницы\r\n- **Вовлеченность пользователей**: 53% мобильных пользователей покидают сайты, которые загружаются дольше 3 секунд\r\n- **Расход батареи**: неэффективная загрузка изображений быстрее разряжает батарею\r\n- **Потребление трафика**: важно для пользователей с ограниченными тарифами\r\n- **SEO-ранжирование**: мобильный индекс Google (mobile-first) приоритизирует производительность на мобильных\r\n\r\n### Особые проблемы мобильной среды\r\n\r\nМобильная среда предъявляет уникальные требования к оптимизации:\r\n- **Переменные сетевые условия**: от медленного 2G до быстрого 5G\r\n- **Ограниченная вычислительная мощность**: мобильные процессоры слабее десктопных\r\n- **Ограничения по памяти**: у мобильных устройств меньше RAM\r\n- **Разнообразие экранов**: сотни размеров и плотностей\r\n- **Сенсорный интерфейс**: другие паттерны взаимодействия, чем на десктопе\r\n\r\n## Особенности отображения на мобильных\r\n\r\n### Плотность экрана и DPR\r\n\r\nDevice Pixel Ratio (DPR) влияет на требования к изображениям:\r\n\r\n```javascript\r\n// Определить device pixel ratio\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Рассчитать оптимальный размер изображения\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Пример использования\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Оптимальный размер: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Типовые конфигурации мобильных экранов\r\n\r\n**Популярные разрешения мобильных устройств:**\r\n- iPhone 14/15: 390x844 pt (1179x2556 px, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 pt (1284x2778 px, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 pt (1344x2992 px, 3.25x DPR)\r\n- Google Pixel 8: 384x854 pt (1080x2400 px, 2.8125x DPR)\r\n\r\n## Сетевая оптимизация изображений\r\n\r\n### Доставка в зависимости от соединения\r\n\r\nАдаптируйте качество изображений под скорость соединения:\r\n\r\n```javascript\r\n// Загрузчик изображений с учетом сети\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // По умолчанию\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Классификация качества сети\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Пример использования\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Реализация адаптивных изображений\r\n\r\n### Элемент picture для мобильных\r\n\r\nПродвинутая реализация адаптивных изображений:\r\n\r\n```html\r\n\u003C!-- Полная настройка адаптивного изображения -->\r\n\u003Cpicture>\r\n    \u003C!-- Экраны с высокой плотностью (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Стандартные мобильные экраны (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG-фолбэк -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Финальный фолбэк -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Описательный alt-текст\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Прогрессивные стратегии загрузки\r\n\r\n### Lazy loading, оптимизированный для мобильных\r\n\r\nРеализуйте эффективную отложенную загрузку для мобильных:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Использовать Intersection Observer, если доступно\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Начать загрузку за 50px до появления во viewport\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Инициализация lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Оптимизация формата для мобильных\r\n\r\n### Алгоритм выбора формата\r\n\r\nВыберите оптимальный формат в зависимости от возможностей устройства:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Всегда поддерживается\r\n            png: true   // Всегда поддерживается\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Для медленных соединений или экономии трафика — меньшие файлы\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Для фото — современные форматы с хорошим сжатием\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Оптимизация батареи и производительности\r\n\r\n### Эффективная обработка изображений на CPU\r\n\r\nМинимизируйте использование CPU при работе с изображениями на мобильных:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Следить за состоянием батареи, если возможно\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Настроить параллелизм под возможности устройства\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Для слабых устройств — консервативно\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // При низком заряде батареи — снизить интенсивность\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Оптимизация Core Web Vitals\r\n\r\n### Оптимизация Largest Contentful Paint (LCP)\r\n\r\nОптимизируйте LCP для мобильных:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Определить изображения в зоне первого экрана и приоритезировать их\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Загрузка с высоким приоритетом\r\n            img.loading = 'eager';\r\n            \r\n            // Preload, если вероятно LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Предотвращение Cumulative Layout Shift (CLS)\r\n\r\nИзбегайте сдвигов макета на мобильных:\r\n\r\n```css\r\n/* Контейнеры с соотношением сторон для предотвращения CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading для предотвращения CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Тестирование и мониторинг\r\n\r\n### Тестирование производительности изображений на мобильных\r\n\r\nКомплексное тестирование производительности изображений на мобильных:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Мониторинг производительности загрузки изображений\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Рассмотрите более агрессивное сжатие изображений');\r\n            recommendations.push('Используйте прогрессивный JPEG для больших изображений');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Инициализация тестера производительности\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Заключение\r\n\r\nОптимизация изображений для мобильных — это многогранная задача, требующая понимания сетевых условий, возможностей устройства, поведения пользователей и метрик производительности. Успех зависит от внедрения адаптивных стратегий, которые учитывают реальные ограничения мобильной среды и обеспечивают наилучший визуальный опыт.\r\n\r\nКлючевые моменты оптимизации изображений для мобильных:\r\n\r\n1. **Учет сети**: адаптируйте качество и стратегию загрузки под скорость и ограничения трафика\r\n2. **Адаптация к устройству**: учитывайте плотность экрана, вычислительную мощность и батарею\r\n3. **Фокус на производительности**: приоритезируйте Core Web Vitals и пользовательские метрики\r\n4. **Постепенное улучшение**: оптимизируйте по слоям — от базового к продвинутому\r\n5. **Постоянный мониторинг**: регулярно тестируйте и отслеживайте производительность\r\n\r\nС развитием 5G, увеличением вычислительной мощности и появлением новых форматов изображений важно быть в курсе современных техник оптимизации и обеспечивать обратную совместимость для отличного мобильного опыта.\r\n\r\nБудущее оптимизации изображений для мобильных — за интеллектуальными адаптивными системами, которые автоматически подстраиваются под окружение пользователя, возможности устройства и сетевые условия, обеспечивая наилучшее качество изображения в этих рамках.\r\n","# Mobiele Afbeeldingsoptimalisatie: Complete Prestatiegids\r\n\r\nMobiele apparaten zijn nu goed voor meer dan 60% van het wereldwijde webverkeer, waardoor het optimaliseren van afbeeldingen voor mobiel cruciaal is voor gebruikerservaring, prestaties en zakelijk succes. Mobiele gebruikers worden geconfronteerd met unieke uitdagingen zoals beperkte bandbreedte, uiteenlopende schermformaten en batterijverbruik. Deze uitgebreide gids behandelt geavanceerde strategieën, technieken en tools die speciaal zijn ontworpen voor het optimaliseren van afbeeldingen op mobiele apparaten.\r\n\r\n## Waarom Mobiele Afbeeldingsoptimalisatie Essentieel is\r\n\r\n### Impact op Mobiele Prestaties\r\n\r\nMobiele optimalisatie beïnvloedt direct belangrijke statistieken:\r\n- **Pagina-laadsnelheid**: Afbeeldingen zijn doorgaans goed voor 50-70% van het paginagewicht\r\n- **Gebruikersbetrokkenheid**: 53% van de mobiele gebruikers verlaat sites die langer dan 3 seconden laden\r\n- **Batterijverbruik**: Inefficiënt laden van afbeeldingen verbruikt sneller batterij\r\n- **Dataverbruik**: Belangrijk voor gebruikers met beperkte databundels\r\n- **SEO-rankings**: Google's mobile-first indexering geeft prioriteit aan mobiele prestaties\r\n\r\n### Mobiel-specifieke Uitdagingen\r\n\r\nDe mobiele omgeving brengt unieke optimalisatie-uitdagingen met zich mee:\r\n- **Variabele Netwerkcondities**: Van trage 2G tot snelle 5G verbindingen\r\n- **Beperkte Verwerkingskracht**: Mobiele CPU's zijn minder krachtig dan desktop CPU's\r\n- **Geheugenbeperkingen**: Mobiele apparaten hebben beperkte RAM\r\n- **Schermdiversiteit**: Honderden verschillende schermformaten en -dichtheden\r\n- **Touch-interface**: Andere interactiepatronen dan desktop\r\n\r\n## Inzicht in Mobiele Weergavekenmerken\r\n\r\n### Schermdichtheid en DPR\r\n\r\nDevice Pixel Ratio (DPR) beïnvloedt de afbeeldingsvereisten:\r\n\r\n```javascript\r\n// Detecteer device pixel ratio\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Bereken optimale afbeeldingsgrootte\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Voorbeeldgebruik\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Optimale grootte: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Veelvoorkomende Mobiele Schermconfiguraties\r\n\r\n**Populaire Mobiele Resoluties:**\r\n- iPhone 14/15: 390x844 punten (1179x2556 pixels, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 punten (1284x2778 pixels, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 punten (1344x2992 pixels, 3.25x DPR)\r\n- Google Pixel 8: 384x854 punten (1080x2400 pixels, 2.8125x DPR)\r\n\r\n## Netwerkbewuste Afbeeldingsoptimalisatie\r\n\r\n### Levering op Basis van Verbinding\r\n\r\nPas de afbeeldingskwaliteit aan op basis van de verbindingssnelheid:\r\n\r\n```javascript\r\n// Netwerkbewuste afbeeldingslader\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Standaard aanname\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Categoriseer netwerkkwaliteit\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Gebruik\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Implementatie van Responsieve Afbeeldingen\r\n\r\n### Picture-element voor Mobiel\r\n\r\nGeavanceerde implementatie van responsieve afbeeldingen:\r\n\r\n```html\r\n\u003C!-- Volledige responsieve afbeelding setup -->\r\n\u003Cpicture>\r\n    \u003C!-- Hoge resolutie mobiele schermen (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Standaard mobiele schermen (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG fallback -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Laatste fallback -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Beschrijvende alt-tekst\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Progressieve Laadstrategieën\r\n\r\n### Mobiel-geoptimaliseerde Lazy Loading\r\n\r\nImplementeer efficiënte lazy loading voor mobiel:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Gebruik intersection observer indien beschikbaar\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Begin met laden 50px voor het in beeld komt\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Initialiseer lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Mobiel-specifieke Formaatoptimalisatie\r\n\r\n### Formaatselectie-algoritme\r\n\r\nKies het optimale formaat op basis van mobiele mogelijkheden:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Altijd ondersteund\r\n            png: true   // Altijd ondersteund\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Geef bij trage verbindingen of databesparing de voorkeur aan kleinere bestanden\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Voor foto's, geef de voorkeur aan moderne formaten met goede compressie\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Batterij- en Prestatieoptimalisatie\r\n\r\n### CPU-efficiënte Afbeeldingsverwerking\r\n\r\nMinimaliseer het CPU-gebruik van mobiel bij afbeeldingsbewerkingen:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Bewaak batterijstatus indien beschikbaar\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Pas gelijktijdigheid aan op basis van apparaatmogelijkheden\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Voorzichtig voor minder krachtige apparaten\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Verminder intensiteit bij lage batterij\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Core Web Vitals Optimalisatie\r\n\r\n### Largest Contentful Paint (LCP) Optimalisatie\r\n\r\nOptimaliseer LCP voor mobiele apparaten:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Identificeer afbeeldingen boven de vouw en geef prioriteit\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Voeg hoge prioriteit toe aan laden\r\n            img.loading = 'eager';\r\n            \r\n            // Preload indien waarschijnlijk LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Cumulative Layout Shift (CLS) Voorkomen\r\n\r\nVoorkom layoutverschuivingen op mobiel:\r\n\r\n```css\r\n/* Aspect-ratio containers om CLS te voorkomen */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading om CLS te voorkomen */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Testen en Monitoring\r\n\r\n### Mobiele Afbeeldingsprestatie Testen\r\n\r\nUitgebreide test van mobiele afbeeldingsprestaties:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Monitor afbeeldingslaadprestaties\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Overweeg agressievere afbeeldingscompressie');\r\n            recommendations.push('Implementeer progressieve JPEG voor grote afbeeldingen');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Initialiseer prestatie-tester\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Conclusie\r\n\r\nMobiele afbeeldingsoptimalisatie is een veelzijdige uitdaging die inzicht vereist in netwerkcondities, apparaatmogelijkheden, gebruikersgedrag en prestatie-indicatoren. Succes hangt af van het implementeren van adaptieve strategieën die inspelen op echte mobiele beperkingen en toch de best mogelijke visuele ervaring bieden.\r\n\r\nBelangrijke punten voor mobiele afbeeldingsoptimalisatie:\r\n\r\n1. **Netwerkbewustzijn**: Pas afbeeldingskwaliteit en laadstrategieën aan op verbindingssnelheid en datalimieten\r\n2. **Apparaataanpassing**: Houd rekening met schermdichtheid, verwerkingskracht en batterijduur bij optimalisatiebeslissingen\r\n3. **Prestatiegerichte aanpak**: Geef prioriteit aan Core Web Vitals en gebruikerservaringsstatistieken\r\n4. **Progressieve verbetering**: Stapel optimalisaties van basisfunctionaliteit tot geavanceerde functies\r\n5. **Continue monitoring**: Regelmatig testen en monitoren van prestaties zorgt voor voortdurende optimalisatie\r\n\r\nNaarmate mobiele technologie zich ontwikkelt, inclusief 5G-netwerken, verbeterde verwerkingskracht en nieuwe afbeeldingsformaten, is het essentieel om up-to-date te blijven met optimalisatietechnieken en tegelijkertijd achterwaartse compatibiliteit te behouden voor een uitstekende mobiele ervaring.\r\n\r\nDe toekomst van mobiele afbeeldingsoptimalisatie ligt in intelligente, adaptieve systemen die zich automatisch aanpassen aan de gebruikersomgeving, apparaatmogelijkheden en netwerkcondities, terwijl ze binnen die beperkingen de hoogst mogelijke visuele kwaliteit behouden.\r\n","# Optymalizacja obrazów mobilnych: Kompletny przewodnik po wydajności\r\n\r\nUrządzenia mobilne stanowią obecnie ponad 60% globalnego ruchu w sieci, co sprawia, że optymalizacja obrazów na urządzeniach mobilnych jest kluczowa dla doświadczenia użytkownika, wydajności i sukcesu biznesowego. Użytkownicy mobilni napotykają unikalne wyzwania, takie jak ograniczona przepustowość, różnorodne rozmiary ekranów i zużycie baterii. Ten kompleksowy przewodnik obejmuje zaawansowane strategie, techniki i narzędzia zaprojektowane specjalnie do optymalizacji obrazów na urządzeniach mobilnych.\r\n\r\n## Dlaczego optymalizacja obrazów mobilnych jest kluczowa\r\n\r\n### Wpływ na wydajność mobilną\r\n\r\nOptymalizacja mobilna bezpośrednio wpływa na kluczowe wskaźniki:\r\n- **Szybkość ładowania strony**: Obrazy stanowią zazwyczaj 50–70% wagi strony\r\n- **Zaangażowanie użytkownika**: 53% użytkowników mobilnych opuszcza strony, które ładują się dłużej niż 3 sekundy\r\n- **Zużycie baterii**: Nieefektywne ładowanie obrazów szybciej rozładowuje baterię\r\n- **Zużycie danych**: Ważne dla użytkowników z ograniczonymi pakietami danych\r\n- **Pozycjonowanie SEO**: Indeksowanie mobile-first Google priorytetowo traktuje wydajność mobilną\r\n\r\n### Wyzwania specyficzne dla urządzeń mobilnych\r\n\r\nŚrodowisko mobilne stawia unikalne wyzwania optymalizacyjne:\r\n- **Zmienność warunków sieciowych**: Od wolnego 2G do szybkiego 5G\r\n- **Ograniczona moc obliczeniowa**: Procesory mobilne są mniej wydajne niż desktopowe\r\n- **Ograniczenia pamięci**: Urządzenia mobilne mają ograniczoną ilość RAM\r\n- **Różnorodność ekranów**: Setki różnych rozmiarów i gęstości ekranów\r\n- **Interfejs dotykowy**: Inne wzorce interakcji niż na desktopie\r\n\r\n## Zrozumienie cech wyświetlania mobilnego\r\n\r\n### Gęstość ekranu i DPR\r\n\r\nWspółczynnik pikseli urządzenia (DPR) wpływa na wymagania dotyczące obrazów:\r\n\r\n```javascript\r\n// Wykrywanie współczynnika pikseli urządzenia\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Obliczanie optymalnego rozmiaru obrazu\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Przykład użycia\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Optymalny rozmiar: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Typowe konfiguracje ekranów mobilnych\r\n\r\n**Popularne rozdzielczości mobilne:**\r\n- iPhone 14/15: 390x844 punktów (1179x2556 pikseli, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 punktów (1284x2778 pikseli, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 punktów (1344x2992 pikseli, 3.25x DPR)\r\n- Google Pixel 8: 384x854 punktów (1080x2400 pikseli, 2.8125x DPR)\r\n\r\n## Optymalizacja obrazów z uwzględnieniem sieci\r\n\r\n### Dostarczanie w zależności od połączenia\r\n\r\nDostosuj jakość obrazu do prędkości połączenia:\r\n\r\n```javascript\r\n// Ładowanie obrazów z uwzględnieniem sieci\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Domyślne założenie\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Kategoryzacja jakości sieci\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Użycie\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Implementacja obrazów responsywnych\r\n\r\n### Element picture dla urządzeń mobilnych\r\n\r\nZaawansowana implementacja obrazów responsywnych:\r\n\r\n```html\r\n\u003C!-- Kompleksowa konfiguracja obrazu responsywnego -->\r\n\u003Cpicture>\r\n    \u003C!-- Wyświetlacze mobilne o wysokiej rozdzielczości (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Standardowe wyświetlacze mobilne (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Fallback JPEG -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Ostateczny fallback -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Opisowy tekst alternatywny\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Strategie progresywnego ładowania\r\n\r\n### Lazy loading zoptymalizowany pod kątem urządzeń mobilnych\r\n\r\nWdrażaj wydajny lazy loading dla urządzeń mobilnych:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Użyj intersection observer, jeśli dostępny\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Rozpocznij ładowanie 50px przed wejściem do viewportu\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Inicjalizacja lazy loadera\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Optymalizacja formatu specyficzna dla urządzeń mobilnych\r\n\r\n### Algorytm wyboru formatu\r\n\r\nWybierz optymalny format w zależności od możliwości urządzenia mobilnego:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Zawsze obsługiwany\r\n            png: true   // Zawsze obsługiwany\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Dla wolnych połączeń lub oszczędzania danych preferuj mniejsze pliki\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Dla zdjęć preferuj nowoczesne formaty z dobrą kompresją\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Optymalizacja baterii i wydajności\r\n\r\n### Efektywne przetwarzanie obrazów przez CPU\r\n\r\nMinimalizuj użycie CPU podczas operacji na obrazach na urządzeniach mobilnych:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Monitoruj stan baterii, jeśli dostępny\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Dostosuj współbieżność do możliwości urządzenia\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Ostrożne podejście dla słabszych urządzeń\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Zmniejsz intensywność przetwarzania przy niskim poziomie baterii\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Optymalizacja Core Web Vitals\r\n\r\n### Optymalizacja Largest Contentful Paint (LCP)\r\n\r\nOptymalizuj LCP dla urządzeń mobilnych:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Zidentyfikuj obrazy nad linią zgięcia i nadaj im priorytet\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Dodaj wysoki priorytet ładowania\r\n            img.loading = 'eager';\r\n            \r\n            // Preload jeśli prawdopodobnie LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Zapobieganie Cumulative Layout Shift (CLS)\r\n\r\nZapobiegaj przesunięciom układu na urządzeniach mobilnych:\r\n\r\n```css\r\n/* Kontenery proporcji, aby zapobiec CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading, aby zapobiec CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Testowanie i monitorowanie\r\n\r\n### Testowanie wydajności obrazów mobilnych\r\n\r\nKompleksowe testowanie wydajności obrazów na urządzeniach mobilnych:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Monitoruj wydajność ładowania obrazów\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Rozważ bardziej agresywną kompresję obrazów');\r\n            recommendations.push('Zaimplementuj progresywny JPEG dla dużych obrazów');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Inicjalizacja testera wydajności\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Podsumowanie\r\n\r\nOptymalizacja obrazów mobilnych to wieloaspektowe wyzwanie wymagające zrozumienia warunków sieciowych, możliwości urządzenia, zachowań użytkowników i wskaźników wydajności. Sukces zależy od wdrożenia adaptacyjnych strategii, które odpowiadają rzeczywistym ograniczeniom mobilnym, zapewniając jednocześnie najlepsze możliwe wrażenia wizualne.\r\n\r\nKluczowe wnioski dotyczące optymalizacji obrazów mobilnych:\r\n\r\n1. **Świadomość sieci**: Dostosuj jakość obrazów i strategie ładowania do prędkości połączenia i ograniczeń danych\r\n2. **Dostosowanie do urządzenia**: Uwzględnij gęstość ekranu, moc obliczeniową i żywotność baterii przy decyzjach optymalizacyjnych\r\n3. **Podejście zorientowane na wydajność**: Priorytetowo traktuj Core Web Vitals i wskaźniki doświadczenia użytkownika\r\n4. **Progresywne ulepszanie**: Warstwuj optymalizacje od podstawowej funkcjonalności po zaawansowane funkcje\r\n5. **Ciągłe monitorowanie**: Regularne testowanie i monitorowanie wydajności zapewnia ciągłą optymalizację\r\n\r\nWraz z rozwojem technologii mobilnych, w tym sieci 5G, większej mocy obliczeniowej i nowych formatów obrazów, kluczowe jest pozostawanie na bieżąco z technikami optymalizacji, przy jednoczesnym zachowaniu kompatybilności wstecznej, aby zapewnić doskonałe doświadczenia mobilne.\r\n\r\nPrzyszłość optymalizacji obrazów mobilnych leży w inteligentnych, adaptacyjnych systemach, które automatycznie dostosowują się do środowiska użytkownika, możliwości urządzenia i warunków sieciowych, zachowując jednocześnie najwyższą możliwą jakość wizualną w tych ograniczeniach.\r\n","# Optimalizace obrázků pro mobilní zařízení: Kompletní průvodce výkonem\r\n\r\nMobilní zařízení nyní tvoří více než 60 % celosvětového webového provozu, což činí optimalizaci obrázků pro mobily klíčovou pro uživatelský zážitek, výkon i obchodní úspěch. Uživatelé mobilních zařízení čelí jedinečným výzvám, včetně omezené šířky pásma, různých velikostí obrazovek a spotřeby baterie. Tento komplexní průvodce pokrývá pokročilé strategie, techniky a nástroje speciálně navržené pro optimalizaci obrázků na mobilních zařízeních.\r\n\r\n## Proč je optimalizace obrázků pro mobily kritická\r\n\r\n### Dopad na výkon mobilních zařízení\r\n\r\nOptimalizace pro mobily přímo ovlivňuje klíčové metriky:\r\n- **Rychlost načítání stránky**: Obrázky obvykle tvoří 50–70 % hmotnosti stránky\r\n- **Zapojení uživatelů**: 53 % mobilních uživatelů opustí stránky, které se načítají déle než 3 sekundy\r\n- **Spotřeba baterie**: Neefektivní načítání obrázků rychleji vybíjí baterii\r\n- **Využití dat**: Důležité pro uživatele s omezenými datovými tarify\r\n- **SEO hodnocení**: Mobilní indexace Google upřednostňuje výkon na mobilech\r\n\r\n### Specifické výzvy mobilního prostředí\r\n\r\nMobilní prostředí přináší jedinečné výzvy:\r\n- **Proměnlivé síťové podmínky**: Od pomalého 2G po rychlé 5G připojení\r\n- **Omezený výpočetní výkon**: Mobilní CPU jsou méně výkonné než desktopové\r\n- **Paměťová omezení**: Mobilní zařízení mají omezenou RAM\r\n- **Různorodost obrazovek**: Stovky různých velikostí a hustot obrazovek\r\n- **Dotykové rozhraní**: Odlišné vzory interakce než na desktopu\r\n\r\n## Porozumění vlastnostem mobilního zobrazení\r\n\r\n### Hustota obrazovky a DPR\r\n\r\nPoměr pixelů zařízení (DPR) ovlivňuje požadavky na obrázky:\r\n\r\n```javascript\r\n// Zjištění poměru pixelů zařízení\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Výpočet optimální velikosti obrázku\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Příklad použití\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Optimální velikost: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Běžné konfigurace mobilních obrazovek\r\n\r\n**Oblíbená mobilní rozlišení:**\r\n- iPhone 14/15: 390x844 bodů (1179x2556 pixelů, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 bodů (1284x2778 pixelů, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 bodů (1344x2992 pixelů, 3.25x DPR)\r\n- Google Pixel 8: 384x854 bodů (1080x2400 pixelů, 2.8125x DPR)\r\n\r\n## Optimalizace obrázků podle sítě\r\n\r\n### Dodávání podle typu připojení\r\n\r\nUpravte kvalitu obrázku podle rychlosti připojení:\r\n\r\n```javascript\r\n// Načítání obrázků podle sítě\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Výchozí předpoklad\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Kategorizace kvality sítě\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Použití\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Implementace responzivních obrázků\r\n\r\n### Prvek picture pro mobily\r\n\r\nPokročilá implementace responzivních obrázků:\r\n\r\n```html\r\n\u003C!-- Komplexní nastavení responzivního obrázku -->\r\n\u003Cpicture>\r\n    \u003C!-- Displeje s vysokým rozlišením (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Standardní mobilní displeje (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Záložní JPEG -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Konečná záloha -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Popisný alternativní text\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Strategie progresivního načítání\r\n\r\n### Lazy loading optimalizované pro mobily\r\n\r\nEfektivní implementace lazy loadingu pro mobily:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Použijte Intersection Observer pokud je dostupný\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Načítat 50px před vstupem do viewportu\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Inicializace lazy loaderu\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Optimalizace formátu specifická pro mobily\r\n\r\n### Algoritmus výběru formátu\r\n\r\nVyberte optimální formát podle možností mobilního zařízení:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Vždy podporováno\r\n            png: true   // Vždy podporováno\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Pro pomalé připojení nebo omezená data preferujte menší soubory\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Pro fotografie preferujte moderní formáty s dobrou kompresí\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Optimalizace baterie a výkonu\r\n\r\n### Efektivní zpracování obrázků na CPU\r\n\r\nMinimalizujte využití CPU při práci s obrázky na mobilu:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Sledování stavu baterie pokud je dostupné\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Přizpůsobení podle možností zařízení\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Konzervativní přístup pro slabší zařízení\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Snižte intenzitu zpracování při nízké baterii\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Optimalizace Core Web Vitals\r\n\r\n### Optimalizace Largest Contentful Paint (LCP)\r\n\r\nOptimalizujte LCP pro mobilní zařízení:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Identifikujte obrázky nad záhybem a upřednostněte je\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Přidejte vysokou prioritu načítání\r\n            img.loading = 'eager';\r\n            \r\n            // Přednačtěte pokud je pravděpodobné, že půjde o LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Prevence Cumulative Layout Shift (CLS)\r\n\r\nZabraňte posunům rozvržení na mobilu:\r\n\r\n```css\r\n/* Poměrové kontejnery pro prevenci CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading pro prevenci CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Testování a monitoring\r\n\r\n### Testování výkonu obrázků na mobilu\r\n\r\nKomplexní testování výkonu obrázků na mobilních zařízeních:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Sledujte výkon načítání obrázků\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Zvažte agresivnější kompresi obrázků');\r\n            recommendations.push('Implementujte progresivní JPEG pro velké obrázky');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Inicializace testeru výkonu\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Závěr\r\n\r\nOptimalizace obrázků pro mobilní zařízení je mnohovrstevný úkol, který vyžaduje pochopení síťových podmínek, možností zařízení, chování uživatelů a výkonnostních metrik. Úspěch závisí na implementaci adaptivních strategií, které reagují na reálná omezení mobilních zařízení a zároveň poskytují co nejlepší vizuální zážitek.\r\n\r\nKlíčové body pro optimalizaci obrázků na mobilech:\r\n\r\n1. **Vědomí sítě**: Přizpůsobte kvalitu obrázků a strategie načítání podle rychlosti připojení a datových omezení\r\n2. **Přizpůsobení zařízení**: Zohledněte hustotu obrazovky, výpočetní výkon a výdrž baterie\r\n3. **Přístup zaměřený na výkon**: Upřednostněte Core Web Vitals a metriky uživatelského zážitku\r\n4. **Progresivní vylepšování**: Optimalizace vrstvěte od základní funkčnosti po pokročilé funkce\r\n5. **Nepřetržité sledování**: Pravidelné testování a monitoring výkonu zajistí trvalou optimalizaci\r\n\r\nJak se mobilní technologie dále vyvíjí, včetně sítí 5G, vyššího výpočetního výkonu a nových obrazových formátů, je nezbytné držet krok s optimalizačními technikami a zároveň zachovat zpětnou kompatibilitu pro poskytování špičkových mobilních zážitků.\r\n\r\nBudoucnost optimalizace obrázků pro mobily spočívá v inteligentních, adaptivních systémech, které se automaticky přizpůsobují uživatelskému prostředí, možnostem zařízení a síťovým podmínkám a zároveň udržují co nejvyšší vizuální kvalitu v daných omezeních.\r\n","# Mobilkép-optimalizálás: Teljesítmény útmutató\r\n\r\nA mobil eszközök ma már a globális webforgalom több mint 60%-át teszik ki, így a mobilkép-optimalizálás kulcsfontosságú a felhasználói élmény, a teljesítmény és az üzleti siker szempontjából. A mobilfelhasználók egyedi kihívásokkal néznek szembe, beleértve a korlátozott sávszélességet, a változó képernyőméreteket és az akkumulátor-fogyasztást. Ez az átfogó útmutató fejlett stratégiákat, technikákat és eszközöket mutat be, amelyeket kifejezetten a mobil eszközök képeinek optimalizálására terveztek.\r\n\r\n## Miért kritikus a mobilkép-optimalizálás?\r\n\r\n### A mobil teljesítményre gyakorolt hatás\r\n\r\nA mobiloptimalizálás közvetlenül befolyásolja a kulcsfontosságú mutatókat:\r\n- **Oldalbetöltési sebesség**: A képek általában az oldal tömegének 50–70%-át teszik ki\r\n- **Felhasználói elköteleződés**: A mobilfelhasználók 53%-a elhagyja azokat az oldalakat, amelyek betöltése több mint 3 másodpercig tart\r\n- **Akkumulátor-fogyasztás**: A nem hatékony képtöltés gyorsabban meríti az akkumulátort\r\n- **Adathasználat**: Fontos a korlátozott adatcsomaggal rendelkező felhasználók számára\r\n- **SEO rangsor**: A Google mobile-first indexelése előnyben részesíti a mobil teljesítményt\r\n\r\n### Mobil-specifikus kihívások\r\n\r\nA mobil környezet egyedi optimalizálási kihívásokat jelent:\r\n- **Változó hálózati feltételek**: Lassú 2G-től a gyors 5G-ig\r\n- **Korlátozott feldolgozási teljesítmény**: A mobil CPU-k kevésbé erősek, mint az asztaliak\r\n- **Memóriakorlátok**: A mobil eszközökben korlátozott RAM áll rendelkezésre\r\n- **Képernyődiverzitás**: Több száz különböző képernyőméret és -sűrűség\r\n- **Érintőképernyős felület**: Más interakciós minták, mint asztali gépen\r\n\r\n## A mobil kijelző jellemzőinek megértése\r\n\r\n### Képernyősűrűség és DPR\r\n\r\nAz eszköz pixelaránya (DPR) befolyásolja a képkövetelményeket:\r\n\r\n```javascript\r\n// Eszköz pixelarányának lekérdezése\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Optimális képméret kiszámítása\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Példa használatra\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Optimális méret: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Gyakori mobilképernyő-konfigurációk\r\n\r\n**Népszerű mobil felbontások:**\r\n- iPhone 14/15: 390x844 pont (1179x2556 pixel, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 pont (1284x2778 pixel, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 pont (1344x2992 pixel, 3.25x DPR)\r\n- Google Pixel 8: 384x854 pont (1080x2400 pixel, 2.8125x DPR)\r\n\r\n## Hálózattudatos képoptimalizálás\r\n\r\n### Kapcsolat-alapú kézbesítés\r\n\r\nA képminőség igazítása a kapcsolat sebessége alapján:\r\n\r\n```javascript\r\n// Hálózattudatos képtöltés\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Alapértelmezett\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Hálózati minőség kategorizálása\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Használat\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Reszponzív képek megvalósítása\r\n\r\n### Mobil picture elem\r\n\r\nFejlett reszponzív képmegvalósítás:\r\n\r\n```html\r\n\u003C!-- Átfogó reszponzív képbeállítás -->\r\n\u003Cpicture>\r\n    \u003C!-- Nagy felbontású mobil kijelzők (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Standard mobil kijelzők (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG tartalékok -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Végső tartalék -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Leíró alternatív szöveg\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Progresszív betöltési stratégiák\r\n\r\n### Mobilra optimalizált lusta betöltés\r\n\r\nHatékony lusta betöltés megvalósítása mobilon:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Használja az intersection observer-t, ha elérhető\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // 50px-el a nézet előtt kezdje a betöltést\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Lusta betöltő inicializálása\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Mobil-specifikus formátumoptimalizálás\r\n\r\n### Formátumválasztó algoritmus\r\n\r\nVálassza ki az optimális formátumot a mobil képességek alapján:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Mindig támogatott\r\n            png: true   // Mindig támogatott\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Lassú kapcsolat vagy adatspórolás esetén kisebb fájlokat részesítsen előnyben\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Fotókhoz modern, jó tömörítésű formátumokat részesítsen előnyben\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Akkumulátor- és teljesítményoptimalizálás\r\n\r\n### CPU-hatékony képfeldolgozás\r\n\r\nMinimalizálja a mobil CPU használatát képműveletek során:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Akkumulátor állapotának figyelése, ha elérhető\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Párhuzamosság igazítása az eszköz képességeihez\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Óvatos megközelítés gyengébb eszközökhöz\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Csökkentse a feldolgozási intenzitást alacsony töltöttségnél\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Core Web Vitals optimalizálás\r\n\r\n### Largest Contentful Paint (LCP) optimalizálás\r\n\r\nOptimalizálja az LCP-t mobil eszközökre:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Azonosítsa a hajtás feletti képeket és priorizálja azokat\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Magas prioritású betöltés\r\n            img.loading = 'eager';\r\n            \r\n            // Előtöltés, ha valószínűleg LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Cumulative Layout Shift (CLS) megelőzése\r\n\r\nElrendezés elcsúszásának megelőzése mobilon:\r\n\r\n```css\r\n/* Képarány konténerek a CLS megelőzésére */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading a CLS megelőzésére */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Tesztelés és monitorozás\r\n\r\n### Mobilkép-teljesítmény tesztelése\r\n\r\nÁtfogó mobilkép-teljesítmény tesztelés:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Képtöltési teljesítmény monitorozása\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Fontolja meg agresszívebb képkompresszió alkalmazását');\r\n            recommendations.push('Valósítson meg progresszív JPEG-et nagy képekhez');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Teljesítménytesztelő inicializálása\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Összegzés\r\n\r\nA mobilkép-optimalizálás többrétegű kihívás, amely megköveteli a hálózati feltételek, az eszköz képességei, a felhasználói viselkedés és a teljesítménymutatók megértését. A siker azon múlik, hogy adaptív stratégiákat alkalmazunk, amelyek reagálnak a mobil eszközök valós korlátaira, miközben a lehető legjobb vizuális élményt nyújtják.\r\n\r\nFőbb tanulságok a mobilkép-optimalizáláshoz:\r\n\r\n1. **Hálózattudatosság**: Igazítsa a képminőséget és a betöltési stratégiákat a kapcsolat sebességéhez és adatkorlátokhoz\r\n2. **Eszközhöz igazítás**: Vegye figyelembe a képernyő sűrűségét, a feldolgozási teljesítményt és az akkumulátor élettartamát az optimalizálási döntéseknél\r\n3. **Teljesítmény-központú megközelítés**: Helyezze előtérbe a Core Web Vitals-t és a felhasználói élmény mutatóit\r\n4. **Progresszív fejlesztés**: Rétegezze az optimalizálásokat az alapvető funkcionalitástól a fejlett funkciókig\r\n5. **Folyamatos monitorozás**: A rendszeres tesztelés és teljesítményfigyelés biztosítja a folyamatos optimalizálást\r\n\r\nAhogy a mobiltechnológia fejlődik – beleértve az 5G hálózatokat, a jobb feldolgozási teljesítményt és az új képformátumokat –, elengedhetetlen, hogy naprakészek maradjunk az optimalizálási technikákkal, miközben megőrizzük a visszafelé kompatibilitást a kiváló mobilélmény érdekében.\r\n\r\nA mobilkép-optimalizálás jövője az intelligens, adaptív rendszerekben rejlik, amelyek automatikusan alkalmazkodnak a felhasználói környezethez, az eszköz képességeihez és a hálózati feltételekhez, miközben a lehető legjobb vizuális minőséget tartják fenn ezek között a korlátok között.\r\n","# การเพิ่มประสิทธิภาพรูปภาพสำหรับมือถือ: คู่มือสมบูรณ์ด้านประสิทธิภาพ\r\n\r\nอุปกรณ์มือถือปัจจุบันคิดเป็นมากกว่า 60% ของทราฟฟิกเว็บทั่วโลก การเพิ่มประสิทธิภาพรูปภาพสำหรับมือถือจึงมีความสำคัญอย่างยิ่งต่อประสบการณ์ผู้ใช้ ประสิทธิภาพ และความสำเร็จทางธุรกิจ ผู้ใช้มือถือเผชิญกับความท้าทายเฉพาะ เช่น แบนด์วิดท์ที่จำกัด ความหลากหลายของขนาดหน้าจอ และการใช้พลังงานแบตเตอรี่ คู่มือฉบับนี้จะครอบคลุมกลยุทธ์ เทคนิค และเครื่องมือขั้นสูงสำหรับการเพิ่มประสิทธิภาพรูปภาพบนอุปกรณ์มือถือ\r\n\r\n## ทำไมการเพิ่มประสิทธิภาพรูปภาพสำหรับมือถือจึงสำคัญ\r\n\r\n### ผลกระทบต่อประสิทธิภาพบนมือถือ\r\n\r\nการเพิ่มประสิทธิภาพสำหรับมือถือส่งผลโดยตรงต่อเมตริกหลัก:\r\n- **ความเร็วในการโหลดหน้าเว็บ**: รูปภาพมักคิดเป็น 50–70% ของน้ำหนักหน้าเว็บ\r\n- **การมีส่วนร่วมของผู้ใช้**: 53% ของผู้ใช้มือถือจะออกจากเว็บไซต์ที่โหลดเกิน 3 วินาที\r\n- **การใช้พลังงานแบตเตอรี่**: การโหลดรูปภาพที่ไม่มีประสิทธิภาพจะทำให้แบตเตอรี่หมดเร็วขึ้น\r\n- **การใช้ข้อมูล**: สำคัญสำหรับผู้ใช้ที่มีแพ็กเกจข้อมูลจำกัด\r\n- **อันดับ SEO**: Google mobile-first index ให้ความสำคัญกับประสิทธิภาพบนมือถือ\r\n\r\n### ความท้าทายเฉพาะของมือถือ\r\n\r\nสภาพแวดล้อมมือถือมีความท้าทายในการเพิ่มประสิทธิภาพที่เฉพาะเจาะจง:\r\n- **สภาพเครือข่ายที่หลากหลาย**: ตั้งแต่ 2G ที่ช้าไปจนถึง 5G ที่เร็ว\r\n- **พลังประมวลผลจำกัด**: CPU มือถือมีประสิทธิภาพน้อยกว่าเดสก์ท็อป\r\n- **ข้อจำกัดของหน่วยความจำ**: อุปกรณ์มือถือมี RAM จำกัด\r\n- **ความหลากหลายของหน้าจอ**: มีขนาดและความหนาแน่นของหน้าจอหลายร้อยแบบ\r\n- **อินเทอร์เฟซแบบสัมผัส**: รูปแบบการโต้ตอบต่างจากเดสก์ท็อป\r\n\r\n## ทำความเข้าใจลักษณะการแสดงผลบนมือถือ\r\n\r\n### ความหนาแน่นของหน้าจอและ DPR\r\n\r\nDevice Pixel Ratio (DPR) มีผลต่อข้อกำหนดของรูปภาพ:\r\n\r\n```javascript\r\n// ตรวจสอบ device pixel ratio\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// คำนวณขนาดรูปภาพที่เหมาะสม\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// ตัวอย่างการใช้งาน\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`ขนาดที่เหมาะสม: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### การกำหนดค่าหน้าจอมือถือที่พบบ่อย\r\n\r\n**ความละเอียดหน้าจอยอดนิยม:**\r\n- iPhone 14/15: 390x844 พอยต์ (1179x2556 พิกเซล, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 พอยต์ (1284x2778 พิกเซล, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 พอยต์ (1344x2992 พิกเซล, 3.25x DPR)\r\n- Google Pixel 8: 384x854 พอยต์ (1080x2400 พิกเซล, 2.8125x DPR)\r\n\r\n## การเพิ่มประสิทธิภาพรูปภาพตามเครือข่าย\r\n\r\n### การส่งมอบตามการเชื่อมต่อ\r\n\r\nปรับคุณภาพรูปภาพตามความเร็วของเครือข่าย:\r\n\r\n```javascript\r\n// ตัวโหลดรูปภาพที่รับรู้เครือข่าย\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // ค่าเริ่มต้น\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // จัดประเภทคุณภาพเครือข่าย\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// ตัวอย่างการใช้งาน\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## การใช้งานรูปภาพแบบ Responsive\r\n\r\n### องค์ประกอบ picture สำหรับมือถือ\r\n\r\nการใช้งานรูปภาพแบบ responsive ขั้นสูง:\r\n\r\n```html\r\n\u003C!-- การตั้งค่ารูปภาพ responsive แบบสมบูรณ์ -->\r\n\u003Cpicture>\r\n    \u003C!-- หน้าจอมือถือความละเอียดสูง (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- หน้าจอมือถือมาตรฐาน (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Fallback JPEG -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Fallback สุดท้าย -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"ข้อความ alt ที่อธิบายได้\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## กลยุทธ์การโหลดแบบ Progressive\r\n\r\n### Lazy Loading ที่เหมาะกับมือถือ\r\n\r\nใช้งาน lazy loading ที่มีประสิทธิภาพสำหรับมือถือ:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // ใช้ Intersection Observer หากมี\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // เริ่มโหลดก่อนเข้า viewport 50px\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// เริ่มต้น lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## การเพิ่มประสิทธิภาพฟอร์แมตเฉพาะมือถือ\r\n\r\n### อัลกอริทึมการเลือกฟอร์แมต\r\n\r\nเลือกฟอร์แมตที่เหมาะสมที่สุดตามความสามารถของอุปกรณ์มือถือ:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // รองรับเสมอ\r\n            png: true   // รองรับเสมอ\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // สำหรับการเชื่อมต่อช้า/ประหยัดข้อมูล ให้เลือกไฟล์ขนาดเล็ก\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // สำหรับภาพถ่าย ให้เลือกฟอร์แมตใหม่ที่บีบอัดได้ดี\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## การเพิ่มประสิทธิภาพแบตเตอรี่และประสิทธิภาพโดยรวม\r\n\r\n### การประมวลผลรูปภาพที่ประหยัด CPU\r\n\r\nลดการใช้ CPU ในการประมวลผลรูปภาพบนมือถือ:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // ตรวจสอบสถานะแบตเตอรี่ถ้าเป็นไปได้\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // ปรับจำนวนงานพร้อมกันตามความสามารถของอุปกรณ์\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // สำหรับอุปกรณ์ประสิทธิภาพต่ำ ให้ระวัง\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // ลดความเข้มข้นเมื่อแบตเตอรี่น้อย\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## การเพิ่มประสิทธิภาพ Core Web Vitals\r\n\r\n### การเพิ่มประสิทธิภาพ Largest Contentful Paint (LCP)\r\n\r\nเพิ่มประสิทธิภาพ LCP สำหรับมือถือ:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // ระบุรูปภาพที่อยู่เหนือ fold และให้โหลดก่อน\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // โหลดด้วยความสำคัญสูง\r\n            img.loading = 'eager';\r\n            \r\n            // Preload ถ้ามีแนวโน้มเป็น LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### การป้องกัน Cumulative Layout Shift (CLS)\r\n\r\nป้องกันการเลื่อนเลย์เอาต์บนมือถือ:\r\n\r\n```css\r\n/* คอนเทนเนอร์อัตราส่วนภาพเพื่อป้องกัน CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading เพื่อป้องกัน CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## การทดสอบและการมอนิเตอร์\r\n\r\n### การทดสอบประสิทธิภาพรูปภาพบนมือถือ\r\n\r\nทดสอบประสิทธิภาพรูปภาพบนมือถืออย่างครอบคลุม:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // มอนิเตอร์ประสิทธิภาพการโหลดรูปภาพ\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('พิจารณาบีบอัดรูปภาพให้มากขึ้น');\r\n            recommendations.push('ใช้ JPEG แบบ progressive สำหรับรูปภาพขนาดใหญ่');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// เริ่มต้น performance tester\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## สรุป\r\n\r\nการเพิ่มประสิทธิภาพรูปภาพสำหรับมือถือเป็นความท้าทายหลายมิติที่ต้องเข้าใจสภาพเครือข่าย ความสามารถของอุปกรณ์ พฤติกรรมผู้ใช้ และเมตริกประสิทธิภาพ ความสำเร็จขึ้นอยู่กับการนำกลยุทธ์ที่ปรับตัวได้ซึ่งตอบสนองต่อข้อจำกัดจริงของมือถือและมอบประสบการณ์ภาพที่ดีที่สุด\r\n\r\nประเด็นสำคัญของการเพิ่มประสิทธิภาพรูปภาพสำหรับมือถือ:\r\n\r\n1. **ตระหนักถึงเครือข่าย**: ปรับคุณภาพและกลยุทธ์การโหลดตามความเร็วและข้อจำกัดของข้อมูล\r\n2. **ปรับให้เหมาะกับอุปกรณ์**: คำนึงถึงความหนาแน่นหน้าจอ ประสิทธิภาพการประมวลผล และแบตเตอรี่\r\n3. **เน้นประสิทธิภาพ**: ให้ความสำคัญกับ Core Web Vitals และเมตริกประสบการณ์ผู้ใช้\r\n4. **ปรับปรุงแบบ progressive**: เพิ่มประสิทธิภาพเป็นชั้น ๆ จากพื้นฐานถึงขั้นสูง\r\n5. **มอนิเตอร์อย่างต่อเนื่อง**: ทดสอบและมอนิเตอร์เป็นประจำเพื่อรักษาการเพิ่มประสิทธิภาพ\r\n\r\nเมื่อเทคโนโลยีมือถือพัฒนา เช่น 5G, พลังประมวลผลที่สูงขึ้น และฟอร์แมตรูปภาพใหม่ ๆ การอัปเดตเทคนิคการเพิ่มประสิทธิภาพและการรักษาความเข้ากันได้ย้อนหลังเป็นสิ่งสำคัญเพื่อประสบการณ์มือถือที่ยอดเยี่ยม\r\n\r\nอนาคตของการเพิ่มประสิทธิภาพรูปภาพสำหรับมือถืออยู่ที่ระบบอัจฉริยะที่ปรับตัวได้โดยอัตโนมัติตามสภาพแวดล้อมของผู้ใช้ ความสามารถของอุปกรณ์ และเงื่อนไขเครือข่าย โดยยังคงคุณภาพภาพที่ดีที่สุดภายใต้ข้อจำกัดเหล่านั้น\r\n","# Tối ưu hóa hình ảnh cho di động: Hướng dẫn toàn diện về hiệu suất\r\n\r\nHiện nay, thiết bị di động chiếm hơn 60% lưu lượng web toàn cầu. Tối ưu hóa hình ảnh cho di động là yếu tố then chốt để nâng cao trải nghiệm người dùng, hiệu suất và thành công kinh doanh. Người dùng di động đối mặt với các thách thức riêng như băng thông hạn chế, đa dạng kích thước màn hình và tiêu thụ pin. Hướng dẫn này trình bày các chiến lược, kỹ thuật và công cụ nâng cao để tối ưu hóa hình ảnh trên thiết bị di động.\r\n\r\n## Tại sao tối ưu hóa hình ảnh cho di động lại quan trọng\r\n\r\n### Ảnh hưởng đến hiệu suất di động\r\n\r\nTối ưu hóa cho di động ảnh hưởng trực tiếp đến các chỉ số chính:\r\n- **Tốc độ tải trang**: Hình ảnh thường chiếm 50–70% trọng lượng trang\r\n- **Tương tác người dùng**: 53% người dùng di động rời khỏi trang nếu tải quá 3 giây\r\n- **Tiêu thụ pin**: Tải hình ảnh không tối ưu làm pin cạn nhanh hơn\r\n- **Dữ liệu sử dụng**: Quan trọng với người dùng có gói dữ liệu hạn chế\r\n- **Xếp hạng SEO**: Google mobile-first index ưu tiên hiệu suất di động\r\n\r\n### Thách thức riêng của di động\r\n\r\nMôi trường di động có các thách thức tối ưu hóa đặc thù:\r\n- **Điều kiện mạng đa dạng**: Từ 2G chậm đến 5G nhanh\r\n- **Sức mạnh xử lý hạn chế**: CPU di động yếu hơn máy tính để bàn\r\n- **Giới hạn bộ nhớ**: Thiết bị di động thường có RAM thấp\r\n- **Đa dạng màn hình**: Hàng trăm kích thước và mật độ khác nhau\r\n- **Giao diện cảm ứng**: Kiểu tương tác khác máy tính để bàn\r\n\r\n## Hiểu đặc điểm hiển thị trên di động\r\n\r\n### Mật độ màn hình và DPR\r\n\r\nDevice Pixel Ratio (DPR) ảnh hưởng đến yêu cầu hình ảnh:\r\n\r\n```javascript\r\n// Kiểm tra device pixel ratio\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Tính kích thước hình ảnh tối ưu\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Ví dụ sử dụng\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Kích thước tối ưu: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Các cấu hình màn hình di động phổ biến\r\n\r\n**Độ phân giải màn hình phổ biến:**\r\n- iPhone 14/15: 390x844 điểm (1179x2556 pixel, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 điểm (1284x2778 pixel, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 điểm (1344x2992 pixel, 3.25x DPR)\r\n- Google Pixel 8: 384x854 điểm (1080x2400 pixel, 2.8125x DPR)\r\n\r\n## Tối ưu hóa hình ảnh theo mạng\r\n\r\n### Phân phối theo kết nối\r\n\r\nĐiều chỉnh chất lượng hình ảnh theo tốc độ mạng:\r\n\r\n```javascript\r\n// Trình tải hình ảnh nhận biết mạng\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Mặc định\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Phân loại chất lượng mạng\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Ví dụ sử dụng\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Sử dụng hình ảnh responsive\r\n\r\n### Thẻ picture cho di động\r\n\r\nCách sử dụng hình ảnh responsive nâng cao:\r\n\r\n```html\r\n\u003C!-- Thiết lập hình ảnh responsive đầy đủ -->\r\n\u003Cpicture>\r\n    \u003C!-- Màn hình di động độ phân giải cao (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Màn hình di động tiêu chuẩn (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG dự phòng -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Dự phòng cuối cùng -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Văn bản alt mô tả\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Chiến lược tải progressive\r\n\r\n### Lazy Loading tối ưu cho di động\r\n\r\nTriển khai lazy loading hiệu quả cho di động:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Sử dụng Intersection Observer nếu có\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Tải trước khi vào viewport 50px\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Khởi tạo lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Tối ưu hóa định dạng chuyên biệt cho di động\r\n\r\n### Thuật toán chọn định dạng\r\n\r\nChọn định dạng tối ưu nhất dựa trên khả năng thiết bị di động:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Luôn hỗ trợ\r\n            png: true   // Luôn hỗ trợ\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Kết nối chậm/tiết kiệm dữ liệu: chọn file nhỏ\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Ảnh chụp: ưu tiên định dạng mới nén tốt\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Tối ưu hóa pin và hiệu suất tổng thể\r\n\r\n### Xử lý hình ảnh tiết kiệm CPU\r\n\r\nGiảm sử dụng CPU khi xử lý hình ảnh trên di động:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Kiểm tra trạng thái pin nếu có thể\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Điều chỉnh số lượng xử lý song song theo khả năng thiết bị\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Thiết bị yếu: cẩn trọng\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Pin yếu, giảm tải\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Tối ưu hóa Core Web Vitals\r\n\r\n### Tối ưu hóa Largest Contentful Paint (LCP)\r\n\r\nTối ưu hóa LCP cho di động:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Xác định hình ảnh trên màn hình đầu và ưu tiên tải\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Ưu tiên tải\r\n            img.loading = 'eager';\r\n            \r\n            // Nếu có khả năng là LCP thì preload\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Ngăn chặn Cumulative Layout Shift (CLS)\r\n\r\nNgăn dịch chuyển bố cục trên di động:\r\n\r\n```css\r\n/* Container tỷ lệ khung hình để ngăn CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading để ngăn CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Kiểm thử và giám sát\r\n\r\n### Kiểm thử hiệu suất hình ảnh trên di động\r\n\r\nKiểm thử hiệu suất hình ảnh trên di động toàn diện:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Giám sát hiệu suất tải hình ảnh\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Cân nhắc nén hình ảnh nhiều hơn');\r\n            recommendations.push('Dùng JPEG progressive cho hình lớn');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Khởi tạo performance tester\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Kết luận\r\n\r\nTối ưu hóa hình ảnh cho di động là một thách thức đa chiều, đòi hỏi hiểu biết về điều kiện mạng, khả năng thiết bị, hành vi người dùng và các chỉ số hiệu suất. Thành công phụ thuộc vào việc áp dụng các chiến lược thích ứng, đáp ứng các giới hạn thực tế của di động và mang lại trải nghiệm hình ảnh tốt nhất.\r\n\r\nCác điểm chính của tối ưu hóa hình ảnh cho di động:\r\n\r\n1. **Nhận biết mạng**: Điều chỉnh chất lượng và chiến lược tải theo tốc độ và giới hạn dữ liệu\r\n2. **Tối ưu theo thiết bị**: Xem xét mật độ màn hình, hiệu suất xử lý và pin\r\n3. **Tập trung vào hiệu suất**: Ưu tiên Core Web Vitals và các chỉ số trải nghiệm người dùng\r\n4. **Cải tiến theo từng lớp**: Tối ưu hóa từ cơ bản đến nâng cao\r\n5. **Giám sát liên tục**: Thường xuyên kiểm thử và giám sát để duy trì tối ưu hóa\r\n\r\nKhi công nghệ di động phát triển (5G, sức mạnh xử lý cao hơn, định dạng hình ảnh mới), việc cập nhật kỹ thuật tối ưu hóa và đảm bảo tương thích ngược là rất quan trọng để có trải nghiệm di động tuyệt vời.\r\n\r\nTương lai của tối ưu hóa hình ảnh cho di động nằm ở các hệ thống thông minh tự động thích ứng với môi trường người dùng, khả năng thiết bị và điều kiện mạng, đồng thời vẫn đảm bảo chất lượng hình ảnh tốt nhất trong các giới hạn đó.\r\n","# Optimasi Gambar Mobile: Panduan Lengkap Performa\r\n\r\nPerangkat mobile kini menyumbang lebih dari 60% lalu lintas web global, menjadikan optimasi gambar mobile sangat penting untuk pengalaman pengguna, performa, dan kesuksesan bisnis. Pengguna mobile menghadapi tantangan unik seperti bandwidth terbatas, ukuran layar yang bervariasi, dan konsumsi baterai. Panduan komprehensif ini membahas strategi, teknik, dan alat canggih yang dirancang khusus untuk mengoptimalkan gambar pada perangkat mobile.\r\n\r\n## Mengapa Optimasi Gambar Mobile Sangat Penting\r\n\r\n### Dampak pada Performa Mobile\r\n\r\nOptimasi mobile secara langsung memengaruhi metrik utama:\r\n- **Kecepatan Muat Halaman**: Gambar biasanya menyumbang 50–70% dari berat halaman\r\n- **Keterlibatan Pengguna**: 53% pengguna mobile meninggalkan situs yang memuat lebih dari 3 detik\r\n- **Konsumsi Baterai**: Pemrosesan gambar yang tidak efisien menguras baterai lebih cepat\r\n- **Penggunaan Data**: Penting untuk pengguna dengan paket data terbatas\r\n- **Peringkat SEO**: Pengindeksan mobile-first Google memprioritaskan performa mobile\r\n\r\n### Tantangan Khusus Mobile\r\n\r\nLingkungan mobile menghadirkan tantangan optimasi unik:\r\n- **Kondisi Jaringan Bervariasi**: Dari 2G lambat hingga 5G cepat\r\n- **Daya Proses Terbatas**: CPU mobile kurang bertenaga dibanding desktop\r\n- **Keterbatasan Memori**: Perangkat mobile memiliki RAM terbatas\r\n- **Keberagaman Layar**: Ratusan ukuran dan kepadatan layar berbeda\r\n- **Antarmuka Sentuh**: Pola interaksi berbeda dari desktop\r\n\r\n## Memahami Karakteristik Tampilan Mobile\r\n\r\n### Kepadatan Layar dan DPR\r\n\r\nDevice Pixel Ratio (DPR) memengaruhi kebutuhan gambar:\r\n\r\n```javascript\r\n// Deteksi device pixel ratio\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Hitung ukuran gambar optimal\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Contoh penggunaan\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Ukuran optimal: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Konfigurasi Layar Mobile Umum\r\n\r\n**Resolusi Mobile Populer:**\r\n- iPhone 14/15: 390x844 poin (1179x2556 piksel, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 poin (1284x2778 piksel, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 poin (1344x2992 piksel, 3.25x DPR)\r\n- Google Pixel 8: 384x854 poin (1080x2400 piksel, 2.8125x DPR)\r\n\r\n## Optimasi Gambar Berdasarkan Jaringan\r\n\r\n### Pengiriman Berdasarkan Koneksi\r\n\r\nSesuaikan kualitas gambar berdasarkan kecepatan koneksi:\r\n\r\n```javascript\r\n// Pemrosesan gambar berdasarkan jaringan\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Asumsi default\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Kategorikan kualitas jaringan\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Penggunaan\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Implementasi Gambar Responsif\r\n\r\n### Elemen Picture untuk Mobile\r\n\r\nImplementasi gambar responsif tingkat lanjut:\r\n\r\n```html\r\n\u003C!-- Pengaturan gambar responsif lengkap -->\r\n\u003Cpicture>\r\n    \u003C!-- Layar mobile resolusi tinggi (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Layar mobile standar (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG fallback -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Fallback akhir -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Teks alt deskriptif\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Strategi Pemrosesan Bertahap\r\n\r\n### Lazy Loading yang Dioptimalkan untuk Mobile\r\n\r\nImplementasikan lazy loading yang efisien untuk mobile:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Gunakan intersection observer jika tersedia\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Mulai memuat 50px sebelum masuk viewport\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Inisialisasi lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Optimasi Format Khusus Mobile\r\n\r\n### Algoritma Pemilihan Format\r\n\r\nPilih format optimal berdasarkan kemampuan perangkat mobile:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Selalu didukung\r\n            png: true   // Selalu didukung\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Untuk koneksi lambat atau penghematan data, pilih file lebih kecil\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Untuk foto, pilih format modern dengan kompresi baik\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Optimasi Baterai dan Performa\r\n\r\n### Pemrosesan Gambar Efisien CPU\r\n\r\nMinimalkan penggunaan CPU mobile saat operasi gambar:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Pantau status baterai jika tersedia\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Sesuaikan concurrency berdasarkan kemampuan perangkat\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Pendekatan konservatif untuk perangkat kelas bawah\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Kurangi intensitas pemrosesan saat baterai rendah\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Optimasi Core Web Vitals\r\n\r\n### Optimasi Largest Contentful Paint (LCP)\r\n\r\nOptimalkan LCP untuk perangkat mobile:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Identifikasi gambar di atas lipatan dan prioritaskan\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Tambahkan prioritas pemuatan tinggi\r\n            img.loading = 'eager';\r\n            \r\n            // Preload jika kemungkinan LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Pencegahan Cumulative Layout Shift (CLS)\r\n\r\nCegah pergeseran tata letak pada mobile:\r\n\r\n```css\r\n/* Kontainer rasio aspek untuk mencegah CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading untuk mencegah CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Pengujian dan Pemantauan\r\n\r\n### Pengujian Performa Gambar Mobile\r\n\r\nPengujian performa gambar mobile yang komprehensif:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Pantau performa pemuatan gambar\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Pertimbangkan kompresi gambar yang lebih agresif');\r\n            recommendations.push('Implementasikan JPEG progresif untuk gambar besar');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Inisialisasi penguji performa\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Kesimpulan\r\n\r\nOptimasi gambar mobile adalah tantangan multifaset yang membutuhkan pemahaman tentang kondisi jaringan, kemampuan perangkat, perilaku pengguna, dan metrik performa. Keberhasilan bergantung pada penerapan strategi adaptif yang merespons keterbatasan nyata mobile sambil memberikan pengalaman visual terbaik.\r\n\r\nPoin penting untuk optimasi gambar mobile:\r\n\r\n1. **Kesadaran Jaringan**: Sesuaikan kualitas gambar dan strategi pemuatan berdasarkan kecepatan koneksi dan batas data\r\n2. **Adaptasi Perangkat**: Pertimbangkan kepadatan layar, daya proses, dan baterai dalam keputusan optimasi\r\n3. **Pendekatan Berbasis Performa**: Prioritaskan Core Web Vitals dan metrik pengalaman pengguna\r\n4. **Peningkatan Progresif**: Lapisi optimasi dari fungsi dasar hingga fitur lanjutan\r\n5. **Pemantauan Berkelanjutan**: Pengujian dan pemantauan rutin memastikan optimasi berkelanjutan\r\n\r\nSeiring berkembangnya teknologi mobile, termasuk jaringan 5G, daya proses yang lebih baik, dan format gambar baru, sangat penting untuk tetap mengikuti teknik optimasi sambil menjaga kompatibilitas ke belakang demi memberikan pengalaman mobile yang luar biasa.\r\n\r\nMasa depan optimasi gambar mobile terletak pada sistem cerdas dan adaptif yang secara otomatis menyesuaikan dengan lingkungan pengguna, kemampuan perangkat, dan kondisi jaringan, sambil mempertahankan kualitas visual terbaik dalam batasan tersebut.\r\n","# Mobil Görsel Optimizasyonu: Performans İçin Kapsamlı Rehber\r\n\r\nGünümüzde mobil cihazlar, küresel web trafiğinin %60'ından fazlasını oluşturuyor. Mobil görsel optimizasyonu, kullanıcı deneyimi, performans ve iş başarısı için kritik öneme sahiptir. Mobil kullanıcılar, sınırlı bant genişliği, farklı ekran boyutları ve pil ömrü gibi benzersiz zorluklarla karşı karşıyadır. Bu rehber, mobilde görsel optimizasyonu için gelişmiş stratejileri, teknikleri ve araçları kapsar.\r\n\r\n## Neden Mobil Görsel Optimizasyonu Önemlidir?\r\n\r\n### Mobil Performansa Etkisi\r\n\r\nMobil optimizasyon, temel metrikleri doğrudan etkiler:\r\n- **Sayfa Yükleme Hızı**: Görseller genellikle sayfa ağırlığının %50–70'ini oluşturur\r\n- **Kullanıcı Etkileşimi**: Mobil kullanıcıların %53'ü, 3 saniyeden uzun sürede yüklenen siteleri terk eder\r\n- **Pil Tüketimi**: Verimsiz görsel yükleme, pilin daha hızlı bitmesine neden olur\r\n- **Veri Kullanımı**: Sınırlı veri paketine sahip kullanıcılar için kritiktir\r\n- **SEO Sıralaması**: Google'ın mobile-first index'i, mobil performansa öncelik verir\r\n\r\n### Mobilin Özgün Zorlukları\r\n\r\nMobil ortamda optimizasyon için özel zorluklar vardır:\r\n- **Değişken Ağ Koşulları**: Yavaş 2G'den hızlı 5G'ye kadar\r\n- **Sınırlı İşlem Gücü**: Mobil CPU'lar masaüstüne göre daha zayıftır\r\n- **Bellek Kısıtlamaları**: Mobil cihazlarda RAM genellikle azdır\r\n- **Ekran Çeşitliliği**: Yüzlerce farklı boyut ve yoğunluk\r\n- **Dokunmatik Arayüz**: Masaüstünden farklı etkileşim biçimleri\r\n\r\n## Mobil Ekran Özelliklerini Anlamak\r\n\r\n### Ekran Yoğunluğu ve DPR\r\n\r\nDevice Pixel Ratio (DPR), görsel gereksinimlerini etkiler:\r\n\r\n```javascript\r\n// Cihaz piksel oranını kontrol et\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Uygun görsel boyutunu hesapla\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Kullanım örneği\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Uygun boyut: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Yaygın Mobil Ekran Konfigürasyonları\r\n\r\n**Popüler ekran çözünürlükleri:**\r\n- iPhone 14/15: 390x844 puan (1179x2556 piksel, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 puan (1284x2778 piksel, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 puan (1344x2992 piksel, 3.25x DPR)\r\n- Google Pixel 8: 384x854 puan (1080x2400 piksel, 2.8125x DPR)\r\n\r\n## Ağ Tabanlı Görsel Optimizasyonu\r\n\r\n### Bağlantıya Göre Sunum\r\n\r\nGörsel kalitesini ağ hızına göre ayarlayın:\r\n\r\n```javascript\r\n// Ağ farkındalıklı görsel yükleyici\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Varsayılan\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Ağ kalitesini sınıflandır\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Kullanım örneği\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Duyarlı (Responsive) Görsel Kullanımı\r\n\r\n### Mobil için picture elementi\r\n\r\nGelişmiş responsive görsel kullanımı:\r\n\r\n```html\r\n\u003C!-- Tam responsive görsel ayarı -->\r\n\u003Cpicture>\r\n    \u003C!-- Yüksek çözünürlüklü mobil ekranlar (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Standart mobil ekranlar (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG Yedeği -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Son yedek -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Açıklayıcı alt metin\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Kademeli Yükleme Stratejileri\r\n\r\n### Mobil için Lazy Loading\r\n\r\nMobilde etkili lazy loading uygulaması:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Intersection Observer varsa kullan\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // viewport'a 50px kala yükle\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Lazy loader'ı başlat\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Mobil Odaklı Format Optimizasyonu\r\n\r\n### Format Seçim Algoritması\r\n\r\nMobil cihaz yeteneklerine göre en uygun formatı seçin:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Her zaman desteklenir\r\n            png: true   // Her zaman desteklenir\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Yavaş bağlantı/veri tasarrufu için küçük dosya seç\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Fotoğraflar için yeni formatları tercih et\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Pil ve Genel Performans Optimizasyonu\r\n\r\n### CPU Dostu Görsel İşleme\r\n\r\nMobilde görsel işleme sırasında CPU kullanımını azaltın:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Pil durumu uygunsa kontrol et\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Cihaz yeteneklerine göre eşzamanlılık ayarla\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Düşük performanslı cihazlar için dikkatli ol\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Pil azsa yoğunluğu azalt\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Core Web Vitals Optimizasyonu\r\n\r\n### Largest Contentful Paint (LCP) Optimizasyonu\r\n\r\nMobilde LCP'yi optimize edin:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Kat üstü görselleri tespit edip önce yükle\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Yüksek öncelikli yükle\r\n            img.loading = 'eager';\r\n            \r\n            // LCP adayıysa preload et\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Cumulative Layout Shift (CLS) Önleme\r\n\r\nMobilde layout kaymasını önleyin:\r\n\r\n```css\r\n/* CLS önleyici oran konteyneri */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* CLS için iskelet yükleme */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Test ve İzleme\r\n\r\n### Mobil Görsel Performans Testi\r\n\r\nMobilde görsel performansını kapsamlı test edin:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Görsel yükleme performansını izle\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Görselleri daha fazla sıkıştırmayı düşünün');\r\n            recommendations.push('Büyük görseller için progressive JPEG kullanın');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Performans testini başlat\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Sonuç\r\n\r\nMobil görsel optimizasyonu, ağ koşulları, cihaz yetenekleri, kullanıcı davranışı ve performans metriklerini anlamayı gerektiren çok boyutlu bir zorluktur. Başarı, mobilin gerçek kısıtlamalarına yanıt veren ve en iyi görsel deneyimi sunan uyarlanabilir stratejiler uygulamaya bağlıdır.\r\n\r\nMobil görsel optimizasyonunun temel noktaları:\r\n\r\n1. **Ağ Farkındalığı**: Kaliteyi ve yükleme stratejilerini hız ve veri kısıtlarına göre ayarlayın\r\n2. **Cihaza Uyum**: Ekran yoğunluğu, işlem gücü ve pil durumunu göz önünde bulundurun\r\n3. **Performansa Odaklanın**: Core Web Vitals ve kullanıcı deneyimi metriklerine öncelik verin\r\n4. **Kademeli İyileştirme**: Temelden ileri seviyeye katmanlı optimizasyon uygulayın\r\n5. **Sürekli İzleme**: Optimizasyonu sürdürmek için düzenli test ve izleme yapın\r\n\r\nMobil teknolojiler geliştikçe (5G, daha yüksek işlem gücü, yeni görsel formatları), optimizasyon tekniklerini güncel tutmak ve geriye dönük uyumluluğu sağlamak, mükemmel bir mobil deneyim için önemlidir.\r\n\r\nMobil görsel optimizasyonunun geleceği, kullanıcı ortamına, cihaz yeteneklerine ve ağ koşullarına otomatik olarak uyum sağlayan, kısıtlar dahilinde en iyi görsel kalitesini sunan akıllı sistemlerde yatmaktadır.\r\n","# Mobilbildoptimering: Komplett prestandaguide\r\n\r\nMobila enheter står nu för över 60 % av den globala webbtrafiken, vilket gör optimering av bilder för mobil avgörande för användarupplevelse, prestanda och affärsframgång. Mobilanvändare möter unika utmaningar som begränsad bandbredd, varierande skärmstorlekar och batteriförbrukning. Den här omfattande guiden täcker avancerade strategier, tekniker och verktyg för bildoptimering på mobila enheter.\r\n\r\n## Varför mobilbildoptimering är viktigt\r\n\r\n### Påverkan på mobil prestanda\r\n\r\nMobiloptimering påverkar direkt viktiga mätvärden:\r\n- **Sidladdningshastighet**: Bilder utgör ofta 50–70 % av sidans vikt\r\n- **Användarengagemang**: 53 % av mobilanvändare lämnar sajter som tar mer än 3 sekunder att ladda\r\n- **Batteriförbrukning**: Ineffektiv bildladdning drar ur batteriet snabbare\r\n- **Dataanvändning**: Viktigt för användare med begränsade dataplaner\r\n- **SEO-ranking**: Googles mobile-first-index prioriterar mobil prestanda\r\n\r\n### Mobilspecifika utmaningar\r\n\r\nMobilmiljön innebär unika optimeringsutmaningar:\r\n- **Varierande nätverksförhållanden**: Från långsamt 2G till snabbt 5G\r\n- **Begränsad processorkraft**: Mobil-CPU:er är svagare än stationära\r\n- **Minnesbegränsningar**: Mobila enheter har begränsat RAM\r\n- **Skärmvariation**: Hundratals olika skärmstorlekar och densiteter\r\n- **Pekskärmsgränssnitt**: Annorlunda interaktionsmönster än på desktop\r\n\r\n## Förstå mobilskärmens egenskaper\r\n\r\n### Skärmdensitet och DPR\r\n\r\nEnhetens pixelkvot (DPR) påverkar bildkraven:\r\n\r\n```javascript\r\n// Hämta device pixel ratio\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Beräkna optimal bildstorlek\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Exempel på användning\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Optimal storlek: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Vanliga mobilskärmskonfigurationer\r\n\r\n**Populära mobilupplösningar:**\r\n- iPhone 14/15: 390x844 punkter (1179x2556 pixlar, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 punkter (1284x2778 pixlar, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 punkter (1344x2992 pixlar, 3.25x DPR)\r\n- Google Pixel 8: 384x854 punkter (1080x2400 pixlar, 2.8125x DPR)\r\n\r\n## Nätverksanpassad bildoptimering\r\n\r\n### Leverans baserat på anslutning\r\n\r\nJustera bildkvalitet efter anslutningshastighet:\r\n\r\n```javascript\r\n// Nätverksanpassad bildladdare\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Standard\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Kategorisera nätverkskvalitet\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Exempel på användning\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Implementering av responsiva bilder\r\n\r\n### picture-elementet för mobil\r\n\r\nAvancerad implementering av responsiva bilder:\r\n\r\n```html\r\n\u003C!-- Komplett responsiv bilduppsättning -->\r\n\u003Cpicture>\r\n    \u003C!-- Högupplösta mobildisplayer (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Standard mobildisplayer (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG-fallback -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Sista fallback -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Beskrivande alt-text\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Progressiva laddningsstrategier\r\n\r\n### Mobiloptimerad lazy loading\r\n\r\nImplementera effektiv lazy loading för mobil:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Använd Intersection Observer om tillgängligt\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Börja ladda 50px innan synlighet\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Initiera lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Mobilspecifik formatoptimering\r\n\r\n### Formatvalsalgoritm\r\n\r\nVälj optimalt format utifrån mobilens kapacitet:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Alltid stöds\r\n            png: true   // Alltid stöds\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Vid långsamma anslutningar eller databesparing, prioritera mindre filer\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // För foton, prioritera moderna format med bra komprimering\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Optimering för batteri och prestanda\r\n\r\n### CPU-effektiv bildbehandling\r\n\r\nMinimera CPU-användning vid bildoperationer på mobil:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Övervaka batteristatus om möjligt\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Justera samtidighet efter enhetens kapacitet\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Var försiktig för svagare enheter\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Minska intensitet vid låg batterinivå\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Optimering av Core Web Vitals\r\n\r\n### Optimering av Largest Contentful Paint (LCP)\r\n\r\nOptimera LCP för mobil:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Identifiera bilder ovanför vyn och prioritera dem\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Ladda med hög prioritet\r\n            img.loading = 'eager';\r\n            \r\n            // Preload om sannolik LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Förhindra Cumulative Layout Shift (CLS)\r\n\r\nUndvik layoutskiften på mobil:\r\n\r\n```css\r\n/* Behållare för bildförhållande för att undvika CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skelettladdning för att undvika CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Testning och övervakning\r\n\r\n### Test av mobil bildprestanda\r\n\r\nOmfattande test av bildprestanda på mobil:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Övervaka bildladdningsprestanda\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Överväg mer aggressiv bildkomprimering');\r\n            recommendations.push('Implementera progressiv JPEG för stora bilder');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Initiera prestandatestare\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Slutsats\r\n\r\nMobilbildoptimering är en mångfacetterad utmaning som kräver förståelse för nätverksförhållanden, enhetskapacitet, användarbeteende och prestandamått. Framgång beror på att implementera adaptiva strategier som svarar mot verkliga mobila begränsningar och samtidigt ger bästa möjliga visuella upplevelse.\r\n\r\nViktiga punkter för mobilbildoptimering:\r\n\r\n1. **Nätverksmedvetenhet**: Justera bildkvalitet och laddningsstrategi efter hastighet och databegränsningar\r\n2. **Enhetsanpassning**: Ta hänsyn till skärmdensitet, processorkraft och batteritid\r\n3. **Prestandafokus**: Prioritera Core Web Vitals och användarupplevelsemått\r\n4. **Progressiv förbättring**: Optimera i lager, från grundläggande till avancerade funktioner\r\n5. **Kontinuerlig övervakning**: Testa och övervaka regelbundet för att bibehålla optimeringen\r\n\r\nI takt med att 5G, ökad processorkraft och nya bildformat utvecklas är det avgörande att hålla sig uppdaterad med optimeringstekniker och säkerställa bakåtkompatibilitet för en utmärkt mobilupplevelse.\r\n\r\nFramtiden för mobilbildoptimering ligger i intelligenta, adaptiva system som automatiskt anpassar sig till användarens miljö, enhetskapacitet och nätverksförhållanden, och bibehåller bästa möjliga bildkvalitet inom dessa begränsningar.\r\n","# Mobilbilledoptimering: Komplet ydelsesguide\r\n\r\nMobile enheder står nu for over 60 % af den globale webtrafik, hvilket gør mobilbilledoptimering afgørende for brugeroplevelse, performance og forretningssucces. Mobilbrugere står over for unikke udfordringer såsom begrænset båndbredde, varierende skærmstørrelser og batteriforbrug. Denne omfattende guide dækker avancerede strategier, teknikker og værktøjer, der er specielt designet til at optimere billeder til mobile enheder.\r\n\r\n## Hvorfor mobilbilledoptimering er kritisk\r\n\r\n### Indvirkning på mobilperformance\r\n\r\nMobiloptimering påvirker direkte nøglemålinger:\r\n- **Sideindlæsningstid**: Billeder udgør typisk 50-70 % af sidens vægt\r\n- **Brugerengagement**: 53 % af mobilbrugere forlader sider, der tager mere end 3 sekunder at indlæse\r\n- **Batteriforbrug**: Ineffektiv billedindlæsning dræner batteriet hurtigere\r\n- **Dataforbrug**: Vigtigt for brugere med begrænsede dataplaner\r\n- **SEO-rangeringer**: Googles mobile-first-indeksering prioriterer mobilperformance\r\n\r\n### Mobilspecifikke udfordringer\r\n\r\nMobilmiljøet præsenterer unikke optimeringsudfordringer:\r\n- **Varierende netværksforhold**: Fra langsomt 2G til hurtigt 5G\r\n- **Begrænset processorkraft**: Mobil-CPU'er er mindre kraftfulde end desktop-CPU'er\r\n- **Hukommelsesbegrænsninger**: Mobile enheder har begrænset RAM\r\n- **Skærmdiversitet**: Hundredvis af forskellige skærmstørrelser og -tætheder\r\n- **Touch-interface**: Anderledes interaktionsmønstre end desktop\r\n\r\n## Forstå mobilskærmens karakteristika\r\n\r\n### Skærmtæthed og DPR\r\n\r\nEnhedens pixel-forhold (DPR) påvirker billedkravene:\r\n\r\n```javascript\r\n// Registrer enhedens pixel-forhold\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Beregn optimal billedstørrelse\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Eksempel på brug\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Optimal størrelse: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Almindelige mobilskærmskonfigurationer\r\n\r\n**Populære mobilopløsninger:**\r\n- iPhone 14/15: 390x844 punkter (1179x2556 pixels, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 punkter (1284x2778 pixels, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 punkter (1344x2992 pixels, 3.25x DPR)\r\n- Google Pixel 8: 384x854 punkter (1080x2400 pixels, 2.8125x DPR)\r\n\r\n## Netværksbevidst billedoptimering\r\n\r\n### Levering baseret på forbindelse\r\n\r\nJuster billedkvalitet baseret på forbindelseshastighed:\r\n\r\n```javascript\r\n// Netværksbevidst billedindlæsning\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Standardantagelse\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Kategoriser netværkskvalitet\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Brug\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Implementering af responsive billeder\r\n\r\n### Mobilbilledet \u003Cpicture>\r\n\r\nAvanceret implementering af responsive billeder:\r\n\r\n```html\r\n\u003C!-- Omfattende responsivt billedsetup -->\r\n\u003Cpicture>\r\n    \u003C!-- Højopløselige mobildisplays (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Standard mobildisplays (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG fallback -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Endelig fallback -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Beskrivende alt-tekst\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Progressive indlæsningsstrategier\r\n\r\n### Mobiloptimeret lazy loading\r\n\r\nImplementer effektiv lazy loading til mobil:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Brug intersection observer hvis tilgængelig\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Start indlæsning 50px før synlighed\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Initialiser lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Mobilspecifik formatoptimering\r\n\r\n### Formatvalg-algoritme\r\n\r\nVælg det optimale format baseret på mobilens kapaciteter:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Altid understøttet\r\n            png: true   // Altid understøttet\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // For langsomme forbindelser eller databegrænsning, foretræk mindre filer\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // For fotos, foretræk moderne formater med god komprimering\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Batteri- og ydelsesoptimering\r\n\r\n### CPU-effektiv billedbehandling\r\n\r\nMinimer mobil-CPU-brug under billedoperationer:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Overvåg batteristatus hvis tilgængelig\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Tilpas samtidighed baseret på enhedens kapaciteter\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Konservativ tilgang for lavere enheder\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Reducer behandlingsintensitet ved lavt batteri\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Core Web Vitals-optimering\r\n\r\n### Largest Contentful Paint (LCP)-optimering\r\n\r\nOptimer LCP for mobile enheder:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Identificer billeder over folden og prioriter dem\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Tilføj høj prioritet indlæsning\r\n            img.loading = 'eager';\r\n            \r\n            // Forudindlæs hvis det sandsynligvis er LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Forebyggelse af Cumulative Layout Shift (CLS)\r\n\r\nForhindre layoutskift på mobil:\r\n\r\n```css\r\n/* Aspect ratio-containere for at forhindre CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeletindlæsning for at forhindre CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Test og overvågning\r\n\r\n### Mobil billedperformance-test\r\n\r\nOmfattende test af billedperformance på mobil:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Overvåg billedindlæsning\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Overvej mere aggressiv billedkomprimering');\r\n            recommendations.push('Implementér progressiv JPEG til store billeder');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Initialiser performance-tester\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Konklusion\r\n\r\nMobilbilledoptimering er en kompleks udfordring, der kræver forståelse for netværksforhold, enhedskapaciteter, brugeradfærd og performancemålinger. Succes afhænger af at implementere adaptive strategier, der reagerer på virkelige mobile begrænsninger og samtidig leverer den bedst mulige visuelle oplevelse.\r\n\r\nVigtige pointer for mobilbilledoptimering:\r\n\r\n1. **Netværksbevidsthed**: Tilpas billedkvalitet og indlæsningsstrategier efter forbindelseshastighed og databegrænsninger\r\n2. **Enhedstilpasning**: Overvej skærmtæthed, processorkraft og batterilevetid i optimeringsbeslutninger\r\n3. **Performance-først tilgang**: Prioritér Core Web Vitals og brugeroplevelsesmålinger\r\n4. **Progressiv forbedring**: Lag optimeringer fra grundlæggende funktionalitet til avancerede funktioner\r\n5. **Løbende overvågning**: Regelmæssig test og performanceovervågning sikrer løbende optimering\r\n\r\nEfterhånden som mobilteknologi udvikler sig, herunder 5G-netværk, forbedret processorkraft og nye billedformater, er det afgørende at holde sig opdateret med optimeringsteknikker og samtidig bevare bagudkompatibilitet for at levere fremragende mobile oplevelser.\r\n\r\nFremtiden for mobilbilledoptimering ligger i intelligente, adaptive systemer, der automatisk tilpasser sig brugerens miljø, enhedskapaciteter og netværksforhold, mens de opretholder den højest mulige visuelle kvalitet inden for disse begrænsninger.\r\n","# Mobiilikuvien optimointi: Täydellinen suorituskykyopas\r\n\r\nMobiililaitteet muodostavat nyt yli 60 % maailmanlaajuisesta verkkoliikenteestä, joten mobiilikuvien optimointi on ratkaisevan tärkeää käyttäjäkokemuksen, suorituskyvyn ja liiketoiminnan menestyksen kannalta. Mobiilikäyttäjät kohtaavat ainutlaatuisia haasteita, kuten rajoitetun kaistanleveyden, vaihtelevat näyttökoot ja akun kulutuksen. Tämä kattava opas kattaa edistyneet strategiat, tekniikat ja työkalut, jotka on suunniteltu erityisesti mobiililaitteiden kuvien optimointiin.\r\n\r\n## Miksi mobiilikuvien optimointi on kriittistä\r\n\r\n### Vaikutus mobiilisuorituskykyyn\r\n\r\nMobiilioptimointi vaikuttaa suoraan keskeisiin mittareihin:\r\n- **Sivun latausnopeus**: Kuvat muodostavat tyypillisesti 50–70 % sivun painosta\r\n- **Käyttäjien sitoutuminen**: 53 % mobiilikäyttäjistä poistuu sivuilta, joiden lataus kestää yli 3 sekuntia\r\n- **Akun kulutus**: Tehoton kuvien lataus kuluttaa akkua nopeammin\r\n- **Datankäyttö**: Tärkeää käyttäjille, joilla on rajoitetut datapaketit\r\n- **SEO-sijoitukset**: Googlen mobile-first-indeksointi painottaa mobiilisuorituskykyä\r\n\r\n### Mobiilikohtaiset haasteet\r\n\r\nMobiiliympäristö tuo mukanaan ainutlaatuisia optimointihaasteita:\r\n- **Vaihtelevat verkkoyhteydet**: Hitaasta 2G:stä nopeaan 5G:hen\r\n- **Rajoitettu prosessointiteho**: Mobiili-CPU:t ovat vähemmän tehokkaita kuin pöytäkoneiden\r\n- **Muistirajoitukset**: Mobiililaitteissa on rajoitetusti RAM-muistia\r\n- **Näyttöjen monimuotoisuus**: Satoja erilaisia näyttökokoja ja -tiheyksiä\r\n- **Kosketusliittymä**: Eri käyttötavat kuin pöytäkoneella\r\n\r\n## Mobiilinäytön ominaisuuksien ymmärtäminen\r\n\r\n### Näytön tiheys ja DPR\r\n\r\nLaitteen pikselisuhde (DPR) vaikuttaa kuvan vaatimuksiin:\r\n\r\n```javascript\r\n// Tunnista laitteen pikselisuhde\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Laske optimaalinen kuvan koko\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Käyttöesimerkki\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Optimaalinen koko: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Yleiset mobiilinäyttöjen kokoonpanot\r\n\r\n**Suositut mobiilinäytön resoluutiot:**\r\n- iPhone 14/15: 390x844 pistettä (1179x2556 pikseliä, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 pistettä (1284x2778 pikseliä, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 pistettä (1344x2992 pikseliä, 3.25x DPR)\r\n- Google Pixel 8: 384x854 pistettä (1080x2400 pikseliä, 2.8125x DPR)\r\n\r\n## Verkkotietoinen kuvien optimointi\r\n\r\n### Yhteysperusteinen toimitus\r\n\r\nSäädä kuvan laatua yhteysnopeuden mukaan:\r\n\r\n```javascript\r\n// Verkkotietoinen kuvien lataus\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Oletus\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Luokittele verkon laatu\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Käyttö\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Responsiivisten kuvien toteutus\r\n\r\n### Mobiilin picture-elementti\r\n\r\nEdistynyt responsiivisten kuvien toteutus:\r\n\r\n```html\r\n\u003C!-- Kattava responsiivinen kuvasetti -->\r\n\u003Cpicture>\r\n    \u003C!-- Korkean resoluution mobiilinäytöt (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Tavalliset mobiilinäytöt (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG-varaversiot -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Viimeinen varaversio -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Kuvaileva vaihtoehtoinen teksti\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Progressiiviset latausstrategiat\r\n\r\n### Mobiilioptimoitu laiska lataus\r\n\r\nToteuta tehokas laiska lataus mobiilille:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Käytä intersection observeria jos saatavilla\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Aloita lataus 50px ennen näkymää\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Käynnistä lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Mobiilikohtainen formaatin optimointi\r\n\r\n### Formaattivalinta-algoritmi\r\n\r\nValitse optimaalinen formaatti mobiililaitteen kykyjen mukaan:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Aina tuettu\r\n            png: true   // Aina tuettu\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Hitailla yhteyksillä tai datarajoituksilla suosi pienempiä tiedostoja\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Valokuville suosi moderneja formaatteja hyvällä pakkauksella\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Akun ja suorituskyvyn optimointi\r\n\r\n### Prosessoritehokas kuvankäsittely\r\n\r\nMinimoi mobiililaitteen CPU:n käyttö kuvatoiminnoissa:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Tarkkaile akun tilaa jos saatavilla\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Sovita rinnakkaisuus laitteen kykyihin\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Varovainen lähestymistapa heikommille laitteille\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Vähennä prosessointia matalalla akulla\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Core Web Vitals -optimointi\r\n\r\n### Largest Contentful Paint (LCP) -optimointi\r\n\r\nOptimoi LCP mobiililaitteille:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Tunnista yläosan kuvat ja priorisoi ne\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Lisää korkea latausprioriteetti\r\n            img.loading = 'eager';\r\n            \r\n            // Esilataa jos todennäköisesti LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Cumulative Layout Shift (CLS) -ehkäisy\r\n\r\nEstä asettelun siirtymät mobiilissa:\r\n\r\n```css\r\n/* Kuvasuhdekontit CLS:n ehkäisyyn */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading CLS:n ehkäisyyn */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Testaus ja seuranta\r\n\r\n### Mobiilikuvien suorituskyvyn testaus\r\n\r\nKattava mobiilikuvien suorituskyvyn testaus:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Seuraa kuvien lataussuorituskykyä\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Harkitse aggressiivisempaa kuvien pakkausta');\r\n            recommendations.push('Ota käyttöön progressiivinen JPEG suurille kuville');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Käynnistä suorituskykytesteri\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Yhteenveto\r\n\r\nMobiilikuvien optimointi on monivaiheinen haaste, joka vaatii ymmärrystä verkkoyhteyksistä, laitekyvyistä, käyttäytymisestä ja suorituskykymittareista. Onnistuminen edellyttää mukautuvien strategioiden toteuttamista, jotka vastaavat mobiililaitteiden todellisiin rajoituksiin ja tarjoavat parhaan mahdollisen visuaalisen kokemuksen.\r\n\r\nKeskeiset huomiot mobiilikuvien optimointiin:\r\n\r\n1. **Verkkotietoisuus**: Säädä kuvan laatua ja latausstrategioita yhteysnopeuden ja datarajoitusten mukaan\r\n2. **Laitteeseen mukautuminen**: Ota huomioon näytön tiheys, prosessointiteho ja akun kesto optimointipäätöksissä\r\n3. **Suorituskyky ensin**: Priorisoi Core Web Vitals ja käyttäjäkokemuksen mittarit\r\n4. **Progressiivinen parantaminen**: Kerrosta optimointeja perustoiminnallisuudesta edistyneisiin ominaisuuksiin\r\n5. **Jatkuva seuranta**: Säännöllinen testaus ja suorituskyvyn seuranta varmistavat jatkuvan optimoinnin\r\n\r\nMobiiliteknologian kehittyessä, mukaan lukien 5G-verkot, parempi prosessointiteho ja uudet kuvamuodot, on tärkeää pysyä ajan tasalla optimointitekniikoista ja säilyttää taaksepäin yhteensopivuus huippuluokan mobiilikokemusten tarjoamiseksi.\r\n\r\nMobiilikuvien optimoinnin tulevaisuus on älykkäissä, mukautuvissa järjestelmissä, jotka mukautuvat automaattisesti käyttäjän ympäristöön, laitekykyihin ja verkkoyhteyksiin, säilyttäen samalla parhaan mahdollisen visuaalisen laadun näissä rajoissa.\r\n","# Optimizarea imaginilor pentru mobil: Ghid complet de performanță\r\n\r\nDispozitivele mobile reprezintă acum peste 60% din traficul web global, ceea ce face ca optimizarea imaginilor pentru mobil să fie esențială pentru experiența utilizatorului, performanță și succesul afacerii. Utilizatorii de mobil se confruntă cu provocări unice precum lățime de bandă limitată, diversitate de dimensiuni ale ecranului și consum de baterie. Acest ghid cuprinzător acoperă strategii, tehnici și instrumente avansate pentru optimizarea imaginilor pe dispozitive mobile.\r\n\r\n## De ce este importantă optimizarea imaginilor pentru mobil\r\n\r\n### Impactul asupra performanței pe mobil\r\n\r\nOptimizarea pentru mobil influențează direct indicatorii cheie:\r\n- **Viteza de încărcare a paginii**: imaginile reprezintă adesea 50–70% din greutatea paginii\r\n- **Angajamentul utilizatorului**: 53% dintre utilizatorii de mobil părăsesc site-urile care se încarcă în peste 3 secunde\r\n- **Consum de baterie**: încărcarea ineficientă a imaginilor consumă bateria mai rapid\r\n- **Consum de date**: important pentru utilizatorii cu planuri de date limitate\r\n- **Clasare SEO**: indexarea mobile-first a Google prioritizează performanța pe mobil\r\n\r\n### Provocări specifice mediului mobil\r\n\r\nMediul mobil aduce provocări unice de optimizare:\r\n- **Condiții de rețea variabile**: de la 2G lent la 5G rapid\r\n- **Putere de procesare limitată**: procesoarele mobile sunt mai puțin performante decât cele desktop\r\n- **Limitări de memorie**: dispozitivele mobile au RAM limitat\r\n- **Diversitate de ecrane**: sute de dimensiuni și densități de ecran\r\n- **Interfață tactilă**: modele de interacțiune diferite față de desktop\r\n\r\n## Înțelegerea caracteristicilor de afișare pe mobil\r\n\r\n### Densitatea ecranului și DPR\r\n\r\nRaportul de pixeli al dispozitivului (DPR) influențează cerințele pentru imagini:\r\n\r\n```javascript\r\n// Detectarea raportului de pixeli al dispozitivului\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Calcularea dimensiunii optime a imaginii\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Exemplu de utilizare\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Dimensiune optimă: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Configurații comune de ecrane mobile\r\n\r\n**Rezoluții populare pentru mobil:**\r\n- iPhone 14/15: 390x844 puncte (1179x2556 pixeli, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 puncte (1284x2778 pixeli, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 puncte (1344x2992 pixeli, 3.25x DPR)\r\n- Google Pixel 8: 384x854 puncte (1080x2400 pixeli, 2.8125x DPR)\r\n\r\n## Optimizarea imaginilor în funcție de rețea\r\n\r\n### Livrare în funcție de conexiune\r\n\r\nAjustați calitatea imaginii în funcție de viteza conexiunii:\r\n\r\n```javascript\r\n// Loader de imagini sensibil la rețea\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Implicit\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Clasificarea calității rețelei\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Exemplu de utilizare\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Implementarea imaginilor responsive\r\n\r\n### Elementul picture pentru mobil\r\n\r\nImplementare avansată a imaginilor responsive:\r\n\r\n```html\r\n\u003C!-- Configurație completă pentru imagine responsive -->\r\n\u003Cpicture>\r\n    \u003C!-- Ecrane mobile cu rezoluție înaltă (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Ecrane mobile standard (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Fallback JPEG -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Fallback final -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Text alternativ descriptiv\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Strategii de încărcare progresivă\r\n\r\n### Lazy loading optimizat pentru mobil\r\n\r\nImplementați lazy loading eficient pentru mobil:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Folosiți Intersection Observer dacă este disponibil\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Începe încărcarea cu 50px înainte de a intra în viewport\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Inițializați lazy loader-ul\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Optimizare de format specifică pentru mobil\r\n\r\n### Algoritm de selecție a formatului\r\n\r\nAlegeți formatul optim în funcție de capabilitățile dispozitivului mobil:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Mereu suportat\r\n            png: true   // Mereu suportat\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Pentru conexiuni lente sau economisire de date, preferați fișiere mai mici\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Pentru fotografii, preferați formate moderne cu compresie bună\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Optimizare pentru baterie și performanță\r\n\r\n### Procesare eficientă a imaginilor pe CPU\r\n\r\nMinimizați utilizarea CPU la operațiunile pe imagini pe mobil:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Monitorizați starea bateriei dacă este posibil\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Ajustați concurența în funcție de capabilitățile dispozitivului\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Pentru dispozitive cu performanță redusă, fiți conservatori\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Reduceți intensitatea dacă bateria este scăzută\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Optimizarea Core Web Vitals\r\n\r\n### Optimizarea Largest Contentful Paint (LCP)\r\n\r\nOptimizați LCP pentru mobil:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Identificați imaginile deasupra fold-ului și prioritizați-le\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Încărcare cu prioritate mare\r\n            img.loading = 'eager';\r\n            \r\n            // Preload dacă este probabil LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Prevenirea Cumulative Layout Shift (CLS)\r\n\r\nEvitați deplasările de layout pe mobil:\r\n\r\n```css\r\n/* Containere de aspect pentru a preveni CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading pentru a preveni CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Testare și monitorizare\r\n\r\n### Testarea performanței imaginilor pe mobil\r\n\r\nTestare cuprinzătoare a performanței imaginilor pe mobil:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Monitorizați performanța încărcării imaginilor\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Luați în considerare o compresie mai agresivă a imaginilor');\r\n            recommendations.push('Implementați JPEG progresiv pentru imagini mari');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Inițializați testerul de performanță\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Concluzie\r\n\r\nOptimizarea imaginilor pentru mobil este o provocare complexă care necesită înțelegerea condițiilor de rețea, a capabilităților dispozitivului, a comportamentului utilizatorului și a indicatorilor de performanță. Succesul depinde de implementarea unor strategii adaptive care să răspundă limitărilor reale ale mediului mobil, oferind în același timp cea mai bună experiență vizuală posibilă.\r\n\r\nPuncte cheie pentru optimizarea imaginilor mobile:\r\n\r\n1. **Conștientizarea rețelei**: ajustați calitatea și strategia de încărcare în funcție de viteză și restricții de date\r\n2. **Adaptarea la dispozitiv**: luați în considerare densitatea ecranului, puterea de procesare și durata bateriei\r\n3. **Focalizare pe performanță**: prioritizați Core Web Vitals și indicatorii de experiență a utilizatorului\r\n4. **Îmbunătățire progresivă**: optimizați în straturi, de la funcționalitatea de bază la cea avansată\r\n5. **Monitorizare continuă**: testați și monitorizați regulat pentru a menține optimizarea\r\n\r\nOdată cu evoluția 5G, creșterea puterii de procesare și apariția unor noi formate de imagine, este esențial să rămâneți la curent cu tehnicile de optimizare și să asigurați compatibilitatea retroactivă pentru o experiență mobilă excelentă.\r\n\r\nViitorul optimizării imaginilor pentru mobil constă în sisteme inteligente și adaptive care se ajustează automat la mediul utilizatorului, capabilitățile dispozitivului și condițiile de rețea, menținând cea mai bună calitate vizuală posibilă în aceste limite.\r\n","# Βελτιστοποίηση εικόνων για κινητά: Πλήρης οδηγός απόδοσης\r\n\r\nΟι κινητές συσκευές αντιπροσωπεύουν πλέον πάνω από το 60% της παγκόσμιας διαδικτυακής κίνησης, καθιστώντας τη βελτιστοποίηση εικόνων για κινητά κρίσιμη για την εμπειρία χρήστη, την απόδοση και την επιχειρηματική επιτυχία. Οι χρήστες κινητών αντιμετωπίζουν μοναδικές προκλήσεις όπως περιορισμένο εύρος ζώνης, ποικίλα μεγέθη οθόνης και ανησυχίες για την κατανάλωση μπαταρίας. Αυτός ο ολοκληρωμένος οδηγός καλύπτει προηγμένες στρατηγικές, τεχνικές και εργαλεία ειδικά σχεδιασμένα για τη βελτιστοποίηση εικόνων σε κινητές συσκευές.\r\n\r\n## Γιατί η βελτιστοποίηση εικόνων για κινητά είναι κρίσιμη\r\n\r\n### Επίδραση στην απόδοση κινητών\r\n\r\nΗ βελτιστοποίηση για κινητά επηρεάζει άμεσα βασικές μετρήσεις:\r\n- **Ταχύτητα φόρτωσης σελίδας**: Οι εικόνες αποτελούν συνήθως το 50-70% του βάρους της σελίδας\r\n- **Αλληλεπίδραση χρήστη**: Το 53% των χρηστών κινητών εγκαταλείπουν ιστότοπους που φορτώνουν πάνω από 3 δευτερόλεπτα\r\n- **Κατανάλωση μπαταρίας**: Η αναποτελεσματική φόρτωση εικόνων εξαντλεί τη μπαταρία πιο γρήγορα\r\n- **Χρήση δεδομένων**: Σημαντικό για χρήστες με περιορισμένα πακέτα δεδομένων\r\n- **SEO κατάταξη**: Η mobile-first ευρετηρίαση της Google δίνει προτεραιότητα στην απόδοση σε κινητά\r\n\r\n### Προκλήσεις ειδικά για κινητά\r\n\r\nΤο περιβάλλον κινητών παρουσιάζει μοναδικές προκλήσεις βελτιστοποίησης:\r\n- **Μεταβλητές συνθήκες δικτύου**: Από αργό 2G έως γρήγορο 5G\r\n- **Περιορισμένη επεξεργαστική ισχύς**: Οι CPU κινητών είναι λιγότερο ισχυρές από των υπολογιστών\r\n- **Περιορισμένη μνήμη**: Οι κινητές συσκευές έχουν περιορισμένη RAM\r\n- **Ποικιλία οθονών**: Εκατοντάδες διαφορετικά μεγέθη και πυκνότητες οθόνης\r\n- **Διεπαφή αφής**: Διαφορετικά μοτίβα αλληλεπίδρασης από το desktop\r\n\r\n## Κατανόηση χαρακτηριστικών εμφάνισης σε κινητά\r\n\r\n### Πυκνότητα οθόνης και DPR\r\n\r\nΟ λόγος pixel συσκευής (DPR) επηρεάζει τις απαιτήσεις εικόνας:\r\n\r\n```javascript\r\n// Εντοπισμός DPR συσκευής\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Υπολογισμός βέλτιστου μεγέθους εικόνας\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Παράδειγμα χρήσης\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Βέλτιστο μέγεθος: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Συνήθεις διαμορφώσεις οθόνης κινητών\r\n\r\n**Δημοφιλείς αναλύσεις κινητών:**\r\n- iPhone 14/15: 390x844 σημεία (1179x2556 pixels, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 σημεία (1284x2778 pixels, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 σημεία (1344x2992 pixels, 3.25x DPR)\r\n- Google Pixel 8: 384x854 σημεία (1080x2400 pixels, 2.8125x DPR)\r\n\r\n## Βελτιστοποίηση εικόνων με βάση το δίκτυο\r\n\r\n### Παράδοση με βάση τη σύνδεση\r\n\r\nΠροσαρμόστε την ποιότητα εικόνας με βάση την ταχύτητα σύνδεσης:\r\n\r\n```javascript\r\n// Φόρτωση εικόνας με επίγνωση δικτύου\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Προεπιλογή\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Κατηγοριοποίηση ποιότητας δικτύου\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Χρήση\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Υλοποίηση responsive εικόνων\r\n\r\n### Στοιχείο picture για κινητά\r\n\r\nΠροηγμένη υλοποίηση responsive εικόνων:\r\n\r\n```html\r\n\u003C!-- Πλήρης ρύθμιση responsive εικόνας -->\r\n\u003Cpicture>\r\n    \u003C!-- Οθόνες κινητών υψηλής ανάλυσης (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Τυπικές οθόνες κινητών (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Εναλλακτικά JPEG -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Τελικό fallback -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Περιγραφικό alt κείμενο\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Στρατηγικές προοδευτικής φόρτωσης\r\n\r\n### Lazy loading βελτιστοποιημένο για κινητά\r\n\r\nΥλοποιήστε αποδοτικό lazy loading για κινητά:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Χρησιμοποιήστε intersection observer αν είναι διαθέσιμο\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Ξεκινήστε φόρτωση 50px πριν μπει στο viewport\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Αρχικοποίηση lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Βελτιστοποίηση μορφής ειδικά για κινητά\r\n\r\n### Αλγόριθμος επιλογής μορφής\r\n\r\nΕπιλέξτε τη βέλτιστη μορφή με βάση τις δυνατότητες της συσκευής:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Πάντα υποστηρίζεται\r\n            png: true   // Πάντα υποστηρίζεται\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Για αργές συνδέσεις ή περιορισμένα δεδομένα, προτιμήστε μικρότερα αρχεία\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Για φωτογραφίες, προτιμήστε σύγχρονες μορφές με καλή συμπίεση\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Βελτιστοποίηση μπαταρίας και απόδοσης\r\n\r\n### Αποδοτική επεξεργασία εικόνων στην CPU\r\n\r\nΕλαχιστοποιήστε τη χρήση CPU κατά τις λειτουργίες εικόνας σε κινητά:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Παρακολούθηση κατάστασης μπαταρίας αν είναι διαθέσιμη\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Προσαρμόστε τη σύγχρονη επεξεργασία με βάση τις δυνατότητες της συσκευής\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Συντηρητική προσέγγιση για συσκευές χαμηλότερης κατηγορίας\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Μειώστε την ένταση επεξεργασίας σε χαμηλή μπαταρία\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Βελτιστοποίηση Core Web Vitals\r\n\r\n### Βελτιστοποίηση Largest Contentful Paint (LCP)\r\n\r\nΒελτιστοποιήστε το LCP για κινητές συσκευές:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Εντοπίστε εικόνες πάνω από το fold και δώστε τους προτεραιότητα\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Προσθέστε φόρτωση υψηλής προτεραιότητας\r\n            img.loading = 'eager';\r\n            \r\n            // Προφόρτωση αν είναι πιθανό να είναι LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Πρόληψη Cumulative Layout Shift (CLS)\r\n\r\nΑποτρέψτε μετατοπίσεις διάταξης σε κινητά:\r\n\r\n```css\r\n/* Containers αναλογίας διαστάσεων για πρόληψη CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading για πρόληψη CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Δοκιμή και παρακολούθηση\r\n\r\n### Δοκιμή απόδοσης εικόνων σε κινητά\r\n\r\nΟλοκληρωμένη δοκιμή απόδοσης εικόνων σε κινητά:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Παρακολούθηση απόδοσης φόρτωσης εικόνων\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Εξετάστε πιο επιθετική συμπίεση εικόνων');\r\n            recommendations.push('Υλοποιήστε προοδευτικό JPEG για μεγάλες εικόνες');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Αρχικοποίηση δοκιμαστή απόδοσης\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Συμπέρασμα\r\n\r\nΗ βελτιστοποίηση εικόνων για κινητά είναι μια πολυδιάστατη πρόκληση που απαιτεί κατανόηση των συνθηκών δικτύου, των δυνατοτήτων της συσκευής, της συμπεριφοράς των χρηστών και των μετρήσεων απόδοσης. Η επιτυχία εξαρτάται από την υλοποίηση προσαρμοστικών στρατηγικών που ανταποκρίνονται στους πραγματικούς περιορισμούς των κινητών, προσφέροντας παράλληλα την καλύτερη δυνατή οπτική εμπειρία.\r\n\r\nΒασικά σημεία για τη βελτιστοποίηση εικόνων σε κινητά:\r\n\r\n1. **Επίγνωση δικτύου**: Προσαρμόστε την ποιότητα εικόνας και τις στρατηγικές φόρτωσης με βάση την ταχύτητα σύνδεσης και τους περιορισμούς δεδομένων\r\n2. **Προσαρμογή στη συσκευή**: Λάβετε υπόψη την πυκνότητα οθόνης, την επεξεργαστική ισχύ και τη διάρκεια μπαταρίας\r\n3. **Προσέγγιση με έμφαση στην απόδοση**: Δώστε προτεραιότητα στα Core Web Vitals και στις μετρήσεις εμπειρίας χρήστη\r\n4. **Προοδευτική βελτίωση**: Εφαρμόστε βελτιστοποιήσεις από τη βασική λειτουργικότητα έως τις προηγμένες δυνατότητες\r\n5. **Συνεχής παρακολούθηση**: Τακτικός έλεγχος και παρακολούθηση απόδοσης διασφαλίζουν συνεχή βελτιστοποίηση\r\n\r\nΚαθώς η τεχνολογία κινητών εξελίσσεται, συμπεριλαμβανομένων των δικτύων 5G, της βελτιωμένης επεξεργαστικής ισχύος και των νέων μορφών εικόνας, είναι απαραίτητο να παραμένετε ενημερωμένοι με τις τεχνικές βελτιστοποίησης διατηρώντας παράλληλα τη συμβατότητα προς τα πίσω για την παροχή εξαιρετικών εμπειριών σε κινητά.\r\n\r\nΤο μέλλον της βελτιστοποίησης εικόνων για κινητά βρίσκεται σε έξυπνα, προσαρμοστικά συστήματα που προσαρμόζονται αυτόματα στο περιβάλλον του χρήστη, στις δυνατότητες της συσκευής και στις συνθήκες δικτύου, διατηρώντας παράλληλα την υψηλότερη δυνατή οπτική ποιότητα εντός αυτών των περιορισμών.\r\n","# Optimizacija slik za mobilne naprave: Popoln vodnik za zmogljivost\r\n\r\nMobilne naprave zdaj predstavljajo več kot 60 % svetovnega spletnega prometa, zato je optimizacija slik za mobilne naprave ključna za uporabniško izkušnjo, zmogljivost in poslovni uspeh. Mobilni uporabniki se soočajo z edinstvenimi izzivi, kot so omejena pasovna širina, raznolikost velikosti zaslonov in poraba baterije. Ta celovit vodnik pokriva napredne strategije, tehnike in orodja za optimizacijo slik na mobilnih napravah.\r\n\r\n## Zakaj je optimizacija slik za mobilne naprave pomembna\r\n\r\n### Vpliv na mobilno zmogljivost\r\n\r\nMobilna optimizacija neposredno vpliva na ključne metrike:\r\n- **Hitrost nalaganja strani**: slike pogosto predstavljajo 50–70 % teže strani\r\n- **Vključenost uporabnikov**: 53 % mobilnih uporabnikov zapusti strani, ki se nalagajo več kot 3 sekunde\r\n- **Poraba baterije**: neučinkovito nalaganje slik hitreje izprazni baterijo\r\n- **Poraba podatkov**: pomembno za uporabnike z omejenimi podatkovnimi paketi\r\n- **SEO uvrstitev**: Google mobile-first indeks daje prednost mobilni zmogljivosti\r\n\r\n### Izzivi, specifični za mobilno okolje\r\n\r\nMobilno okolje prinaša edinstvene izzive optimizacije:\r\n- **Spremenljive omrežne razmere**: od počasnega 2G do hitrega 5G\r\n- **Omejena procesorska moč**: mobilni procesorji so šibkejši od namiznih\r\n- **Omejitve pomnilnika**: mobilne naprave imajo omejen RAM\r\n- **Raznolikost zaslonov**: stotine velikosti in gostot zaslonov\r\n- **Zaslon na dotik**: drugačni vzorci interakcije kot na namizju\r\n\r\n## Razumevanje značilnosti prikaza na mobilnih napravah\r\n\r\n### Gostota zaslona in DPR\r\n\r\nRazmerje slikovnih pik naprave (DPR) vpliva na zahteve za slike:\r\n\r\n```javascript\r\n// Zaznaj razmerje slikovnih pik naprave\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Izračunaj optimalno velikost slike\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Primer uporabe\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Optimalna velikost: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Pogoste konfiguracije mobilnih zaslonov\r\n\r\n**Priljubljene ločljivosti mobilnih naprav:**\r\n- iPhone 14/15: 390x844 točk (1179x2556 pik, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 točk (1284x2778 pik, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 točk (1344x2992 pik, 3.25x DPR)\r\n- Google Pixel 8: 384x854 točk (1080x2400 pik, 2.8125x DPR)\r\n\r\n## Omrežno prilagodljiva optimizacija slik\r\n\r\n### Dostava glede na povezavo\r\n\r\nPrilagodite kakovost slike glede na hitrost povezave:\r\n\r\n```javascript\r\n// Omrežno prilagodljiv nalagalnik slik\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Privzeto\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Klasifikacija kakovosti omrežja\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Primer uporabe\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Implementacija odzivnih slik\r\n\r\n### Element picture za mobilne naprave\r\n\r\nNapredna implementacija odzivnih slik:\r\n\r\n```html\r\n\u003C!-- Popolna nastavitev odzivne slike -->\r\n\u003Cpicture>\r\n    \u003C!-- Zasloni z visoko ločljivostjo (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Standardni mobilni zasloni (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Fallback JPEG -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Končni fallback -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Opisni nadomestni tekst\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Progresivne strategije nalaganja\r\n\r\n### Lazy loading optimiziran za mobilne naprave\r\n\r\nUvedite učinkovito lazy loading za mobilne naprave:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Uporabite Intersection Observer, če je na voljo\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Začni nalaganje 50px pred vstopom v viewport\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Inicializiraj lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Optimizacija formata, specifična za mobilne naprave\r\n\r\n### Algoritem izbire formata\r\n\r\nIzberite optimalen format glede na zmožnosti mobilne naprave:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Vedno podprto\r\n            png: true   // Vedno podprto\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // Za počasne povezave ali varčevanje s podatki dajte prednost manjšim datotekam\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // Za fotografije dajte prednost sodobnim formatom z dobro kompresijo\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Optimizacija baterije in zmogljivosti\r\n\r\n### Učinkovita obdelava slik na CPU\r\n\r\nZmanjšajte uporabo CPU pri obdelavi slik na mobilnih napravah:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Spremljajte stanje baterije, če je mogoče\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Prilagodite sočasnost glede na zmožnosti naprave\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Za šibkejše naprave bodite konservativni\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Zmanjšajte intenzivnost pri nizki bateriji\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Optimizacija Core Web Vitals\r\n\r\n### Optimizacija Largest Contentful Paint (LCP)\r\n\r\nOptimizirajte LCP za mobilne naprave:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Prepoznajte slike nad pregibom in jim dajte prednost\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Naložite z visoko prioriteto\r\n            img.loading = 'eager';\r\n            \r\n            // Preload, če je verjetno LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Preprečevanje Cumulative Layout Shift (CLS)\r\n\r\nPreprečite premike postavitve na mobilnih napravah:\r\n\r\n```css\r\n/* Vsebniški razmerij za preprečevanje CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skeleton loading za preprečevanje CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Testiranje in spremljanje\r\n\r\n### Testiranje zmogljivosti slik na mobilnih napravah\r\n\r\nCelovito testiranje zmogljivosti slik na mobilnih napravah:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Spremljajte zmogljivost nalaganja slik\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Razmislite o bolj agresivni kompresiji slik');\r\n            recommendations.push('Uporabite progresivni JPEG za velike slike');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Inicializiraj tester zmogljivosti\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Zaključek\r\n\r\nOptimizacija slik za mobilne naprave je večplastni izziv, ki zahteva razumevanje omrežnih razmer, zmožnosti naprave, vedenja uporabnikov in metrik zmogljivosti. Uspeh je odvisen od uvedbe prilagodljivih strategij, ki upoštevajo dejanske omejitve mobilnega okolja in zagotavljajo najboljšo možno vizualno izkušnjo.\r\n\r\nKljučne točke optimizacije slik za mobilne naprave:\r\n\r\n1. **Zavedanje omrežja**: prilagodite kakovost in strategijo nalaganja glede na hitrost in omejitve podatkov\r\n2. **Prilagoditev napravi**: upoštevajte gostoto zaslona, procesorsko moč in baterijo\r\n3. **Osredotočenost na zmogljivost**: dajte prednost Core Web Vitals in uporabniškim metrikam\r\n4. **Postopno izboljševanje**: optimizirajte po plasteh, od osnovnih do naprednih funkcij\r\n5. **Nenehno spremljanje**: redno testirajte in spremljajte za ohranjanje optimizacije\r\n\r\nZ razvojem 5G, večjo procesorsko močjo in novimi formati slik je ključno, da ostanete na tekočem z optimizacijskimi tehnikami in zagotavljate združljivost za odlično mobilno izkušnjo.\r\n\r\nPrihodnost optimizacije slik za mobilne naprave je v inteligentnih, prilagodljivih sistemih, ki se samodejno prilagajajo okolju uporabnika, zmožnostim naprave in omrežnim razmeram ter v teh omejitvah ohranjajo najboljšo možno vizualno kakovost.\r\n","# Mobilbildeoptimalisering: Komplett ytelsesguide\r\n\r\nMobilenheter står nå for over 60 % av global nett-trafikk, noe som gjør optimalisering av bilder for mobil avgjørende for brukeropplevelse, ytelse og forretningssuksess. Mobilbrukere møter unike utfordringer som begrenset båndbredde, varierende skjermstørrelser og batteriforbruk. Denne omfattende guiden dekker avanserte strategier, teknikker og verktøy spesielt utviklet for å optimalisere bilder for mobile enheter.\r\n\r\n## Hvorfor mobilbildeoptimalisering er kritisk\r\n\r\n### Innvirkning på mobil ytelse\r\n\r\nMobiloptimalisering påvirker direkte nøkkelindikatorer:\r\n- **Sideinnlastingshastighet**: Bilder utgjør vanligvis 50–70 % av sidevekten\r\n- **Brukerengasjement**: 53 % av mobilbrukere forlater sider som tar mer enn 3 sekunder å laste\r\n- **Batteriforbruk**: Ineffektiv bildelasting tømmer batteriet raskere\r\n- **Databruk**: Viktig for brukere med begrensede dataplaner\r\n- **SEO-rangeringer**: Googles mobile-first-indeksering prioriterer mobil ytelse\r\n\r\n### Mobilspesifikke utfordringer\r\n\r\nMobilmiljøet gir unike optimaliseringsutfordringer:\r\n- **Varierende nettverksforhold**: Fra tregt 2G til raskt 5G\r\n- **Begrenset prosesseringskraft**: Mobil-CPU-er er mindre kraftige enn stasjonære\r\n- **Minnebegrensninger**: Mobile enheter har begrenset RAM\r\n- **Skjermmangfold**: Hundrevis av ulike skjermstørrelser og -tettheter\r\n- **Berøringsgrensesnitt**: Andre interaksjonsmønstre enn på desktop\r\n\r\n## Forstå mobilskjermens egenskaper\r\n\r\n### Skjermtetthet og DPR\r\n\r\nEnhetens pikselforhold (DPR) påvirker bildekravene:\r\n\r\n```javascript\r\n// Oppdag enhetens pikselforhold\r\nfunction getDevicePixelRatio() {\r\n    return window.devicePixelRatio || 1;\r\n}\r\n\r\n// Beregn optimal bildestørrelse\r\nfunction getOptimalImageSize(baseWidth, baseHeight) {\r\n    const dpr = getDevicePixelRatio();\r\n    return {\r\n        width: Math.ceil(baseWidth * dpr),\r\n        height: Math.ceil(baseHeight * dpr)\r\n    };\r\n}\r\n\r\n// Eksempel på bruk\r\nconst optimalSize = getOptimalImageSize(320, 240);\r\nconsole.log(`Optimal størrelse: ${optimalSize.width}x${optimalSize.height}`);\r\n```\r\n\r\n### Vanlige mobilskjermkonfigurasjoner\r\n\r\n**Populære mobiloppløsninger:**\r\n- iPhone 14/15: 390x844 punkter (1179x2556 piksler, 3x DPR)\r\n- iPhone 14/15 Plus: 428x926 punkter (1284x2778 piksler, 3x DPR)\r\n- Samsung Galaxy S24: 412x915 punkter (1344x2992 piksler, 3.25x DPR)\r\n- Google Pixel 8: 384x854 punkter (1080x2400 piksler, 2.8125x DPR)\r\n\r\n## Nettverksbevisst bildeoptimalisering\r\n\r\n### Levering basert på tilkobling\r\n\r\nJuster bildekvalitet basert på tilkoblingshastighet:\r\n\r\n```javascript\r\n// Nettverksbevisst bildelaster\r\nclass NetworkAwareImageLoader {\r\n    constructor() {\r\n        this.connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\r\n        this.networkType = this.getNetworkType();\r\n    }\r\n    \r\n    getNetworkType() {\r\n        if (!this.connection) return '4g'; // Standardantakelse\r\n        \r\n        const effectiveType = this.connection.effectiveType;\r\n        const downlink = this.connection.downlink;\r\n        \r\n        // Kategoriser nettverkskvalitet\r\n        if (effectiveType === 'slow-2g' || downlink \u003C 0.5) return 'slow';\r\n        if (effectiveType === '2g' || downlink \u003C 1.5) return '2g';\r\n        if (effectiveType === '3g' || downlink \u003C 10) return '3g';\r\n        return '4g';\r\n    }\r\n    \r\n    getOptimalImageSrc(basePath, imageName) {\r\n        const qualityMap = {\r\n            'slow': { quality: 60, width: 480 },\r\n            '2g': { quality: 70, width: 640 },\r\n            '3g': { quality: 80, width: 800 },\r\n            '4g': { quality: 85, width: 1200 }\r\n        };\r\n        \r\n        const settings = qualityMap[this.networkType];\r\n        return `${basePath}/${imageName}_w${settings.width}_q${settings.quality}.jpg`;\r\n    }\r\n}\r\n\r\n// Bruk\r\nconst imageLoader = new NetworkAwareImageLoader();\r\nconst imageSrc = imageLoader.getOptimalImageSrc('/images', 'hero-image');\r\n```\r\n\r\n## Implementering av responsive bilder\r\n\r\n### Picture-element for mobil\r\n\r\nAvansert implementering av responsive bilder:\r\n\r\n```html\r\n\u003C!-- Komplett responsivt bildesett -->\r\n\u003Cpicture>\r\n    \u003C!-- Høyoppløselige mobilskjermer (2x-3x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px) and (-webkit-min-device-pixel-ratio: 2)\"\r\n            srcset=\"image-mobile-1080w.webp 1080w,\r\n                    image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- Standard mobilskjermer (1x-2x DPR) -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.webp 720w,\r\n                    image-mobile-480w.webp 480w,\r\n                    image-mobile-320w.webp 320w\"\r\n            sizes=\"100vw\"\r\n            type=\"image/webp\">\r\n    \r\n    \u003C!-- JPEG-fallback -->\r\n    \u003Csource media=\"(max-width: 767px)\"\r\n            srcset=\"image-mobile-720w.jpg 720w,\r\n                    image-mobile-480w.jpg 480w,\r\n                    image-mobile-320w.jpg 320w\"\r\n            sizes=\"100vw\">\r\n    \r\n    \u003C!-- Siste fallback -->\r\n    \u003Cimg src=\"image-mobile-480w.jpg\" \r\n         alt=\"Beskrivende alt-tekst\"\r\n         width=\"480\" \r\n         height=\"320\"\r\n         loading=\"lazy\">\r\n\u003C/picture>\r\n```\r\n\r\n## Progressiv lastestrategi\r\n\r\n### Mobiloptimalisert lazy loading\r\n\r\nImplementer effektiv lazy loading for mobil:\r\n\r\n```javascript\r\nclass MobileLazyLoader {\r\n    constructor() {\r\n        this.intersectionObserver = null;\r\n        this.loadedImages = new Set();\r\n        this.init();\r\n    }\r\n    \r\n    init() {\r\n        // Bruk intersection observer hvis tilgjengelig\r\n        if ('IntersectionObserver' in window) {\r\n            this.intersectionObserver = new IntersectionObserver(\r\n                this.handleIntersection.bind(this),\r\n                {\r\n                    rootMargin: '50px 0px', // Start lasting 50px før synlighet\r\n                    threshold: 0.01\r\n                }\r\n            );\r\n            \r\n            this.observeImages();\r\n        }\r\n    }\r\n    \r\n    observeImages() {\r\n        const lazyImages = document.querySelectorAll('img[data-src], picture source[data-srcset]');\r\n        lazyImages.forEach(img => {\r\n            this.intersectionObserver.observe(img);\r\n        });\r\n    }\r\n    \r\n    handleIntersection(entries) {\r\n        entries.forEach(entry => {\r\n            if (entry.isIntersecting) {\r\n                this.loadImage(entry.target);\r\n                this.intersectionObserver.unobserve(entry.target);\r\n            }\r\n        });\r\n    }\r\n    \r\n    loadImage(element) {\r\n        if (this.loadedImages.has(element)) return;\r\n        \r\n        if (element.tagName === 'IMG') {\r\n            if (element.dataset.src) {\r\n                element.src = element.dataset.src;\r\n            }\r\n            if (element.dataset.srcset) {\r\n                element.srcset = element.dataset.srcset;\r\n            }\r\n        }\r\n        \r\n        element.classList.add('loaded');\r\n        this.loadedImages.add(element);\r\n    }\r\n}\r\n\r\n// Initialiser lazy loader\r\nconst lazyLoader = new MobileLazyLoader();\r\n```\r\n\r\n## Mobilspesifikk formatoptimalisering\r\n\r\n### Formatvalg-algoritme\r\n\r\nVelg optimalt format basert på mobilens egenskaper:\r\n\r\n```javascript\r\nclass MobileFormatOptimizer {\r\n    constructor() {\r\n        this.supportedFormats = this.detectSupportedFormats();\r\n        this.deviceCapabilities = this.analyzeDeviceCapabilities();\r\n    }\r\n    \r\n    detectSupportedFormats() {\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 1;\r\n        canvas.height = 1;\r\n        \r\n        return {\r\n            webp: canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0,\r\n            avif: canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0,\r\n            jpeg: true, // Alltid støttet\r\n            png: true   // Alltid støttet\r\n        };\r\n    }\r\n    \r\n    selectOptimalFormat(imageType = 'photo') {\r\n        const { isSlowConnection, isLimitedData } = this.deviceCapabilities;\r\n        \r\n        // For trege forbindelser eller databegrensning, foretrekk mindre filer\r\n        if (isSlowConnection || isLimitedData) {\r\n            if (this.supportedFormats.avif) return 'avif';\r\n            if (this.supportedFormats.webp) return 'webp';\r\n            return 'jpeg';\r\n        }\r\n        \r\n        // For bilder, foretrekk moderne formater med god komprimering\r\n        if (this.supportedFormats.avif) return 'avif';\r\n        if (this.supportedFormats.webp) return 'webp';\r\n        return 'jpeg';\r\n    }\r\n}\r\n```\r\n\r\n## Batteri- og ytelsesoptimalisering\r\n\r\n### CPU-effektiv bildebehandling\r\n\r\nMinimer mobilens CPU-bruk ved bildeoperasjoner:\r\n\r\n```javascript\r\nclass BatteryEfficientImageLoader {\r\n    constructor() {\r\n        this.processingQueue = [];\r\n        this.maxConcurrent = this.getOptimalConcurrency();\r\n        \r\n        // Overvåk batteristatus hvis tilgjengelig\r\n        if ('getBattery' in navigator) {\r\n            navigator.getBattery().then(battery => {\r\n                this.battery = battery;\r\n                this.adaptToBatteryLevel();\r\n            });\r\n        }\r\n    }\r\n    \r\n    getOptimalConcurrency() {\r\n        // Tilpass samtidighet etter enhetens egenskaper\r\n        const cores = navigator.hardwareConcurrency || 4;\r\n        const memory = navigator.deviceMemory || 4;\r\n        \r\n        // Konservativ tilnærming for svakere enheter\r\n        if (memory \u003C 4 || cores \u003C 4) return 1;\r\n        if (memory \u003C 8 || cores \u003C 8) return 2;\r\n        return 3;\r\n    }\r\n    \r\n    adaptToBatteryLevel() {\r\n        if (!this.battery) return;\r\n        \r\n        const batteryLevel = this.battery.level;\r\n        const isCharging = this.battery.charging;\r\n        \r\n        // Reduser prosesseringsintensitet ved lavt batteri\r\n        if (batteryLevel \u003C 0.2 && !isCharging) {\r\n            this.maxConcurrent = Math.max(1, Math.floor(this.maxConcurrent / 2));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Core Web Vitals-optimalisering\r\n\r\n### Largest Contentful Paint (LCP)-optimalisering\r\n\r\nOptimaliser LCP for mobile enheter:\r\n\r\n```javascript\r\nclass MobileLCPOptimizer {\r\n    constructor() {\r\n        this.lcpElement = null;\r\n        this.observeLCP();\r\n        this.optimizeAboveFoldImages();\r\n    }\r\n    \r\n    observeLCP() {\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            const lastEntry = entries[entries.length - 1];\r\n            \r\n            this.lcpElement = lastEntry.element;\r\n            this.optimizeLCPElement();\r\n        }).observe({ entryTypes: ['largest-contentful-paint'] });\r\n    }\r\n    \r\n    optimizeAboveFoldImages() {\r\n        // Identifiser bilder over folden og prioriter dem\r\n        const aboveFoldImages = this.getAboveFoldImages();\r\n        \r\n        aboveFoldImages.forEach(img => {\r\n            // Legg til høy prioritet for lasting\r\n            img.loading = 'eager';\r\n            \r\n            // Forhåndslast hvis sannsynlig LCP\r\n            if (this.isLikelyLCP(img)) {\r\n                this.preloadImage(img);\r\n            }\r\n        });\r\n    }\r\n    \r\n    getAboveFoldImages() {\r\n        const viewportHeight = window.innerHeight;\r\n        const images = document.querySelectorAll('img');\r\n        \r\n        return Array.from(images).filter(img => {\r\n            const rect = img.getBoundingClientRect();\r\n            return rect.top \u003C viewportHeight;\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Forebygging av Cumulative Layout Shift (CLS)\r\n\r\nForhindre layoutskift på mobil:\r\n\r\n```css\r\n/* Forholdskontainere for å forhindre CLS */\r\n.aspect-ratio-container {\r\n    position: relative;\r\n    width: 100%;\r\n    height: 0;\r\n}\r\n\r\n.aspect-ratio-16-9 {\r\n    padding-bottom: 56.25%; /* 9/16 = 0.5625 */\r\n}\r\n\r\n.aspect-ratio-container img {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    object-fit: cover;\r\n}\r\n\r\n/* Skjelettlasting for å forhindre CLS */\r\n.image-skeleton {\r\n    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\r\n    background-size: 200% 100%;\r\n    animation: loading 1.5s infinite;\r\n}\r\n\r\n@keyframes loading {\r\n    0% { background-position: 200% 0; }\r\n    100% { background-position: -200% 0; }\r\n}\r\n```\r\n\r\n## Testing og overvåking\r\n\r\n### Testing av mobil bildeytelse\r\n\r\nOmfattende testing av bildeytelse på mobil:\r\n\r\n```javascript\r\nclass MobileImagePerformanceTester {\r\n    constructor() {\r\n        this.metrics = {\r\n            loadTimes: [],\r\n            fileSizes: [],\r\n            renderTimes: [],\r\n            networkUsage: []\r\n        };\r\n        \r\n        this.startMonitoring();\r\n    }\r\n    \r\n    startMonitoring() {\r\n        // Overvåk bildeinnlastingsytelse\r\n        new PerformanceObserver((list) => {\r\n            const entries = list.getEntries();\r\n            entries.forEach(entry => {\r\n                if (entry.name.match(/\\.(jpg|jpeg|png|webp|avif)$/i)) {\r\n                    this.recordImageMetrics(entry);\r\n                }\r\n            });\r\n        }).observe({ entryTypes: ['resource'] });\r\n    }\r\n    \r\n    recordImageMetrics(entry) {\r\n        this.metrics.loadTimes.push({\r\n            url: entry.name,\r\n            loadTime: entry.responseEnd - entry.requestStart,\r\n            size: entry.transferSize,\r\n            timestamp: entry.startTime\r\n        });\r\n    }\r\n    \r\n    generateReport() {\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        const totalDataUsage = this.metrics.loadTimes.reduce((sum, m) => sum + m.size, 0);\r\n        \r\n        return {\r\n            averageImageLoadTime: avgLoadTime,\r\n            totalImageDataUsage: totalDataUsage,\r\n            imageCount: this.metrics.loadTimes.length,\r\n            recommendations: this.generateRecommendations()\r\n        };\r\n    }\r\n    \r\n    generateRecommendations() {\r\n        const recommendations = [];\r\n        const avgLoadTime = this.calculateAverage(this.metrics.loadTimes.map(m => m.loadTime));\r\n        \r\n        if (avgLoadTime > 1000) {\r\n            recommendations.push('Vurder mer aggressiv bildekomprimering');\r\n            recommendations.push('Implementer progressiv JPEG for store bilder');\r\n        }\r\n        \r\n        return recommendations;\r\n    }\r\n    \r\n    calculateAverage(values) {\r\n        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;\r\n    }\r\n}\r\n\r\n// Initialiser ytelsestester\r\nconst performanceTester = new MobileImagePerformanceTester();\r\n```\r\n\r\n## Konklusjon\r\n\r\nMobilbildeoptimalisering er en sammensatt utfordring som krever forståelse av nettverksforhold, enhetsegenskaper, brukeradferd og ytelsesindikatorer. Suksess avhenger av å implementere adaptive strategier som svarer på reelle mobilbegrensninger og samtidig gir best mulig visuell opplevelse.\r\n\r\nNøkkelpunkter for mobilbildeoptimalisering:\r\n\r\n1. **Nettverksbevissthet**: Juster bildekvalitet og lastestrategier etter tilkoblingshastighet og databegrensninger\r\n2. **Enhetstilpasning**: Ta hensyn til skjermtetthet, prosesseringskraft og batterilevetid i optimaliseringsbeslutninger\r\n3. **Ytelsesfokusert tilnærming**: Prioriter Core Web Vitals og brukeropplevelsesindikatorer\r\n4. **Progressiv forbedring**: Lag optimaliseringer fra grunnleggende funksjonalitet til avanserte funksjoner\r\n5. **Kontinuerlig overvåking**: Regelmessig testing og ytelsesovervåking sikrer vedvarende optimalisering\r\n\r\nEtter hvert som mobilteknologi utvikler seg, inkludert 5G-nettverk, forbedret prosesseringskraft og nye bildeformater, er det avgjørende å holde seg oppdatert på optimaliseringsteknikker og samtidig opprettholde bakoverkompatibilitet for å levere enestående mobilopplevelser.\r\n\r\nFremtiden for mobilbildeoptimalisering ligger i intelligente, adaptive systemer som automatisk tilpasser seg brukerens miljø, enhetsegenskaper og nettverksforhold, samtidig som de opprettholder høyest mulig visuell kvalitet innenfor disse begrensningene.\r\n",1772179186660]