ภาพเคลื่อนไหวบนเว็บ - ขณะนี้เอลิเมนต์.animate() อยู่ใน Chrome 36 แล้ว

เบรนแดน เคนนี
Brendan Kenny

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

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

เว็บแอนิเมชันยืนรับสายและส่วนแรกของวิดีโอลงจอดใน Chrome 36 ในรูปแบบ element.animate() ฟังก์ชันใหม่นี้จะช่วยให้คุณสร้างภาพเคลื่อนไหวได้ใน JavaScript เท่านั้น และทำงานได้อย่างมีประสิทธิภาพเช่นเดียวกับภาพเคลื่อนไหวหรือการเปลี่ยนผ่าน CSS (อันที่จริงเครื่องมือภาพเคลื่อนไหวบนเว็บตัวเดียวกันที่ใช้วิธีเหล่านี้ทั้งหมดใช้ใน Chrome 34)

รูปแบบคำสั่งนี้เรียบง่ายและคุณน่าจะคุ้นเคยกับส่วนต่างๆ ของส่วนนี้ หากคุณเคยเขียนการเปลี่ยน CSS หรือภาพเคลื่อนไหวมาแล้ว:

element.animate([
    {cssProperty: value0},
    {cssProperty: value1},
    {cssProperty: value2},
    //...
], {
    duration: timeInMs,
    iterations: iterationCount,
    delay: delayValue
});

ข้อดีที่ดีที่สุดของฟังก์ชันใหม่นี้คือการขจัดปัญหาติดขัดต่างๆ ที่ก่อนหน้านี้ต้องลองเพื่อให้ภาพเคลื่อนไหวลื่นไหลไม่มีสะดุด

ตัวอย่างเช่น สำหรับ Santa Tracker เมื่อปีที่แล้ว เราอยากให้หิมะตกอย่างต่อเนื่อง เราจึงตัดสินใจสร้างภาพเคลื่อนไหวผ่าน CSS เพื่อให้ดำเนินการได้อย่างมีประสิทธิภาพ

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

เราจึงใช้แนวทางต่อไปนี้ ซึ่งคงจะคุ้นเคยกันดีแล้ว

snowFlake.style.transform = 'translate(' + snowLeft + 'px, -100%)';
// wait a frame
snowFlake.offsetWidth;
snowFlake.style.transitionProperty = 'transform';
snowFlake.style.transitionDuration = '1500ms';
snowFlake.style.transform = 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)';

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

ในทางกลับกัน การเรียก element.animate() ที่เทียบเท่าก็ไม่อาจเจาะจงได้อย่างแน่ชัดว่าต้องทำอะไร:

snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);

มีตัวเลือกอีกมากมาย ภาพเคลื่อนไหวบนเว็บอาจหน่วงเวลาและทำซ้ำได้เช่นเดียวกับเวอร์ชัน CSS อื่น

snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], {
    duration: 1500,
    iterations: 10,
    delay: 300
});

AnimationPlayer

element.animate() จะส่งออบเจ็กต์ AnimationPlayer กลับมา ซึ่งจะมีความสำคัญมากขึ้นเรื่อยๆ เมื่อมีการเปิดตัวข้อกำหนดของ Web Animations มากขึ้น ทั้งภาพเคลื่อนไหวที่สร้างด้วย JavaScript และ CSS จะมี AnimationPlayer เชื่อมโยงกันอยู่ ทำให้สามารถผสมผสานกันได้อย่างลงตัวและมีประโยชน์และน่าสนใจ

สำหรับตอนนี้ AnimationPlayer มีฟังก์ชันการทำงานเพียง 2 ส่วนเท่านั้น ซึ่งทั้งคู่มีประโยชน์มากๆ คุณยกเลิกภาพเคลื่อนไหวได้ทุกเมื่อโดยใช้ AnimationPlayer.cancel() ดังนี้

var player = snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
// less than 1500ms later...changed my mind
player.cancel();

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

var player = snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
player.onfinish = function(e) {
    console.log('per aspera ad terra!');
}

ลองเลย

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

มีการสาธิตเอฟเฟกต์หิมะให้คุณลองใช้ทั้ง element.animate() เวอร์ชันดั้งเดิมและ polyfill

บอกให้เราทราบว่าคุณคิดอย่างไร

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

แน่นอนว่าความคิดเห็นในโพสต์นี้จะมีประโยชน์ และคุณก็ส่งความคิดเห็นในมาตรฐานไปยังคณะทำงาน CSS และ SVG ได้ผ่านรายชื่ออีเมล fx สาธารณะ

อัปเดตเดือนตุลาคม 2014: Chrome 39 เพิ่มการรองรับวิธีอื่นๆ เพิ่มเติมที่เกี่ยวข้องกับการควบคุมการเล่น เช่น play(), pause() และ reverse() และยังรองรับการข้ามไปยังจุดที่เจาะจงในไทม์ไลน์ของภาพเคลื่อนไหวผ่านพร็อพเพอร์ตี้ currentTime ด้วย ดูการทำงานจริงของฟังก์ชันนี้ได้ในการสาธิตใหม่นี้

ขอขอบคุณ Addy Osmani และ Max Heinritz ที่ให้ความช่วยเหลือเกี่ยวกับโพสต์นี้