İstemci ipuçlarıyla kaynak seçimini otomatikleştirme

Ilya Grigorik
Ilya Grigorik

Web için içerik oluşturmak, eriştiğiniz kitlenin büyüklüğü açısından rakipsizdir. Web uygulamanız, marka veya platformdan bağımsız olarak hemen hemen her bağlı cihazda (akıllı telefon, tablet, dizüstü ve masaüstü bilgisayar, TV vb.) tek tıklamayla kullanılabilir. En iyi deneyimi sunmak için sunumu ve işlevselliği her form faktörüne uyarlayan bir duyarlı site oluşturdunuz. Artık uygulamanın olabildiğince hızlı yüklenmesini sağlamak için performans yapılacaklar listenizi gözden geçiriyorsunuz: Kritik oluşturma yolunuzu optimize ettiniz, metin kaynaklarınızı sıkıştırıp önbelleğe aldınız ve şimdi genellikle aktarılan baytların çoğunu oluşturan resim kaynaklarınıza bakıyorsunuz. Sorun şu ki resim optimizasyonu zordur:

  • Uygun biçimi (vektor ve raster) belirleme
  • Optimum kodlama biçimlerini (jpeg, webp vb.) belirleyin.
  • Doğru sıkıştırma ayarlarını belirleme (kaybetmeyle sıkıştırma ve kayıpsız sıkıştırma)
  • Hangi meta verilerin saklanacağını veya kaldırılacağını belirleme
  • Her ekran ve DPR çözünürlüğü için her birinin birden fazla varyantını oluşturun
  • ...
  • Kullanıcının ağ türünü, hızını ve tercihlerini hesaba katın

Bunlar ayrı ayrı iyi bilinen sorunlardır. Bu kaynaklar, geliştiriciler olarak genellikle göz ardı ettiğimiz veya ihmal ettiğimiz büyük bir optimizasyon alanı oluşturur. İnsanlar, özellikle çok sayıda adım olduğunda aynı arama alanını tekrar tekrar keşfetme konusunda iyi bir performans gösteremez. Bilgisayarlar ise bu tür görevlerde çok başarılıdır.

Resimler ve benzer özelliklere sahip diğer kaynaklar için iyi ve sürdürülebilir bir optimizasyon stratejisinin cevabı basittir: otomasyon. Kaynaklarınızı manuel olarak ayarlıyorsanız bunu yanlış yapıyorsunuz demektir: Unutacaksınız, tembel olacaksınız veya başka biri bu hataları sizin için yapacak.

Performansa duyarlı geliştiricinin hikayesi

Resim optimizasyon alanında arama, derleme zamanı ve çalışma zamanı olmak üzere iki farklı aşamadan oluşur.

  • Bazı optimizasyonlar kaynağın kendisine özgüdür (ör.uygun biçim ve kodlama türünü seçme, her kodlayıcı için sıkıştırma ayarlarını ayarlama, gereksiz meta verileri kaldırma vb.). Bu adımlar "derleme zamanında" gerçekleştirilebilir.
  • Diğer optimizasyonlar, bunu isteyen istemcinin türüne ve özelliklerine göre belirlenir ve "çalışma zamanında" gerçekleştirilmelidir: istemcinin ağ hızı, kullanıcı ve uygulama tercihleri vb. dikkate alınarak istemcinin DPR'si ve amaçlanan görüntü genişliği için uygun kaynak seçilir.

Derleme zamanı araçları mevcuttur ancak daha iyi hale getirilebilir. Örneğin, her resim ve resim biçimi için "kalite" ayarını dinamik olarak ayarlayarak çok fazla tasarruf elde edilebilir. Ancak henüz bu özelliği araştırma dışında kullanan kimse görmedim. Bu, yenilik için uygun bir alandır ancak bu makale kapsamında konuyu burada bırakacağım. Hikayenin çalışma zamanı bölümüne odaklanalım.

<img src="/image/thing" sizes="50vw"
        alt="image thing displayed at 50% of viewport width">

Uygulama amacı çok basittir: Resmi getirip kullanıcının görüntü alanının% 50'sinde gösterin. Çoğu tasarımcı bu noktada ellerini yıkayıp bara gider. Bu sırada ekipteki performansa duyarlı geliştirici uzun bir gece geçirir:

  1. En iyi sıkıştırmayı elde etmek için her istemci için en uygun resim biçimini kullanmak istiyor: Chrome için WebP, Edge için JPEG XR ve diğer istemciler için JPEG.
  2. En iyi görsel kaliteyi elde etmek için her resmin farklı çözünürlüklerde (1x, 1,5x, 2x, 2,5x, 3x ve hatta arada birkaç tane daha) birden fazla varyantını oluşturması gerekir.
  3. Gereksiz piksel yayınlamamak için "kullanıcı görüntü alanının% 50'si aslında ne anlama geliyor?" sorusunu yanıtlaması gerekiyor. Görüntü alanı genişlikleri çok farklı olabilir.
  4. İdeal olarak, daha yavaş ağlardaki kullanıcıların otomatik olarak daha düşük bir çözünürlük alacağı dayanıklı bir deneyim de sunmak ister. Sonuçta, camın zamanı geldi.
  5. Uygulama, hangi resim kaynağının getirileceğini etkileyen bazı kullanıcı denetimlerini de gösterir. Bu nedenle, bu faktörü de göz önünde bulundurmanız gerekir.

Tasarımcı, okunabilirliği optimize etmek için görüntü alanı boyutu küçükse% 100 genişlikte farklı bir resim göstermesi gerektiğini de fark eder. Bu nedenle, aynı işlemi bir öğe daha için tekrarlamamız ve ardından getirme işlemini ekran boyutuna bağlı hale getirmemiz gerekiyor. Bu işin zorluğundan bahsetmiş miydim? Peki, hadi başlayalım. picture öğesi bize oldukça fazla bilgi verir:

<picture>
    <!-- serve WebP to Chrome and Opera -->
    <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.webp 200w, /image/thing-400.webp 400w,
        /image/thing-800.webp 800w, /image/thing-1200.webp 1200w,
        /image/thing-1600.webp 1600w, /image/thing-2000.webp 2000w"
    type="image/webp">
    <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.webp 200w, /image/thing-crop-400.webp 400w,
        /image/thing-crop-800.webp 800w, /image/thing-crop-1200.webp 1200w,
        /image/thing-crop-1600.webp 1600w, /image/thing-crop-2000.webp 2000w"
    type="image/webp">
    <!-- serve JPEGXR to Edge -->
    <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.jpgxr 200w, /image/thing-400.jpgxr 400w,
        /image/thing-800.jpgxr 800w, /image/thing-1200.jpgxr 1200w,
        /image/thing-1600.jpgxr 1600w, /image/thing-2000.jpgxr 2000w"
    type="image/vnd.ms-photo">
    <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.jpgxr 200w, /image/thing-crop-400.jpgxr 400w,
        /image/thing-crop-800.jpgxr 800w, /image/thing-crop-1200.jpgxr 1200w,
        /image/thing-crop-1600.jpgxr 1600w, /image/thing-crop-2000.jpgxr 2000w"
    type="image/vnd.ms-photo">
    <!-- serve JPEG to others -->
    <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.jpg 200w, /image/thing-400.jpg 400w,
        /image/thing-800.jpg 800w, /image/thing-1200.jpg 1200w,
        /image/thing-1600.jpg 1600w, /image/thing-2000.jpg 2000w">
    <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.jpg 200w, /image/thing-crop-400.jpg 400w,
        /image/thing-crop-800.jpg 800w, /image/thing-crop-1200.jpg 1200w,
        /image/thing-crop-1600.jpg 1600w, /image/thing-crop-2000.jpg 2000w">
    <!-- fallback for browsers that don't support picture -->
    <img src="/image/thing.jpg" width="50%">
</picture>

Sanat yönünü ve biçim seçimini biz üstlendik. Ayrıca, müşterinin cihazının DPR'sinde ve görüntü alanı genişliğindeki değişkenliği hesaba katmak için her resmin altı varyantını sağladık. Etkileyici!

Maalesef picture öğesi, istemcinin bağlantı türüne veya hızına göre nasıl davranması gerektiğine dair herhangi bir kural tanımlamamıza izin vermiyor. Bununla birlikte, işleme algoritması bazı durumlarda kullanıcı aracısının hangi kaynağı getireceğini ayarlamasına izin verir. 5. adıma bakın. Kullanıcı aracısının yeterince akıllı olmasını ummamız gerekiyor. (Not: Mevcut uygulamalardan hiçbiri bu şekilde değildir.) Benzer şekilde, picture öğesinde uygulama veya kullanıcı tercihlerini hesaba katan uygulamaya özel mantığa izin veren kanca yoktur. Bu son iki bit'i elde etmek için yukarıdaki mantığın tamamını JavaScript'e taşımamız gerekir. Ancak bu durumda picture tarafından sunulan ön yükleme tarayıcı optimizasyonları kaybedilir. Hata.

Bu sınırlamalar dışında, bu yöntem işe yarar. En azından bu öğe için. Buradaki gerçek ve uzun vadeli zorluk, tasarımcının veya geliştiricinin her öğe için bu tür bir kod yazmasını bekleyemememizdir. İlk denemenizde eğlenceli bir bulmaca gibi görünse de hemen sonra ilginizi kaybeder. Otomasyona ihtiyacımız var. IDE'ler veya diğer içerik dönüştürme araçları, bizi kurtarabilir ve yukarıdaki şablonu otomatik olarak oluşturabilir.

İstemci ipuçlarıyla kaynak seçimini otomatikleştirme

Derin bir nefes alın, şüphelerinizi bir kenara bırakın ve aşağıdaki örneği inceleyin:

<meta http-equiv="Accept-CH" content="DPR, Viewport-Width, Width">
...
<picture>
    <source media="(min-width: 50em)" sizes="50vw" srcset="/image/thing">
    <img sizes="100vw" src="/image/thing-crop">
</picture>

İnanmayabilirsiniz ancak yukarıdaki örnek, çok daha uzun olan resim işaretlemeyle aynı işlevlerin tümünü sunmaya yeterlidir. Ayrıca, göreceğiniz gibi, resim kaynaklarının nasıl, hangilerinin ve ne zaman getirileceği üzerinde geliştiricinin tam kontrol sahibi olmasını sağlar. "Sihir", istemci ipucu raporlamasını etkinleştiren ve tarayıcıya, cihaz piksel oranını (DPR), düzen görüntü alanı genişliğini (Viewport-Width) ve kaynakların amaçlanan görüntü genişliğini (Width) sunucuya bildirmesini söyleyen ilk satırdadır.

İstemci ipuçları etkinleştirildiğinde, istemci tarafında oluşturulan işaretleme yalnızca sunum şartlarını korur. Tasarımcının resim türleri, istemci çözünürlükleri, yayınlanan baytları azaltmak için optimum kesme noktaları veya diğer kaynak seçim ölçütleri hakkında endişelenmesi gerekmez. Gerçekleri kabul edelim, bunu hiç yapmadılar ve yapmaları gerekmez. Daha da iyisi, gerçek kaynak seçimi istemci ve sunucu tarafından yapıldığından geliştiricinin yukarıdaki işaretlemeyi yeniden yazıp genişletmesi de gerekmez.

Chrome 46, DPR, Width ve Viewport-Widthipuçlarını destekler. İpuçları varsayılan olarak devre dışıdır ve yukarıdaki <meta http-equiv="Accept-CH" content="...">, Chrome'a belirtilen üstbilgileri giden isteklere eklemesini söyleyen bir etkinleştirme sinyali görevi görür. Bu bilgilerle birlikte, örnek bir resim isteği için istek ve yanıt üst bilgilerini inceleyelim:

İstemci ipuçları pazarlığı diyagramı

Chrome, WebP biçimini desteklediğini Accept istek üstbilgisi aracılığıyla bildirir. Yeni Edge tarayıcısı da benzer şekilde Accept üstbilgisi aracılığıyla JPEG XR desteğini bildirir.

Sonraki üç istek üstbilgisi, istemcinin cihazının cihaz piksel oranını (3x), düzen görüntü alanı genişliğini (460 piksel) ve kaynağın amaçlanan görüntü genişliğini (230 piksel) tanıtan istemci ipucu üstbilgileridir. Bu, sunucuya kendi politikalarına göre en uygun resim varyantını seçmesi için gerekli tüm bilgileri sağlar: önceden oluşturulmuş kaynakların kullanılabilirliği, bir kaynağı yeniden kodlamanın veya yeniden boyutlandırmanın maliyeti, bir kaynağın popülerliği, mevcut sunucu yükü vb. Bu durumda sunucu, DPR ve Width ipuçlarından yararlanır ve Content-Type, Content-DPR ve Vary üst bilgilerinde belirtildiği gibi bir WebP kaynağı döndürür.

Burada sihir yok. Kaynak seçimini HTML işaretlemesinden istemci ile sunucu arasındaki istek-yanıt pazarlığına taşıdık. Sonuç olarak HTML yalnızca sunum şartlarıyla ilgilenir ve herhangi bir tasarımcı ve geliştiricinin yazabileceği bir şeydir. Öte yandan, resim optimizasyonu alanındaki aramalar bilgisayarlara devredilir ve artık geniş ölçekte kolayca otomatikleştirilebilir. Performansa önem veren geliştiricimizi hatırlıyor musunuz? Artık yapması gereken, sağlanan ipuçlarından yararlanıp uygun yanıtı döndürebilecek bir resim hizmeti yazmak: İstediği dili veya sunucuyu kullanabilir ya da bu işlemi üçüncü taraf bir hizmetin veya CDN'nin yapmasına izin verebilir.

<img src="/image/thing" sizes="50vw"
        alt="image thing displayed at 50% of viewport width">

Ayrıca, yukarıdaki adamı hatırlıyor musunuz? İstemci ipuçları sayesinde, basit resim etiketi artık ek işaretleme olmadan DPR, ekran boyutu ve genişlik bilincine sahip. Sanat yönetmeni eklemeniz gerekiyorsa yukarıda gösterildiği gibi picture etiketini kullanabilirsiniz. Aksi takdirde, mevcut tüm resim etiketleriniz çok daha akıllı hale geldi. İstemci ipuçları, mevcut img ve picture öğelerini geliştirir.

Hizmet çalışanı ile kaynak seçimini kontrol etme

ServiceWorker, aslında tarayıcınızda çalışan bir istemci tarafı proxy'dir. Tüm giden istekleri durdurur ve yanıtları incelemenize, yeniden yazmanıza, önbelleğe almanıza ve hatta sentezlemenize olanak tanır. Görseller de farklı değildir ve istemci ipuçları etkinleştirildiğinde etkin ServiceWorker, resim isteklerini tanımlayabilir, sağlanan istemci ipuçlarını inceleyebilir ve kendi işleme mantığını tanımlayabilir.

self.onfetch = function(event) {
    var req = event.request.clone();
    console.log("SW received request for: " + req.url)
    for (var entry of req.headers.entries()) {
    console.log("\t" + entry[0] +": " + entry[1])
    }
    ...
}
İstemci ipuçları serviceWorker.

ServiceWorker, kaynak seçimi üzerinde istemci tarafında tam kontrol sahibi olmanızı sağlar. Bu çok önemlidir. Olasılıkların neredeyse sonsuz olduğunu göz önünde bulundurun:

  • Kullanıcı aracısı tarafından ayarlanan istemci ipucu başlık değerlerini yeniden yazabilirsiniz.
  • İsteğe yeni istemci ipucu üstbilgi değerleri ekleyebilirsiniz.
  • URL'yi yeniden yazabilir ve resim isteğini alternatif bir sunucuya (ör. CDN) yönlendirebilirsiniz.
    • Altyapınızda dağıtımı kolaylaştırıyorsa ipucu değerlerini başlıklardan URL'ye bile taşıyabilirsiniz.
  • Yanıtları önbelleğe alabilir ve hangi kaynakların sunulacağıyla ilgili kendi mantığınızı tanımlayabilirsiniz.
  • Yanıtınızı kullanıcıların bağlantısına göre uyarlayabilirsiniz.
  • Uygulama ve kullanıcı tercihi geçersiz kılma işlemlerini hesaba katabilirsiniz.
  • İstediğiniz her şeyi yapabilirsiniz.

picture öğesi, HTML işaretlemede gerekli sanat yönetmenliği kontrolünü sağlar. İstemci ipuçları, kaynak seçim otomasyonunu etkinleştiren, sonuçta ortaya çıkan resim istekleriyle ilgili ek açıklamalar sağlar. ServiceWorker, istemcide istek ve yanıt yönetimi özellikleri sağlar. Bu, genişletilebilir web'in işleyiş şeklidir.

İstemci ipuçları ile ilgili SSS

  1. İstemci ipuçları nerede kullanılabilir? Chrome 46'da kullanıma sunulmuştur. Firefox ve Edge'de değerlendiriliyor.

  2. İstemci ipuçları neden etkinleştirilmelidir? İstemci ipuçları kullanmayacak siteler için ek maliyeti en aza indirmek istiyoruz. İstemci ipuçları etkinleştirildiğinde site, sayfa işaretlemesinde Accept-CH başlığını veya eşdeğer <meta http-equiv> yönergesini sağlamalıdır. Bu iki koşuldan biri varsa kullanıcı aracısı, tüm alt kaynak isteklerine uygun ipuçlarını ekler. Gelecekte, belirli bir kaynak için bu tercihi sürdürecek ek bir mekanizma sağlayabiliriz. Bu mekanizma, gezinme isteklerinde aynı ipuçlarının sunulmasına olanak tanır.

  3. ServiceWorker'ımız varsa neden istemci ipuçlarına ihtiyacımız var? ServiceWorker'ın düzen, kaynak ve görünüm genişliği bilgilerine erişimi yoktur. En azından, maliyetli gidiş dönüşler yapmadan ve resim isteğini önemli ölçüde geciktirmeden (ör. resim isteği önyükleme ayrıştırıcısı tarafından başlatıldığında) olmaz. İstemci ipuçları, bu verileri istek kapsamında kullanılabilir hale getirmek için tarayıcı ile entegre edilir.

  4. İstemci ipuçları yalnızca resim kaynakları için midir? DPR, Viewport-Width ve Width ipuçlarının temel kullanım alanı, resim öğeleri için kaynak seçimini etkinleştirmektir. Ancak türden bağımsız olarak tüm alt kaynaklar için aynı ipuçları gönderilir. Örneğin, CSS ve JavaScript istekleri de aynı bilgileri alır ve bu kaynakları optimize etmek için de kullanılabilir.

  5. Bazı resim isteklerinde genişlik raporlanmıyor. Neden? Site, resmin doğal boyutunu kullandığından tarayıcı, amaçlanan görüntü genişliğini bilmiyor olabilir. Sonuç olarak, bu tür istekler ve "görüntü genişliği"ne sahip olmayan istekler (ör. JavaScript kaynağı) için Genişlik ipucu atlanır. Genişlik ipuçları almak için resimlerinizde bir boyut değeri belirttiğinizden emin olun.

  6. <insert my favorite hint> ne olacak? ServiceWorker, geliştiricilerin tüm giden istekleri durdurup değiştirmesini (ör. yeni üstbilgi ekleme) sağlar. Örneğin, mevcut bağlantı türünü belirtmek için NetInfo tabanlı bilgiler eklemek kolaydır. "ServiceWorker ile özellik raporlama" bölümüne bakın. Chrome'da gönderilen "yerel" ipuçları (DPR, Genişlik, Kaynak-Genişlik), saf donanım tabanlı bir uygulama tüm resim isteklerini geciktireceği için tarayıcıda uygulanır.

  7. Nereden daha fazla bilgi edinebilirim, daha fazla demo görebilirim ve hangi konularda bilgi edinebilirim? Açıklayıcı dokümanı inceleyin ve geri bildiriminiz veya başka sorularınız varsa GitHub'da sorun bildirebilirsiniz.