เนื้อหาเชิงโต้ตอบของ BBC ทำงานอย่างไรใน AMP, แอพ และเว็บ

เผยแพร่แล้ว: 2022-03-10
สรุปอย่างรวดเร็ว ↬ การ เผยแพร่เนื้อหาไปยังสื่อจำนวนมากโดยที่ไม่ต้องเสียค่าใช้จ่ายในการพัฒนาเพิ่มเติมอาจเป็นเรื่องยาก Chris Ashton อธิบายว่าพวกเขาเข้าถึงปัญหาอย่างไรในแผนก Visual Journalism ของ BBC

ในทีม Visual Journalism ของ BBC เราผลิตเนื้อหาที่เป็นภาพที่น่าสนใจ มีส่วนร่วมและโต้ตอบได้ ตั้งแต่เครื่องคำนวณไปจนถึงการแสดงภาพรูปแบบการเล่าเรื่องรูปแบบใหม่

แต่ละแอปพลิเคชันมีความท้าทายเฉพาะตัวในการผลิตด้วยตัวของมันเอง แต่ยิ่งไปกว่านั้น เมื่อคุณพิจารณาว่าเราจำเป็นต้องปรับใช้โปรเจ็กต์ส่วนใหญ่ในภาษาต่างๆ มากมาย เนื้อหาของเราต้องใช้งานได้ไม่เฉพาะในเว็บไซต์ข่าวและกีฬาของ BBC แต่ในแอปที่เทียบเท่ากันบน iOS และ Android รวมถึงเว็บไซต์บุคคลที่สามที่ใช้เนื้อหา BBC

ตอนนี้ให้พิจารณาว่า มีแพลตฟอร์มใหม่ๆ เพิ่มขึ้นเรื่อยๆ เช่น AMP, Facebook Instant Articles และ Apple News แต่ละแพลตฟอร์มมีข้อจำกัดและกลไกการเผยแพร่ที่เป็นกรรมสิทธิ์ของตนเอง การสร้างเนื้อหาเชิงโต้ตอบที่ใช้งานได้ในสภาพแวดล้อมเหล่านี้เป็นความท้าทายที่แท้จริง ฉันจะอธิบายว่าเราแก้ปัญหาที่ BBC ได้อย่างไร

ตัวอย่าง: Canonical กับ AMP

ทั้งหมดนี้เป็นเพียงทฤษฎีเล็กน้อย จนกว่าคุณจะเห็นมันในการดำเนินการ ดังนั้น มาเจาะลึกเข้าไปในตัวอย่างกัน

นี่คือบทความของ BBC ที่มีเนื้อหา Visual Journalism:

สกรีนช็อตของหน้าข่าว BBC ที่มีเนื้อหา Visual Journalism
เนื้อหา Visual Journalism ของเราเริ่มต้นด้วยภาพประกอบของ Donald Trump และอยู่ใน iframe

นี่เป็นเวอร์ชันบัญญัติของบทความ กล่าวคือ เวอร์ชันเริ่มต้น ซึ่งคุณจะได้รับหากคุณไปยังบทความจากหน้าแรก

เพิ่มเติมหลังกระโดด! อ่านต่อด้านล่าง↓

มาดูบทความเวอร์ชัน AMP กัน:

สกรีนช็อตของหน้า BBC News AMP ที่มีเนื้อหาเหมือนเดิม แต่เนื้อหาถูกตัดและมีปุ่มแสดงเพิ่มเติม
เนื้อหานี้ดูเหมือนเนื้อหาเดียวกันกับบทความทั่วไป แต่กำลังดึง iframe อื่นที่ออกแบบมาสำหรับ AMP . โดยเฉพาะ

แม้ว่าเวอร์ชัน Canonical และ AMP จะเหมือนกัน แต่ แท้จริงแล้วเป็นปลายทางสองจุด ที่แตกต่างกันโดยมีพฤติกรรมต่างกัน:

  • เวอร์ชันตามรูปแบบบัญญัติจะเลื่อนคุณไปยังประเทศที่คุณเลือกเมื่อคุณส่งแบบฟอร์ม
  • เวอร์ชัน AMP ไม่เลื่อนให้คุณ เนื่องจากคุณไม่สามารถเลื่อนหน้าหลักจากภายใน AMP iframe
  • เวอร์ชัน AMP แสดง iframe ที่ครอบตัดพร้อมปุ่ม "แสดงเพิ่มเติม" ทั้งนี้ขึ้นอยู่กับขนาดวิวพอร์ตและตำแหน่งการเลื่อน นี่คือคุณลักษณะของ AMP

เช่นเดียวกับเวอร์ชัน Canonical และ AMP ของบทความนี้ โปรเจ็กต์นี้ยังถูกส่งไปยังแอป News ซึ่งเป็นอีกแพลตฟอร์มหนึ่งที่มีความสลับซับซ้อนและข้อจำกัดของตัวเอง แล้ว เราจะสนับสนุนแพลตฟอร์มเหล่านี้ทั้งหมดได้อย่างไร?

เครื่องมือช่างเป็นกุญแจสำคัญ

เราไม่ได้สร้างเนื้อหาของเราตั้งแต่เริ่มต้น เรามีโครงนั่งร้านแบบ Yeoman ซึ่งใช้ Node เพื่อสร้างโครงการสำเร็จรูปด้วยคำสั่งเดียว

โปรเจ็กต์ใหม่มาพร้อมกับ Webpack, SASS, การปรับใช้ และโครงสร้างการจัดองค์ประกอบตั้งแต่แกะกล่อง ความเป็นสากลยังรวมอยู่ในโปรเจ็กต์ของเราโดยใช้ระบบการสร้างเทมเพลตของแฮนด์บาร์ Tom Maslen เขียนเกี่ยวกับสิ่งนี้โดยละเอียดในโพสต์ของเขา 13 เคล็ดลับสำหรับการออกแบบเว็บที่ตอบสนองได้หลายภาษา

ใช้งานได้ดีสำหรับการคอมไพล์สำหรับแพลตฟอร์มเดียว แต่ เราต้องรองรับหลายแพลตฟอร์ม มาเจาะลึกโค้ดกัน

ฝัง vs. สแตนด์อโลน

ใน Visual Journalism บางครั้งเราส่งออกเนื้อหาของเราใน iframe เพื่อให้สามารถ "ฝัง" ที่มีอยู่ในตัวเองในบทความได้โดยไม่ได้รับผลกระทบจากสคริปต์และการจัดรูปแบบทั่วโลก ตัวอย่างนี้เป็นแบบโต้ตอบของโดนัลด์ ทรัมป์ ที่ฝังอยู่ในตัวอย่างตามรูปแบบบัญญัติก่อนหน้าในบทความนี้

ในทางกลับกัน บางครั้งเราส่งออกเนื้อหาของเราในรูปแบบ HTML ดิบ เราทำสิ่งนี้ก็ต่อเมื่อเราสามารถควบคุมทั้งหน้าได้หรือถ้าเราต้องการการโต้ตอบการเลื่อนที่ตอบสนองจริงๆ เรียกเอาต์พุตเหล่านี้ว่า "embed" และ "standalone" ตามลำดับ

ลองนึกภาพว่าเราจะสร้าง "หุ่นยนต์จะรับงานของคุณหรือไม่" โต้ตอบได้ทั้งในรูปแบบ "ฝัง" และ "สแตนด์อโลน"

ภาพหน้าจอสองภาพเคียงข้างกัน หนึ่งแสดงเนื้อหาที่ฝังอยู่ในหน้า อีกอันแสดงเนื้อหาเดียวกันกับหน้าในสิทธิ์ของตนเอง
ตัวอย่างที่ประดิษฐ์ขึ้นโดยแสดง 'ฝัง' ทางด้านซ้าย เทียบกับเนื้อหาที่เป็นหน้า 'สแตนด์อโลน' ทางด้านขวา

เนื้อหาทั้งสองเวอร์ชันจะใช้โค้ดส่วนใหญ่ร่วมกัน แต่จะมีความแตกต่างที่สำคัญบางประการในการใช้งาน JavaScript ระหว่างทั้งสองเวอร์ชัน

ตัวอย่างเช่น ดูที่ปุ่ม 'ค้นหาความเสี่ยงด้านระบบอัตโนมัติของฉัน' เมื่อผู้ใช้กดปุ่มส่ง พวกเขาควรจะเลื่อนไปที่ผลลัพธ์โดยอัตโนมัติ

โค้ดเวอร์ชัน "สแตนด์อโลน" อาจมีลักษณะดังนี้:

 button.on('click', (e) => { window.scrollTo(0, resultsContainer.offsetTop); });

แต่ถ้าคุณสร้างสิ่งนี้เป็นเอาต์พุต "ฝัง" คุณรู้ว่าเนื้อหาของคุณอยู่ใน iframe ดังนั้นจะต้องเขียนโค้ดให้ต่างออกไป:

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

จะเกิดอะไรขึ้นหากแอปพลิเคชันของเราต้องแสดงแบบเต็มหน้าจอ ซึ่งง่ายพอหากคุณอยู่ในหน้า "สแตนด์อโลน":

 document.body.className += ' fullscreen';
 .fullscreen { position: fixed; top: 0; left: 0; right: 0; bottom: 0; } 
ภาพหน้าจอของการฝังแผนที่ด้วยการซ้อนทับ "แตะเพื่อโต้ตอบ" ตามด้วยภาพหน้าจอของแผนที่ในโหมดเต็มหน้าจอหลังจากที่แตะแล้ว
เราใช้ฟังก์ชันแบบเต็มหน้าจอได้สำเร็จเพื่อใช้งานโมดูลแผนที่บนมือถือของเราให้เกิดประโยชน์สูงสุด

หากเราพยายามทำสิ่งนี้จากภายใน "ฝัง" โค้ดเดียวกันนี้จะมีการปรับขนาดเนื้อหาเป็นความกว้างและความสูงของ iframe แทนที่จะเป็นวิวพอร์ต:

สกรีนช็อตของตัวอย่างแผนที่เช่นเดิม แต่โหมดเต็มหน้าจอมีปัญหา ข้อความจากบทความโดยรอบสามารถมองเห็นได้ในที่ที่ไม่ควรปรากฏ
การแสดงเต็มหน้าจอจากภายใน iframe อาจเป็นเรื่องยาก

…ดังนั้น นอกเหนือจากการใช้สไตล์เต็มหน้าจอใน iframe แล้ว เราต้องส่งข้อความไปยังหน้าโฮสต์เพื่อใช้การจัดสไตล์กับ iframe:

 // iframe window.parent.postMessage({ name: 'window:toggleFullScreen' }, '*'); // host page window.addEventListener('message', function () { if (event.data.name === 'window:toggleFullScreen') { document.getElementById(iframeUid).className += ' fullscreen'; } });

สิ่งนี้สามารถแปลเป็นรหัสปาเก็ตตี้ได้มากมายเมื่อคุณเริ่มรองรับหลายแพลตฟอร์ม:

 button.on('click', (e) => { if (inStandalonePage()) { window.scrollTo(0, resultsContainer.offsetTop); } else { window.parent.postMessage({ name: 'scroll', offset: resultsContainer.offsetTop }, '*'); } });

ลองนึกภาพการทำสิ่งที่เทียบเท่ากับทุกๆ การโต้ตอบ DOM ที่มีความหมายในโครงการของคุณ เมื่อคุณสั่นสะท้านเสร็จแล้ว ให้ดื่มชาเพื่อผ่อนคลายและอ่านต่อ

สิ่งที่เป็นนามธรรมคือกุญแจสำคัญ

แทนที่จะบังคับให้นักพัฒนาของเราจัดการกับเงื่อนไขเหล่านี้ภายในโค้ดของพวกเขา เราได้สร้างเลเยอร์ที่เป็นนามธรรมระหว่างเนื้อหากับสภาพแวดล้อม เราเรียกเลเยอร์นี้ว่า 'ตัวห่อหุ้ม'

แทนที่จะสอบถาม DOM หรือเหตุการณ์เบราว์เซอร์ดั้งเดิมโดยตรง ตอนนี้เราสามารถพร็อกซีคำขอของเราผ่านโมดูล wrapper ปเปอร์

 import wrapper from 'wrapper'; button.on('click', () => { wrapper.scrollTo(resultsContainer.offsetTop); });

แต่ละแพลตฟอร์มมีการนำ wrapper ไปใช้โดยสอดคล้องกับอินเทอร์เฟซทั่วไปของเมธอด wrapper เสื้อคลุมห่อหุ้มเนื้อหาของเราและจัดการกับความซับซ้อนสำหรับเรา

ไดอะแกรม UML แสดงว่าเมื่อแอปพลิเคชันของเราเรียกใช้เมธอด Wrapper Scroll แบบสแตนด์อโลน Wrapper จะเรียกใช้เมธอดการเลื่อนแบบเนทีฟในหน้าโฮสต์
การใช้งาน 'scrollTo' อย่างง่ายโดย wrapper แบบสแตนด์อโลน

การปรับใช้ฟังก์ชัน scrollTo ของ wrapper แบบสแตนด์อโลนนั้นง่ายมาก โดยส่งอาร์กิวเมนต์ของเราโดยตรงไปที่ window.scrollTo ภายใต้ประทุน

ตอนนี้ ให้ดูที่ wrapper แยกต่างหากที่ใช้ฟังก์ชันเดียวกันสำหรับ iframe:

ไดอะแกรม UML แสดงว่าเมื่อแอปพลิเคชันของเราเรียกใช้เมธอดการเลื่อน Wrapper แบบฝัง Wrapper แบบฝังจะรวมตำแหน่งการเลื่อนที่ร้องขอเข้ากับออฟเซ็ตของ iframe ก่อนที่จะทริกเกอร์วิธีการเลื่อนแบบเนทีฟในหน้าโฮสต์
การใช้งาน 'scrollTo' ขั้นสูงโดย wrapper แบบฝัง

Wrapper "ฝัง" ใช้อาร์กิวเมนต์เดียวกับในตัวอย่าง "สแตนด์อโลน" แต่จัดการค่าเพื่อพิจารณาออฟเซ็ต iframe หากไม่มีการเพิ่มนี้ เราจะเลื่อนผู้ใช้ของเราไปที่ใดที่หนึ่งโดยไม่ได้ตั้งใจ

รูปแบบกระดาษห่อ

การใช้ wrappers ส่งผลให้โค้ดสะอาดขึ้น อ่านง่ายขึ้น และสอดคล้องกันระหว่างโปรเจ็กต์ต่างๆ นอกจากนี้ยังช่วยให้มีการปรับให้เหมาะสมระดับไมโครเมื่อเวลาผ่านไป เนื่องจากเราทำการปรับปรุงส่วนเพิ่มในเครื่องห่อเพื่อให้วิธีการมีประสิทธิภาพและเข้าถึงได้มากขึ้น ดังนั้น โครงการของคุณสามารถได้รับประโยชน์จากประสบการณ์ของนักพัฒนาหลายคน

ดังนั้นเสื้อคลุมมีลักษณะอย่างไร?

โครงสร้างห่อหุ้ม

Wrapper แต่ละอันประกอบด้วยสามสิ่ง: เทมเพลต Handlebars, ไฟล์ wrapper JS และไฟล์ SASS ที่แสดงถึงสไตล์เฉพาะของ Wrapper นอกจากนี้ยังมีงานสร้างที่เกี่ยวโยงกับเหตุการณ์ที่เปิดเผยโดยโครงนั่งร้านพื้นฐาน เพื่อให้เสื้อคลุมแต่ละตัวมีหน้าที่ในการคอมไพล์ล่วงหน้าและการล้างข้อมูลของตัวเอง

นี่คือมุมมองที่เรียบง่ายของ Wrapper แบบฝัง:

 embed-wrapper/ templates/ wrapper.hbs js/ wrapper.js scss/ wrapper.scss

นั่งร้านพื้นฐานของเราเผยให้เห็นเทมเพลตโครงการหลักของคุณเป็นบางส่วนของแฮนด์บาร์ ซึ่งใช้โดยเสื้อคลุม ตัวอย่างเช่น templates/wrapper.hbs อาจมี:

 <div class="bbc-news-vj-wrapper--embed"> {{>your-application}} </div>

scss/wrapper.scss มีการกำหนดสไตล์เฉพาะของ wrapper ซึ่งโค้ดแอปพลิเคชันของคุณไม่จำเป็นต้องกำหนดเอง ตัวอย่างเช่น Wrapper แบบฝัง จำลองสไตล์ของ BBC News จำนวนมากใน iframe

สุดท้าย js/wrapper.js มีการใช้งาน iframed ของ wrapper API โดยมีรายละเอียดด้านล่าง มันถูกจัดส่งแยกต่างหากไปยังโปรเจ็กต์ แทนที่จะคอมไพล์ด้วยโค้ดแอปพลิเคชัน — เราตั้งค่าสถานะ wrapper เป็นโกลบอลในกระบวนการสร้าง Webpack ของเรา ซึ่งหมายความว่าแม้ว่าเราจะส่งแอปพลิเคชันของเราไปยังหลายแพลตฟอร์ม แต่เรารวบรวมโค้ดเพียงครั้งเดียว

Wrapper API

wrapper API สรุปการโต้ตอบที่สำคัญของเบราว์เซอร์จำนวนหนึ่ง นี่คือสิ่งที่สำคัญที่สุด:

scrollTo(int)

เลื่อนไปยังตำแหน่งที่กำหนดในหน้าต่างที่ใช้งานอยู่ Wrapper จะทำให้จำนวนเต็มที่ให้มาเป็น ปกติ ก่อนที่จะเรียกการเลื่อนเพื่อให้หน้าโฮสต์ถูกเลื่อนไปยังตำแหน่งที่ถูกต้อง

getScrollPosition: int

ส่งกลับตำแหน่งการเลื่อนปัจจุบัน (ปกติ) ของผู้ใช้ ในกรณีของ iframe นี่หมายความว่าตำแหน่งการเลื่อนที่ส่งผ่านไปยังแอปพลิเคชันของคุณนั้นเป็น ค่าลบ จริงๆ จนกว่า iframe จะอยู่ที่ด้านบนสุดของวิวพอร์ต สิ่งนี้มีประโยชน์อย่างยิ่งและช่วยให้เราทำสิ่งต่างๆ เช่น ทำให้องค์ประกอบเคลื่อนไหวได้ก็ต่อเมื่อองค์ประกอบนั้นปรากฏขึ้นเท่านั้น

onScroll(callback)

ให้เบ็ดในเหตุการณ์เลื่อน ใน Wrapper แบบสแตนด์อโลน สิ่งนี้จะเชื่อมโยงกับเหตุการณ์การเลื่อนแบบเนทีฟเป็นหลัก ใน Wrapper ที่ฝัง จะมีความล่าช้าเล็กน้อยในการรับเหตุการณ์การเลื่อน เนื่องจากมันถูกส่งผ่าน postMessage

viewport: {height: int, width: int}

วิธีการดึงข้อมูลความสูงและความกว้างของวิวพอร์ต (เนื่องจากมีการใช้งานแตกต่างกันมากเมื่อสอบถามจากภายใน iframe)

toggleFullScreen

ในโหมดสแตนด์อโลน เราซ่อนเมนู BBC และส่วนท้ายไม่ให้มองเห็นและตั้งค่า position: fixed ในเนื้อหาของเรา ในแอพ News เราไม่ทำอะไรเลย — เนื้อหาเต็มหน้าจออยู่แล้ว สิ่งที่ซับซ้อนคือ iframe ซึ่งอาศัยการใช้สไตล์ทั้งภายในและภายนอก iframe ซึ่งประสานงานผ่าน postMessage

markPageAsLoaded

บอกผู้ห่อว่าเนื้อหาของคุณโหลดแล้ว นี่เป็นสิ่งสำคัญสำหรับเนื้อหาของเราในการทำงานในแอป News ซึ่งจะไม่พยายามแสดงเนื้อหาของเราต่อผู้ใช้จนกว่าเราจะแจ้งให้แอปทราบอย่างชัดเจนว่าเนื้อหาของเราพร้อม นอกจากนี้ยังลบสปินเนอร์การโหลดเนื้อหาในเวอร์ชันเว็บของเราด้วย

รายการห่อ

ในอนาคต เรานึกภาพการสร้าง Wrapper เพิ่มเติมสำหรับแพลตฟอร์มขนาดใหญ่ เช่น Facebook Instant Articles และ Apple News เราได้สร้าง wrappers หกรายการจนถึงปัจจุบัน:

Wrapper แบบสแตนด์อโลน

เวอร์ชันของเนื้อหาของเราที่ควรอยู่ในหน้าแบบสแตนด์อโลน มาพร้อมกับแบรนด์ BBC

Wrapper แบบฝัง

เวอร์ชัน iframe ของเนื้อหาของเรา ซึ่งปลอดภัยสำหรับนั่งอ่านในบทความหรือเผยแพร่ไปยังไซต์ที่ไม่ใช่ BBC เนื่องจากเรายังคงควบคุมเนื้อหา

แอมป์ แรปเปอร์

นี่คือปลายทางที่ดึงเข้ามาเป็น amp-iframe ในหน้า AMP

Wrapper แอปข่าว

เนื้อหาของเราต้องทำการเรียกโปรโตคอล bbcvisualjournalism:// ที่เป็นกรรมสิทธิ์

เครื่องห่อแกน

มีเฉพาะ HTML — ไม่มี CSS หรือ JavaScript ของโครงการของเรา

JSON Wrapper

การแสดง JSON ของเนื้อหาของเรา สำหรับการแบ่งปันข้ามผลิตภัณฑ์ของ BBC

เครื่องพันสายไฟบนแท่น

เพื่อให้เนื้อหาของเราปรากฏบนไซต์ BBC เราจัดเตรียมเส้นทางเนมสเปซให้นักข่าว:

 /include/[department]/[unique ID], eg /include/visual-journalism/123-quiz

นักข่าวใส่ "เส้นทางรวม" นี้ไว้ใน CMS ซึ่งจะบันทึกโครงสร้างบทความลงในฐานข้อมูล ผลิตภัณฑ์และบริการทั้งหมดอยู่ปลายน้ำของกลไกการเผยแพร่นี้ แต่ละแพลตฟอร์มมีหน้าที่ในการเลือกรสชาติของเนื้อหาที่ต้องการและขอเนื้อหานั้นจากพร็อกซีเซิร์ฟเวอร์

สมมติว่าโดนัลด์ทรัมป์โต้ตอบจากก่อนหน้านี้ ที่นี่ เส้นทางรวมใน CMS คือ:

 /include/newsspec/15996-trump-tracker/english/index

หน้าบทความตามรูปแบบบัญญัติรู้ว่าต้องการเนื้อหาเวอร์ชัน "ฝัง" ดังนั้นจึงผนวก /embed ต่อท้ายเส้นทางรวม:

 /include/newsspec/15996-trump-tracker/english/index /embed

…ก่อนที่จะขอจากพร็อกซีเซิร์ฟเวอร์:

 https://news.files.bbci.co.uk/include/newsspec/15996-trump-tracker/english/index/embed

ในทางกลับกัน หน้า AMP จะเห็นเส้นทางรวมและต่อท้าย /amp :

 /include/newsspec/15996-trump-tracker/english/index /amp

ตัวแสดง AMP ใช้เวทย์มนตร์เล็กน้อยในการแสดงผล AMP HTML ซึ่งอ้างอิงเนื้อหาของเรา โดยดึงเวอร์ชัน /amp เป็น iframe:

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

ทุกแพลตฟอร์มที่รองรับมีเนื้อหาในเวอร์ชันของตัวเอง:

 /include/newsspec/15996-trump-tracker/english/index /amp

/include/newsspec/15996-trump-tracker/english/index /core

/include/newsspec/15996-trump-tracker/english/index /envelope

...และอื่นๆ

โซลูชันนี้สามารถปรับขนาดเพื่อรวมประเภทแพลตฟอร์มเพิ่มเติมตามที่เกิดขึ้น

สิ่งที่เป็นนามธรรมเป็นเรื่องยาก

การสร้างสถาปัตยกรรมแบบ "เขียนครั้งเดียว ปรับใช้ได้ทุกที่" ฟังดูเป็นอุดมคติและเป็นเช่นนั้น เพื่อให้สถาปัตยกรรมของ wrapper ทำงานได้ เราต้องเข้มงวด มาก ในการทำงานภายในสิ่งที่เป็นนามธรรม ซึ่งหมายความว่าเราต้องต่อสู้กับสิ่งล่อใจที่จะ "ทำสิ่งที่แฮ็กนี้เพื่อให้ทำงานใน [ใส่ชื่อแพลตฟอร์มที่นี่]" เราต้องการให้เนื้อหาของเราไม่รับรู้ถึงสภาพแวดล้อมที่ส่งเข้ามาโดยสิ้นเชิง แต่พูดง่ายกว่าทำ

คุณสมบัติของแพลตฟอร์มนั้นยากต่อการกำหนดค่าอย่างเป็นนามธรรม

ก่อนแนวทางนามธรรมของเรา เราได้ควบคุมทุกแง่มุมของผลลัพธ์ของเราอย่างสมบูรณ์ ซึ่งรวมถึง ตัวอย่างเช่น มาร์กอัปของ iframe ของเรา หากเราจำเป็นต้องปรับแต่งสิ่งใดๆ ตามแต่ละโปรเจ็กต์ เช่น เพิ่มแอตทริบิวต์ title ให้กับ iframe เพื่อเหตุผลในการเข้าถึง เราสามารถแก้ไขมาร์กอัปได้

ขณะนี้มาร์กอัปของแรปเปอร์แยกจากโปรเจ็กต์แล้ว วิธีเดียวในการกำหนดค่าก็คือการเปิดเผยตะขอในโครงนั่งร้านเอง เราสามารถทำได้ค่อนข้างง่ายสำหรับคุณสมบัติข้ามแพลตฟอร์ม แต่การเปิดเผย hook สำหรับแพลตฟอร์มเฉพาะจะทำลายสิ่งที่เป็นนามธรรม เราไม่ต้องการเปิดเผยตัวเลือกการกำหนดค่า 'ชื่อ iframe' ที่ใช้โดย wrapper เดียวเท่านั้น

เราสามารถตั้งชื่อคุณสมบัติให้กว้างขึ้นได้ เช่น title แล้วใช้ค่านี้เป็นแอตทริบิวต์ title iframe อย่างไรก็ตาม มันเริ่มเป็นเรื่องยากที่จะติดตามว่าสิ่งใดถูกใช้ที่ไหน และเราเสี่ยงที่จะสรุปการกำหนดค่าของเราจนไม่เข้าใจอีกเลย โดยทั่วไปแล้ว เราพยายามรักษาการกำหนดค่าของเราให้น้อยที่สุดเท่าที่จะทำได้ โดยตั้งค่าคุณสมบัติที่มีการใช้งานทั่วโลกเท่านั้น

พฤติกรรมของส่วนประกอบอาจซับซ้อน

บนเว็บ โมดูลเครื่องมือแชร์ของเราจะแยกปุ่มแชร์เครือข่ายสังคมที่สามารถคลิกได้ทีละรายการและเปิดข้อความการแชร์ที่สร้างไว้ล่วงหน้าในหน้าต่างใหม่

ภาพหน้าจอของส่วนเครื่องมือแชร์ของ BBC มีไอคอนโซเชียลมีเดียของ Twitter และ Facebook
เครื่องมือแชร์ BBC Visual Journalism แสดงรายการตัวเลือกการแชร์ทางสังคม

ในแอพ News เราไม่ต้องการแชร์ผ่านเว็บบนมือถือ หากผู้ใช้ติดตั้งแอปพลิเคชันที่เกี่ยวข้อง (เช่น Twitter) เราต้องการแชร์ในแอปเอง ตามหลักการแล้ว เราต้องการนำเสนอเมนูการแชร์สำหรับ iOS/Android ดั้งเดิมแก่ผู้ใช้ จากนั้นให้พวกเขาเลือกตัวเลือกการแชร์ก่อนที่เราจะเปิดแอปสำหรับพวกเขาด้วยข้อความแชร์ที่เติมไว้ล่วงหน้า เราสามารถเรียกเมนูการแชร์แบบเนทีฟจากแอปได้โดยการโทรไปยังโปรโตคอล bbcvisualjournalism:// ที่เป็นกรรมสิทธิ์

สกรีนช็อตของเมนูแชร์บน Android พร้อมตัวเลือกสำหรับการแชร์ผ่าน Messaging, Bluetooth, Copy to clipboard และอื่นๆ
เมนูแชร์แบบเนทีฟบน Android

อย่างไรก็ตาม หน้าจอนี้จะถูกเรียกใช้ไม่ว่าคุณจะแตะ 'Twitter' หรือ 'Facebook' ในส่วน 'แชร์ผลลัพธ์ของคุณ' ดังนั้นผู้ใช้จึงจำเป็นต้องเลือกสองครั้ง ครั้งแรกในเนื้อหาของเรา และครั้งที่สองในป๊อปอัปดั้งเดิม

นี่เป็นการเดินทางของผู้ใช้ที่แปลก เราจึงต้องการลบไอคอนแชร์แต่ละรายการออกจากแอป News และแสดงปุ่มแชร์ทั่วไปแทน เราสามารถทำได้โดยการตรวจสอบอย่างชัดแจ้งว่ามีการใช้กระดาษห่อตัวใดอยู่ก่อนที่เราจะแสดงผลส่วนประกอบ

สกรีนช็อตของปุ่มแชร์แอปข่าว ปุ่มนี้เป็นปุ่มเดียวที่มีข้อความว่า 'แบ่งปันวิธีการที่คุณทำ'
ปุ่มแชร์ทั่วไปที่ใช้ในแอปข่าว

การสร้างเลเยอร์ wrapper abstraction ทำงานได้ดีสำหรับโครงการโดยรวม แต่เมื่อการเลือก wrapper ของคุณส่งผลต่อการเปลี่ยนแปลงในระดับ ส่วนประกอบ เป็นเรื่องยากมากที่จะรักษาสิ่งที่เป็นนามธรรมที่ชัดเจน ในกรณีนี้ เราสูญเสียสิ่งที่เป็นนามธรรมไปเล็กน้อย และเรามีตรรกะในการฟอร์กที่ยุ่งเหยิงในโค้ดของเรา โชคดีที่กรณีเหล่านี้มีอยู่ไม่มากนัก

เราจะจัดการกับคุณสมบัติที่ขาดหายไปได้อย่างไร

การรักษาความเป็นนามธรรมเป็นสิ่งที่ดีและดี รหัสของเราจะบอก wrapper ว่าต้องการให้แพลตฟอร์มทำอะไร เช่น "แสดงเต็มหน้าจอ" แต่ถ้าแพลตฟอร์มที่เราจัดส่งไม่สามารถแสดงแบบเต็มหน้าจอได้จริง ๆ ล่ะ?

กระดาษห่อหุ้มจะพยายามอย่างดีที่สุดที่จะไม่แตกหักเลย แต่ในท้ายที่สุด คุณต้องมีการออกแบบที่ถอยกลับไปใช้โซลูชันการทำงานได้อย่างสง่างามไม่ว่าวิธีการนั้นจะสำเร็จหรือไม่ก็ตาม เราต้องออกแบบเกมรับ

สมมติว่าเรามีส่วนผลลัพธ์ที่มีแผนภูมิแท่งอยู่บ้าง เรามักต้องการให้ค่าแผนภูมิแท่งอยู่ที่ศูนย์จนกว่าแผนภูมิจะถูกเลื่อนเข้าสู่มุมมอง ซึ่งเราจะทริกเกอร์แถบที่เคลื่อนไหวตามความกว้างที่ถูกต้อง

ภาพหน้าจอของชุดแผนภูมิแท่งเปรียบเทียบพื้นที่ของผู้ใช้กับค่าเฉลี่ยทั่วประเทศ แต่ละแถบมีค่าที่แสดงเป็นข้อความทางด้านขวาของแถบ
แผนภูมิแท่งแสดงค่าที่เกี่ยวข้องกับพื้นที่ของฉัน

แต่ถ้าเราไม่มีกลไกที่จะขอเข้าไปในตำแหน่งเลื่อน - เช่นเดียวกับใน Wrapper AMP ของเรา - แถบจะอยู่ที่ศูนย์ตลอดไป ซึ่งเป็นประสบการณ์ที่ทำให้เข้าใจผิดอย่างทั่วถึง

ภาพหน้าจอของแผนภูมิแท่งเหมือนเดิม แต่แท่งมี 0&#37; ความกว้างและค่าของแต่ละแท่งถูกกำหนดไว้ที่ 0&#37; สิ่งนี้ไม่ถูกต้อง
แผนภูมิแท่งจะมีลักษณะอย่างไรหากไม่มีการส่งต่อเหตุการณ์การเลื่อน

เรากำลังพยายามนำวิธีการเพิ่มประสิทธิภาพแบบก้าวหน้ามาใช้ในการออกแบบของเรามากขึ้น ตัวอย่างเช่น เราสามารถจัดเตรียมปุ่มที่จะมองเห็นได้สำหรับทุกแพลตฟอร์มโดยค่าเริ่มต้น แต่จะซ่อนไว้หาก Wrapper รองรับการเลื่อน ด้วยวิธีนี้ หากการเลื่อนไม่สามารถเรียกภาพเคลื่อนไหวได้ ผู้ใช้ยังสามารถเรียกภาพเคลื่อนไหวด้วยตนเองได้

สกรีนช็อตเดียวกันกับแผนภูมิแท่งที่เป็น 0&#37; แผนภูมิแท่ง แต่คราวนี้มีการซ้อนทับสีเทาที่ละเอียดอ่อนและปุ่มตรงกลางที่เชิญชวนผู้ใช้ให้ 'ดูผลลัพธ์'
เราสามารถแสดงปุ่มทางเลือกแทน ซึ่งจะทริกเกอร์ภาพเคลื่อนไหวเมื่อคลิก

แผนสำหรับอนาคต

เราหวังว่าจะพัฒนา wrapper ใหม่สำหรับแพลตฟอร์มต่างๆ เช่น Apple News และ Facebook Instant Articles ตลอดจนเสนอแพลตฟอร์มใหม่ทั้งหมดเป็นเวอร์ชัน 'หลัก' ของเนื้อหาของเราตั้งแต่แกะกล่อง

นอกจากนี้เรายังหวังว่าจะได้รับการปรับปรุงให้ดีขึ้นเรื่อย ๆ การประสบความสำเร็จในด้านนี้หมายถึงการพัฒนาแนวรับ คุณไม่สามารถสรุปได้ว่าทุกแพลตฟอร์มในตอนนี้และในอนาคตจะรองรับการโต้ตอบที่กำหนด แต่ โปรเจ็กต์ที่ออกแบบมาอย่างดีควรจะสามารถถ่ายทอดข้อความหลัก ได้โดยไม่สะดุดกับอุปสรรคทางเทคนิคแรก

การทำงานภายในขอบเขตของกระดาษห่อหุ้มเป็นการเปลี่ยนกระบวนทัศน์เล็กน้อย และให้ความรู้สึกเหมือนอยู่ครึ่งทางในแง่ของการแก้ปัญหา ระยะยาว แต่จนกว่าอุตสาหกรรมจะเติบโตสู่มาตรฐานข้ามแพลตฟอร์ม ผู้เผยแพร่โฆษณาจะถูกบังคับให้เปิดตัวโซลูชันของตนเอง หรือใช้เครื่องมือเช่น Distro สำหรับการแปลงจากแพลตฟอร์มเป็นแพลตฟอร์ม มิฉะนั้นจะเพิกเฉยต่อส่วนต่างๆ ของผู้ชมทั้งหมด

ถือเป็นช่วงแรกๆ สำหรับเรา แต่จนถึงขณะนี้ เราประสบความสำเร็จอย่างมากในการใช้รูปแบบแรปเปอร์เพื่อสร้างเนื้อหาเพียงครั้งเดียว และนำเสนอไปยังแพลตฟอร์มมากมายที่ผู้ชมของเราใช้อยู่