BBC Etkileşimli İçeriği AMP, Uygulamalar ve Web Üzerinde Nasıl Çalışır?
Yayınlanan: 2022-03-10BBC'deki Görsel Gazetecilik ekibinde, hesap makinelerinden görselleştirmelere, yeni hikaye anlatımı formatlarına kadar heyecan verici görsel, ilgi çekici ve etkileşimli içerikler üretiyoruz.
Her uygulama, kendi başına üretmek için benzersiz bir zorluktur, ancak çoğu projeyi birçok farklı dilde dağıtmamız gerektiğini düşündüğünüzde daha da fazlası. İçeriğimiz yalnızca BBC Haber ve Spor web sitelerinde değil, iOS ve Android'deki eşdeğer uygulamalarında ve BBC içeriği tüketen üçüncü taraf sitelerinde çalışmalıdır.
Şimdi, AMP, Facebook Instant Articles ve Apple News gibi artan sayıda yeni platform olduğunu düşünün. Her platformun kendi sınırlamaları ve tescilli yayınlama mekanizması vardır. Tüm bu ortamlarda çalışan etkileşimli içerik oluşturmak gerçek bir meydan okumadır. BBC'de soruna nasıl yaklaştığımızı anlatacağım.
Örnek: Kanonik ve AMP
Eylemde görene kadar bu biraz teorik, o yüzden doğrudan bir örneğe bakalım.
İşte Görsel Gazetecilik içeriği içeren bir BBC makalesi:
Bu, makalenin standart sürümüdür, yani ana sayfadan makaleye giderseniz alacağınız varsayılan sürümdür.
Şimdi yazının AMP versiyonuna bakalım:
Standart ve AMP sürümleri aynı görünse de aslında farklı davranışlara sahip iki farklı uç noktadır:
- Standart sürüm, formu gönderdiğinizde sizi seçtiğiniz ülkeye yönlendirir.
- Bir AMP iframe içinden ana sayfayı kaydıramayacağınız için AMP sürümü sizi kaydırmaz.
- AMP sürümü, görünüm alanı boyutuna ve kaydırma konumuna bağlı olarak 'Daha Fazlasını Göster' düğmesiyle kırpılmış bir iframe gösterir. Bu, AMP'nin bir özelliğidir.
Bu makalenin kanonik ve AMP sürümlerinin yanı sıra bu proje, kendi incelikleri ve sınırlamaları olan başka bir platform olan Haber Uygulamasına da gönderildi. Peki tüm bu platformları nasıl destekleyeceğiz?
Takım Anahtardır
İçeriğimizi sıfırdan oluşturmuyoruz. Tek bir komutla ortak bir proje oluşturmak için Node kullanan Yeoman tabanlı bir iskelemiz var.
Yeni projeler, Webpack, SASS, dağıtım ve kutudan çıktığı gibi bir bileşen oluşturma yapısı ile birlikte gelir. Uluslararasılaştırma, bir Gidon şablonlama sistemi kullanılarak projelerimizde de yer almaktadır. Tom Maslen, duyarlı web tasarımını çok dilli hale getirmek için 13 ipucu yazısında bu konuda ayrıntılı olarak yazıyor.
Kutunun dışında, bu bir platform için derleme yapmak için oldukça iyi çalışıyor ancak birden fazla platformu desteklememiz gerekiyor . Biraz koda girelim.
Gömme ve Bağımsız
Görsel Gazetecilikte bazen içeriğimizi bir iframe içinde çıkarırız, böylece genel komut dosyası ve stilden etkilenmeyen bir makaleye kendi kendine yeten bir "gömülü" olabilir. Bunun bir örneği, bu makalenin önceki bölümlerinde yer alan kurallı örneğe yerleştirilmiş Donald Trump etkileşimidir.
Öte yandan, bazen içeriğimizi ham HTML olarak çıkarırız. Bunu yalnızca tüm sayfa üzerinde kontrolümüz olduğunda veya gerçekten duyarlı kaydırma etkileşimine ihtiyacımız olduğunda yapıyoruz. Bunlara sırasıyla “gömme” ve “bağımsız” çıktılarımız diyelim.
“Bir robot işinizi alacak mı?” hem "gömme" hem de "bağımsız" biçimlerde etkileşimli.
İçeriğin her iki sürümü de kodlarının büyük çoğunluğunu paylaşacak, ancak iki sürüm arasında JavaScript'in uygulanmasında bazı önemli farklılıklar olacaktır.
Örneğin, 'Otomasyon riskimi öğren' düğmesine bakın. Kullanıcı gönder düğmesine bastığında, otomatik olarak sonuçlarına kaydırılmalıdır.
Kodun "bağımsız" versiyonu şöyle görünebilir:
button.on('click', (e) => { window.scrollTo(0, resultsContainer.offsetTop); });
Ancak bunu "gömme" çıktısı olarak oluşturuyorsanız, içeriğinizin bir iframe içinde olduğunu bilirsiniz, bu nedenle onu farklı şekilde kodlamanız gerekir:
// inside the iframe button.on('click', () => { window.parent.postMessage({ name: 'scroll', offset: resultsContainer.offsetTop }, '*'); }); // inside the host page window.addEventListener('message', (event) => { if (event.data.name === 'scroll') { window.scrollTo(0, iframe.offsetTop + event.data.offset); } });
Ayrıca, uygulamamızın tam ekrana geçmesi gerekiyorsa ne olur? "Bağımsız" bir sayfadaysanız, bu yeterince kolaydır:
document.body.className += ' fullscreen';
.fullscreen { position: fixed; top: 0; left: 0; right: 0; bottom: 0; }
Bunu bir "gömme" içinden yapmaya çalışırsak, aynı kod, içeriğin görünüm alanı yerine iframe'in genişliğine ve yüksekliğine göre ölçeklenmesini sağlar:
…yani, iframe içinde tam ekran stili uygulamaya ek olarak, stili iframe'in kendisine uygulamak için ana makine sayfasına bir mesaj göndermemiz gerekiyor:
// iframe window.parent.postMessage({ name: 'window:toggleFullScreen' }, '*'); // host page window.addEventListener('message', function () { if (event.data.name === 'window:toggleFullScreen') { document.getElementById(iframeUid).className += ' fullscreen'; } });
Bu, birden fazla platformu desteklemeye başladığınızda çok sayıda spagetti koduna dönüşebilir:
button.on('click', (e) => { if (inStandalonePage()) { window.scrollTo(0, resultsContainer.offsetTop); } else { window.parent.postMessage({ name: 'scroll', offset: resultsContainer.offsetTop }, '*'); } });
Projenizdeki her anlamlı DOM etkileşimi için bunun bir eşdeğerini yaptığınızı hayal edin. Titremeyi bitirdikten sonra, kendinize rahatlatıcı bir çay yapın ve okumaya devam edin.
Soyutlama Anahtardır
Geliştiricilerimizi bu koşulları kodlarının içinde işlemeye zorlamak yerine, içerikleri ve ortamları arasında bir soyutlama katmanı oluşturduk. Bu katmana 'sarmalayıcı' diyoruz.
DOM veya yerel tarayıcı olaylarını doğrudan sorgulamak yerine, artık isteğimizi wrapper
modül aracılığıyla proxy yapabiliriz.
import wrapper from 'wrapper'; button.on('click', () => { wrapper.scrollTo(resultsContainer.offsetTop); });
Her platformun, ortak bir sarmalayıcı yöntemleri arabirimine uyan kendi sarmalayıcı uygulaması vardır. Sarmalayıcı, içeriğimizi sarar ve karmaşıklığı bizim için halleder.
Bağımsız sarmalayıcının scrollTo
işlevini uygulaması çok basittir, argümanımızı doğrudan başlığın altındaki window.scrollTo
öğesine iletir.
Şimdi aynı işlevi iframe için uygulayan ayrı bir sarmalayıcıya bakalım:
"Gömülü" sarmalayıcı, "bağımsız" örnektekiyle aynı argümanı alır ancak değeri, iframe ofsetinin hesaba katılması için manipüle eder. Bu ekleme olmasaydı, kullanıcımızı tamamen istenmeyen bir yere kaydırmış olurduk.
Sarıcı Kalıbı
Sarmalayıcıları kullanmak, projeler arasında daha temiz, daha okunabilir ve tutarlı kodlar sağlar. Ayrıca, yöntemleri daha performanslı ve erişilebilir hale getirmek için sarmalayıcılarda kademeli iyileştirmeler yaptığımızdan, zaman içinde mikro optimizasyonlara izin verir. Bu nedenle projeniz birçok geliştiricinin deneyiminden yararlanabilir.
Peki, bir sarmalayıcı neye benziyor?
Sarıcı Yapısı
Her sarmalayıcı temelde üç şeyden oluşur: bir Gidon şablonu, sarmalayıcı JS dosyası ve sarmalayıcıya özgü stili belirten bir SASS dosyası. Ek olarak, her bir sarmalayıcının kendi ön derlemesinden ve temizlemesinden sorumlu olması için, temel yapı iskelesinin maruz kaldığı olaylara bağlanan oluşturma görevleri vardır.
Bu, yerleştirme sarmalayıcısının basitleştirilmiş bir görünümüdür:
embed-wrapper/ templates/ wrapper.hbs js/ wrapper.js scss/ wrapper.scss
Temel yapı iskelemiz, ana proje şablonunuzu sarmalayıcı tarafından tüketilen bir Gidon kısmi olarak gösterir. Örneğin, templates/wrapper.hbs
içerebilir:
<div class="bbc-news-vj-wrapper--embed"> {{>your-application}} </div>
scss/wrapper.scss
, uygulama kodunuzun kendisini tanımlaması gerekmeyen sarmalayıcıya özel stil içerir. Örneğin, gömme sarmalayıcı, iframe içinde birçok BBC News stilini çoğaltır.
Son olarak, js/wrapper.js
, aşağıda ayrıntıları verilen sarmalayıcı API'sinin çerçevelenmiş uygulamasını içerir. Uygulama koduyla derlenmek yerine projeye ayrı olarak gönderilir - Web paketi oluşturma sürecimizde wrapper
global olarak işaretliyoruz. Bu, uygulamamızı birden fazla platforma teslim etmemize rağmen, kodu yalnızca bir kez derlediğimiz anlamına gelir.
sarmalayıcı API'si
Sarıcı API, bir dizi önemli tarayıcı etkileşimini özetler. İşte en önemlileri:
scrollTo(int)
Etkin pencerede verilen konuma kaydırır. Sarmalayıcı, ana sayfanın doğru konuma kaydırılması için kaydırmayı tetiklemeden önce sağlanan tamsayıyı normalleştirir .
getScrollPosition: int
Kullanıcının geçerli (normalleştirilmiş) kaydırma konumunu döndürür. İç çerçeve söz konusu olduğunda, bu, uygulamanıza iletilen kaydırma konumunun, iç çerçeve görünümün en üstünde olana kadar aslında negatif olduğu anlamına gelir. Bu çok kullanışlıdır ve bir bileşeni yalnızca görüntülendiğinde canlandırmak gibi şeyler yapmamızı sağlar.
onScroll(callback)
Scroll olayına bir kanca sağlar. Bağımsız sarmalayıcıda bu, esasen yerel kaydırma olayına takılır. Gömme sarmalayıcısında, kaydırma olayı postMessage yoluyla iletildiğinden, alınmasında hafif bir gecikme olacaktır.
viewport: {height: int, width: int}
Görüntü alanı yüksekliğini ve genişliğini almak için bir yöntem (çünkü bu, bir iframe içinden sorgulandığında çok farklı şekilde uygulanır).
toggleFullScreen
Bağımsız modda, BBC menüsünü ve altbilgiyi görünümden gizleriz ve bir position: fixed
. Haber Uygulamasında hiçbir şey yapmıyoruz - içerik zaten tam ekran. Karmaşık olan, iframe'in hem içinde hem de dışında stillerin postMessage ile koordine edilmesine dayanan iframe'dir.
markPageAsLoaded
Paketleyiciye içeriğinizin yüklendiğini söyleyin. Bu, içeriğimizin biz uygulamaya hazır olduğunu açıkça söyleyene kadar içeriğimizi kullanıcıya göstermeye çalışmayacak olan Haber Uygulamasında çalışması için çok önemlidir. Ayrıca içeriğimizin web sürümlerinde yükleme döndürücüyü kaldırır.
Sarmalayıcıların Listesi
Gelecekte, Facebook Instant Articles ve Apple News gibi büyük platformlar için ek paketleyiciler oluşturmayı öngörüyoruz. Bugüne kadar altı sarmalayıcı oluşturduk:
Bağımsız Sarıcı
İçeriğimizin bağımsız sayfalara girmesi gereken versiyonu. BBC markasıyla birlikte gelir.
Gömme Sarmalayıcı
İçeriğin kontrolünü elimizde tuttuğumuzdan, makalelerin içinde oturmak veya BBC dışı sitelere ortak olmak için güvenli olan içeriğimizin iframe sürümü.
AMP Sarıcı
Bu, AMP sayfalarına amp-iframe
olarak alınan uç noktadır.
Haber Uygulaması Sarıcı
İçeriğimiz, tescilli bir bbcvisualjournalism://
protokolüne çağrı yapmalıdır.
çekirdek sarıcı
Yalnızca HTML'yi içerir - projemizin CSS veya JavaScript'lerinden hiçbiri.
JSON Sarıcı
BBC ürünleri arasında paylaşım için içeriğimizin bir JSON temsili.
Platformlara Kadar Kablo Sarmalayıcıları
İçeriğimizin BBC sitesinde görünmesi için gazetecilere ad alanlı bir yol sağlıyoruz:
/include/[department]/[unique ID], eg
/include/visual-journalism/123-quiz
Gazeteci, bu “include path”i, makale yapısını veri tabanına kaydeden CMS'ye koyar. Tüm ürün ve hizmetler bu yayınlama mekanizmasının aşağı akışında yer alır. Her platform, istediği içeriğin lezzetini seçmekten ve bu içeriği bir proxy sunucusundan istemekten sorumludur.
Donald Trump'ı daha önce etkileşimli olarak ele alalım. Burada, CMS'deki içerme yolu:
/include/newsspec/15996-trump-tracker/english/index
Kurallı makale sayfası, içeriğin "gömülü" sürümünü istediğini bildiğinden, içerme yoluna /embed
ekler:
/include/newsspec/15996-trump-tracker/english/index
/embed
…vekil sunucudan talep etmeden önce:
https://news.files.bbci.co.uk/include/newsspec/15996-trump-tracker/english/index/embed
AMP sayfası ise içerme yolunu görür ve /amp
öğesini ekler:
/include/newsspec/15996-trump-tracker/english/index
/amp
AMP oluşturucu, içeriğimize referans veren bazı AMP HTML'lerini oluşturmak için biraz sihir yapar ve /amp
sürümünü bir iframe olarak çeker:
<amp-iframe src="https://news.files.bbci.co.uk/include/newsspec/15996-trump-tracker/english/index/amp" width="640" height="360"> <!-- some other AMP elements here --> </amp-iframe>
Desteklenen her platformun kendi içerik sürümü vardır:
/include/newsspec/15996-trump-tracker/english/index
/amp
/include/newsspec/15996-trump-tracker/english/index
/core
/include/newsspec/15996-trump-tracker/english/index
/envelope
...ve bunun gibi
Bu çözüm, ortaya çıktıkça daha fazla platform türünü içerecek şekilde ölçeklenebilir.
Soyutlama Zordur
Bir "bir kez yaz, her yere dağıt" mimarisi oluşturmak kulağa oldukça idealist geliyor ve öyle. Sarma mimarisinin çalışması için soyutlama içinde çalışma konusunda çok katı olmalıyız. Bu, "[buraya platform adını girin] içinde çalışmasını sağlamak için bu hileli şeyi yapmak" cazibesine karşı savaşmamız gerektiği anlamına gelir. İçeriğimizin gönderildiği ortamdan tamamen habersiz olmasını istiyoruz - ancak bunu söylemek yapmaktan daha kolay.
Platformun Özelliklerini Soyut Olarak Yapılandırmak Zor
Soyutlama yaklaşımımızdan önce, örneğin iframe'imizin işaretlemesi de dahil olmak üzere çıktımızın her yönü üzerinde tam kontrolümüz vardı. Erişilebilirlik nedenleriyle iframe'e bir title
niteliği eklemek gibi proje bazında herhangi bir şeyi ince ayar yapmamız gerekirse, işaretlemeyi düzenleyebilirdik.
Artık sarmalayıcı işaretlemesi projeden ayrı olarak var olduğuna göre, onu yapılandırmanın tek yolu, iskelenin kendisindeki bir kancayı ortaya çıkarmak olacaktır. Bunu platformlar arası özellikler için nispeten kolay bir şekilde yapabiliriz, ancak belirli platformlar için kancaları açığa çıkarmak soyutlamayı bozar. Yalnızca bir sarmalayıcı tarafından kullanılan bir 'iframe başlığı' yapılandırma seçeneğini gerçekten göstermek istemiyoruz.
Özelliği daha genel olarak adlandırabiliriz, örneğin title
, ve ardından bu değeri iframe title
özelliği olarak kullanabiliriz. Bununla birlikte, neyin nerede kullanıldığını takip etmek zorlaşmaya başlar ve konfigürasyonumuzu artık anlayamayacak kadar soyutlama riskine gireriz. Genel olarak, yapılandırmamızı mümkün olduğunca yalın tutmaya çalışıyoruz, yalnızca küresel kullanıma sahip özellikleri ayarlıyoruz.
Bileşen Davranışı Karmaşık Olabilir
Web'de, sharetools modülümüz, ayrı ayrı tıklanabilir ve önceden doldurulmuş bir paylaşım mesajını yeni bir pencerede açan sosyal ağ paylaşım düğmeleri yayar.
Haber Uygulamasında, mobil web üzerinden paylaşmak istemiyoruz. Kullanıcı ilgili uygulamayı yüklemişse (örneğin Twitter), uygulamanın kendisinde paylaşmak istiyoruz. İdeal olarak, kullanıcıya yerel iOS/Android paylaşım menüsünü sunmak, ardından uygulamayı onlar için önceden doldurulmuş bir paylaşım mesajıyla açmadan önce paylaşım seçeneklerini seçmelerine izin vermek istiyoruz. Tescilli bbcvisualjournalism://
protokolüne bir çağrı yaparak uygulamadan yerel paylaşım menüsünü tetikleyebiliriz.
Ancak, 'Sonuçlarınızı paylaşın' bölümünde 'Twitter'a veya 'Facebook'a dokunsanız da bu ekran tetiklenecek, böylece kullanıcı seçimini iki kez yapmak zorunda kalacak; içeriğimizde ilk kez ve yerel açılır pencerede ikinci kez.
Bu garip bir kullanıcı yolculuğu, bu nedenle Haberler uygulamasından tek tek paylaşım simgelerini kaldırmak ve bunun yerine genel bir paylaşım düğmesi göstermek istiyoruz. Bunu, bileşeni oluşturmadan önce hangi sarmalayıcının kullanımda olduğunu açıkça kontrol ederek yapabiliriz.
Sarmalayıcı soyutlama katmanını oluşturmak, bir bütün olarak projeler için iyi sonuç verir, ancak sarmalayıcı seçiminiz bileşen düzeyindeki değişiklikleri etkilediğinde, temiz bir soyutlama elde etmek çok zordur. Bu durumda, biraz soyutlamayı kaybettik ve kodumuzda biraz dağınık çatallama mantığımız var. Neyse ki, bu vakalar nadirdir.
Eksik Özellikleri Nasıl Ele Alırız?
Soyutlamayı sürdürmek her şey yolunda ve iyidir. Kodumuz, sarmalayıcıya platformun ne yapmasını istediğini söyler, örneğin "tam ekrana geç". Ama ya gönderdiğimiz platform tam ekrana geçemezse?
Paketleyici, tamamen kırılmamak için elinden gelenin en iyisini yapacaktır, ancak sonuçta, yöntem başarılı olsun ya da olmasın, incelikle çalışan bir çözüme geri dönen bir tasarıma ihtiyacınız var. Defansif tasarım yapmalıyız.
Diyelim ki bazı çubuk grafikler içeren bir sonuç bölümümüz var. Çubuk grafik değerlerini, grafikler kaydırılana kadar genellikle sıfırda tutmayı severiz, bu noktada çubukları doğru genişliklerinde canlandırmayı tetikleriz.
Ancak, AMP sarmalayıcımızda olduğu gibi, kaydırma konumuna bağlanacak bir mekanizmamız yoksa, çubuklar sonsuza kadar sıfırda kalır ve bu tamamen yanıltıcı bir deneyimdir.
Tasarımlarımızda giderek daha fazla ilerici bir geliştirme yaklaşımı benimsemeye çalışıyoruz. Örneğin, varsayılan olarak tüm platformlar için görünür olacak, ancak sarmalayıcı kaydırmayı destekliyorsa gizlenen bir düğme sağlayabiliriz. Bu şekilde, kaydırma animasyonu tetikleyemezse, kullanıcı yine de animasyonu manuel olarak tetikleyebilir.
Gelecek için planlar
Apple News ve Facebook Instant Articles gibi platformlar için yeni paketleyiciler geliştirmeyi ve tüm yeni platformlara kutudan çıktığı haliyle içeriğimizin 'temel' bir versiyonunu sunmayı umuyoruz.
Ayrıca aşamalı geliştirmede daha iyi olmayı umuyoruz; bu alanda başarılı olmak defansif olarak gelişmek demektir. Şu anda ve gelecekte tüm platformların belirli bir etkileşimi destekleyeceğini asla varsayamazsınız, ancak iyi tasarlanmış bir proje, ilk teknik engele düşmeden temel mesajını iletebilmelidir.
Paketleyicinin sınırları içinde çalışmak biraz paradigma kaymasıdır ve uzun vadeli çözüm açısından biraz yarım kalmış bir ev gibi hissettirir. Ancak sektör, platformlar arası bir standartta olgunlaşana kadar, yayıncılar kendi çözümlerini sunmaya veya platformdan platforma dönüşüm için Distro gibi araçları kullanmaya veya hedef kitlelerinin tüm bölümlerini tamamen görmezden gelmeye zorlanacak.
Bizim için erken günler, ancak şimdiye kadar içeriğimizi bir kez oluşturmak ve izleyicilerimizin şu anda kullandığı sayısız platforma sunmak için sarmalayıcı deseni kullanma konusunda büyük başarı elde ettik.