На сайте бывают блоки с текстом, которые наверняка пользователи захотят скопировать. Чаще всего это блоки с кодом, промокодами, ссылками и т.п.
Сделаем кнопку для копирования в блоке с кодом на нашем сайте. Если комментарии по созданию не интересуют вас — можете сразу перейти к результату и скачать файл с кодом.
Вид блока на начало работ:

📄 Требования к нашей кнопке
- Кнопка должна быть в верхнем правом углу в виде иконки.
- При клике на нее содержимое блока должно быть скопировано.
- При успешном или неуспешном копировании должно показываться кратковременное уведомление с результатом возле кнопки.
🔨 Реализация
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-код — чтобы кнопка работала
Общая логика работы:
- Находим все кнопки для копирования.
- Устанавливаем на них обработчик событий.
- При клике вызываем функцию копирования.
- Функция копирования вызывает функцию вывода сообщения с результатом копирования.
Код:
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);
});
});
🎯 Результат
Полученный результат вы видите в каждом блоке с кодом в этом посте. Буду рад, если статья оказалось полезной для вас, и вы воспользовались кнопками копирования, чтобы поставить и себе такую!