Галоўная / Артыкулы

Кнапка з анімацыяй пазначэння «згодна» без жадных бібліятэкаў анімацый

Створыце віджэт з адзінамі на падзею і адзінамі проты падзею з анімацыяй pop на кансэле ключоўых кадраў, станамі актывацыі і вызовам fetch, выкорыстоўваючы толькі HTML, CSS і калькі ліній JavaScript.

Выдавец: REACTAPP.TOP7 хв чытання1559 слоў

Крыніцы: Creating an Interactive Thumbs Up Feedback Button with HTML, CSS and JavaScript

Кнапкі «Палець угору» і «Палець вніз» — адзін з найяксцявых спосабоў запытаць корыстувачаў, чы рэгламентная сторанка, адказ чы функцыя ім дапамоглі. Звычная рэалізацыя проста зменшвае колер фона пасля кліку, што лёгка працягнуць, калі нічога іншага на сторанцы не змянюецца. У цім кераванні ствараецца адносна багатшая версія: пасля кліку на «Палець угору» іконка на час заменяецца на сяючы смайлік, які з’яўляецца за дапамогою анімазіі масштабавання і роціявання, а пасля — стае выдзеленым «Пальцам угору». Вы пазірэце маркап, CSS, JavaScript, які керуе пераходамі між станамі, а таксама тыя элементы, якія трэба дапрацаваць перш чым выкласты прыладку.

Што робіць прыладка

Інтэрфейс складаецца з двух круглых кнапак: адной для паазітывнай, а другой — для негатыўнай дакументаціі. Клік на паазітывную кнапку запускае короткую серыю дзейнасцей:

  1. Іконка «Палець угору» заменяецца на смайлік, абакоўваючыся сімволамі сяйва.
  • Анімацыя ключоўых кадраў паказвае яго з лёгкым вырастаннем і роцэю.
  • Пасля короткай паузы усмешкаваны сімвал знову ператвараецца на просты пазначак «працуе».
  • Кнапка пераходзіць у актыўны, выдзелены стан.
  • Такія мікро-інтэракцыі дапамагаюць стварыць вражанне чутлівай паляны без аднойчынага фрэймворка для анімацый.

    Маркап для двух кнапак

    Кожная кнапка атрыбутуецца ідэнтыфікатарам для скрыптаў, спяльным класам для стылю і класам-модыфікаторам для свайго сябе актыўнага калеру. Айканыты — гэта сімвалы emoji ўнутры кнапак:

    <div class="feedback">
      <button
          id="thumbsUp"
          class="feedback-btn thumbs-up"
          aria-label="Thumbs up">
          👍🏻
      </button>
      <button
          id="thumbsDown"
          class="feedback-btn thumbs-down"
          aria-label="Thumbs down">
          👎🏻
      </button>
    </div>
    

    Тут важны атрыбут aria-label. Без яго чытальнік экрана абавешчаў бы толькі назву самага emoji (або нічога корыстнага), таму атрыбут дае кожной кнапцы чыстую, доступную назву. Калі хочаце, каб асістуючыя тэхналогіі таксама ведалі, якая опцыя выбрана, дадзіце aria-pressed і адкорэгуйце яго разам з класам active.

    Круглыя кнопкі з адказам на наведэнне

    Базовы стыль фіксуе розмер, падчыняе стандартны выгляд, центруе іконку за дапамою flexbox і ператварае кнопку на круг:

    .feedback-btn {
        width: 52px;
        height: 52px;
        border: 1px solid #ddd;
        background: #fff;
        border-radius: 50%;
        cursor: pointer;
        font-size: 25px;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: all 0.25s ease;
    }
    

    border-radius: 50% для квадратнага элемента стварае круг, а transition робіць пазлычныя змены; указванне конкрэтных атрыбутаў заместо all запобегае анімэйшу прыемоў, якія вы не хацелі.

    Правілле для наведэння светліць фон і трохі падвялічвае розмер кнопкі, так што курсор атрымле негараздзейскі адказ:

    .feedback-btn:hover {
        background: #f5f5f5;
        transform: scale(1.08);
    }
    

    Ключавыя кадры, якія ствараюць анімэйш

    Інтрыгуючы момент — пераход з сімволу «пятачак» на сяючы смайлік. Гэта рэалізуецца за дапамою правілле @keyframes пад назвай sparkle:

    @keyframes sparkle {
        0% {
            transform: scale(0.4) rotate(-20deg);
            opacity: 0;
        }
        35% {
            transform: scale(1.4) rotate(10deg);
            opacity: 1;
        }
        65% {
            transform: scale(1) rotate(-5deg);
        }
        100% {
            transform: scale(1) rotate(0deg);
        }
    }
    

    Як часовая шкала: на 0% контэнт скушчваецца да 40%, нахілваецца назад на 20 градусоў і стае невыразным. На 35% ён досягае масштабу 140%, з лёгкім нахілам у працоўную сторону і повной прозрачнасцю. На 65% ён вяртаецца да нормальных размераў з невелікім протыходным нахілам, а на 100% застаецца у своіх натуральных размерах і куточку нахілу. Гэты перэхід з апошнім стабілізаванням і ўтварае эфект „прыбыць“. Заўважкай, што гэтыя правілы візначаюць толькі рух; околачная класа .sparkle, якая прыменяе іх за дапамою animation: sparkle 0.8s ease forwards, прадстаўлена ў цэлым прыкладзе напрыканце.

    Праця з станамі ў JavaScript

    Функцыя обработкі кліка для пазначкі „паслягнуць“ коордынавае замену контэнту, клас анімацыі і канечны стан:

    thumbsUp.addEventListener("click", function () {
        if (thumbsUp.classList.contains("active")) {
            return;
        }
        thumbsUp.innerHTML = "✨😊✨";
        thumbsUp.classList.add("sparkle");
        setTimeout(function () {
            thumbsUp.innerHTML = "👍";
            thumbsUp.classList.remove("sparkle");
            thumbsUp.classList.add("active");
        }, 900);
    });
    

    Усё пачатваецца з пераконтроўкі: калі кантактны элемент ужэ мае клас active, функцыя-обрабоўчык вяртаеся, таму анімацыю нельга павтарыць праз аднароўныя клікі. Потым ён заменяе вёскпадак на смайлік:

    thumbsUp.innerHTML = "✨😊✨";
    

    і дадае клас, які запускае ключавыя кадры:

    thumbsUp.classList.add("sparkle");
    

    Выкорыстоўваецца setTimeout на 900 мілісекунд, што трохі больш за 0,8 секунды анімацыі; пасля чаго вяртаецца сімвал пальцаў угору, адмахваецца клас sparkle і дадаецца клас active:

    thumbsUp.innerHTML = "👍";
    

    Вёскпадак ніколі не ўзьмальваецца з вводу карыстальніка, таму innerHTML ў гэтым случае ёсць безпечным, хоць textContent лепшая выражае намер.

    Акцэнтаванне выбранага варыянта

    Клас active несе візуальную паўтарэчнасць. Позытывныя адзывы маюць светла-зелёны фон і зелёную рамку:

    .thumbs-up.active {
        background: #e8f5e9;
        border-color: #4caf50;
    }
    

    Негатыўныя адзывы выкорыстоўваюць той самы шаблон у жоŭтым кольры:

    .thumbs-down.active {
        background: #ffebee;
        border-color: #f44336;
    }
    

    Разныя кольры дазволяюць за мгненне пабачыць, які варыянт быў выбран, але не трэба пакладацца толькі на кольры; aria-pressed дапамагае корыстнікам, якія не можуць іх розразліць.

    Забезпечэнне взаімна эксклюзыўнасці варыянтав

    Айконка з пазначкай «не» выкорыстоўвае простэйшую взаімнасць без анімацыі. Яна пераключае свой сабэйшны клас active, ацэнюе позытыўны статус і, калі тады выбрана, вяртае айконку з пазначкай «так» у ўсходзічны вачымку:

    thumbsDown.addEventListener("click", function () {
        thumbsDown.classList.toggle("active");
        thumbsUp.classList.remove("active");
        if (thumbsDown.classList.contains("active")) {
            thumbsUp.innerHTML = "👍🏻";
        }
    });
    

    Адзыённе іншага кантакту запобегае таму, што обе апцыі будуць выглядаць выбранымі адразу. Існуе ўзельны случай: калі паўтарна адбуваецца нажатыя на кантакты «пазначыць» і «знізіць» прыбліжна за 900 мс, тады ўсё раве спрацоўвае таймер і знову актывае кантакт «пазначыць». Калі трэба падрыхтувач кантакта «знізіць», неабходна зберагчы ідэнтыфікатор таймера і вызваць clearTimeout, каб усунуць гэты прыемак. Таксама важна згадаць, што актыўны кантакт «пазначыць» не можа быць анульваны праз яго ж нажатые, тады калі кантакт «знізіць» зміняе статус; трэба прабавіцца супаставіць іх.

    Чаму невялікая анімацыя вартая зусіль

    Статычная зміна колеру парадзіцца сігналам таго, што ўсё-такі адбылося; короткая анімацыя (клік, рух, парадакт) стварае вражанне, што інтэрфейс адказаў. Гэта ўжо так важліва для інлайн-падтрымкі, калі на старонцы няма іншых сігналоў пра успех. Гэта падходзіць для форм зворачанняў па курсах, атрыбутаў FAQ і базы знанняй, інструментаў падтрымкі, адгукоў пра продукты, опытнаў, сайтаў дакументацыі, адказоў чат-ботаў на AI і внутрашняях інструментах.

    Паслухайце параметр prefers-reduced-motion, выключыўшы ключовыя кадры для корыстувачаў, якія прасіюць менш анімацыі.

    Адправка атрыбута рэйтынгу на бэкенд

    У такой форме віджэт ёсць чыста візуальны. У рэальнам продукце неабходна зберагчы выбор, і працэс расшырваецца, ўключаючы запіт:

    User clicks 👍
           ↓
    Animation plays
           ↓
    Feedback recorded
           ↓
    Database updated
           ↓
    User sees confirmation
    

    Можна вікорыстаць будзь-які бэкенд — PHP, Node.js, Python чы ўсё іншае. З функціі обработкі кліка неабходна адправіць рэйтынг на відпаведны канец:

    fetch("/api/feedback", {
        method: "POST",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            feedback: "positive"
        })
    });
    

    Сервер можа зберагчыць сторанку, карыстальніка, адпаведны адказ, час запісу і тып адзвечання. Пераканацеся, чы не response.ok, таму што fetch адхоўваеся толькі пад час сетавых адказоў, і выберыце, чы анімацыя павінна запускатыся оптымістычна (шырэй, але патрабуе вярнення да пачатковага стану, якшы запіс не выйдзе), чы то толькі пасля успеху.

    Полная сторанка

    Усё знаходзіцца ў аднам файле: клас .sparkle, стан :active для падтрымкі натыску, а таксама прыемнік для пазначэння пасляплывучага стану, які ацэнюе выбор:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Feedback Buttons</title>
    
    <style>
        .feedback {
            display: flex;
            gap: 12px;
            align-items: center;
        }
    
        .feedback-btn {
            width: 52px;
            height: 52px;
            border: 1px solid #ddd;
            background: #fff;
            border-radius: 50%;
            cursor: pointer;
            font-size: 25px;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.25s ease;
        }
    
        .feedback-btn:hover {
            background: #f5f5f5;
            transform: scale(1.08);
        }
    
        .feedback-btn:active {
            transform: scale(0.92);
        }
    
        /* Sparkle animation */
        .sparkle {
            animation: sparkle 0.8s ease forwards;
        }
    
        @keyframes sparkle {
            0% {
                transform: scale(0.4) rotate(-20deg);
                opacity: 0;
            }
    
            35% {
                transform: scale(1.4) rotate(10deg);
                opacity: 1;
            }
    
            65% {
                transform: scale(1) rotate(-5deg);
            }
    
            100% {
                transform: scale(1) rotate(0deg);
            }
        }
    
        /* Filled thumbs up */
        .thumbs-up.active {
            background: #e8f5e9;
            border-color: #4caf50;
        }
    
        .thumbs-down.active {
            background: #ffebee;
            border-color: #f44336;
        }
    </style>
    </head>
    
    <body>
    
    <div class="feedback">
    
        <button
            id="thumbsUp"
            class="feedback-btn thumbs-up"
            aria-label="Thumbs up">
            👍🏻
        </button>
    
        <button
            id="thumbsDown"
            class="feedback-btn thumbs-down"
            aria-label="Thumbs down">
            👎🏻
        </button>
    
    </div>
    
    <script>
    
    const thumbsUp = document.getElementById("thumbsUp");
    const thumbsDown = document.getElementById("thumbsDown");
    
    thumbsUp.addEventListener("click", function () {
    
        // Prevent repeated animation
        if (thumbsUp.classList.contains("active")) {
            return;
        }
    
        // Step 1: Sparkling smiley
        thumbsUp.innerHTML = "✨😊✨";
        thumbsUp.classList.add("sparkle");
    
        // Step 2: Change to filled thumbs up
        setTimeout(function () {
    
            thumbsUp.innerHTML = "👍";
            thumbsUp.classList.remove("sparkle");
            thumbsUp.classList.add("active");
    
        }, 900);
    
        // Remove thumbs down selection
        thumbsDown.classList.remove("active");
    });
    
    thumbsDown.addEventListener("click", function () {
    
        thumbsDown.classList.toggle("active");
    
        // Remove thumbs up selection
        thumbsUp.classList.remove("active");
    
        if (thumbsDown.classList.contains("active")) {
            thumbsUp.innerHTML = "👍🏻";
        }
    });
    
    </script>
    
    </body>
    </html>
    

    Заключэнне

    Для качанай сістэмы адзвечання патрабуецца толькі HTML, CSS і калькі ліній JavaScript. Ключавыя кадры забезпечваюць ефект „поп“, а парады змены класоў за часам керуюць станамі, а падсвечаны іконка на канцы паўтарае выбор.

    • Логіку анімацыі трэба залішыць у CSS, а JavaScript павінен толькі перэключаць класы і контэнт.
  • Сачыце за часам выканання задачы, каб швыдкія нажатыя на іншую кнопку не моглі заставіць обе опцыі актыўнымі.
  • Дадзіце атрыбут aria-pressed і альтэрнатыўны варыант з паслабленам рухам, каб віджэт застаўся доступным.
  • Спрыяйце адносу з серверам як частыні взаімадзеяння: керуйце неудачамі і выбірайце межу оптымістычнай і паверанай адпаведзі.
  • Той жа падход прыменяецца да іконак SVG, анімацый Lottie, звуковых сігналоў і болей развітых робочых пракцэсаў, апаратныхя на API.