वैरिएबल पिक्सल डेंसिटी के लिए ज़्यादा डीपीआई इमेज

बोरिस स्मस
बोरिस स्मस

आज के दौर में डिवाइस लैंडस्केप की एक जटिल सुविधा यह है कि स्क्रीन पिक्सल डेंसिटी की बहुत ज़्यादा रेंज उपलब्ध है. कुछ डिवाइस में बहुत ही हाई रिज़ॉल्यूशन डिसप्ले होते हैं, जबकि कुछ डिवाइस के पीछे पीछे चलते हैं. ऐप्लिकेशन डेवलपर को अलग-अलग पिक्सल डेंसिटी का समर्थन करना होगा, जो काफ़ी चुनौती भरा हो सकता है. मोबाइल वेब पर, चुनौतियां कई चीज़ों से जुड़ी होती हैं:

  • अलग-अलग नाप या आकार वाले डिवाइसों की बड़ी रेंज.
  • सीमित नेटवर्क बैंडविड्थ और बैटरी लाइफ़.

इमेज के बारे में बात करें, तो वेब ऐप्लिकेशन डेवलपर का लक्ष्य सबसे अच्छी क्वालिटी की इमेज को ज़्यादा से ज़्यादा असरदार तरीके से दिखाना है. इस लेख में, आज और आने वाले समय में ऐसा करने की कुछ तकनीकों के बारे में बताया गया है.

अगर हो सके, तो इमेज अपलोड करने से बचें

वर्म का यह कैन खोलने से पहले, याद रखें कि वेब में कई ऐसी बेहतरीन टेक्नोलॉजी हैं जो काफ़ी हद तक रिज़ॉल्यूशन और डीपीआई से स्वतंत्र हैं. खास तौर पर, वेब पर अपने-आप पिक्सल स्केलिंग करने की सुविधा (devicePixelRatio) की वजह से, टेक्स्ट, SVG, और कई सीएसएस "सिर्फ़ काम" करेंगी.

हालांकि, रास्टर इमेज से हमेशा बचा नहीं जा सकता. उदाहरण के लिए, आपको ऐसी एसेट दी जा सकती हैं जिन्हें सिर्फ़ SVG/सीएसएस में कॉपी करना मुश्किल होगा या आपको किसी फ़ोटोग्राफ़ के साथ काम करना होगा. इमेज को अपने-आप SVG में बदला जा सकता है, लेकिन वेक्टराइज़ करने वाले फ़ोटो लेने से बहुत मदद मिलती है. क्योंकि बड़े किए गए वर्शन आम तौर पर अच्छे नहीं दिखते.

बैकग्राउंड

डिसप्ले सघनता का बहुत कम इतिहास

शुरुआत में, कंप्यूटर डिसप्ले की पिक्सल सघनता 72 या 96 डीपीआई (डॉट प्रति इंच) थी.

पिक्सल डेंसिटी के हिसाब से डिसप्ले धीरे-धीरे बेहतर होते जाते हैं. ज़्यादातर मामलों में मोबाइल का इस्तेमाल किया जाता है. इस दौरान उपयोगकर्ता आम तौर पर अपना फ़ोन अपने चेहरे के करीब रखते हैं, जिससे पिक्सल ज़्यादा दिखने लगते हैं. साल 2008 तक, 150 डीपीआई फ़ोन नए मानक बन चुके थे. डिसप्ले सघनता में बढ़ोतरी का रुझान जारी रहा. साथ ही, आज-कल के नए फ़ोन में 300 डीपीआई डिसप्ले (Apple की "Retina" ब्रैंड की गई) है.

होली ग्रेल, एक तरह का डिसप्ले है जिसमें पिक्सल पूरी तरह से दिखते नहीं हैं. फ़ोन के नाप या आकार के लिए, Retina/HiDPI डिसप्ले की मौजूदा जनरेशन, सही तरीके से काम कर सकती है. हालांकि, Project Glass जैसे हार्डवेयर और पहने जाने वाले डिवाइसों की नई क्लास से, Pixel की डेंसिटी बढ़ती रहेगी.

व्यावहारिक तौर पर, कम सघनता वाली इमेज पुरानी स्क्रीन की तरह ही नई स्क्रीन पर दिखने चाहिए लेकिन ज़्यादा सघनता वाली इमेज के मुकाबले ज़्यादा ज़्यादा डेंसिटी वाली तस्वीरें देखने वाले उपयोगकर्ता को देखते हैं, लेकिन कम सघनता वाली इमेज मुश्किल और पिक्सलेट दिखती हैं. इस उदाहरण में बताया गया है कि 1x इमेज को 2x डिसप्ले पर कैसा दिखेगा. इसके उलट, 2x इमेज बहुत अच्छी दिखती है.

बबून 1x
बबून 2x
बबून! अलग-अलग पिक्सल डेंसिटी पर.

वेब पर पिक्सल

जब वेब को डिज़ाइन किया गया था, तब 99% डिसप्ले 96 डीपीआई (या ऐसा ऐसा होने के बारे में अनुमान था) के थे. इस हिस्से में बदलाव के लिए कुछ ही प्रावधान किए गए थे. स्क्रीन के साइज़ और डेंसिटी में बहुत ज़्यादा बदलाव होने की वजह से, हमें अलग-अलग स्क्रीन डेंसिटी और डाइमेंशन में इमेज अच्छी दिखाने के लिए, स्टैंडर्ड तरीके की ज़रूरत होती है.

एचटीएमएल स्पेसिफ़िकेशन ने हाल ही में एक रेफ़रंस पिक्सल तय करके इस समस्या को हल किया है. इस पिक्सल का इस्तेमाल करके मैन्युफ़ैक्चरर, सीएसएस पिक्सल का साइज़ तय करते हैं.

रेफ़रंस पिक्सल का इस्तेमाल करके मैन्युफ़ैक्चरर, स्टैंडर्ड या आदर्श पिक्सल के मुकाबले डिवाइस के फ़िज़िकल पिक्सल का साइज़ तय कर सकता है. इस अनुपात को डिवाइस पिक्सल रेशियो कहा जाता है.

डिवाइस पिक्सल का अनुपात कैलकुलेट किया जा रहा है

मान लीजिए कि किसी स्मार्ट फ़ोन की स्क्रीन में 180 पिक्सल प्रति इंच (ppi) वाला फ़िज़िकल पिक्सल साइज़ होता है. डिवाइस पिक्सल रेशियो को कैलकुलेट करने के लिए तीन चरण होते हैं:

  1. देखें कि रेफ़रंस पिक्सल की असल दूरी पर डिवाइस को कितनी दूरी पर रखा गया है.

    स्पेसिफ़िकेशन के मुताबिक, हमें पता है कि 28 इंच का साइज़ 96 पिक्सल प्रति इंच होता है. हालांकि, यह स्मार्ट फ़ोन है, इसलिए लोग लैपटॉप के मुकाबले डिवाइस को अपने चेहरे के पास पकड़कर रखते हैं. मान लेते हैं कि दूरी 18 इंच है.

  2. तय की गई दूरी के लिए सबसे सही पिक्सल डेंसिटी पाने के लिए, स्टैंडर्ड डेंसिटी (96ppi) से दूरी के अनुपात को गुणा करें.

    आदर्शPixel डेंसिटी = (28/18) * 96 = 150 पिक्सल प्रति इंच (करीब)

  3. यह जानने के लिए कि डिवाइस पिक्सल का रेशियो क्या है, फ़िज़िकल पिक्सल डेंसिटी का अनुपात आदर्श पिक्सल डेंसिटी रखें.

    devicePixelRatio = 180/150 = 1.2

devicePixelRatio को कैलकुलेट करने का तरीका.
एक डायग्राम में ऐंगुलर पिक्सल का एक रेफ़रंस दिया गया है. इससे यह दिखाया जा सकता है कि devicePixelRatio को कैसे कैलकुलेट किया जाता है.

इसलिए, अब जब किसी ब्राउज़र को यह जानने की ज़रूरत होती है कि इमेज को आदर्श या स्टैंडर्ड रिज़ॉल्यूशन के हिसाब से स्क्रीन पर फ़िट करने के लिए, इमेज का साइज़ कैसे बदलना है, तो ब्राउज़र का मतलब डिवाइस पिक्सल रेशियो 1.2 है. इसका मतलब है कि हर आदर्श पिक्सल के लिए, इस डिवाइस में 1.2 फ़िज़िकल पिक्सल हैं. आदर्श (जैसा कि वेब की जानकारी में बताया गया है) और फ़िज़िकल (डिवाइस स्क्रीन पर मौजूद बिंदु) पिक्सल के बीच जाने का फ़ॉर्मूला इस तरह है:

physicalPixels = window.devicePixelRatio * idealPixels

अब तक, डिवाइस वेंडर devicePixelRatios (डीपीआर) को राउंड ऑफ़ करते रहे हैं. Apple के iPhone और iPad के लिए 1 का DPR है और उसकी Retina की रिपोर्ट 2 है. सीएसएस की खास बातें में सुझाव दिया गया है कि

पिक्सल यूनिट, डिवाइस के उन पिक्सल की पूरी संख्या को दिखाती है जो रेफ़रंस पिक्सल का सबसे सही अनुमान लगाते हैं.

गोल अनुपातों के बेहतर होने की एक वजह यह है कि उनमें सब-पिक्सल आर्टफ़ैक्ट की संख्या कम हो सकती है.

हालांकि, डिवाइस की असल दुनिया में काफ़ी अंतर है और Android फ़ोन में अक्सर 1.5 का डीपीआर होता है. Nexus 7 टैबलेट का DPR ~1.33 का है, जो ऊपर बताए गए तरीके से मिलती-जुलती है. आने वाले समय में, वैरिएबल DPR वाले और डिवाइस देखने को मिल सकते हैं. इस वजह से, आपको यह कभी नहीं मानना चाहिए कि आपके क्लाइंट के पास पूर्णांक DPR होंगे.

HiDPI इमेज तकनीक की खास जानकारी

सबसे अच्छी क्वालिटी वाली इमेज को जल्द से जल्द दिखाने की समस्या को हल करने की ऐसी कई तकनीकें हैं जिन्हें आम तौर पर इन दो कैटगरी में बांटा जाता है:

  1. एक इमेज को ऑप्टिमाइज़ करना और
  2. कई इमेज के बीच चुने जाने को ऑप्टिमाइज़ किया जा रहा है.

एक इमेज बनाने का तरीका: एक इमेज का इस्तेमाल करें, लेकिन इसके साथ समझदारी से काम करें. इन तरीकों की एक खासियत यह है कि इससे डिवाइस की परफ़ॉर्मेंस कम हो जाती है. ऐसा इसलिए होता है, क्योंकि कम डीपीआई वाले पुराने डिवाइसों पर भी HiDPI इमेज डाउनलोड की जाती हैं. यहां एक इमेज वाले केस के लिए कुछ तरीके बताए गए हैं:

  • बहुत ज़्यादा कंप्रेस की गई HiDPI इमेज
  • बिलकुल शानदार इमेज फ़ॉर्मैट
  • प्रोग्रेसिव इमेज फ़ॉर्मैट

इमेज इस्तेमाल करने के कई तरीके हैं: कई इमेज का इस्तेमाल करें, लेकिन लोड करने के लिए इमेज चुनें. इन तरीकों में डेवलपर को एक ही एसेट के कई वर्शन बनाने और फ़ैसले की रणनीति तय करने की ज़रूरत होती है. विकल्प यहां दिए गए हैं:

  • JavaScript
  • सर्वर साइड डिलीवरी
  • सीएसएस मीडिया क्वेरी
  • पहले से मौजूद ब्राउज़र की सुविधाएं (image-set(), <img srcset>)

बहुत ज़्यादा कंप्रेस की गई HiDPI इमेज

इमेज में पहले से ही एक औसत वेबसाइट डाउनलोड करने में 60% बैंडविड्थ का ही खर्च होता है. सभी क्लाइंट को HiDPI इमेज दिखाकर, हम इस संख्या को बढ़ा देंगे. यह कितना बड़ा हो जाएगा?

मैंने कुछ टेस्ट किए, जिनसे JPEG क्वालिटी वाले 1x और 2x इमेज फ़्रैगमेंट 90, 50, और 20 पर मिले. यह रही शेल स्क्रिप्ट जिसका इस्तेमाल मैंने (ImageMagick को लागू करने के लिए) उन्हें जनरेट करने के लिए किया था:

टाइल का पहला उदाहरण. टाइल का दूसरा उदाहरण. टाइल का तीसरा उदाहरण.
अलग-अलग कंप्रेशन और पिक्सल डेंसिटी पर इमेज के सैंपल.

इस छोटी, अवैज्ञानिक सैंपलिंग से, ऐसा लगता है कि बड़ी इमेज को कंप्रेस करने से क्वालिटी के हिसाब से एक जैसा फ़ायदा मिलता है. मेरी नज़र में, बहुत ज़्यादा कंप्रेस की गई 2x तस्वीरें, बिना कंप्रेस की गई 1x तस्वीरों से बेहतर दिखती हैं.

हालांकि, दो गुना या उससे ज़्यादा डिवाइसों पर हल्की क्वालिटी वाली और ज़्यादा कंप्रेस की गई 2x इमेज दिखाना, अच्छी क्वालिटी वाली इमेज दिखाने से खराब होता है. साथ ही, ऊपर बताए गए तरीके को अपनाने पर, इमेज क्वालिटी पर जुर्माना लगाया जाता है. अगर क्वालिटी की तुलना 90 इमेज और क्वालिटी: 20 इमेज से की जाती है, तो आपको साफ़ इमेज में गिरावट दिखेगी. साथ ही, इमेज का धुंधलापन बढ़ जाएगा. ये आर्टफ़ैक्ट उन मामलों में स्वीकार नहीं किए जा सकते हैं जिनके लिए अच्छी क्वालिटी वाली इमेज अहम होती हैं (उदाहरण के लिए, फ़ोटो व्यूअर ऐप्लिकेशन) या फिर उन ऐप्लिकेशन डेवलपर के लिए स्वीकार नहीं किए जाते जो समझौता करने के लिए तैयार नहीं हैं.

ऊपर बताई गई तुलना, पूरी तरह कंप्रेस किए गए JPEG फ़ॉर्मैट की मदद से की गई है. ध्यान दें कि ज़्यादातर जगहों पर इस्तेमाल किए जाने वाले इमेज फ़ॉर्मैट (JPEG, PNG, GIF) में कई अंतर हैं. इन वजहों से हमें यहां...

बिलकुल शानदार इमेज फ़ॉर्मैट

WebP, बेहतरीन इमेज फ़ॉर्मैट है. यह इमेज की क्वालिटी को बनाए रखते हुए, बहुत अच्छी तरह कंप्रेस करता है. बेशक, इसे अभी तक हर जगह लागू नहीं किया गया है!

JavaScript के ज़रिए यह पता लगाना है कि WebP काम कर रहा है या नहीं. data-uri की मदद से 1px की इमेज लोड करनी होती है, लोड होने या गड़बड़ी वाले इवेंट ट्रिगर होने का इंतज़ार करना होता है, और फिर पुष्टि करना है कि साइज़ सही है. मॉडर्निज़र, ऐसी सुविधा का पता लगाने वाली स्क्रिप्ट के साथ शिपिंग करता है, जो Modernizr.webp पर उपलब्ध होती है.

हालांकि, ऐसा करने का एक बेहतर तरीका सीधे सीएसएस में image() फ़ंक्शन का इस्तेमाल करना है. इसलिए, अगर आपके पास WebP इमेज और JPEG फ़ॉलबैक है, तो यह लिखा जा सकता है:

#pic {
  background: image("foo.webp", "foo.jpg");
}

इस तरीके में कुछ समस्याएं हैं. पहली बात, image() को बड़े पैमाने पर लागू नहीं किया गया है. दूसरी वजह यह है कि WebP फ़ॉर्मैट में कंप्रेस करने की सुविधा JPEG को बेहतर बनाती है, फिर भी यह पहले के मुकाबले 30% कम है. WebP गैलरी के आधार पर यह सुधार 30% कम है. इसलिए, हाई डीपीआई की समस्या को हल करने के लिए WebP सिर्फ़ काफ़ी नहीं होता.

प्रोग्रेसिव इमेज फ़ॉर्मैट

JPEG 2000, प्रोग्रेसिव JPEG, PNG, और GIF जैसे प्रोग्रेसिव इमेज फ़ॉर्मैट में, इमेज के पूरी तरह से लोड होने से पहले ही सही जगह पर दिखने की कुछ हद तक बहस होती है. ये सिर पर कुछ बड़े खर्चे आ सकते हैं, हालांकि, इस बात के सबूत मौजूद हैं. जेफ़ एटवुड का दावा किया कि प्रोग्रेसिव मोड "इमेज का साइज़ बदलने के लिए करीब 20% और JPEG या GIF इमेज का साइज़ करीब 10% बढ़ाता है". हालांकि, स्टोयन स्टेफ़ानोव ने दावा किया कि बड़ी फ़ाइलों के लिए, प्रोग्रेसिव मोड ज़्यादा असरदार होता है (ज़्यादातर मामलों में).

पहली नज़र में, बेहतरीन क्वालिटी की इमेज को तेज़ी से दिखाने के मामले में प्रोग्रेसिव इमेज काफ़ी शानदार दिखती हैं. इसका मतलब है कि जब ब्राउज़र को यह पता चल जाता है कि अतिरिक्त डेटा से इमेज क्वालिटी नहीं बढ़ेगी, तो वह इमेज डाउनलोड और डिकोड करना बंद कर देगा. उदाहरण के लिए, फ़िडेलिटी में किए गए सभी सुधार सब-पिक्सल में किए जाते हैं.

कनेक्शन खत्म करना आसान होता है, लेकिन अक्सर इन्हें फिर से शुरू करना महंगा होता है. कई इमेज वाली साइट के लिए, सबसे अच्छा तरीका यह है कि किसी एक एचटीटीपी कनेक्शन को चालू रखा जाए और ज़्यादा से ज़्यादा समय के लिए उसका फिर से इस्तेमाल किया जाए. अगर एक इमेज को अच्छी तरह डाउनलोड कर लेने की वजह से कनेक्शन समय से पहले खत्म हो जाता है, तो ब्राउज़र को एक नया कनेक्शन बनाना होगा, जो कम इंतज़ार के माहौल में धीमा हो सकता है.

इसका एक तरीका यह है कि आप एचटीटीपी रेंज अनुरोध का इस्तेमाल करें. इससे ब्राउज़र, फ़ेच करने के लिए बाइट की रेंज तय कर सकते हैं. स्मार्ट ब्राउज़र हेडर पर जाने के लिए एक head अनुरोध बना सकता है, उसे प्रोसेस कर सकता है, यह तय कर सकता है कि असल में कितनी इमेज की ज़रूरत है, और फिर उसे फ़ेच कर सकता है. माफ़ करें, वेब सर्वर पर एचटीटीपी रेंज सही तरीके से काम नहीं करती. इसलिए, यह तरीका काम नहीं करता.

आखिर में, इस तरीके की एक खास सीमा यह है कि आपको लोड करने के लिए इमेज नहीं चुननी होती, सिर्फ़ एक ही इमेज की अलग-अलग फ़िडेलिटी होती है. इस वजह से, यह "कला के निर्देश" के इस्तेमाल के उदाहरण से जुड़ी समस्या को हल नहीं करता.

JavaScript का इस्तेमाल करके तय करें कि कौनसी इमेज लोड करनी है

कौनसी इमेज लोड करनी है, यह तय करने का पहला और सबसे आसान तरीका क्लाइंट में JavaScript का इस्तेमाल करना है. इस तरीके से, आपको अपने उपयोगकर्ता एजेंट के बारे में सब कुछ पता करने और सही काम करने में मदद मिलती है. window.devicePixelRatio की मदद से, डिवाइस पिक्सल का अनुपात तय किया जा सकता है स्क्रीन की चौड़ाई और लंबाई देखी जा सकती है. साथ ही, navigator.कनेक्शन के ज़रिए या foresight.js लाइब्रेरी की तरह नकली अनुरोध जारी करके, हो सकता है कि कुछ नेटवर्क कनेक्शन भी स्निफ़ किया जा सके. यह पूरी जानकारी इकट्ठा करने के बाद, यह तय किया जा सकता है कि कौनसी इमेज लोड करनी है.

ऐसी करीब 10 लाख JavaScript लाइब्रेरी हैं जो ऊपर बताए गए काम करती हैं. हालांकि, हमें अफ़सोस है कि इनमें से कोई भी खास तौर से बकाया नहीं है.

इस तरीके का एक बड़ा नुकसान यह है कि JavaScript का इस्तेमाल करने का मतलब है कि लुक-अहेड पार्सर पूरा होने तक इमेज लोड होने में देरी होगी. इसका मतलब यह है कि pageload इवेंट ट्रिगर होने तक, इमेज डाउनलोड होना भी शुरू नहीं होंगी. इस बारे में ज़्यादा जानने के लिए, जेसन ग्रिग्बी का लेख पढ़ें.

तय करें कि सर्वर पर कौनसी इमेज लोड करनी है

अपनी तरफ़ से दिखाई जाने वाली हर इमेज के लिए, पसंद के मुताबिक अनुरोध हैंडलर लिखकर, इस फ़ैसले को सर्वर-साइड पर टाला जा सकता है. ऐसा हैंडलर, उपयोगकर्ता एजेंट (सर्वर को भेजी जाने वाली जानकारी का एकमात्र हिस्सा) के आधार पर रेटिना से जुड़ी सहायता की जांच करेगा. इसके बाद, सर्वर-साइड लॉजिक, HiDPI एसेट दिखाना चाहता है या नहीं, इसके आधार पर आपको सही एसेट लोड करनी होती है (जिसे आम तौर पर इस्तेमाल किए जाने वाले तरीकों के नाम पर जाना जाता है).

माफ़ करें, उपयोगकर्ता एजेंट इस बात का फ़ैसला लेने के लिए ज़रूरी जानकारी नहीं देते कि डिवाइस पर अच्छी क्वालिटी की इमेज होनी चाहिए या कम. साथ ही, यह बिना किसी निर्देश के यह भी कहा जाता है कि उपयोगकर्ता-एजेंट से जुड़ी कोई भी बात एक हैक है और अगर हो सके, तो इससे बचना चाहिए.

सीएसएस मीडिया क्वेरी का इस्तेमाल करना

डिक्लेरेटिव टोन में, सीएसएस मीडिया क्वेरी से आपको अपने मकसद के बारे में बताने में मदद मिलती है. साथ ही, ब्राउज़र आपकी ओर से सही काम कर पाता है. मीडिया क्वेरी के सबसे आम इस्तेमाल के अलावा — डिवाइस के साइज़ का मिलान — इसके अलावा, आप devicePixelRatio का भी मिलान कर सकते हैं. इससे जुड़ी मीडिया क्वेरी, डिवाइस-पिक्सल-रेशियो है. साथ ही, इसमें कम से कम और ज़्यादा से ज़्यादा साइज़ के वैरिएंट शामिल होते हैं, जो आपकी उम्मीद के मुताबिक हो सकते हैं. अगर आपको ज़्यादा डीपीआई इमेज लोड करनी हैं और डिवाइस का पिक्सल रेशियो तय सीमा से ज़्यादा है, तो आपको ये काम करने होंगे:

#my-image { background: (low.png); }

@media only screen and (min-device-pixel-ratio: 1.5) {
  #my-image { background: (high.png); }
}

सभी वेंडर प्रीफ़िक्स को मिलाकर, यह थोड़ा और मुश्किल हो जाता है. खास तौर पर, "कम से कम" और "ज़्यादा से ज़्यादा" प्रीफ़िक्स के प्लेसमेंट में अंतर होने की वजह से ऐसा होता है:

@media only screen and (min--moz-device-pixel-ratio: 1.5),
    (-o-min-device-pixel-ratio: 3/2),
    (-webkit-min-device-pixel-ratio: 1.5),
    (min-device-pixel-ratio: 1.5) {

  #my-image {
    background:url(high.png);
  }
}

इस तरीके से, आपको लुक-अहेड पार्सिंग के फ़ायदे फिर से मिल जाते हैं, जो JS समाधान से खत्म हो जाता था. आपको अपना रिस्पॉन्सिव ब्रेकपॉइंट चुनने की सुविधा भी मिल जाती है (उदाहरण के लिए, आपके पास कम, मिड और हाई डीपीआई इमेज हो सकती हैं), जो सर्वर-साइड वाले अप्रोच की वजह से हट गई थीं.

हालांकि, यह अब भी थोड़ा मुश्किल है और इसकी वजह से यह एक अजीब सा दिखने वाला सीएसएस बन जाता है (या इसे प्रोसेस करने की ज़रूरत पड़ती है). साथ ही, यह तरीका सीएसएस प्रॉपर्टी तक ही सीमित है. इसलिए, <img src> सेट करने का कोई तरीका नहीं है. साथ ही, आपकी इमेज में मौजूद सभी एलिमेंट में बैकग्राउंड वाला एलिमेंट होना चाहिए. आखिर में, डिवाइस पिक्सल रेशियो पर पूरी तरह भरोसा करने से, आपको हाई-डीपीआई स्मार्ट फ़ोन में EDGE कनेक्शन पर 2x इमेज ऐसेट को डाउनलोड करने का विकल्प मिल सकता है. यह उपयोगकर्ता का सबसे अच्छा अनुभव नहीं है.

ब्राउज़र की नई सुविधाओं का इस्तेमाल करना

हाल में हाई डीपीआई इमेज समस्या के लिए वेब प्लैटफ़ॉर्म सपोर्ट को लेकर काफ़ी चर्चा हुई है. Apple ने हाल ही में स्पेस में शामिल हुआ है. इसमें WebKit में image-set() सीएसएस फ़ंक्शन जोड़ा गया है. इस वजह से, Safari और Chrome, दोनों इसके साथ काम करते हैं. यह एक सीएसएस फ़ंक्शन है, इसलिए image-set(), <img> टैग की समस्या को हल नहीं करता. ऐसा @srcset डालें, जो इस समस्या को हल करता हो. हालांकि, इस ईमेल के जवाब देते समय, रेफ़रंस के तौर पर अभी तक कोई रेफ़रंस लागू नहीं किया गया है. अगला सेक्शन image-set और srcset के बारे में ज़्यादा जानकारी देता है.

हाई डीपीआई से काम करने वाले ब्राउज़र की सुविधाएं

आखिरकार, आपको कौनसा तरीका अपनाना चाहिए, यह आपकी खास ज़रूरतों पर निर्भर करता है. इसलिए, ध्यान रखें कि ऊपर बताए गए सभी तरीकों की कुछ कमियां होती हैं. हालांकि, अगर आने वाले समय में image-set और srcset को बड़े पैमाने पर इस्तेमाल किया जाएगा, तो इस समस्या का समाधान हो जाएगा. अभी के लिए, आइए कुछ ऐसे सबसे सही तरीकों के बारे में बात करते हैं जो हमें उस आदर्श भविष्य के करीब ला सकते हैं.

सबसे पहले, ये दोनों अलग-अलग कैसे हैं? वैसे, image-set() एक सीएसएस फ़ंक्शन है, जिसका इस्तेमाल बैकग्राउंड सीएसएस प्रॉपर्टी की वैल्यू के तौर पर किया जा सकता है. srcset एक जैसे सिंटैक्स वाले <img> एलिमेंट के लिए खास एट्रिब्यूट है. ये दोनों टैग आपको इमेज के बारे में एलान करने की सुविधा देते हैं. हालांकि, srcset एट्रिब्यूट की मदद से यह तय किया जा सकता है कि व्यूपोर्ट के साइज़ के हिसाब से कौनसी इमेज लोड होनी है.

इमेज सेट करने के सबसे सही तरीके

image-set() सीएसएस फ़ंक्शन, -webkit-image-set() के तौर पर उपलब्ध होता है. सिंटैक्स बहुत आसान है. इसमें एक या उससे ज़्यादा कॉमा लगाकर अलग की गई इमेज के एलान किए जाते हैं. इनमें यूआरएल स्ट्रिंग या url() फ़ंक्शन के बाद उनसे जुड़ा रिज़ॉल्यूशन होता है. उदाहरण के लिए:

background-image:  -webkit-image-set(
  url(icon1x.jpg) 1x,
  url(icon2x.jpg) 2x
);

इससे, ब्राउज़र को पता चलता है कि यहां चुनने के लिए दो इमेज मौजूद हैं. इनमें से एक, 1x डिसप्ले के लिए और दूसरे को 2x डिसप्ले के लिए ऑप्टिमाइज़ किया गया है. इसके बाद, ब्राउज़र कई चीज़ों के आधार पर यह चुनता है कि किस पेज को लोड करना है. अगर ब्राउज़र स्मार्ट है, तो नेटवर्क की स्पीड भी शामिल हो सकती है. फ़िलहाल, मेरी जानकारी के हिसाब से इसे लागू नहीं किया गया है.

सही इमेज लोड करने के साथ-साथ, ब्राउज़र उसे उसके मुताबिक स्केल भी करेगा. दूसरे शब्दों में, ब्राउज़र यह मानता है कि दो इमेज की साइज़, 1x इमेज से दोगुनी होगी. इसी तरह, 2x इमेज को 2 के फ़ैक्टर से कम स्केल करने पर, पेज पर इमेज का साइज़ एक जैसा दिखेगा.

1x, 1.5x या Nx के बारे में बताने के बजाय, डीपीआई में किसी डिवाइस पिक्सल की डेंसिटी को भी तय किया जा सकता है.

यह ठीक से काम करता है. हालांकि, इसमें उन ब्राउज़र को शामिल नहीं किया जाता जो image-set प्रॉपर्टी के साथ काम नहीं करते. इसमें कोई इमेज नहीं दिखेगी! यह साफ़ तौर पर बुरा है. इसलिए, इस समस्या को ठीक करने के लिए, आपको फ़ॉलबैक (या फ़ॉलबैक की सीरीज़) का इस्तेमाल करना होगा:

background-image: url(icon1x.jpg);
background-image: -webkit-image-set(
  url(icon1x.jpg) 1x,
  url(icon2x.jpg) 2x
);
/* This will be useful if image-set gets into the platform, unprefixed.
    Also include other prefixed versions of this */
background-image: image-set(
  url(icon1x.jpg) 1x,
  url(icon2x.jpg) 2x
);

ऊपर दी गई ऐसेट, इमेज-सेट पर काम करने वाले ब्राउज़र में सही ऐसेट लोड करेगी. अगर ऐसा नहीं है, तो ऐसेट एक गुना ऐसेट पर वापस आ जाएगी. सबसे ज़रूरी बात यह है कि भले ही image-set() ब्राउज़र पर काम नहीं करता, लेकिन ज़्यादातर उपयोगकर्ता एजेंट को एक गुना ऐसेट मिलेगी.

इस डेमो में सही इमेज लोड करने के लिए image-set() का इस्तेमाल किया जाता है. अगर यह सीएसएस फ़ंक्शन काम नहीं करता है, तो सही इमेज लोड करने के लिए, एक बार ऐसेट का इस्तेमाल किया जाता है.

अब आपके मन में यह सवाल होगा कि क्यों न सिर्फ़ पॉलीफ़िल (यानी कि इसके लिए JavaScript शिम बनाएं) image-set() और इसे दिन के तौर पर मानें? जैसा कि हमने देखा है, सीएसएस फ़ंक्शन के लिए बेहतर पॉलीफ़िल लागू करना काफ़ी मुश्किल है. (इसकी वजह जानने के लिए, यह www-style चर्चा देखें).

इमेज srcset

यहां srcset का एक उदाहरण दिया गया है:

<img alt="my awesome image"
  src="banner.jpeg"
  srcset="banner-HD.jpeg 2x, banner-phone.jpeg 640w, banner-phone-HD.jpeg 640w 2x">

जैसा कि आपको दिख रहा है, image-set के दिए गए x एलान के अलावा, srcset एलिमेंट में w और h की वैल्यू भी ली जाती हैं, जो व्यूपोर्ट के साइज़ से मेल खाती हैं. इससे सबसे सही वर्शन दिखाने की कोशिश की जाती है. ऊपर 640 पिक्सल से कम स्क्रीन वाले व्यूपोर्ट की चौड़ाई 640 पिक्सल वाले डिवाइसों के लिए बैनर-phone.jpeg, छोटी स्क्रीन वाले हाई डीपीआई डिवाइस के लिए बैनर-फ़ोन-एचडी.jpeg, 640 पिक्सल से ज़्यादा स्क्रीन वाले हाई डीपीआई डिवाइसों के लिए बैनर-phone.jpeg, और बाकी सभी चीज़ों के लिए बैनर.jpeg का इस्तेमाल किया जाएगा.

इमेज एलिमेंट के लिए, इमेज-सेट का इस्तेमाल करना

ज़्यादातर ब्राउज़र में img एलिमेंट पर srcset एट्रिब्यूट लागू नहीं किया जाता है. इसलिए, हो सकता है कि img एलिमेंट को बैकग्राउंड वाले <div> से बदलना अच्छा लगे और इमेज के लिए सेट करने के तरीके का इस्तेमाल करें. यह चेतावनियों के साथ काम करेगा. इस समस्या की वजह यह है कि <img> टैग में लंबे समय का सिमैंटिक वैल्यू होती है. असल में, यह वेब क्रॉलर और सुलभता की वजहों के लिए ज़रूरी है.

अगर आप -webkit-image-set का इस्तेमाल करते हैं, तो हो सकता है कि आप बैकग्राउंड सीएसएस प्रॉपर्टी का इस्तेमाल करना चाहें. इस तरीके की कमी यह है कि आपको इमेज का साइज़ बताने की ज़रूरत होती है, जो बिना 1x वाली इमेज का इस्तेमाल करने पर पता नहीं होता. ऐसा करने के बजाय, कॉन्टेंट सीएसएस प्रॉपर्टी का इस तरह इस्तेमाल किया जा सकता है:

<div id="my-content-image"
  style="content: -webkit-image-set(
    url(icon1x.jpg) 1x,
    url(icon2x.jpg) 2x);">
</div>

इससे, devicePixelRatio के हिसाब से इमेज का साइज़ अपने-आप तय हो जाएगा. ऊपर दी गई तकनीक का यह उदाहरण देखें. इसमें उन ब्राउज़र के लिए url() में एक और फ़ॉलबैक शामिल किया गया है जिन परimage-set काम नहीं करता.

पॉलीफ़िलिंग srcset

srcset की एक आसान सुविधा यह है कि यह प्राकृतिक फ़ॉलबैक के साथ आता है. ऐसे मामले में जहां srcset एट्रिब्यूट लागू नहीं किया जाता है, वहां सभी ब्राउज़र को src एट्रिब्यूट को प्रोसेस करने का पता चलता है. यह सिर्फ़ एक एचटीएमएल एट्रिब्यूट है. इसलिए, JavaScript की मदद से पॉलीफ़िल बनाना भी मुमकिन है.

इस पॉलीफ़िल में यूनिट की जांच की जाती है, ताकि यह पक्का किया जा सके कि यह जानकारी के जितना हो सके उतना करीब हो. इसके अलावा, ऐसी जांच भी होती हैं जो पॉलीफ़िल को किसी भी कोड को लागू करने से रोकती हैं, अगर srcset को नेटिव तौर पर लागू किया गया हो.

यहां, इस्तेमाल की जा रही पॉलीफ़िल का डेमो दिया गया है.

नतीजा

हाई डीपीआई इमेज की समस्या को हल करने के लिए कोई मैजिक बुलेट नहीं है.

इसका सबसे आसान तरीका यह है कि इमेज को इस्तेमाल करने से बचें. इसके बजाय, SVG और सीएसएस का इस्तेमाल करें. हालांकि, हमेशा यह सच नहीं होता, खास तौर पर तब, जब आपकी साइट पर अच्छी क्वालिटी की तस्वीरें हों.

JS, सीएसएस, और सर्वर-साइड का इस्तेमाल करने वाले सभी तरीकों की अपनी-अपनी खूबियां और कमज़ोरियां होती हैं. हालांकि, सबसे सही तरीका है नई ब्राउज़र सुविधाओं का फ़ायदा लेना. हालांकि, ब्राउज़र पर image-set और srcset अब भी काम नहीं करता है, लेकिन अभी इस्तेमाल करने के लिए कुछ फ़ॉलबैक सही हैं.

संक्षेप में, मेरे सुझाव इस प्रकार हैं:

  • बैकग्राउंड इमेज के लिए, जिन ब्राउज़र पर यह काम नहीं करता उनके लिए सही फ़ॉलबैक के साथ image-set का इस्तेमाल करें.
  • कॉन्टेंट की इमेज के लिए, srcset polyfill का इस्तेमाल करें. इसके अलावा, image-set इस्तेमाल करने के लिए फ़ॉलबैक का इस्तेमाल करें (ऊपर देखें).
  • ऐसी स्थितियों में, जहां आपको इमेज की क्वालिटी से छेड़छाड़ करनी हो, बहुत ज़्यादा कंप्रेस्ड 2x इमेज का इस्तेमाल करें.