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

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

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

การสาธิต

หากต้องการดูวิดีโอ โปรดดูโพสต์นี้ใน YouTube

ภาพรวม

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

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

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

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

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

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

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

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

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

การเตรียม CSS แบบมีเงื่อนไข

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

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

การเตรียม JS แบบมีเงื่อนไข

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

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)

ไวยากรณ์ การกระจาย จาก 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 ลิงก์ที่ด้านล่างของบทความนี้เพื่อช่วยสร้างแรงบันดาลใจในการแยกเพลง

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

ตัวอักษรแยก

ฉันพบว่า 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%);
      }
    }
  }
}

ตัวอย่างการแยกคำเพื่อสร้างภาพเคลื่อนไหว

ในตัวอย่างภาพเคลื่อนไหวนี้ ฉันใช้ 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