Делаем красивую кнопку копирования текста на html, css и js

366
0
Делаем красивую кнопку копирования текста

На сайте бывают блоки с текстом, которые наверняка пользователи захотят скопировать. Чаще всего это блоки с кодом, промокодами, ссылками и т.п.

Сделаем кнопку для копирования в блоке с кодом на нашем сайте. Если комментарии по созданию не интересуют вас — можете сразу перейти к результату и скачать файл с кодом.

Вид блока на начало работ:

📄 Требования к нашей кнопке

  1. Кнопка должна быть в верхнем правом углу в виде иконки.
  2. При клике на нее содержимое блока должно быть скопировано.
  3. При успешном или неуспешном копировании должно показываться кратковременное уведомление с результатом возле кнопки.

🔨 Реализация

html-часть кнопки

Без кнопки код блока <pre> выглядит так:

<pre class="block-code">
    <code>Текст, который нужно скопировать</code>
</pre>

Добавим два тега внутрь тега pre: button — сама кнопка для копирования и span — для вывода уведомления. Получим:

<pre class="block-code">
    <code>Текст, который нужно скопировать</code>
    <button class="copy-icon"></button>
    <span class="copy-message hidden"></span>
</pre>

Сразу добавили классы, которые будем использовать позднее для css и javascript-кода.

css-часть нашей красивой кнопки

В первую очередь пропишем стили для нашей кнопки.

Зададим относительные размеры в rem и разместим элемент в верхнем правом углу. SVG-иконку встроим прямо в CSS, чтобы не зависеть от внешних файлов и библиотек. В результате получим:

.copy-icon {
    width: 1.5rem;
    height: 1.5rem;
    position: absolute;
    top: 1rem;
    right: 1rem;
    background-color: #ccc;
    border: none;
    cursor: pointer;
    opacity: 0.6;
    transition: opacity 0.2s ease, background-color 0.2s ease;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: cover;
    mask-size: cover;
    /* Встраиваем SVG-иконку прямо в CSS, чтобы не зависеть от внешних файлов */
    -webkit-mask-image: url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>');
    mask-image: url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>');
}

.copy-icon:hover {
    opacity: 1;
    background-color: #fff;
}

Оформим состояние иконки после успешного копирования:

.copy-icon.copied {
    background-color: #28a745;
    /* Меняем иконку на галочку */
    -webkit-mask-image: url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"></path></svg>');
    mask-image: url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"></path></svg>');
}

Так как использовали абсолютное позиционирование — добавим соответствующее свойство родительскому элементу:

.block-code{
  position: relative;
}

И осталось задать стили для нашего span, в котором будут появляться сообщения:

.hidden{
  display: none;
}
.copy-message {
    position: absolute;
    top: 1rem;
    right: 3.5rem; /* Располагаем слева от иконки */
    background-color: #333;
    color: #fff;
    padding: 0.5rem 1rem;
    border-radius: 0.25rem;
    font-size: 0.8rem;
    opacity: 0;
    transform: translateX(10px);
    transition: opacity 0.3s ease, transform 0.3s ease;
    pointer-events: none; /* Чтобы не мешало кликам */
}

/* Для плавного появления уведомления */
.copy-message.visible {
    opacity: 1;
    transform: translateX(0);
}

javascript-код — чтобы кнопка работала

Общая логика работы:

  1. Находим все кнопки для копирования.
  2. Устанавливаем на них обработчик событий.
  3. При клике вызываем функцию копирования.
  4. Функция копирования вызывает функцию вывода сообщения с результатом копирования.

Код:

document.addEventListener('DOMContentLoaded', () => {
    const copyButtons = document.querySelectorAll('.copy-icon');

    // Функция для показа анимированного сообщения
    const showMessage = (messageElement, text) => {
        messageElement.textContent = text;
        messageElement.classList.remove('hidden');
        messageElement.classList.add('visible');

        setTimeout(() => {
            messageElement.classList.remove('visible');
            setTimeout(() => {
                messageElement.classList.add('hidden');
            }, 300); // Даем время на завершение анимации исчезновения
        }, 2000); // Сообщение видно 2 секунды
    };

    // Основная функция-обработчик клика
    const handleCopyClick = async (event) => {
        const copyButton = event.currentTarget;
        const codeBlock = copyButton.closest('.block-code'); // Находим ближайшего родителя
        const messageElement = codeBlock.querySelector('.copy-message');

        if (!codeBlock || !messageElement) {
            console.error('Не найден родительский блок или элемент сообщения.');
            return;
        }
        
        // Чтобы скопировать только текст, мы клонируем блок и удаляем из него кнопку и сообщение.
        const codeToCopyContainer = codeBlock.cloneNode(true);
        codeToCopyContainer.querySelector('.copy-icon')?.remove();
        codeToCopyContainer.querySelector('.copy-message')?.remove();
        
        const textToCopy = codeToCopyContainer.innerText.trim();

        if (!textToCopy) {
            showMessage(messageElement, 'Нечего копировать');
            return;
        }

        try {
            // Используем современный API для работы с буфером обмена
            await navigator.clipboard.writeText(textToCopy);
            
            showMessage(messageElement, 'Скопировано');
            copyButton.classList.add('copied'); // Меняем иконку на галочку

            // Через 2.5 секунды возвращаем исходную иконку
            setTimeout(() => {
                copyButton.classList.remove('copied');
            }, 2500);

        } catch (err) {
            console.error('Не удалось скопировать текст: ', err);
            showMessage(messageElement, 'Ошибка копирования');
        }
    };

    copyButtons.forEach(button => {
        button.addEventListener('click', handleCopyClick);
    });
});

🎯 Результат

Полученный результат вы видите в каждом блоке с кодом в этом посте. Буду рад, если статья оказалось полезной для вас, и вы воспользовались кнопками копирования, чтобы поставить и себе такую!

🎁 Бонус

Скачать файл с html, css и javascript

Роберт
WRITTEN BY

Роберт

Автор likedislike, интернет-маркетолог со стажем более 10 лет.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *