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

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

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

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

अगर हो सके, तो इमेज का इस्तेमाल न करें

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

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

बैकग्राउंड

डिसप्ले डेंसिटी (सघनता) का बहुत छोटा इतिहास

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

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

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

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

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

वेब पर पिक्सल

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

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

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

डिवाइस के पिक्सल के अनुपात की गणना की जा रही है

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

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

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

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

    आदर्श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 का DPR और उसकी रेटिना बराबर रिपोर्ट 2. सीएसएस स्पेसिफ़िकेशन के मुताबिक,

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

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

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

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

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

  1. एक इमेज को ऑप्टिमाइज़ करना, और
  2. एक से ज़्यादा इमेज में से चुनने के लिए, ऑप्टिमाइज़ेशन की सुविधा.

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

  • ज़्यादा कंप्रेस की गई HiDPI इमेज
  • Totally awesome image format
  • प्रोग्रेसिव इमेज फ़ॉर्मैट

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

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

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

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

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

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

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

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

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

इमेज का बेहतरीन फ़ॉर्मैट

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

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

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

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

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

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

प्रोग्रेसिव इमेज फ़ॉर्मैट, जैसे कि JPEG 2000, प्रोग्रेसिव JPEG, प्रोग्रेसिव PNG, और GIF, इमेज के पूरी तरह लोड होने से पहले उसे सही जगह पर देखने का एक फ़ायदा (कुछ हद तक बहस वाली) है. ऐसा हो सकता है कि इनको, सिर के ऊपर वाले हिस्से का कुछ हिस्सा दिखे. हालांकि, इसके बारे में विरोधी सबूत हैं. जेफ़ एटवुड ने दावा किया कि प्रोग्रेसिव मोड से, "पीएनजी इमेज का साइज़ करीब 20% होता है. साथ ही, जेपीईजी और GIF इमेज का साइज़ करीब 10 प्रतिशत होता है". हालांकि, Stoyan Stefanov ने दावा किया है कि ज़्यादातर मामलों में, बड़ी फ़ाइलों के लिए प्रोग्रेसिव मोड ज़्यादा असरदार होता है.

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

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

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

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

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

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

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

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

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

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

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

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

सीएसएस मीडिया क्वेरी, एलान करने वाली होती हैं. इनकी मदद से, अपनी ज़रूरत के हिसाब से ब्राउज़र को निर्देश दिए जा सकते हैं. मीडिया क्वेरी के सबसे सामान्य इस्तेमाल के अलावा, डिवाइस के साइज़ से मैच करने के लिए भी 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> सेट करने का कोई तरीका नहीं है. साथ ही, आपकी सभी इमेज, बैकग्राउंड वाले एलिमेंट होनी चाहिए. आखिर में, डिवाइस के पिक्सल रेशियो पर पूरी तरह से भरोसा करने पर, आपको ऐसी स्थितियां मिल सकती हैं जहां आपका हाई-डीपीआई स्मार्ट फ़ोन, ईडीजी कनेक्शन पर दो गुना बड़ी इमेज एसेट डाउनलोड कर लेता है. इससे उपयोगकर्ताओं को बेहतर अनुभव नहीं मिलता.

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

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

उच्च DPI समर्थन के लिए ब्राउज़र सुविधाएं

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

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

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

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

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

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

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

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
);

ऊपर दिया गया कोड, उन ब्राउज़र में सही ऐसेट लोड करेगा जो इमेज-सेट की सुविधा के साथ काम करते हैं. अगर ऐसा नहीं होता है, तो यह 1x ऐसेट पर स्विच कर देगा. ध्यान रखें कि image-set() ब्राउज़र के साथ काम करने वाले ऐप्लिकेशन कम हैं. इसलिए, ज़्यादातर उपयोगकर्ता एजेंट को 1x एसेट मिलेगी.

यह डेमो सही इमेज लोड करने के लिए image-set() का इस्तेमाल करता है. अगर यह CSS फ़ंक्शन काम नहीं करता है, तो यह 1x एसेट पर स्विच कर देता है.

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

इमेज एसआरसेट

यहां 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 पिक्सल से कम व्यूपोर्ट चौड़ाई वाले डिवाइसों पर banner-phone.jpeg, छोटी स्क्रीन वाले हाई डीपीआई डिवाइसों पर banner-phone-HD.jpeg, 640 पिक्सल से ज़्यादा स्क्रीन वाले हाई डीपीआई डिवाइसों पर banner-HD.jpeg, और बाकी सभी डिवाइसों पर banner.jpeg दिखाएगी.

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

ज़्यादातर ब्राउज़र में, img एलिमेंट पर srcset एट्रिब्यूट लागू नहीं होता. इसलिए, हो सकता है कि आप अपने img एलिमेंट को <div>s के साथ बैकग्राउंड में बदलना चाहें और इमेज-सेट वाले तरीके का इस्तेमाल करें. हालांकि, इसमें कुछ शर्तें लागू होंगी. इसकी वजह यह है कि <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 के आधार पर इमेज अपने-आप स्केल हो जाएगी. ऊपर बताई गई तकनीक को इस्तेमाल करने का यह उदाहरण देखें. इसमें image-set के साथ काम न करने वाले ब्राउज़र के लिए, url() का अतिरिक्त फ़ॉलबैक भी दिया गया है.

पॉलीफ़िलिंग एसर्ससेट

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

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

यहां पॉलिफ़िल का डेमो दिया गया है.

नतीजा

ज़्यादा डीपीआई वाली इमेज की समस्या को हल करने का कोई आसान तरीका नहीं है.

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

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

खास जानकारी के तौर पर, मेरे सुझाव यहां दिए गए हैं: