Алексей Костюк

Решено. Бесплатный современный и настраиваемый виджет мессенджеров для сайта

Недавно один клиент попросил сделать плавающий виджет мессенджеров и на хабре увидел вопрос, где можно взять готовый скрипт виджета и оказалось бесплатных нет вообще. Одни офигевшие ребята продают аж за 3000 р. в месяц. Скрипт нужный и на самом деле часто просят клиенты такое сделать, поэтому я решил написать скрипт на JS и поделиться с вами абсолютно бесплатно.

Требования к скрипту

  1. Легко внедряемый и настраиваемый. Возможность легко включить и отключать нужные мессенджеры.
  2. Адаптивный под разные устройства (desktop. mobile).
  3. Максимум вариантов мессенджеров.
  4. Возможность позвонить при нажатии на кнопку.
  5. Анимация кнопки для привлечения внимания.

Установка скрипта

Всё довольно просто. Скачиваете в конце поста файл и закидываете в файловую часть вашего сайта, самое простое в корень сайта и в header вашего сайта подключаете скрипт между тегами <head></head> или в footer перед закрывающимся </body>

<head> 
<script src="/widget.js"></script>
</head>

После внесения изменений перезагружаете страницу Ctrl+F5 и скрипт должен заработать сразу.

Наглядно показываю как работает скрипт Наглядно показываю как работает скрипт

Полный код скрипта

(function() {
    'use strict';
    const styles = `
       .messenger-widget {
            position: fixed;
            bottom: 20px;
            right: 20px;
            z-index: 9999;
            font-family: Arial, sans-serif;
            width: 70px;
            height: 70px;
        }
       .messenger-buttons {
            position: absolute;
            bottom: 0;
            right: 6px;
            padding-bottom: 7px;
            display: flex;
            flex-direction: column-reverse;
            align-items: center;
            gap: 15px;
            opacity: 0;
            transform: translateY(10px);
            pointer-events: none;
            transition: opacity 0.25s ease, transform 0.25s ease;
        }
        .messenger-buttons.active {
            opacity: 1;
            transform: translateY(0);
            pointer-events: auto;
        }
        .messenger-btn {
            width: 60px;
            height: 60px;
            border-radius: 50%;
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            text-decoration: none;
            position: relative;
            opacity: 0;
            transform: scale(0.3);
            transition:
                opacity 0.25s ease,
                transform 0.25s cubic-bezier(.34,1.56,.64,1);
        }
        .messenger-buttons.active .messenger-btn {
            opacity: 1;
            transform: scale(1);
        }
        .messenger-btn:hover {
            transform: scale(1.1);
            box-shadow: 0 6px 16px rgba(0,0,0,0.2);
        }
        .btn-phone {
            background: linear-gradient(135deg, #00E676 0%, #00C853 100%);
            transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.3s ease 0.4s;
        }
        .btn-whatsapp {
            background: linear-gradient(135deg, #25D366 0%, #128C7E 100%);
            transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.3s ease 0.3s;
        }
        .btn-telegram {
            background: linear-gradient(135deg, #54A9EB 0%, #0088CC 100%);
            transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.3s ease 0.2s;
        }
        .btn-viber {
            background: linear-gradient(135deg, #7C529E 0%, #665CA7 100%);
            transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.3s ease 0.25s;
        }
        .btn-max {
            background: linear-gradient(90deg, #2E87FB 0%, #5139EC 50%, #8439DC 100%);
            transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.3s ease 0.1s;
        }
        .btn-close {
            background: linear-gradient(135deg, #FF6B9D 0%, #FF4081 100%);
            transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.3s ease 0s;
        }
        .messenger-btn svg {
            width: 30px;
            height: 30px;
            fill: white;
        }
        .btn-max svg {
            width: 40px;
            height: 40px;
        }
        .messenger-btn::before {
            content: attr(data-tooltip);
            position: absolute;
            right: 70px;
            background: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 8px 12px;
            border-radius: 6px;
            font-size: 14px;
            white-space: nowrap;
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.2s ease;
            z-index: 10000;
        }

        .messenger-btn::after {
            content: '';
            position: absolute;
            right: 60px;
            border: 6px solid transparent;
            border-left-color: rgba(0, 0, 0, 0.8);
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.2s ease;
            z-index: 10000;
        }

        .messenger-btn:hover::before,
        .messenger-btn:hover::after {
            opacity: 1;
        }

        .btn-close::before,
        .btn-close::after {
            display: none;
        }

        .main-button {
            width: 70px;
            height: 70px;
            border-radius: 50%;
            background: linear-gradient(135deg, #FF8A65 0%, #FF5722 100%);
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 4px 16px rgba(255, 87, 34, 0.4);
            transition:  opacity 0.25s ease, transform 0.35s cubic-bezier(.34,1.56,.64,1);
            opacity: 1;
            transform: scale(1);
            position: relative;
            z-index: 10000;
        }

        .main-button.hidden {
            opacity: 0;
           transform: translateY(10px) scale(0.8);
            pointer-events: none;
        }

        .main-button:hover {
            transform: scale(1.05);
            box-shadow: 0 6px 20px rgba(255, 87, 34, 0.5);
        }

        .main-button.hidden:hover {
            transform: scale(0.3);
        }

        .main-button svg {
            width: 35px;
            height: 35px;
            fill: white;
        }

        .main-button:before, 
        .main-button:after {
            content: "";
            display: block;
            position: absolute;
            width: 110px;
            height: 110px;
            border: 1px solid #FF5722;
            border-radius: 50%;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%) scale(0.5);
            animation: animate 1.5s linear infinite;
            opacity: 0;
            backface-visibility: hidden;
            pointer-events: none;
        }

        .main-button:after {
            animation-delay: 0.5s;
        }

        @keyframes animate {
            0% {
                transform: translate(-50%, -50%) scale(0.5);
                opacity: 0;
            }

            50% {
                opacity: 1;
            }

            100% {
                transform: translate(-50%, -50%) scale(1.2);
                opacity: 0;
            }
        }
    `;

    const defaultConfig = {
        phone: {
            enabled: false,
            number: '+79001234567',
            tooltip: 'Позвонить'
        },
        whatsapp: {
            enabled: false,
            number: '+79001234567',
            message: '',
            tooltip: 'WhatsApp'
        },
        telegram: {
            enabled: true,
            username: '+79193626600',
            tooltip: 'Telegram'
        },
        viber: {
            enabled: false,
            number: '+79001234567',
            tooltip: 'Viber'
        },
        max: {
            enabled: true,
            url: 'https://max.ru/u/f9LHodD0cOJr018vwqHM_EKXcrvnplV1yKfCdU_Wt5hehUTrWMy40LskPYw',
            tooltip: 'MAX'
        },
        position: {
            bottom: '108px',
            right: '40px',
            mobile: {
                bottom: '85px',
                right: '18px'
            }
        }
    };

    const config = Object.assign({}, defaultConfig, window.messengerWidgetConfig || {});

    Object.keys(defaultConfig).forEach(key => {
        if (typeof defaultConfig[key] === 'object' && window.messengerWidgetConfig && window.messengerWidgetConfig[key]) {
            config[key] = Object.assign({}, defaultConfig[key], window.messengerWidgetConfig[key]);
        }
    });

    const icons = {
        chat: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/><circle cx="12" cy="10" r="1"/><circle cx="8" cy="10" r="1"/><circle cx="16" cy="10" r="1"/></svg>',
        close: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>',
        telegram: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M9.78 18.65l.28-4.23 7.68-6.92c.34-.31-.07-.46-.52-.19L7.74 13.3 3.64 12c-.88-.25-.89-.86.2-1.3l15.97-6.16c.73-.33 1.43.18 1.15 1.3l-2.72 12.81c-.19.91-.74 1.13-1.5.71L12.6 16.3l-1.99 1.93c-.23.23-.42.42-.83.42z"/></svg>',
        whatsapp: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>',
        phone: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/></svg>',
        viber: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M11.4 0C9.473.028 5.333.344 3.02 2.467 1.302 4.187.696 6.7.633 9.817.57 12.933.488 18.617 6.55 20.41h.005l-.004 2.416s-.037.977.61 1.177c.777.242 1.234-.5 1.98-1.302.407-.44.97-1.084 1.397-1.58 3.85.326 6.812-.416 7.15-.525.776-.253 5.176-.816 5.892-6.657.74-6.02-.36-9.83-2.34-11.546-.596-.55-3.006-2.3-8.375-2.323 0 0-.395-.025-1.037-.006zm.058 1.693c.545-.004.88.017.88.017 4.542.02 6.717 1.388 7.222 1.846 1.675 1.434 2.528 4.867 1.906 10.01-.593 4.936-4.126 5.272-4.8 5.493-.283.093-2.933.753-6.378.493 0 0-2.524 3.05-3.32 3.857-.123.125-.27.175-.37.15-.128-.033-.163-.18-.16-.4l.015-4.007c-.015-.002-.027-.007-.04-.01-5.144-1.53-4.833-6.387-4.78-8.978.05-2.59.545-4.7 1.92-6.15 1.948-1.836 5.498-2.1 7.166-2.12z"/></svg>',
        max: '<svg viewBox="0 0 164 164" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M83.015 122.907C74.8942 122.907 71.1204 121.722 64.5605 116.98C60.4112 122.315 47.2718 126.484 46.6988 119.351C46.6988 113.996 45.5133 109.472 44.1697 104.532C42.5693 98.4463 40.7515 91.6691 40.7515 81.8492C40.7515 58.3958 59.9963 40.7515 82.7976 40.7515C105.619 40.7515 123.5 59.2652 123.5 82.0665C123.577 104.515 105.464 122.788 83.015 122.907ZM83.3509 61.0237C72.2466 60.4507 63.5924 68.1368 61.6758 80.1895C60.0951 90.1675 62.9008 102.319 65.2916 102.951C66.4376 103.228 69.3223 100.896 71.1204 99.0984C74.0935 101.152 77.5557 102.386 81.1577 102.675C92.6635 103.228 102.495 94.4686 103.267 82.9754C103.717 71.4579 94.8583 61.7026 83.3509 61.0435L83.3509 61.0237Z" fill="white"/></svg>'
    };
    function createMessengerButton(type, config, icon) {
        let href = '';
        
        switch(type) {
            case 'phone':
                href = `tel:${config.number}`;
                break;
            case 'whatsapp':
                const waNumber = config.number.replace(/[^0-9]/g, '');
                const waMessage = config.message ? `?text=${encodeURIComponent(config.message)}` : '';
                href = `https://wa.me/${waNumber}${waMessage}`;
                break;
            case 'telegram':
                href = `https://t.me/${config.username}`;
                break;
            case 'viber':
                const viberNumber = config.number.replace(/[^0-9]/g, '');
                href = `viber://chat?number=${viberNumber}`;
                break;
            case 'max':
                href = config.url;
                break;
        }

        return `<a href="${href}" target="_blank" class="messenger-btn btn-${type}" data-tooltip="${config.tooltip}">${icon}</a>`;
    }
    function applyWidgetPosition(widget) {
        const isMobile = window.innerWidth <= 767;

        const pos = isMobile && config.position.mobile
            ? config.position.mobile
            : config.position;

        widget.style.bottom = pos.bottom;
        widget.style.right = pos.right;
    }
    function init() {
        const styleSheet = document.createElement('style');
        styleSheet.textContent = styles;
        document.head.appendChild(styleSheet);

        // Создаем контейнер виджета
        const widget = document.createElement('div');
        widget.className = 'messenger-widget';
        applyWidgetPosition(widget);

        let buttonsHTML = '';

        buttonsHTML += `<button class="messenger-btn btn-close" id="closeBtn">${icons.close}</button>`;
          if (config.phone.enabled) {
            buttonsHTML += createMessengerButton('phone', config.phone, icons.phone);
        }
        
        if (config.viber.enabled) {
            buttonsHTML += createMessengerButton('viber', config.viber, icons.viber);
        }
        
        if (config.whatsapp.enabled) {
            buttonsHTML += createMessengerButton('whatsapp', config.whatsapp, icons.whatsapp);
        }
        
        if (config.telegram.enabled) {
            buttonsHTML += createMessengerButton('telegram', config.telegram, icons.telegram);
        }

        if (config.max.enabled) {
            buttonsHTML += createMessengerButton('max', config.max, icons.max);
        }

        widget.innerHTML = `
            <div class="messenger-buttons" id="messengerButtons">
                ${buttonsHTML}
            </div>
            <button class="main-button" id="mainButton">
                ${icons.chat}
            </button>
        `;

        document.body.appendChild(widget);

        // Обработчики событий
        const mainButton = document.getElementById('mainButton');
        const messengerButtons = document.getElementById('messengerButtons');
        const closeBtn = document.getElementById('closeBtn');

        mainButton.addEventListener('click', function() {
            mainButton.classList.add('hidden');
            messengerButtons.classList.add('active');
        });

       closeBtn.addEventListener('click', () => {
            messengerButtons.classList.remove('active');
            mainButton.classList.remove('hidden');
        });
    }
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();

А теперь пояснение как настраивать скрипт.

Стили виджета

Визуальное оформление находится в самом вверху скрипт в переменной  const styles и если разбираетесь в CSS, то легко сможете настроить по своему вкусу виджет и кнопки.

Настройка вывода и мессенджеров

Скрипт поддерживает следующие мессенджеры:

  1. Мессенджер MAX.
  2. Мессенджер Telegram.
  3. Мессенджер WhatsApp.
  4. Мессенджер Viber.
  5. Кнопка Позвонить (прямой вызов телефона).

Конфигурация кнопок находится в этой части скрипта:

const defaultConfig = {
        phone: {
            enabled: false,
            number: '+79001234567',
            tooltip: 'Позвонить'
        },
        whatsapp: {
            enabled: false,
            number: '+79001234567',
            message: '',
            tooltip: 'WhatsApp'
        },
        telegram: {
            enabled: true,
            username: '+79193626600',
            tooltip: 'Telegram'
        },
        viber: {
            enabled: false,
            number: '+79001234567',
            tooltip: 'Viber'
        },
        max: {
            enabled: true,
            url: 'https://max.ru/u/f9LHodD0cOJr018vwqHM_EKXcrvnplV1yKfCdU_Wt5hehUTrWMy40LskPYw',
            tooltip: 'MAX'
        },
        position: {
            bottom: '108px',
            right: '40px',
            mobile: {
                bottom: '85px',
                right: '18px'
            }
        }
    };

Параметры:

  1. enabled: false отключает кнопку, enabled: true включает.
  2. В параметре number: '+79001234567', указываем либо телефон, либо никнейм для Телеграма, либо ссылку для Макса (её получить можно в настройках аккаунта).
  3. tooltip: 'Viber' выводит надпись при наведении на кнопку.
  4. position этот параметр отвечает за расположение кнопки. Первая группа параметров для десктопной версии, а mobile для мобильной версии сайта. Поиграйтесь с настройками позиционирования до нужного результата.

В переменной isMobile задаётся ширина при которой скрипт будет считать сайт мобильной версией. Можете поставить любую нужную цифру.

const isMobile = window.innerWidth <= 767;

Скачать скрипт виджета

Вот и всё. Удачных проектов!

2
0
2
2
0
Алексей Костюк
Привет Username! Я Алексей Костюк
16 лет занимаюсь тем, что помогаю людям создавать сайты и дизайн, настраивать рекламу, продвигать проекты в Интернете. Я создал этот блог, чтобы делиться своим опытом и мыслями, а если вы хотите, то можете меня поддержать, это поможет мне создавать больше полезных статей для вас.