Quảng cáo thị sai hiệu suất

Robert Flack
Robert Flack

Dù thích hay không thích thì thị sai vẫn sẽ tồn tại. Nếu được sử dụng thận trọng, tăng thêm chiều sâu và sự tinh tế cho ứng dụng web. Tuy nhiên, vấn đề đặt ra là việc triển khai thị sai một cách hiệu quả có thể là thách thức. Trong bài viết này, chúng tôi sẽ thảo luận về một giải pháp vừa hiệu quả, vừa quan trọng là hiệu quả trên nhiều trình duyệt.

Hình minh hoạ quảng cáo thị sai.

Tóm tắt

  • Không dùng sự kiện cuộn hoặc background-position để tạo ảnh động thị sai.
  • Sử dụng các biến đổi CSS 3D để tạo hiệu ứng thị sai chính xác hơn.
  • Đối với Mobile Safari, hãy sử dụng position: sticky để đảm bảo rằng hiệu ứng thị sai được nhân bản.

Nếu bạn muốn có giải pháp thả xuống, hãy chuyển đến kho lưu trữ GitHub mẫu phần tử giao diện người dùng và lấy Trình trợ giúp thị sai JS! Bạn có thể xem bản minh hoạ trực tiếp về công cụ cuộn thị sai trong Kho lưu trữ GitHub.

Thị sai vấn đề

Để bắt đầu, hãy tìm hiểu hai cách phổ biến để đạt được thị sai hiệu quả và cụ thể là tại sao chúng không phù hợp với mục đích của chúng tôi.

Không phù hợp: sử dụng sự kiện cuộn

Yêu cầu chính của thị sai là nó phải được ghép nối; với mọi thay đổi về vị trí cuộn của trang, phần tử thị sai vị trí sẽ được cập nhật. Mặc dù điều đó nghe có vẻ đơn giản nhưng một cơ chế quan trọng để trình duyệt hiện đại là khả năng hoạt động không đồng bộ. Điều này áp dụng, trong trường hợp cụ thể, để cuộn sự kiện. Trong hầu hết các trình duyệt, sự kiện cuộn được phân phối là "nỗ lực tối đa" và không đảm bảo được phân phối trên mọi khung hình của hoạt ảnh cuộn!

Thông tin quan trọng này cho chúng tôi biết tại sao chúng tôi cần tránh Giải pháp dựa trên JavaScript di chuyển các phần tử dựa trên sự kiện cuộn: JavaScript không đảm bảo rằng thị sai sẽ bắt kịp với vị trí cuộn của trang. Trong các phiên bản cũ hơn của Mobile Safari, các sự kiện cuộn thực sự được phân phối ở cuối cuộn, điều này khiến không thể tạo ra Hiệu ứng cuộn dựa trên JavaScript. Các phiên bản gần đây hơn phân phối sự kiện cuộn trong suốt ảnh động, nhưng tương tự như với Chrome, một "nỗ lực tối đa" cơ sở. Nếu luồng chính đang bận với mọi tác vụ khác, nên các sự kiện cuộn sẽ không được gửi tức là hiệu ứng thị sai sẽ bị mất.

Không phù hợp: đang cập nhật background-position

Một tình huống khác chúng tôi muốn tránh là vẽ trên mọi khung hình. Nhiều giải pháp cố thay đổi background-position để tạo ra giao diện thị sai. khiến trình duyệt vẽ lại những phần bị ảnh hưởng của trang khi cuộn và điều đó có thể tốn kém để làm ảnh động đáng kể.

Nếu muốn thực hiện triển vọng của chuyển động thị sai, chúng tôi muốn điều gì đó có thể được áp dụng như một thuộc tính tăng tốc (điều này có nghĩa là bạn nên duy trì biến đổi và độ mờ) và không dựa vào sự kiện cuộn.

CSS trong mô hình 3D

Cả Scott KellumKeith Clark đều có đã thực hiện công việc quan trọng trong lĩnh vực sử dụng CSS 3D để đạt được chuyển động thị sai, và kỹ thuật họ sử dụng là rất hiệu quả:

  • Thiết lập một phần tử chứa để cuộn bằng overflow-y: scroll (và có thể là overflow-x: hidden).
  • Áp dụng giá trị perspectiveperspective-origin cho cùng phần tử đó được đặt thành top left hoặc 0 0.
  • Đối với các phần tử con của phần tử đó, hãy áp dụng bản dịch bằng Z và thu nhỏ chúng lại để cung cấp chuyển động thị sai mà không ảnh hưởng đến kích thước của chúng trên màn hình.

CSS cho phương pháp này có dạng như sau:

.container {
  width: 100%;
  height: 100%;
  overflow-x: hidden;
  overflow-y: scroll;
  perspective: 1px;
  perspective-origin: 0 0;
}

.parallax-child {
  transform-origin: 0 0;
  transform: translateZ(-2px) scale(3);
}

Giả sử một đoạn mã HTML như sau:

<div class="container">
    <div class="parallax-child"></div>
</div>

Điều chỉnh tỷ lệ cho phối cảnh

Đẩy phần tử con trở lại sẽ làm cho phần tử đó nhỏ hơn tỷ lệ với giá trị phối cảnh. Bạn có thể tính toán số tiền cần thiết để mở rộng quy mô phương trình này: (góc độ xem - khoảng cách) / phối cảnh. Vì rất có thể chúng tôi muốn phần tử thị sai thành thị sai nhưng xuất hiện ở kích thước mà chúng ta đã tạo ra, nó cần được mở rộng theo cách này, thay vì giữ nguyên.

Trong trường hợp của mã trên, phối cảnh là 1px và Khoảng cách Z của parallax-child-2px. Điều này có nghĩa là phần tử sẽ cần được tăng thêm 3x, mà bạn có thể thấy là giá trị được cắm vào mã: scale(3).

Đối với mọi nội dung không áp dụng giá trị translateZ, bạn có thể thế vào một giá trị bằng 0. Tức là tỷ lệ (góc nhìn - 0) / phối cảnh, thu được ở giá trị bằng 1, có nghĩa là quảng cáo được điều chỉnh theo tỷ lệ cả lên hoặc xuống. Khá tiện lợi, thực sự hữu ích.

Cách hoạt động của phương pháp này

Điều quan trọng là phải biết rõ lý do tại sao làm như vậy hiệu quả, vì chúng ta sẽ sử dụng sớm nhất có thể. Cuộn là một cách biến đổi hiệu quả, đó là lý do tại sao nó có thể accelerated; chủ yếu liên quan đến việc dịch chuyển các lớp bằng GPU. Trong một cuộn thông thường, tức là không có bất kỳ khái niệm nào về phối cảnh, cuộn xảy ra theo cách 1:1 khi so sánh phần tử cuộn và phần tử con. Nếu bạn cuộn một phần tử xuống 300px, thì phần tử con của phần tử đó sẽ được chuyển đổi lên trên với cùng số tiền là: 300px.

Tuy nhiên, việc áp dụng giá trị phối cảnh cho phần tử cuộn sẽ gây lộn xộn với quy trình này; nó thay đổi ma trận làm cơ sở cho phép biến đổi cuộn. Giờ đây, cuộn 300px chỉ có thể di chuyển phần tử con 150px, tuỳ thuộc vào Giá trị perspectivetranslateZ mà bạn đã chọn. Nếu một phần tử có Giá trị translateZ là 0, nó sẽ được cuộn ở tỷ lệ 1:1 (như trước đây), nhưng là một phần tử con bị đẩy vào Z từ gốc phối cảnh sẽ được cuộn ở một vị trí khác ! Kết quả ròng: chuyển động thị sai. Và một điều rất quan trọng là chúng tôi xử lý việc này là một phần của bộ máy cuộn nội bộ của trình duyệt, nghĩa là luôn có không cần nghe sự kiện scroll hoặc thay đổi background-position.

Một con ruồi trong thuốc mỡ: Mobile Safari

Tất cả các hiệu ứng đều có các cảnh báo và một cảnh báo quan trọng về chuyển đổi là về việc duy trì hiệu ứng 3D cho các phần tử con. Nếu có các phần tử trong hệ thống phân cấp giữa phần tử có phối cảnh và phần tử con thị sai, phối cảnh 3D bị "làm phẳng", nghĩa là hiệu ứng bị mất.

<div class="container">
    <div class="parallax-container">
    <div class="parallax-child"></div>
    </div>
</div>

Trong HTML ở trên, .parallax-container là mã mới và sẽ được thiết lập hiệu quả làm phẳng giá trị perspective và chúng ta sẽ mất hiệu ứng thị sai. Giải pháp, trong hầu hết các trường hợp sẽ khá đơn giản: bạn thêm transform-style: preserve-3d vào phần tử, khiến nó truyền bất kỳ hiệu ứng 3D nào (như phối cảnh của chúng ta giá trị) đã được áp dụng cho phía trên cây.

.parallax-container {
  transform-style: preserve-3d;
}

Tuy nhiên, trong trường hợp của Mobile Safari, mọi thứ phức tạp hơn một chút. Việc áp dụng overflow-y: scroll cho phần tử vùng chứa sẽ hoạt động về mặt kỹ thuật, nhưng ở chi phí để có thể hất phần tử cuộn. Giải pháp là thêm -webkit-overflow-scrolling: touch, nhưng cũng sẽ làm phẳng perspective và chúng tôi sẽ không nhận được bất kỳ thị sai nào.

Nếu xét theo góc nhìn ngày càng nâng cao thì đây có thể không phải là quá vấn đề. Nếu chúng ta không thể thị sai trong mọi tình huống, ứng dụng của chúng ta sẽ vẫn hoạt động nhưng nó thì tốt nhất là tìm ra giải pháp.

position: sticky giải cứu!

Trên thực tế, có một số trợ giúp ở dạng position: sticky, tồn tại để cho phép các phần tử "dính" lên đầu khung nhìn hoặc một phần tử mẹ nhất định trong khi cuộn. Thông số kỹ thuật, giống như hầu hết các thông số này, khá lớn, nhưng vẫn chứa viên ngọc nhỏ hữu ích bên trong:

Điều này có vẻ không có ý nghĩa lớn khi mới nhìn thoáng qua, nhưng là điểm chính trong câu đó là khi đề cập chính xác đến mức độ hấp dẫn của một phần tử được tính: "độ lệch được tính toán có tham chiếu đến đối tượng cấp trên gần nhất bằng hộp cuộn". Nói cách khác, khoảng cách để di chuyển phần tử cố định (để thành phần hiển thị này xuất hiện được đính kèm vào một phần tử khác hoặc khung nhìn) được được tính toán trước khi áp dụng bất kỳ phép biến đổi nào khác, chứ không phải sau. Điều này có nghĩa là rất giống với ví dụ cuộn trước đó, nếu độ lệch được tính ở 300px, bạn sẽ có cơ hội mới để sử dụng các quan điểm (hoặc bất kỳ biến đổi nào khác) để thao tác với giá trị bù trừ 300px đó trước khi giá trị đó được áp dụng cho bất kỳ quảng cáo cố định nào phần tử.

Bằng cách áp dụng position: -webkit-sticky cho phần tử thị sai, chúng ta có thể "đảo ngược" hiệu quả hiệu ứng làm phẳng của -webkit-overflow-scrolling: touch. Điều này đảm bảo rằng phần tử thị sai tham chiếu đến giá trị đối tượng cấp trên có hộp cuộn, trong trường hợp này là .container. Sau đó: tương tự như trước, .parallax-container áp dụng giá trị perspective, thay đổi độ lệch cuộn đã tính và tạo hiệu ứng thị sai.

<div class="container">
    <div class="parallax-container">
    <div class="parallax-child"></div>
    </div>
</div>
.container {
  overflow-y: scroll;
  -webkit-overflow-scrolling: touch;
}

.parallax-container {
  perspective: 1px;
}

.parallax-child {
  position: -webkit-sticky;
  top: 0px;
  transform: translate(-2px) scale(3);
}

Thao tác này sẽ khôi phục hiệu ứng thị sai cho Mobile Safari. Đây là tin tuyệt vời tròn!

Lưu ý về vị trí cố định

Tuy nhiên, một sự khác biệt ở đây: position: sticky làm thay đổi cơ học thị sai. Vị trí cố định cố gắng gắn phần tử vào vùng chứa cuộn, trong khi phiên bản không dính thì không. Điều này có nghĩa là thị sai có cố định sẽ trở thành nghịch đảo của giá trị không có:

  • Với position: sticky, phần tử càng gần z=0 thì phần tử càng thấp hơn di chuyển.
  • Không có position: sticky, phần tử càng gần z=0 thì càng nhiều nó di chuyển.

Nếu tất cả có vẻ hơi trừu tượng, hãy xem bản minh hoạ này của Robert Flack. thể hiện cách các phần tử hoạt động khác nhau khi có và không có cố định vị trí. Để thấy sự khác biệt, bạn cần có Chrome Canary (phiên bản 56) vào thời điểm viết) hoặc Safari.

Ảnh chụp màn hình phối cảnh thị sai

Bản minh hoạ của Robert Flack minh hoạ cách position: sticky ảnh hưởng đến việc cuộn thị sai.

Các loại lỗi và cách giải quyết

Mặc dù vậy, như bất kỳ thứ gì vẫn còn những cục u và bướu cần được giải quyết đã làm mượt:

  • Sự hỗ trợ cố định không nhất quán. Dịch vụ hỗ trợ vẫn đang được triển khai trong Chrome, Edge không hỗ trợ hoàn toàn, còn Firefox gặp lỗi vẽ lỗi khi tính năng cố định kết hợp với biến đổi phối cảnh. Trong phạm vi như vậy trong trường hợp, bạn nên thêm một mã nhỏ để chỉ thêm position: sticky ( phiên bản có tiền tố -webkit-) khi cần. Phiên bản này dành cho Mobile Safari .
  • Hiệu ứng không "chỉ có tác dụng" trong Edge. Edge cố gắng xử lý thao tác cuộn tại cấp hệ điều hành, nhìn chung là tốt, nhưng trong trường hợp này, nó sẽ ngăn chặn phát hiện các thay đổi về phối cảnh trong khi cuộn. Để khắc phục vấn đề này, bạn có thể thêm một phần tử vị trí cố định, vì thao tác này dường như chuyển Edge sang phương thức cuộn không phải hệ điều hành, và đảm bảo rằng công cụ này tính đến các thay đổi về góc nhìn.
  • "Nội dung trên trang vô cùng lớn!" Nhiều trình duyệt chiếm tỷ lệ này khi quyết định kích thước của nội dung trên trang, nhưng rất tiếc là Chrome và Safari không xét đến quan điểm. Loại đối thủ sau lượt đánh bóng giả sử nếu áp dụng thang điểm 3x cho một nguyên tố, bạn có thể bạn cũng sẽ thấy thanh cuộn và những thứ tương tự, ngay cả khi phần tử ở mức 1x sau Đã áp dụng perspective. Có thể giải quyết vấn đề này bằng cách điều chỉnh tỷ lệ các phần tử ở góc dưới cùng bên phải (bằng transform-origin: bottom right), cách này phù hợp vì sẽ khiến các phần tử quá khổ phát triển lên "khu vực phủ định" (thường là trên cùng bên trái) của khu vực có thể cuộn; có thể cuộn không bao giờ cho phép bạn xem hoặc cuộn đến nội dung trong khu vực phủ định.

Kết luận

Quảng cáo thị sai là một hiệu ứng thú vị khi được sử dụng một cách thấu đáo. Như bạn có thể thấy, có thể để triển khai thẻ theo cách hiệu quả, cuộn cùng nhau và trên nhiều trình duyệt. Vì phương pháp này yêu cầu một chút khó khăn về toán học và một lượng nhỏ mã nguyên mẫu để có được hiệu ứng mong muốn, chúng tôi đã gói gọn một thư viện trình trợ giúp nhỏ và mẫu mà bạn có thể tìm thấy trong kho lưu trữ GitHub về mẫu phần tử giao diện người dùng.

Hãy chơi và cho chúng tôi biết kết quả của bạn nhé.