การสร้างภาพเคลื่อนไหวแบบข้อความแบบแยก

ภาพรวมพื้นฐานเกี่ยวกับวิธีสร้างภาพเคลื่อนไหวของตัวอักษรและคำที่แยกออกจากกัน

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

สาธิต

หากต้องการดูวิดีโอ โปรดดูโพสต์เวอร์ชัน YouTube ที่นี่

ภาพรวม

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

ภาพรวมทั่วไปของเวิร์กโฟลว์และผลลัพธ์มีดังนี้

  1. เตรียมตัวแปรแบบมีเงื่อนไขของการเคลื่อนไหวที่ลดลงสำหรับ CSS และ JS
  2. เตรียมยูทิลิตีการแยกข้อความใน JavaScript
  3. จัดระเบียบเงื่อนไขและยูทิลิตีเมื่อโหลดหน้าเว็บ
  4. เขียนการเปลี่ยนและภาพเคลื่อนไหว CSS สำหรับตัวอักษรและคำ (ส่วนเจ๋งๆ)

ต่อไปนี้คือตัวอย่างผลลัพธ์แบบมีเงื่อนไขที่เราต้องการ

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

หากผู้ใช้ต้องการลดการเคลื่อนไหว เราจะไม่เปลี่ยนแปลงเอกสาร HTML และไม่ใส่ภาพเคลื่อนไหว หากการเคลื่อนไหวเรียบร้อยดี เราจะตัดวิดีโอออกเป็นส่วนๆ ต่อไปนี้คือตัวอย่าง HTML หลังจากที่ JavaScript แยกข้อความตามตัวอักษร

ภาพหน้าจอของเครื่องมือสำหรับนักพัฒนาเว็บของ Chrome ที่มีแผงองค์ประกอบเปิดอยู่และตั้งค่าการเคลื่อนไหวที่ลดลงเป็น "ลด" และ h1 แสดงโดยไม่แยก
ผู้ใช้ยอมรับการเคลื่อนไหวได้ ข้อความแยกออกเป็นองค์ประกอบ <span> หลายรายการ

การเตรียมเงื่อนไขการเคลื่อนไหว

ระบบจะใช้คิวรีสื่อ @media (prefers-reduced-motion: reduce) ที่พร้อมใช้งานจาก CSS และ JavaScript ในโปรเจ็กต์นี้ การค้นหาสื่อนี้เป็นเงื่อนไขหลักในการตัดสินว่าจะแยกข้อความหรือไม่ ระบบจะใช้คำค้นหาสื่อ CSS เพื่อระงับการเปลี่ยนภาพและภาพเคลื่อนไหว ส่วนคำค้นหาสื่อ JavaScript จะใช้เพื่อระงับการจัดการ HTML

เตรียมเงื่อนไข CSS

ฉันใช้ PostCSS เพื่อเปิดใช้ไวยากรณ์ของ Media Queries ระดับ 5 ซึ่งฉันสามารถจัดเก็บบูลีน Media Query ไว้ในตัวแปรได้ ดังนี้

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

เตรียมเงื่อนไข JS

ใน JavaScript เบราว์เซอร์มีวิธีตรวจสอบคําค้นหาสื่อ ซึ่งเราใช้การจัดโครงสร้างใหม่เพื่อดึงข้อมูลและเปลี่ยนชื่อผลลัพธ์บูลีนจากการตรวจสอบคําค้นหาสื่อ ดังนี้

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

จากนั้นฉันจะทดสอบ motionOK และเปลี่ยนเอกสารเฉพาะในกรณีที่ผู้ใช้ไม่ได้ขอให้ลดการเคลื่อนไหว

if (motionOK) {
  // document split manipulations
}

ฉันตรวจสอบค่าเดียวกันได้โดยใช้ PostCSS เพื่อเปิดใช้ไวยากรณ์ @nest จากNesting Draft 1 ซึ่งช่วยให้ฉันเก็บเหตุผลทั้งหมดเกี่ยวกับภาพเคลื่อนไหวและข้อกำหนดด้านสไตล์สำหรับองค์ประกอบหลักและองค์ประกอบย่อยไว้ในที่เดียวได้

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

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

การแยกข้อความ

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

  1. สร้างฟังก์ชันยูทิลิตี JavaScript สำหรับการแยกสตริงออกเป็นองค์ประกอบ
  2. จัดการการใช้ยูทิลิตีเหล่านี้

ฟังก์ชันยูทิลิตีการแยกตัวอักษร

จุดเริ่มต้นที่น่าสนใจคือฟังก์ชันที่รับสตริงและแสดงผลตัวอักษรแต่ละตัวในอาร์เรย์

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

รูปแบบคำสั่ง spread จาก ES6 ช่วยทําให้งานนี้เสร็จเร็วขึ้นมาก

ฟังก์ชันยูทิลิตีการแยกคำ

ฟังก์ชันนี้จะรับสตริงและแสดงผลแต่ละคำเป็นอาร์เรย์ ซึ่งคล้ายกับการแยกตัวอักษร

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

วิธีการ split() ในสตริง JavaScript ช่วยให้เราระบุอักขระที่จะตัดได้ ฉันผ่านพื้นที่ว่าง ซึ่งบ่งบอกถึงการแยกระหว่างคำ

การสร้างฟังก์ชันยูทิลิตีของกล่อง

เอฟเฟกต์นี้ต้องใช้กล่องสำหรับแต่ละตัวอักษร และเราเห็นว่าในฟังก์ชันเหล่านั้น map() กำลังเรียกใช้ด้วยฟังก์ชัน span() นี่คือฟังก์ชัน span()

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

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

  return node
}

โปรดทราบว่ามีการตั้งค่าพร็อพเพอร์ตี้ที่กำหนดเองชื่อ --index ด้วยตําแหน่งอาร์เรย์ การมีช่องสำหรับภาพเคลื่อนไหวของตัวอักษรนั้นยอดเยี่ยม แต่การมีดัชนีที่จะใช้ใน CSS นั้นดูเหมือนจะเป็นการเพิ่มเล็กๆ น้อยๆ ที่มีผลอย่างมาก สิ่งที่เห็นได้ชัดที่สุดจากผลกระทบที่ยิ่งใหญ่นี้คือการเพิ่มขึ้นอย่างมาก เราจะใช้ --index เป็นวิธีเลื่อนภาพเคลื่อนไหวเพื่อดูแบบสลับกันได้

สรุปเกี่ยวกับยูทิลิตี

โมดูล 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)

ขั้นตอนถัดไปคือการนําเข้าและใช้ฟังก์ชัน byLetter() และ byWord() เหล่านี้

การจัดการเป็นกลุ่มแบบแยก

เมื่อยูทิลิตีการแยกพร้อมใช้งานแล้ว การนำทุกอย่างมารวมกันจะมีลักษณะดังนี้

  1. การค้นหาองค์ประกอบที่จะแยก
  2. แยกและแทนที่ข้อความด้วย HTML

หลังจากนั้น CSS จะเข้ามาควบคุมและทำให้องค์ประกอบ / กล่องเคลื่อนไหว

การค้นหาองค์ประกอบ

เราเลือกที่จะใช้แอตทริบิวต์และค่าเพื่อจัดเก็บข้อมูลเกี่ยวกับภาพเคลื่อนไหวที่ต้องการและวิธีแยกข้อความ ฉันชอบใส่ตัวเลือกแบบประกาศเหล่านี้ลงใน HTML แอตทริบิวต์ split-by ใช้จาก JavaScript เพื่อค้นหาองค์ประกอบและสร้างกล่องสำหรับตัวอักษรหรือคำ แอตทริบิวต์ letter-animation หรือ word-animation ใช้จาก CSS เพื่อกำหนดเป้าหมายองค์ประกอบย่อยและใช้การเปลี่ยนรูปแบบและภาพเคลื่อนไหว

ต่อไปนี้คือตัวอย่าง HTML ที่แสดงแอตทริบิวต์ 2 รายการนี้

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

การค้นหาองค์ประกอบจาก JavaScript

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

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

การค้นหาองค์ประกอบจาก CSS

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

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

การแยกข้อความในตำแหน่ง

สําหรับเป้าหมายการแยกแต่ละรายการที่เราพบใน JavaScript เราจะแยกข้อความโดยอิงตามค่าของแอตทริบิวต์ และแมปสตริงแต่ละรายการกับ <span> จากนั้นเราจะแทนที่ข้อความขององค์ประกอบด้วยกล่องที่เราสร้างขึ้นได้ ดังนี้

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

สรุปการจัดการเป็นกลุ่ม

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 นี้อ่านเป็นภาษาอังกฤษได้ดังนี้

  1. นําเข้าฟังก์ชันยูทิลิตีตัวช่วยบางรายการ
  2. ตรวจสอบว่าผู้ใช้รายนี้สามารถใช้ฟีเจอร์การเคลื่อนไหวได้หรือไม่ หากไม่ ให้ดำเนินการใดๆ ทั้งสิ้น
  3. สําหรับองค์ประกอบแต่ละรายการที่ต้องการแยก
    1. แบ่งตามวิธีที่ผู้ใช้ต้องการ
    2. แทนที่ข้อความด้วยองค์ประกอบ

การแยกภาพเคลื่อนไหวและการเปลี่ยน

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

มาดูกันว่าคุณจะทำอะไรได้บ้าง เราจะแชร์ภาพเคลื่อนไหวและการเปลี่ยน CSS 4 แบบ 🤓

แยกตัวอักษร

เราพบว่า CSS ต่อไปนี้มีประโยชน์ต่อการวางรากฐานสำหรับเอฟเฟกต์การแยกตัวอักษร ฉันใส่ทรานซิชันและแอนิเมชันทั้งหมดไว้หลังข้อความค้นหาสื่อแบบเคลื่อนไหว แล้วกำหนดพร็อพเพอร์ตี้การแสดงผลและสไตล์สำหรับจัดการกับเว้นวรรคให้กับตัวอักษรย่อย span ใหม่แต่ละตัว ดังนี้

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

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

ตัวอย่างตัวอักษรแบ่งช่วงการเปลี่ยน

ตัวอย่างนี้ใช้การเปลี่ยนภาพ CSS กับเอฟเฟกต์ข้อความแยก สำหรับทรานซิชัน เราต้องใช้สถานะต่างๆ เพื่อให้เครื่องยนต์แสดงภาพเคลื่อนไหวระหว่างสถานะต่างๆ และเราเลือกสถานะ 3 สถานะ ได้แก่ ไม่วางเมาส์เหนือ วางเมาส์เหนือในประโยค และวางเมาส์เหนือตัวอักษร

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

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

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

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

ตัวอย่างตัวอักษรแบบแยกที่เคลื่อนไหว

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

@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;
  }
}

แยกคำ

Flexbox ทำงานเป็นประเภทคอนเทนเนอร์สำหรับฉันในตัวอย่างเหล่านี้ โดยใช้ประโยชน์จากหน่วย ch เป็นความยาวช่องว่างที่เหมาะสม

word-animation {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 1ch;
}
เครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ Flexbox ที่แสดงช่องว่างระหว่างคำ

ตัวอย่างคำที่แบ่งช่วงทรานซิชัน

ในตัวอย่างนี้ เราจะใช้การโฮเวอร์อีกครั้ง เนื่องจากเอฟเฟกต์จะซ่อนเนื้อหาไว้จนกว่าจะมีการวางเมาส์เหนือ เราจึงตรวจสอบว่าใช้การโต้ตอบและสไตล์เฉพาะในกรณีที่อุปกรณ์สามารถวางเมาส์เหนือได้

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

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

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

ตัวอย่างคำที่แยกออกเป็น 2 พยางค์

ในตัวอย่างภาพเคลื่อนไหวนี้ เราใช้ CSS @keyframes อีกครั้งเพื่อสร้างภาพเคลื่อนไหวแบบสลับไปมาแบบไม่สิ้นสุดในย่อหน้าข้อความปกติ

[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;
  }
}

บทสรุป

ตอนนี้คุณรู้วิธีที่เราทําแล้ว คุณจะทําอย่างไร 🙂

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

แหล่งที่มา

ตัวอย่างและแรงบันดาลใจเพิ่มเติม

รีมิกซ์ของชุมชน

  • <text-hover> คอมโพเนนต์เว็บโดย gnehcwu ใน CodeSandbox