डेटा URI किसी फ़ाइल को सीधे दस्तावेज़ के अंदर रख देता है: तस्वीर अलग रिक्वेस्ट के बजाय HTML या CSS के भीतर सफ़र करती है। सालों तक यह आम ऑप्टिमाइज़ेशन था, और इसके पीछे का तर्क काफ़ी हद तक पुराना पड़ चुका है।
इसकी क़ीमत
Base64 तीन बाइट को चार अक्षरों में बदलता है, इसलिए एन्कोड किया रूप फ़ाइल से लगभग 33% बड़ा होता है। यह एन्कोडिंग का स्वभाव है, कोई लागू करने का ब्योरा नहीं: यह मनमाने बाइट दिखाने के लिए 64 छपने लायक़ अक्षर इस्तेमाल करता है, और 64 है 2⁶, इसलिए जिस हर अक्षर में आठ बिट आ सकते थे उसमें छह जाते हैं। data:image/png;base64, उपसर्ग ऊपर से दो दर्जन के आसपास अक्षर जोड़ता है, जो फ़ोटो पर कुछ नहीं और 200 बाइट के आइकन पर कुछ मायने रखता है।
इस 33% के बारे में सटीक रहना ज़रूरी है, क्योंकि इसे अक्सर बढ़ा-चढ़ाकर बताया जाता है। डिस्क पर रखी फ़ाइल में, पार्स किए दस्तावेज़ में और मेमोरी में यह पूरी तरह असली है। नेटवर्क पर ज़्यादातर नहीं। टेक्स्ट कंप्रेशन इसे खा जाता है: 12 KB का पहले से कंप्रेस हुआ इमेज डेटा लीजिए, जो JPEG या WebP होता है, तो Base64 रूप 16,000 अक्षर है, पर gzip के बाद वह 12,070 बाइट पर लौट आता है, जबकि मूल gzip होकर 12,023 है। यह एक-तिहाई नहीं, आधे प्रतिशत से कम का ट्रांसफ़र जुर्माना है। कंप्रेशन तस्वीर के डेटा के अंदर पैटर्न नहीं ढूँढ पाता, पर उसके ऊपर बिछाई गई 64 अक्षरों की वर्णमाला में आसानी से ढूँढ लेता है।
यानी आकार वाला तर्क उतना मज़बूत नहीं जितना आम तौर पर बताया जाता है। कैशिंग वाला तर्क मज़बूत है।
अलग इमेज फ़ाइल एक बार डाउनलोड होती है, अपने URL के तहत कैश होती है, और उसे इस्तेमाल करने वाले हर पेज पर और हर वापसी पर दोबारा काम आती है। एम्बेड की गई तस्वीर दस्तावेज़ का हिस्सा है। वह उसे ढोने वाले हर पेज के साथ फिर डाउनलोड होती है, हर बार फिर डिकोड होती है, और आसपास के टेक्स्ट से अलग कभी कैश नहीं हो सकती, इसलिए पेज का एक शब्द बदलना तस्वीर को भी अमान्य कर देता है।
एक पेज पर लगे लोगो के लिए यह कुछ नहीं। साइट के हर पेज पर लगे लोगो के लिए यह अलग फ़ाइल से साफ़ तौर पर बदतर है, और अंतर तस्वीर के आकार के साथ नहीं, पेजों की गिनती के साथ बढ़ता है।
कैश के अलावा क्या छूटता है
कम दिखने वाली क़ीमत यह है कि एम्बेड की गई तस्वीर बाक़ी प्लेटफ़ॉर्म की नज़र में तस्वीर नहीं रह जाती।
| आप खोते हैं | क्योंकि |
|---|---|
loading="lazy" |
वह दस्तावेज़ के साथ पहले ही आ चुकी |
srcset और <picture> |
हर संस्करण अंदर एक और पूरी कॉपी होगा |
| CDN पर रीसाइज़ और फ़ॉर्मैट चुनना | बीच में पकड़ने को कोई URL नहीं बचा |
| कैश की अपनी अवधि | दस्तावेज़ के साथ ही ख़त्म होती है |
| काम की त्रुटि | ग़लत बना URI बस दिखता नहीं |
कंटेंट सिक्योरिटी पॉलिसी में भी एक पेच है। img-src 'self' वाली सख़्त पॉलिसी डेटा URI को सीधे रोक देती है, और उन्हें इजाज़त देने का मतलब है डायरेक्टिव में data: जोड़ना। यह छोटा पर असली ढीलापन है: img-src में data: आम तौर पर स्वीकार्य माना जाता है, जबकि script-src में data: बिल्कुल नहीं, और आदतन दोनों को साथ ढीला कर देना आसान है।
जगह भी जितना लगता है उससे ज़्यादा मायने रखती है। CSS रेंडर रोकता है: ब्राउज़र कुछ भी रंगने से पहले स्टाइलशीट पूरी डाउनलोड और पार्स करता है। स्टाइलशीट में बैठा आधा मेगाबाइट Base64 पूरे पेज की पहली झलक देर से लाता है, उन सब हिस्सों समेत जिनका तस्वीर से कोई लेना-देना नहीं।
फ़ायदा क्यों सिकुड़ गया
HTTP/1.1 में ब्राउज़र हर होस्ट के लिए लगभग छह कनेक्शन खोलते थे और रिक्वेस्ट एक-दूसरे के पीछे क़तार में लगती थीं। एक रिक्वेस्ट हटाना सचमुच मदद करता था, और स्प्राइट शीट और एम्बेडिंग जैसी तकनीकें इसी वजह से थीं।
HTTP/2 और HTTP/3 एक ही कनेक्शन पर कई रिक्वेस्ट साथ चलाते हैं, इसलिए दूसरी फ़ाइल की क़ीमत अब छोटी है और एम्बेडिंग को सही ठहराने वाला हिसाब ज़्यादातर नहीं टिकता। उसी दौर में HTTP/2 Server Push आया, जो बचा हुआ एक चक्कर भी हटाने के लिए था, और Chrome ने 2022 में उसका समर्थन यह कहकर हटा दिया कि उसे सही करना उसकी क़ीमत से ज़्यादा मुश्किल था। पैटर्न एक ही है: रिक्वेस्ट अब महँगा हिस्सा नहीं रही।
कब यह अब भी सही फ़ैसला है
| हालत | क्यों |
|---|---|
| CSS फ़ाइल में छोटा आइकन | कुछ सौ बाइट के लिए एक रिक्वेस्ट बचती है |
| HTML ईमेल | बाहरी तस्वीरें डिफ़ॉल्ट रूप से रुकी होती हैं |
| अकेली, अपने में पूरी फ़ाइल | साथ भेजने को कोई एसेट नहीं |
| ज़रूरी प्लेसहोल्डर | बाक़ी कुछ लोड होने से पहले दिखता है |
चलन एक रेखा पर नहीं, एक धुंधली पट्टी पर टिका है: कुछ किलोबाइट इतने कम हैं कि रिक्वेस्ट बचाना जीतता है, दस या ज़्यादा इतने कि नहीं, और बीच का हिस्सा इस पर निर्भर है कि पेज कितनी बार परोसा जाता है और उसमें वही तस्वीर एक से ज़्यादा बार आती है या नहीं। अक्सर आकार से ज़्यादा दोहराव फ़ैसला करता है। ऐसी लैंडिंग पेज पर 20 KB का एक चित्र जिस पर कोई लौटता नहीं, ठीक है; डॉक्यूमेंटेशन साइट के हर पेज में एम्बेड किया 2 KB का आइकन नहीं, और किलोबाइट में लिखी कोई सीमा आपको यह नहीं बताएगी।
SVG का अपवाद
SVG के लिए Base64 छोड़ दें। SVG टेक्स्ट है, इसलिए CSS में उसे प्रतिशत-एन्कोड करना उसी फ़ाइल के Base64 से छोटा नतीजा देता है: प्रतिशत-एन्कोडिंग सिर्फ़ उन अक्षरों को फैलाती है जिन्हें सचमुच एस्केप करना है, जबकि Base64 सब कुछ एक-तिहाई फैला देता है। इस साइट का 299 बाइट का एक आइकन Base64 में 400 अक्षर है और CSS की ज़रूरी न्यूनतम एस्केपिंग के साथ 329।
बाद में वह स्टाइलशीट में पढ़ा भी जा सकता है, जो कभी-कभी मायने रखता है, और भरने का रंग बदलना दोबारा एन्कोडिंग नहीं, एक सीधा बदलाव है।
लोग जो पूछते हैं
क्या एन्कोडिंग तस्वीर को दोबारा कंप्रेस करती है? नहीं करनी चाहिए। मूल बाइट एन्कोड करने से बाइट-दर-बाइट वही तस्वीर मिलती है; कैनवस से गुज़ारने पर वह दोबारा एन्कोड होगी।
क्या img टैग में डेटा URI इस्तेमाल कर सकता हूँ? हाँ, और CSS के url() में, और SVG के image एलिमेंट में भी।
क्या ये ईमेल में चलते हैं? ज़्यादातर नहीं; Gmail और Outlook उन्हें हटा देते हैं या मना कर देते हैं। यह वह इकलौता मामला है जहाँ जवाब अटैचमेंट है।
क्या कोई आकार सीमा है? ब्राउज़र कई मेगाबाइट ले लेते हैं, पर इतना बड़ा डेटा URI उसे रखने वाली फ़ाइल को हाथ से पढ़ने लायक़ नहीं छोड़ता और प्रोसेसिंग धीमी कर देता है।
अगर देना एक ही फ़ाइल है तो? तब सब कुछ एम्बेड करें, और तर्क ख़त्म। ऑफ़लाइन रिपोर्ट, टेम्पलेट, अटैचमेंट में भेजा पेज: अलग से कैश करने को कुछ नहीं, इसलिए बची क़ीमत बस वह एक-तिहाई है जिसे कंप्रेशन ज़्यादातर हटा देता है।
इमेज से Base64 टूल मूल बाइट एन्कोड करता है और आपको CSS या HTML वाला रूप देता है, Base64 एन्कोड और Base64 डिकोड टेक्स्ट सँभालते हैं, तीनों फ़िलहाल अंग्रेज़ी में, और इमेज कंप्रेस करें इन सबसे पहले उठाने लायक़ क़दम है, क्योंकि छोटी फ़ाइल का एक-तिहाई छोटा एक-तिहाई है।