Cách NRK sử dụng ảnh động cuộn để làm cho câu chuyện trở nên sống động

Ngày xuất bản: 26 tháng 2 năm 2026

Ảnh động do cuộn điều khiển đã phát triển từ việc triển khai JavaScript luồng chính bị giật, không mượt mà thành trải nghiệm mượt mà, dễ tiếp cận, không phải luồng chính bằng cách sử dụng các tính năng CSS và giao diện người dùng hiện đại như Dòng thời gian cuộn và Dòng thời gian xem. Sự thay đổi này cho phép tạo nhanh bản minh hoạ và ảnh động hiệu suất cao, đồng thời cho phép các nhóm tạo các trang cuộn để kể chuyện được đánh bóng như minh hoạ trong bài viết này.

NRK và nghệ thuật kể chuyện

NRK (Công ty phát thanh truyền hình Na Uy) là công ty phát sóng dịch vụ công cộng ở Na Uy. Nhóm triển khai được mô tả trong bài viết này có tên là Visuelle Historier (tiếng Na Uy) và có nghĩa là Visual Stories (Câu chuyện trực quan) trong tiếng Anh. Nhóm này làm việc với các dự án thiết kế, đồ hoạ và phát triển cho các dự án biên tập trên TV, đài phát thanh và web, phát triển bản sắc hình ảnh, đồ hoạ nội dung, bài viết chuyên đề và các định dạng kể chuyện bằng hình ảnh mới. Nhóm này cũng làm việc với hồ sơ thiết kế và các thương hiệu phụ của NRK, tạo ra các công cụ và mẫu để giúp dễ dàng phát hành nội dung phù hợp với bản sắc thương hiệu của NRK.

Cách NRK sử dụng ảnh động do cuộn

Ảnh động do cuộn và được kích hoạt bằng thao tác cuộn giúp bài viết kể chuyện trở nên tương tác, hấp dẫn và dễ nhớ hơn. Phương pháp này đặc biệt hữu ích trong các câu chuyện phi hư cấu có ít hoặc không có hình ảnh.

Những ảnh động này giúp củng cố hoặc tạo điểm kịch tính, thúc đẩy câu chuyện phát triển và phát triển các câu chuyện nhỏ bằng hình ảnh phù hợp hoặc củng cố văn bản. Bằng cách được điều khiển bằng thao tác cuộn, các ảnh động này cho phép người dùng kiểm soát tiến trình của câu chuyện thông qua thao tác cuộn.

Nâng cao trải nghiệm người dùng

Thông tin chi tiết về người dùng của NRK cho thấy rằng độc giả đánh giá cao cách những ảnh động này hướng sự chú ý của họ. Bằng cách làm nổi bật văn bản hoặc ảnh động khi cuộn, người dùng sẽ dễ dàng xác định các điểm chính và hiểu được những khía cạnh quan trọng nhất của câu chuyện, đặc biệt là khi lướt xem.

Ngoài ra, ảnh động đồ hoạ có thể đơn giản hoá thông tin phức tạp, giúp người dùng dễ dàng nắm bắt các mối quan hệ và thay đổi theo thời gian. Bằng cách tạo, thêm hoặc làm nổi bật thông tin một cách linh động, NRK có thể trình bày nội dung theo cách sư phạm và hấp dẫn hơn.

Đặt tâm trạng

Ảnh động có thể là công cụ hữu ích để tạo hoặc nâng cao tâm trạng của câu chuyện. Bằng cách điều chỉnh thời gian, tốc độ và kiểu ảnh động, NRK có thể khơi dậy cảm xúc phù hợp với giọng điệu của câu chuyện.

Chia văn bản thành nhiều phần và tạo điểm nhấn hình ảnh

NRK thường sử dụng các hình minh hoạ động nhỏ để chia các khối văn bản dài thành hình ảnh động đơn giản hoặc hình minh hoạ nhỏ, giúp người đọc tạm dừng một chút trong khi đọc. Nhiều người dùng đánh giá cao biến thể này, lưu ý rằng biến thể này giúp phân chia văn bản và giúp dễ hiểu hơn. Họ cảm thấy rằng đó là một điểm dừng phù hợp trong câu chuyện.

Tôn trọng nhu cầu hỗ trợ tiếp cận và lựa chọn ưu tiên của người dùng

Tất cả công dân Na Uy phải có thể truy cập vào các trang công khai của NRK. Do đó, các trang phải tuân theo lựa chọn ưu tiên của người dùng về việc giảm chuyển động. Tất cả nội dung trang phải được cung cấp cho những người dùng đã bật chế độ cài đặt trình duyệt này.

Thiết kế ảnh động do cuộn

NRK đã đơn giản hoá quy trình thiết kế bằng cách phát triển và tích hợp một công cụ ảnh động cuộn mới trực tiếp vào Hệ thống quản lý nội dung (CMS) Sanity. Được phát triển thông qua hoạt động cộng tác giữa các nhóm phát triển và duy trì trang web cũng như các giải pháp CMS, công cụ này cho phép các nhà thiết kế dễ dàng tạo bản minh hoạ và triển khai ảnh động cuộn bằng các tín hiệu hình ảnh cho vị trí bắt đầu và kết thúc của một phần tử ảnh động, cũng như khả năng xem trước ảnh động theo thời gian thực. Sự đổi mới này giúp nhà thiết kế có nhiều quyền kiểm soát hơn và đẩy nhanh quy trình thiết kế ngay trong CMS.

Hiển thị vùng đã cuộn vào chế độ xem trong một công cụ.
Ví dụ tương tự về các tín hiệu hình ảnh cho vị trí bắt đầu và kết thúc của các phần tử ảnh động – không phải là công cụ CMS thực sự.

Ảnh động do thao tác cuộn trong trình duyệt

Ảnh động dựa trên câu chuyện

Người đàn ông không bị bỏ lỡ.

Bài viết này nói về một người đàn ông đã chết trong căn hộ của mình suốt 9 năm, phải dựa nhiều vào hình minh hoạ do thiếu các thành phần hình ảnh khác. Hình minh hoạ được tạo ảnh động thông qua tính năng cuộn để làm nổi bật câu chuyện, chẳng hạn như trong ảnh động khi màn đêm buông xuống, ánh sáng trong một toà nhà nhiều tầng bật lên dần dần cho đến khi chỉ còn một căn hộ không sáng. Ảnh động này được tạo bằng công cụ ảnh động do NRK phát triển, hoạt động theo phương thức cuộn.

Ảnh động mờ dần cho văn bản

Đất băng vĩnh cửu.

Bài viết này bắt đầu bằng phần giới thiệu ngắn gọn, phản ánh trình tự mở đầu của một bộ phim. Văn bản ngắn gọn kết hợp với hình ảnh toàn màn hình được thiết kế để gợi ý nội dung của bài viết, tạo sự mong đợi để khuyến khích độc giả tìm hiểu toàn bộ bài viết. Trang tiêu đề được thiết kế giống như áp phích phim, với ảnh động cuộn được sử dụng để tăng cường cảm giác này bằng cách tạo ảnh động mượt mà cho văn bản lên và ra ngoài.

.article-section {
  animation: fade-up linear;
  animation-timeline: view();
  animation-range: entry 100% exit 100%;
}

Kiểu chữ có ảnh động cuộn

Kiểu chữ động trong tiêu đề của một bài viết — Nghỉ ốm.

Với phần giới thiệu trong "Sjukt sjuke" (tạm dịch là "Bệnh tật bệnh tật"), NRK muốn thu hút độc giả đọc bài viết về tỷ lệ nghỉ ốm ngày càng tăng ở Na Uy. Tiêu đề này nhằm thu hút sự chú ý của người đọc, đồng thời cho họ biết rằng đây không phải là một câu chuyện thông thường, nhàm chán và chỉ dựa trên số liệu như họ có thể mong đợi. Nhóm NRK muốn văn bản và hình minh hoạ thể hiện chủ đề của tác phẩm, sử dụng kiểu chữ và ảnh động cuộn để tăng cường điều này. Bài viết sử dụng phông chữ và hồ sơ thiết kế mới của NRK News.

<h1 aria-label="sjuke">
  <span>s</span><span>j</span><span>u</span><span>k</span><span>e</span>
<h1>
h1 span {
  display: inline-block;
}
if (window.matchMedia('print, (prefers-reduced-motion: reduce)').matches) {
  return;
}

const heading = document.querySelector("h1");
const letters = heading.querySelectorAll("span");

const timeline = new ViewTimeline({ subject: heading });
const scales = [/**/];
const rotations = [/**/];

for ([index, el] of letters.entries()) {
  el.animate(
    {
      scale: ["1", scales[index]],
      rotate: ["0deg", rotations[index]]
    },
    {
      timeline,
      fill: "both",
      rangeStart: "contain 30%",
      rangeEnd: "contain 70%",
      easing: "ease-out"
    }
  );
}

Làm nổi bật các mục được chụp nhanh khi cuộn

Trẻ em trong các tổ chức.

Những độc giả đã đọc hết một bài viết thường muốn đọc thêm về cùng một vấn đề. Trong các bài viết về việc thanh thiếu niên sử dụng chất gây nghiện trong các cơ sở, NRK muốn đề xuất một bài viết để độc giả đọc tiếp, đồng thời cho phép độc giả chọn một số bài viết khác nếu họ muốn. Giải pháp là một thành phần điều hướng có thể vuốt được triển khai bằng tính năng cuộn nhanh và ảnh động do cuộn. Ảnh động đảm bảo rằng phần tử đang hoạt động nằm trong tiêu điểm, trong khi các phần tử còn lại bị làm mờ.

for (let item of items) {
  const timeline = new ViewTimeline({ subject: item, axis: "inline" });
  const animation = new Animation(effect, timeline);
  item.animate(
    {
      opacity: [0.3, 1, 0.3]
    },
    { timeline, easing: "ease-in-out", fill: "both" }
  );
  animation.rangeStart = "cover calc(50% - 100px)";
  animation.rangeEnd = "cover calc(50% + 100px)";
}

Ảnh động cuộn kích hoạt ảnh động thông thường

Ngân sách.

Trong bài viết này về ngân sách quốc gia của Na Uy, NRK muốn giúp người xem dễ tiếp cận và cá nhân hoá hơn một câu chuyện nặng nề và tẻ nhạt dựa trên con số. Mục tiêu của bài viết là phân tích một con số ngân sách khổng lồ và khó hiểu, đồng thời giúp người đọc biết được tiền thuế của họ được chi tiêu vào những mục đích gì. Mỗi mục phụ tập trung vào một mục cụ thể trong ngân sách quốc gia. Tổng số tiền đóng góp thuế của người đọc được biểu thị bằng một thanh màu xanh dương được chia ra để cho thấy số tiền đóng góp của người đọc cho từng mục riêng lẻ này. Hiệu ứng chuyển đổi này được thực hiện bằng ảnh động do cuộn điều khiển, kích hoạt các mục riêng lẻ để tạo ảnh động.

const timeline = new ViewTimeline({
  subject: containerElement
});

// Setup scroll-driven animation
const scrollAnimation = containerElement.animate(
  {
    "--cover-color": ["blue", "lightblue"],
    scale: ["1 0.2", "1 3"]
  },
  {
    timeline,
    easing: "cubic-bezier(1, 0, 0, 0)",
    rangeStart: "cover 0%",
    rangeEnd: "cover 50%"
  }
);

// Wait for scroll-driven animation to complete
await scrollAnimation.finished;
scrollAnimation.cancel();

// Trigger time-driven animations
for (let [index, postElement] of postElements.entries()) {
  const animation = postElement?.animate(
    { scale: ["1 3", "1 1"] },
    {
      duration: 200,
      delay: index * 33,
      easing: "ease-out",
      fill: "backwards"
    }
  );
}

"Chúng tôi đã tạo ảnh động do cuộn trong một thời gian dài. Trước khi có Web Animations API, chúng ta phải sử dụng các sự kiện cuộn, sau đó kết hợp với Intersection Observer API. Đây thường là một nhiệm vụ rất tốn thời gian, nhưng giờ đây, việc này trở nên đơn giản nhờ API Ảnh động trên web và Ảnh động do cuộn điều khiển" – Helge Silset, Nhà phát triển giao diện người dùng tại NRK

NRK có nhiều Thành phần web khác nhau có thể được cắm vào một trong các phần tử tuỳ chỉnh của chúng, được gọi là ScrollAnimationDriver (<scroll-animation-driver>), hỗ trợ các ảnh động sau:

  • Lớp có [KeyframeEffects](https://developer.mozilla.org/docs/Web/API/KeyframeEffect)
  • Ảnh động Lottie
  • mp4
  • three.js
  • <canvas>

Ví dụ sau đây sử dụng các lớp có KeyframeEffects:

<scroll-animation-driver data-range-start='entry-crossing 50%' data-range-end='exit-crossing 50%'>
  <layered-animation-effect>
    <picture>
      <source />
      <img />
    </picture>

    <picture>
      <source />
      <img />
    </picture>

    <picture>
      <source />
      <img />
    </picture>
  </layered-animation-effect>
</scroll-animation-driver>

Cách triển khai JavaScript của NRK cho phần tử tuỳ chỉnh <scroll-animation-driver>:

export default class ScrollAnimationDriver extends HTMLElement {
  #timeline

  connectedCallback() {
    this.#timeline = new ViewTimeline({subject: this})
    for (const child of this.children) {
      for (const effect of child.effects ?? []) {
        this.#setupAnimationEffect(effect)
      }
    }
  }

  #setupAnimationEffect(effect) {
    const animation = new Animation(effect, this.#timeline) 
    animation.rangeStart = this.rangeStart
    animation.rangeEnd = this.rangeEnd

    if (this.prefersReducedMotion) {
      animation.currentTime = CSS.percent(this.defaultProgress * 100)
    } else {
      animation.play()
    }
  }
}

export default class LayeredAnimationEffect extends HTMLElement {
  get effects() {
    return this.layers.flatMap(layer => toKeyframeEffects(layer))
  }
}

Hiệu suất cuộn

NRK đã triển khai JavaScript rất hiệu quả trước khi sử dụng ảnh động do cuộn, nhưng giờ đây, ảnh động do cuộn cho phép họ có hiệu suất tốt hơn mà không phải lo lắng về hiện tượng giật khi cuộn, ngay cả trên các thiết bị có công suất thấp.

  • Thời lượng tác vụ không phải SDA: 1 mili giây.
  • Thời lượng tác vụ SDA: 0,16 mili giây.
Thẻ Hiệu suất của Chrome DevTools.
Bản ghi trong thẻ Hiệu suất của Chrome DevTools với tốc độ CPU chậm hơn 6 lần cho thấy 0,16 mili giây cho mỗi tác vụ trong một khung mới.

Để đọc thêm về sự khác biệt về hiệu suất cuộn giữa các phương thức triển khai JavaScript và ảnh động do cuộn, hãy xem bài viết Nghiên cứu điển hình về hiệu suất của ảnh động do cuộn để biết thêm chi tiết.

Những điểm cần cân nhắc về khả năng hỗ trợ tiếp cận và trải nghiệm người dùng

Tính năng hỗ trợ tiếp cận đóng vai trò quan trọng trong các trang công khai của NRK vì tất cả công dân Na Uy đều có thể truy cập vào các trang này trong nhiều trường hợp. NRK đảm bảo rằng bạn có thể truy cập vào ảnh động cuộn theo một số cách:

  • Tôn trọng lựa chọn ưu tiên của người dùng về việc giảm chuyển động: Sử dụng truy vấn nội dung đa phương tiện screen and (prefers-reduced-motion: no-preference) để áp dụng ảnh động làm tính năng nâng cao dần. Việc này cũng hữu ích khi xử lý các kiểu in cùng một lúc.
  • Xem xét nhiều loại thiết bị và độ chính xác khác nhau của hoạt động nhập bằng thao tác cuộn: Một số người dùng có thể cuộn theo từng bước (phím cách hoặc phím lên/xuống, di chuyển đến các điểm đánh dấu bằng trình đọc màn hình) và không xem được toàn bộ ảnh động. Đảm bảo không bỏ lỡ thông tin quan trọng.
  • Cẩn thận với ảnh động hiển thị hoặc ẩn nội dung: Đối với những người dùng dựa vào tính năng thu phóng của Hệ điều hành (OS), họ có thể khó nhận thấy nội dung ẩn sẽ xuất hiện khi cuộn. Tránh việc người dùng phải tìm kiếm. Nếu cần ẩn hoặc hiện nội dung, hãy đảm bảo tính nhất quán về vị trí nội dung xuất hiện và biến mất.
  • Tránh thay đổi lớn về độ sáng hoặc độ tương phản trong ảnh động: Vì ảnh động do cuộn điều khiển phụ thuộc vào chế độ điều khiển của người dùng, nên sự thay đổi đột ngột về độ sáng có thể xuất hiện dưới dạng nhấp nháy, điều này có thể kích hoạt cơn co giật ở một số người dùng.
@media (prefers-reduced-motion: no-preference) {
  .article-image {
    opacity: 0;
    transition: opacity 1s ease-in-out;
  }
  .article-image.visible {
    opacity: 1;
  }
}

Hỗ trợ trình duyệt

Để hỗ trợ trình duyệt rộng hơn cho ScrollTimelineViewTimeline, NRK sử dụng một polyfill nguồn mởcộng đồng tích cực đóng góp.

Hiện tại, polyfill được tải có điều kiện khi không có ScrollTimeline và sử dụng phiên bản rút gọn của polyfill không hỗ trợ CSS.

if (!('ScrollTimeline' in window)) {
  await import('scroll-timeline.js')
}

Phát hiện và xử lý tính năng hỗ trợ trình duyệt trong CSS:

@supports not (animation-timeline: view()) {
  .article-section {
    translate: 0 calc(-15vh * var(--fallback-progress));
    opacity: var(--fallback-progress);
  }
}

@supports (animation-timeline: view()) {
  .article-section {
    animation: --fade-up linear;
    animation-timeline: view();
    animation-range: entry 100% exit 100%;
  }
}

Trong ví dụ trước về các trình duyệt không được hỗ trợ, NRK đang sử dụng một biến CSS, --fallback-progress, làm phương án dự phòng để kiểm soát tiến trình ảnh động cho các thuộc tính translateopacity.

Sau đó, biến CSS --fallback-progress được cập nhật bằng trình nghe sự kiện scrollrequestAnimationFrame trong JavaScript như sau:

function updateProgress() {
  const end = el.offsetTop + el.offsetHeight;
  const start = end - window.innerHeight;
  const scrollTop = document.scrollingElement.scrollTop;
  const progress = (scrollTop - start) / (end - start);
  document.body.style.setProperty('--fallback-progress', clamp(progress, 0, 1));
}


if (!CSS.supports("animation-timeline: view()")) {
  document.addEventListener('scroll', () => {
    if (!visible || updating) {
      return;
    }

    window.requestAnimationFrame(() => {
      updateProgress();
      updating = false;
    });

    updating = true;
  });
}

Tài nguyên

Xin cảm ơn đặc biệt Hannah Van Opstal, Bramus và Andrew Kean Guan của Google, cũng như Ingrid Reime của NRK vì những đóng góp quý giá của họ cho công việc này.