ساخت ابزار پالت‌ساز و تبدیل رنگ پیشرفته با HTML و JS

آموزش ساخت یک ابزار حرفه‌ای پالت‌ساز و تبدیل‌گر کدهای رنگی HEX، RGB و HSL با یک فایل HTML و جاوا اسکریپت؛ کاملاً رایگان و کاربردی برای طراحان وب.

🎧 خلاصه صوتی مقاله (پادکست ۲ دقیقه‌ای):

فرصت مطالعه ندارید؟ چکیده این مطلب را همین‌جا گوش دهید:

مدیریت رنگ‌ها و تبدیل کدهای رنگی به یکدیگر یکی از کارهای روزمره طراحان وب، توسعه‌دهندگان رابط کاربری و برنامه‌نویسان فرانت‌اند است. هنگامی که روی پروژه‌های بزرگ کار می‌کنید، سرعت دسترسی به ابزارهایی که کدهای HEX، RGB و HSL را به سرعت به هم تبدیل کنند و امکان ذخیره پالت‌های دلخواه را به شما بدهند، اهمیت بسیار زیادی پیدا می‌کند. همان‌طور که در نقشه راه بهینه‌سازی سرعت و عملکرد وب‌سایت برای توسعه‌دهندگان فرانت‌اند اشاره شده است، ابزارهای سبک و بدون وابستگی به کتابخانه‌های سنگین خارجی می‌توانند نقش مهمی در افزایش بهره‌وری و بهبود فرآیند توسعه ایفا کنند.

در این مقاله قصد داریم یک ابزار کامل، زیبا و کاربردی تحت وب را بررسی کنیم که به شما اجازه می‌دهد رنگ‌ها را به صورت زنده انتخاب کنید، کدهای مختلف آن‌ها را استخراج کنید، پالت‌های شخصی خود را بسازید و با یک کلیک کدهای CSS را کپی کنید. این پروژه به‌صورت کاملاً یک‌پارچه در یک فایل واحد نوشته شده است و نیازی به نصب هیچ‌گونه پکیج یا ابزار اضافه‌ای ندارد.

ویژگیمقدار / مشخصات
زبان‌های استفاده شدهHTML5, CSS3, JavaScript (Vanilla)
ساختار فایلتک‌فایلی (Single File)
قابلیت ذخیره‌سازیپشتیبانی از حافظه محلی مرورگر (localStorage)
هزینه۱۰۰٪ رایگان و متن‌باز
وضعیت دسترسی ایرانبدون محدودیت (قابل اجرا در مرورگر محلی)

چرا داشتن یک ابزار پالت‌ساز اختصاصی اهمیت دارد؟

بسیاری از طراحان برای انتخاب رنگ به وب‌سایت‌های آنلاین مختلفی مراجعه می‌کنند که گاهی با کندی بارگذاری، تبلیغات آزاردهنده یا محدودیت‌های دسترسی مواجه می‌شوند. داشتن یک ابزار سبک شخصی روی سیستم خودتان یا در محیط لوکال هاست، این مشکل را به‌کل حل می‌کند. علاوه بر این، تسلط بر نحوه تبدیل فرمت‌های رنگی مختلف در جاوا اسکریپت، به شما کمک می‌کند تا درک عمیق‌تری از نحوه پردازش داده‌های بصری در مرورگر داشته باشید.

این ابزار به شما امکان می‌دهد:

  • مقادیر رنگ را از طریق یک انتخابگر استاندارد (Color Picker) یا ورود دستی کدهای HEX وارد کنید.
  • به‌طور هم‌زمان معادل دقیق کدهای RGB و HSL را مشاهده کنید.
  • رنگ‌های دلخواه خود را به لیست پالت‌های ذخیره‌شده اضافه کنید تا با بستن مرورگر نیز از بین نروند.
  • با قابلیت کپی سریع و بازخورد بصری (Toast)، کدهای CSS را بدون معطلی به کلیپ‌بورد منتقل کنید.

کد کامل پروژه (HTML، CSS و جاوا اسکریپت)

برای استفاده از این ابزار، کافی است کد زیر را داخل یک فایل متنی با پسوند .html (مثلاً color-tool.html) ذخیره کنید و آن را با هر مرورگر وب مدرنی باز کنید. هیچ نیازی به سرور محلی یا نصب پیش‌نیاز دیگری نیست.

<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ابزار پیشرفته پالت‌ساز و تبدیل رنگ</title>
    <style>
        :root {
            --bg-color: #0f172a;
            --card-bg: #1e293b;
            --text-color: #f8fafc;
            --primary: #3b82f6;
            --primary-hover: #2563eb;
            --border: #334155;
        }
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-family: system-ui, -apple-system, sans-serif;
        }
        body {
            background-color: var(--bg-color);
            color: var(--text-color);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }
        .container {
            width: 100%;
            max-width: 600px;
            background-color: var(--card-bg);
            border: 1px solid var(--border);
            border-radius: 16px;
            padding: 30px;
            box-shadow: 0 10px 25px rgba(0,0,0,0.3);
        }
        h1 {
            font-size: 1.5rem;
            margin-bottom: 20px;
            text-align: center;
        }
        .picker-section {
            display: flex;
            gap: 15px;
            align-items: center;
            margin-bottom: 25px;
        }
        input[type="color"] {
            appearance: none;
            border: none;
            width: 60px;
            height: 60px;
            border-radius: 12px;
            cursor: pointer;
            background: none;
        }
        input[type="color"]::-webkit-color-swatch-wrapper {
            padding: 0;
        }
        input[type="color"]::-webkit-color-swatch {
            border: 2px solid var(--border);
            border-radius: 12px;
        }
        .color-inputs {
            flex-grow: 1;
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .input-group {
            display: flex;
            justify-content: space-between;
            background: var(--bg-color);
            padding: 8px 12px;
            border-radius: 8px;
            border: 1px solid var(--border);
            align-items: center;
        }
        .input-group span {
            font-size: 0.85rem;
            color: #94a3b8;
        }
        .input-group strong {
            font-family: monospace;
            cursor: pointer;
        }
        .btn {
            background-color: var(--primary);
            color: white;
            border: none;
            padding: 12px;
            border-radius: 8px;
            font-weight: bold;
            cursor: pointer;
            width: 100%;
            transition: background 0.2s;
            margin-bottom: 20px;
        }
        .btn:hover {
            background-color: var(--primary-hover);
        }
        .palette-section h2 {
            font-size: 1.1rem;
            margin-bottom: 12px;
        }
        .palette-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(50px, 1fr));
            gap: 10px;
            min-height: 60px;
            background: var(--bg-color);
            padding: 12px;
            border-radius: 8px;
            border: 1px solid var(--border);
        }
        .palette-item {
            width: 100%;
            height: 50px;
            border-radius: 6px;
            cursor: pointer;
            border: 1px solid rgba(255,255,255,0.2);
            transition: transform 0.2s;
        }
        .palette-item:hover {
            transform: scale(1.05);
        }
        .toast {
            position: fixed;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%) translateY(100px);
            background: #10b981;
            color: white;
            padding: 10px 20px;
            border-radius: 8px;
            transition: transform 0.3s ease;
            font-weight: bold;
            box-shadow: 0 5px 15px rgba(0,0,0,0.2);
        }
        .toast.show {
            transform: translateX(-50%) translateY(0);
        }
    </style>
</head>
<body>

    <div class="container">
        <h1>انتخابگر و پالت‌ساز رنگ</h1>
        
        <div class="picker-section">
            <input type="color" id="colorPicker" value="#3b82f6">
            <div class="color-inputs">
                <div class="input-group">
                    <span>HEX</span>
                    <strong id="hexVal" onclick="copyToClipboard('#hexVal')">#3b82f6</strong>
                </div>
                <div class="input-group">
                    <span>RGB</span>
                    <strong id="rgbVal" onclick="copyToClipboard('#rgbVal')">rgb(59, 130, 246)</strong>
                </div>
                <div class="input-group">
                    <span>HSL</span>
                    <strong id="hslVal" onclick="copyToClipboard('#hslVal')">hsl(217, 91%, 60%)</strong>
                </div>
            </div>
        </div>

        <button class="btn" id="saveBtn">افزودن به پالت من</button>

        <div class="palette-section">
            <h2>پالت‌های ذخیره شده (کلیک برای کپی)</h2>
            <div class="palette-grid" id="paletteGrid"></div>
        </div>
    </div>

    <div class="toast" id="toast">کد رنگ کپی شد!</div>

    <script>
        const colorPicker = document.getElementById('colorPicker');
        const hexVal = document.getElementById('hexVal');
        const rgbVal = document.getElementById('rgbVal');
        const hslVal = document.getElementById('hslVal');
        const saveBtn = document.getElementById('saveBtn');
        const paletteGrid = document.getElementById('paletteGrid');
        const toast = document.getElementById('toast');

        let savedColors = JSON.parse(localStorage.getItem('savedColors')) || [];

        function hexToRgb(hex) {
            let r = parseInt(hex.slice(1, 3), 16);
            let g = parseInt(hex.slice(3, 5), 16);
            let b = parseInt(hex.slice(5, 7), 16);
            return { r, g, b };
        }

        function rgbToHsl(r, g, b) {
            r /= 255; g /= 255; b /= 255;
            let max = Math.max(r, g, b), min = Math.min(r, g, b);
            let h, s, l = (max + min) / 2;

            if (max === min) {
                h = s = 0;
            } else {
                let d = max - min;
                s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
                switch (max) {
                    case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                    case g: h = (b - r) / d + 2; break;
                    case b: h = (r - g) / d + 4; break;
                }
                h /= 6;
            }
            return {
                h: Math.round(h * 360),
                s: Math.round(s * 100),
                l: Math.round(l * 100)
            };
        }

        function updateValues(hex) {
            hexVal.textContent = hex;
            const rgb = hexToRgb(hex);
            rgbVal.textContent = `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
            const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
            hslVal.textContent = `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`;
        }

        colorPicker.addEventListener('input', (e) => {
            updateValues(e.target.value);
        });

        function showToast(message) {
            toast.textContent = message;
            toast.classList.add('show');
            setTimeout(() => {
                toast.classList.remove('show');
            }, 2000);
        }

        function copyToClipboard(selector) {
            const text = document.querySelector(selector).textContent;
            navigator.clipboard.writeText(text).then(() => {
                showToast(`کپی شد: ${text}`);
            });
        }

        function renderPalette() {
            paletteGrid.innerHTML = '';
            if (savedColors.length === 0) {
                paletteGrid.innerHTML = '<span style="color: #64748b; font-size: 0.8rem; grid-column: 1/-1; text-align: center;">هنوز رنگی ذخیره نشده است</span>;';
                return;
            }
            savedColors.forEach(color => {
                const item = document.createElement('div');
                item.className = 'palette-item';
                item.style.backgroundColor = color;
                item.title = color;
                item.addEventListener('click', () => {
                    navigator.clipboard.writeText(color).then(() => {
                        showToast(`کپی شد: ${color}`);
                    });
                });
                paletteGrid.getElementById = 'test';
                paletteGrid.appendChild(item);
            });
        }

        saveBtn.addEventListener('click', () => {
            const currentColor = colorPicker.value;
            if (!savedColors.includes(currentColor)) {
                savedColors.push(currentColor);
                localStorage.setItem('savedColors', JSON.stringify(savedColors));
                renderPalette();
                showToast('رنگ به پالت اضافه شد!');
            } else {
                showToast('این رنگ از قبل در پالت وجود دارد.');
            }
        });

        renderPalette();
    </script>
</body>
</html>

توضیح بخش‌به‌بخش کدهای پروژه

این کد به سه بخش اصلی تقسیم شده است که در ادامه عملکرد هر کدام را بررسی می‌کنیم:

  • ساختار HTML: شامل یک کانتینر مرکزی است که المان‌های ورودی رنگ (Color Picker)، سه کادر نمایش‌دهنده کدهای HEX، RGB و HSL، دکمه ذخیره و گرید نمایش پالت‌های ذخیره‌شده را در خود جای داده است.
  • استایل‌های CSS: طراحی مدرن تاریک (Dark Mode) با استفاده از متغیرهای CSS پیاده‌سازی شده است تا چشم طراحان را در استفاده طولانی‌مدت خسته نکند. همچنین از گرید ریسپانسیو برای نمایش پالت‌ها استفاده شده است.
  • منطق جاوا اسکریپت: توابع ریاضی لازم برای تبدیل کدهای هگزادسیمال به مقادیر RGB و سپس تبدیل آن‌ها به مدل HSL نوشته شده‌اند. رویداد input به صورت آنی مقادیر را آپدیت می‌کند و از localStorage برای حفظ پالت‌ها بین بازه‌های زمانی مختلف استفاده می‌شود.

نکات مهم و محدودیت‌های ابزار

این ابزار به دلیل عدم وابستگی به اینترنت، بسیار سریع و بهینه عمل می‌کند. با این حال توجه به چند نکته خالی از لطف نیست:

  • ذخیره‌سازی پالت‌ها روی حافظه مرورگر دستگاه شما انجام می‌شود؛ بنابراین پاک کردن کش مرورگر ممکن است باعث حذف پالت‌های ذخیره‌شده شود.
  • این ابزار برای مقادیر استاندارد رنگ‌های وب طراحی شده است و از فضاهای رنگی پیشرفته‌تر مثل Display P3 پشتیبانی نمی‌کند که برای پروژه‌های عادی وب کاملاً کافی است.

پرسش‌های متداول

چگونه می‌توانم این ابزار را روی هاست شخصی خودم آپلود کنم؟

کافی است کدهای بالا را درون یک فایل با نام دلخواه مثلا index.html ذخیره کرده و آن را روی هر هاست یا سرویس میزبانی استاتیکی آپلود کنید.

آیا می‌توانم تعداد رنگ‌های ذخیره‌شده در پالت را محدود کنم؟

در کد فعلی محدودیتی وجود ندارد، اما می‌توانید با اضافه کردن شرط طول آرایه savedColors.length در بخش جاوا اسکریپت، حداکثر تعداد مشخصی را تعیین کنید.

چرا کدهای HSL برای طراحی رابط کاربری مفید هستند؟

مدل HSL (رنگ، اشباع، روشنایی) به طراحان اجازه می‌دهد به راحتی سایه‌ها و رنگ‌های روشن‌تر (Tints & Shades) را با تغییر پارامتر روشنایی به دست آورند.

جمع‌بندی

ساخت ابزارهای سفارشی کوچک نه‌تنها مهارت برنامه‌نویسی فرانت‌اند شما را تقویت می‌کند، بلکه سرعت انجام پروژه‌های طراحی را به‌طور چشمگیری افزایش می‌دهد. با استفاده از این ابزار تک‌فایلی، اکنون یک تبدیل‌گر رنگ و پالت‌ساز اختصاصی دارید که همیشه و بدون نیاز به اینترنت در دسترساست.

پاسخی بگذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *