Tạo ảnh động chia tách văn bản

Tổng quan cơ bản về cách tạo ảnh động phân tách chữ cái và từ.

Trong bài đăng này, tôi muốn chia sẻ suy nghĩ về cách giải quyết hoạt ảnh chia tách văn bản và tương tác tối thiểu, có thể truy cập được và hoạt động trên các trình duyệt cho web. Xem bản minh hoạ.

Bản minh hoạ

Nếu bạn thích xem video hơn, sau đây là phiên bản của bài đăng này trên YouTube:

Tổng quan

Ảnh động phân tách văn bản có thể rất thú vị. Chúng tôi sẽ chỉ mới xem xét bề mặt của tiềm năng tạo ảnh động trong bài đăng này, nhưng nó cung cấp nền tảng để tạo dựa trên. Mục tiêu là để tạo ảnh động dần dần. Văn bản phải đọc được bằng mặc định, với ảnh động được tạo ở trên cùng. Hiệu ứng chuyển động chia tách văn bản có thể cho quá tải và có thể gây phiền toái, nên chúng ta sẽ chỉ sử dụng HTML, hoặc áp dụng kiểu chuyển động nếu người dùng OK với chuyển động.

Dưới đây là tổng quan chung về quy trình và kết quả:

  1. Chuẩn bị dữ liệu chuyển động có điều kiện giảm cho CSS và JS.
  2. Chuẩn bị các phần mềm tiện ích văn bản được chia tách trong JavaScript.
  3. Sắp xếp các điều kiện và phần mềm tiện ích trên trang tải.
  4. Viết hiệu ứng chuyển đổi và ảnh động CSS cho chữ cái và từ (phần Rad!).

Dưới đây là bản xem trước của các kết quả có điều kiện mà chúng ta sẽ đạt được:

ảnh chụp màn hình công cụ của Chrome cho nhà phát triển với bảng điều khiển Phần tử đang mở và chuyển động được giảm kích thước được đặt thành "Reduce" (giảm) và màn hình h1 hiển thị không phân tách
Người dùng muốn giảm chuyển động: văn bản dễ đọc / không bị tách

Nếu người dùng muốn giảm chuyển động, chúng tôi sẽ để tài liệu HTML thôi và không ảnh động. Nếu chuyển động được, chúng ta sẽ tiếp tục và cắt thành nhiều mảnh. Sau đây là một bản xem trước HTML sau khi JavaScript đã chia tách văn bản theo chữ cái.

ảnh chụp màn hình công cụ của Chrome cho nhà phát triển với bảng điều khiển Phần tử đang mở và chuyển động được giảm kích thước được đặt thành "Reduce" (giảm) và màn hình h1 hiển thị không phân tách
Người dùng vẫn ổn khi có chuyển động; văn bản được tách thành nhiều <span> phần tử

Đang chuẩn bị điều kiện chuyển động

Truy vấn phương tiện @media (prefers-reduced-motion: reduce) có sẵn thuận tiện sẽ được sử dụng từ CSS và JavaScript trong dự án này. Truy vấn phương tiện này là điều kiện chính của chúng tôi cho quyết định tách văn bản hay không. Truy vấn đa phương tiện CSS sẽ được dùng để giữ lại hiệu ứng chuyển cảnh và hoạt ảnh, trong khi truy vấn phương tiện JavaScript sẽ được dùng để giữ lại thao tác với HTML.

Chuẩn bị điều kiện CSS

Tôi đã sử dụng PostCSS để kích hoạt cú pháp của Truy vấn phương tiện cấp 5, nơi tôi có thể lưu trữ boolean truy vấn phương tiện vào một biến:

@custom-media --motionOK (prefers-reduced-motion: no-preference);

Chuẩn bị điều kiện JS

Trong JavaScript, trình duyệt cung cấp một cách để kiểm tra các truy vấn phương tiện, tôi đã sử dụng phá cấu trúc để trích xuất và đổi tên kết quả boolean từ bước kiểm tra truy vấn đa phương tiện:

const {matches:motionOK} = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
)

Sau đó, tôi có thể kiểm tra motionOK và chỉ thay đổi tài liệu nếu người dùng chưa thay đổi được yêu cầu giảm chuyển động.

if (motionOK) {
  // document split manipulations
}

Tôi có thể kiểm tra cùng một giá trị bằng cách sử dụng PostCSS để kích hoạt cú pháp @nest từ Bản nháp lồng ghép 1. Điều này cho phép tôi lưu trữ tất cả logic về ảnh động và các yêu cầu về kiểu cho ảnh động cha mẹ và con ở cùng một nơi:

letter-animation {
  @media (--motionOK) {
    /* animation styles */
  }
}

Với thuộc tính tuỳ chỉnh PostCSS và boolean JavaScript, chúng tôi đã sẵn sàng nâng cấp hiệu ứng theo điều kiện. Câu này đưa chúng ta đến phần tiếp theo, phân tích JavaScript để chuyển đổi các chuỗi thành các phần tử.

Tách văn bản

Chữ cái, từ, dòng, v.v. không thể tạo ảnh động riêng lẻ với CSS hoặc JS. Để đạt được hiệu ứng, chúng ta cần những chiếc hộp. Nếu chúng ta muốn tạo ảnh động cho từng chữ cái, thì mỗi chữ cái cần phải là một phần tử. Nếu chúng ta muốn tạo ảnh động cho từng từ, thì mỗi từ từ cần phải là một phần tử.

  1. Tạo các hàm tiện ích JavaScript để chia chuỗi thành các phần tử
  2. Sắp xếp việc sử dụng các phần mềm tiện ích này

Hàm hiệu dụng tách chữ cái

Một điểm thú vị để bắt đầu là hàm nhận một chuỗi và trả về mỗi chuỗi chữ cái trong một mảng.

export const byLetter = text =>
  [...text].map(span)

Chiến lược phát hành đĩa đơn lan truyền từ ES6 thực sự giúp biến đó thành một tác vụ nhanh chóng.

Hàm số hiệu dụng của từ được tách

Tương tự như việc tách các chữ cái, hàm này nhận một chuỗi và trả về từng từ trong một mảng.

export const byWord = text =>
  text.split(' ').map(span)

Chiến lược phát hành đĩa đơn split() trên các chuỗi JavaScript cho phép chúng ta chỉ định các ký tự cần cắt. Tôi đi qua một khoảng trống, biểu thị sự phân chia giữa các từ.

Chức năng hữu dụng của hộp chế độ xem

Hiệu ứng này đòi hỏi các hộp cho mỗi chữ cái và chúng ta thấy trong các hàm đó, map() đang được gọi bằng hàm span(). Đây là hàm span().

const span = (text, index) => {
  const node = document.createElement('span')

  node.textContent = text
  node.style.setProperty('--index', index)

  return node
}

Điều quan trọng cần lưu ý là thuộc tính tuỳ chỉnh có tên là --index đang được đặt bằng vị trí mảng. Việc có các hộp cho hoạt ảnh chữ cái thật tuyệt, nhưng có một chỉ mục để sử dụng trong CSS là một hoạt động bổ sung dường như rất nhỏ nhưng lại có tác động lớn. Đáng chú ý nhất trong tác động lớn này là đáng kinh ngạc. Chúng ta sẽ có thể sử dụng --index để bù trừ ảnh động cho một bố cục so le ánh sáng.

Kết luận về phần mềm tiện ích

Đã hoàn tất mô-đun splitting.js:

const span = (text, index) => {
  const node = document.createElement('span')

  node.textContent = text
  node.style.setProperty('--index', index)

  return node
}

export const byLetter = text =>
  [...text].map(span)

export const byWord = text =>
  text.split(' ').map(span)

Tiếp theo là nhập và sử dụng các hàm byLetter()byWord() này.

Sắp xếp tách rời

Khi các tiện ích phân tách đã sẵn sàng cho bạn sử dụng, việc tập hợp tất cả lại đồng nghĩa với việc:

  1. Tìm phần tử cần tách
  2. Chia văn bản và thay thế văn bản bằng HTML

Sau đó, CSS sẽ tiếp quản và tạo ảnh động cho các phần tử / hộp.

Tìm phần tử

Tôi đã chọn sử dụng thuộc tính và giá trị để lưu trữ thông tin về ảnh động và cách tách văn bản. Tôi thích đặt các lựa chọn mang tính khai báo này vào HTML. Thuộc tính split-by được dùng trong JavaScript để tìm và tạo hộp cho các chữ cái hoặc từ. Thuộc tính letter-animation hoặc word-animation được sử dụng trong CSS để nhắm mục tiêu phần tử phần tử con, cũng như áp dụng hiệu ứng biến đổi và ảnh động.

Dưới đây là mẫu HTML thể hiện hai thuộc tính:

<h1 split-by="letter" letter-animation="breath">animated letters</h1>
<h1 split-by="word" word-animation="trampoline">hover the words</h1>

Tìm các phần tử từ JavaScript

Tôi đã sử dụng cú pháp bộ chọn CSS cho sự hiện diện thuộc tính để thu thập danh sách các phần tử muốn tách văn bản:

const splitTargets = document.querySelectorAll('[split-by]')

Tìm các phần tử từ CSS

Tôi cũng đã sử dụng bộ chọn sự hiện diện thuộc tính trong CSS để cung cấp tất cả ảnh động dạng chữ cái có cùng kiểu cơ sở. Sau đó, chúng ta sẽ sử dụng giá trị thuộc tính để thêm thông tin cụ thể hơn kiểu nào đó để đạt được hiệu quả.

letter-animation {
  @media (--motionOK) {
    /* animation styles */
  }
}

Tách văn bản tại chỗ

Đối với mỗi mục tiêu phân tách mà chúng tôi tìm thấy trong JavaScript, chúng tôi sẽ tách văn bản của chúng dựa trên giá trị của thuộc tính và ánh xạ từng chuỗi với một <span>. Chúng ta có thể sau đó thay thế văn bản của phần tử bằng các hộp chúng ta đã tạo:

splitTargets.forEach(node => {
  const type = node.getAttribute('split-by')
  let nodes = null

  if (type === 'letter') {
    nodes = byLetter(node.innerText)
  }
  else if (type === 'word') {
    nodes = byWord(node.innerText)
  }

  if (nodes) {
    node.firstChild.replaceWith(...nodes)
  }
})

Kết luận về việc điều phối

Đã hoàn tất index.js:

import {byLetter, byWord} from './splitting.js'

const {matches:motionOK} = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
)

if (motionOK) {
  const splitTargets = document.querySelectorAll('[split-by]')

  splitTargets.forEach(node => {
    const type = node.getAttribute('split-by')
    let nodes = null

    if (type === 'letter')
      nodes = byLetter(node.innerText)
    else if (type === 'word')
      nodes = byWord(node.innerText)

    if (nodes)
      node.firstChild.replaceWith(...nodes)
  })
}

JavaScript có thể đọc được bằng tiếng Anh sau:

  1. Nhập một số hàm hiệu dụng của trình trợ giúp.
  2. Kiểm tra xem người dùng này có chuyển động được hay không, nếu không thì không làm gì cả.
  3. Cho mỗi phần tử muốn phân tách.
    1. Hãy phân chia chúng theo cách phân chia.
    2. Thay thế văn bản bằng các phần tử.

Tách hoạt ảnh và hiệu ứng chuyển tiếp

Thao tác chia tách tài liệu ở trên đã mở ra vô số các hoạt ảnh và hiệu ứng tiềm năng của CSS hoặc JavaScript. Có một vài đường liên kết ở cuối bài viết này để giúp bạn có cảm hứng chia tách tiềm năng.

Đã đến lúc thể hiện những việc bạn có thể làm với tính năng này! Tôi sẽ chia sẻ 4 ảnh động do CSS điều hướng và chuyển đổi. 🤓

Chia tách chữ cái

Là nền tảng cho các hiệu ứng phân tách chữ cái, tôi nhận thấy CSS sau đây rất hữu ích. Tôi đặt tất cả các hiệu ứng chuyển đổi và hoạt ảnh đằng sau truy vấn phương tiện chuyển động và sau đó cung cấp cho mỗi chữ cái con mới span một thuộc tính hiển thị cùng với một kiểu cho nội dung liên quan đến khoảng trắng:

[letter-animation] > span {
  display: inline-block;
  white-space: break-spaces;
}

Kiểu khoảng trắng đóng vai trò quan trọng để các span chỉ là khoảng trắng, không bị công cụ bố cục thu gọn. Bây giờ, hãy cùng tìm hiểu về nội dung thú vị.

Ví dụ về việc chuyển đổi giữa các chữ cái

Ví dụ này sử dụng hiệu ứng chuyển đổi CSS sang hiệu ứng phân tách văn bản. Với chuyển đổi, chúng tôi cần trạng thái để công cụ tạo hiệu ứng động, và tôi đã chọn 3 trạng thái: không di chuột, di chuột vào câu, di chuột lên một chữ cái.

Khi người dùng di chuột qua câu, hay còn gọi là vùng chứa, tôi thu nhỏ lại tất cả trẻ như thể người dùng đẩy chúng ra xa hơn. Sau đó, khi người dùng di chuột qua thư, tôi đưa ra.

@media (--motionOK) {
  [letter-animation="hover"] {
    &:hover > span {
      transform: scale(.75);
    }

    & > span {
      transition: transform .3s ease;
      cursor: pointer;

      &:hover {
        transform: scale(1.25);
      }
    }
  }
}

Ví dụ về ảnh động tách chữ cái

Ví dụ này sử dụng ảnh động @keyframe xác định trước để tạo ảnh động vô hạn cho mỗi ảnh. chữ cái và tận dụng chỉ mục thuộc tính tuỳ chỉnh cùng dòng để tạo một giao diện hiệu ứng.

@media (--motionOK) {
  [letter-animation="breath"] > span {
    animation:
      breath 1200ms ease
      calc(var(--index) * 100 * 1ms)
      infinite alternate;
  }
}

@keyframes breath {
  from {
    animation-timing-function: ease-out;
  }
  to {
    transform: translateY(-5px) scale(1.25);
    text-shadow: 0 0 25px var(--glow-color);
    animation-timing-function: ease-in-out;
  }
}

Tách từ

Đối với tôi, trong các ví dụ này, Flexbox hoạt động như một loại vùng chứa tận dụng đơn vị ch như một độ dài khoảng trống lành mạnh.

word-animation {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 1ch;
}
Công cụ của nhà phát triển linh hoạt cho thấy khoảng cách giữa các từ

Ví dụ về hiệu ứng chuyển đổi đối với từ được tách

Trong ví dụ về hiệu ứng chuyển đổi này, tôi sử dụng thao tác di chuột một lần nữa. Vì hiệu ứng ban đầu sẽ ẩn cho đến khi di chuột lên, tôi đã đảm bảo rằng tương tác và các kiểu chỉ được áp dụng nếu thiết bị có khả năng di chuột.

@media (hover) {
  [word-animation="hover"] {
    overflow: hidden;
    overflow: clip;

    & > span {
      transition: transform .3s ease;
      cursor: pointer;

      &:not(:hover) {
        transform: translateY(50%);
      }
    }
  }
}

Ví dụ về Tạo ảnh động cho từ được tách

Trong ví dụ về ảnh động này, tôi sử dụng lại CSS @keyframes để tạo một giao diện so le hình động vô hạn trên một đoạn văn bản thông thường.

[word-animation="trampoline"] > span {
  display: inline-block;
  transform: translateY(100%);
  animation:
    trampoline 3s ease
    calc(var(--index) * 150 * 1ms)
    infinite alternate;
}

@keyframes trampoline {
  0% {
    transform: translateY(100%);
    animation-timing-function: ease-out;
  }
  50% {
    transform: translateY(0);
    animation-timing-function: ease-in;
  }
}

Kết luận

Giờ bạn đã biết cách tôi thực hiện điều đó, bạn sẽ làm thế nào?! 🙂

Hãy đa dạng hoá phương pháp tiếp cận và tìm hiểu tất cả các cách xây dựng ứng dụng trên web. Tạo một Codepen hoặc lưu trữ bản minh hoạ của riêng bạn, tweet cho tôi và tôi sẽ thêm nó vào Phần bên dưới là phần các bản phối lại của cộng đồng.

Nguồn

Bản minh hoạ và nguồn cảm hứng khác

Bản phối lại của cộng đồng