دارک مود برای وبسایت با استفاده از css و js


یکی از قابلیت هایی که میتونیم به کاربرامون در استفاده از سایتمون بدیم , تغییر رنگ سایت به دارک و لایته که امروزه اکثر سایت ها از این فیچر استفاده می کنند.

اما این فیچر رو چطور پیاده سازی کنیم ؟

در این پست میخوام به چندین روش موجود بهتون توضیح بدم چطور این قابلیت رو به سایتتون اضافه کنید و قطعا این پست طولانی خواهد شد پس اگه حوصله داری در ادامه این پست همراه من باش!

1 - روش اول استفاده از متاتگ

با استفاده از متاتگ زیر :

<meta name="color-scheme" content="dark light" />

این روش خیلی روش ساده و سریع ای هستش اما مشکلاتی داره! مثلا ما میخوایم یک آیکن در حالت لایت به یک رنگ خاص باشه اما در دارک رنگش فرق کنه ! با استفاده از این متاتگ نمیتونیم همچین چیزی رو پیاده کنیم.

2 - روش دوم استفاده از مدیا کوئری

روش بعدی با استفاده از کد های css میایم حالت دارک مود رو اضافه می کنیم:

@media (prefers-color-scheme: dark) {
} 
@media (prefers-color-scheme: light) { }

این روش نقص های روش اول رو حل میکنه و براساس مرورگر کاربر هم تنظیم میشه ! خیلی خوبه , اما !

در این روش اگه بخوایم حق انتخاب به کاربر بدیم مجبور میشیم کد های بیشتری رو بنویسیم.

3 - روش سوم استفاده از جاوا اسکریپت

این روش بنظر من بهترین روش موجوده و میتونیم هم حق انتخاب به کاربر بدیم هم براساس مرورگر کاربر رنگ وبسایتمون رو تعیین کنیم.

داخل این پست کامل میریم این شیوه رو پیاده سازی میکنیم اما ممکنه کد هایی که نوشتم زیاد تمیز نباشه .

نمونه صفحه ای که با استفاده از این روش پیاده کردم :

https://alirezax5.github.io/darkmode/

خب بریم سراغ کد ها

در html همچین کد داریم :

<body>
<div class="main">
    <span></span>
    <p>Dark Mode</p>
    <button id="toggle">toggle</button>
</div>
</body>

و در css هم کد های ما ایناس :

<style>
    body {
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        height: 100vh;
    }

    span:before {
        font-size: 4rem;
        content: '\1F5A4';
    }

    .main {
        width: 500px;
        text-align: center;
    }
    body.dark {            background-color: #121212;        }
    .dark span:before {
        font-size: 4rem;
        content: '\1F90D';
    }

    .dark p {
        color: #fff;
    }
</style>

کاری که میخوایم کنیم اینه که براساس انتخاب کاربر یا حالتی که در مرورگرش انتخاب کرده کلاس dark رو به body خودمون اضافه کنیم و با استفاده از کلاس dark در سی اس اس میایم رنگ های دلخواهمون رو در صورتی که حالت دارک فعال بود به آیتم هامون میدیم.

در جاوا اسکریپت اولین قدم میایم تعریف میکنیم :


  let btn = document.getElementById("toggle");

بعد میایم یک لیستینر کلیک برای دکمون تعریف می کنیم :

btn.addEventListener('click', function () {
    document.body.classList.toggle("dark");
})

در کد بالا وقتی کاربر روی دکمه کلیک کنه کلاس dark در body ما toggle میشه , یعنی اگه وجود داشت پاکش میکنه اگه نداشت اضافه میکنه.

تا الان کد های ما شد :

<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Dark mode</title>
  <style>
    body {
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      height: 100vh;
    }

    span:before {
      font-size: 4rem;
      content: '\1F5A4';
    }

    .main {
      width: 500px;
      text-align: center;
    }
    body.dark {
      background-color: #121212;
    }

    .dark span:before {
      font-size: 4rem;
      content: '\1F90D';
    }

    .dark p {
      color: #fff;
    }
  </style>
</head>
<body>
<div class="main">
  <span></span>
  <p>Dark Mode</p>
  <button id="toggle">toggle</button>
</div>
</body>

  let btn = document.getElementById("toggle");
  btn.addEventListener('click', function () {
    document.body.classList.toggle("dark");
  })

</html>

الان ما اومدیم یک صفحه ساختیم که با کلیک کاربر رنگ تغییر میکنه , اما با رفرش برمیگرده به حالت اول , برای حل این مشکل ما باید انتخاب کاربر رو در یک جا ذخیره کنیم و اون انتخاب رو هندل کنیم.

3-1 - ذخیره انتخاب کاربر در localStorage

پس میام در بالاترین خط جاوا اسکریپت متغییر زیر رو تعریف میکنم :

let colorMode;

بعد میایم دو فانکشن برای فراخوانی و ذخیره اطلاعات در localStorage تعریف میکنم :

function saveStorage(item, value) {
    localStorage.setItem(item, value)
}

function getStorage(item) {
    return localStorage.getItem(item)
}

یک فانکشن هم برای toggle کردن رنگ تعریف میکنیم:

function toggleColor(color) {
    return color === 'dark' ? 'light' : 'dark'
}

یک فانکشن هم برای بررسی رنگ localStorage از :

function checkLocalStorageColorMode() {
    let mode = getStorage('colorMode');
    return mode == null ? colorMode = 'light' : colorMode = mode;
}

در کد بالا بررسی میکنه اگه مقدار null بود بع متغییر colorMode مقدار light بده در غیر این صورت رنگی که کاربر انتخاب کرده در آخر هم اونو return میکنه.

در ادامه یک فانکشن برای تعریف کلاس برای body اضافه می کنیم :

function setBodyClass() {
    colorMode === 'dark' ? document.body.classList.add("dark") : document.body.classList.remove("dark")
}

در کد بالا اگر متغیر colorMode دارک بود کلاس dark رو اضافه میکنیم در غیر این صورت اون رو حذف میکنیم

در ادامه مطلب بهتون توضیح میدم چرا از toggle استفاده نکردیم.

در ادامه لیستینر کلیک رو به کد زیر ویرایش میکنیم :

btn.addEventListener('click', function () {
    let cToggle = toggleColor(colorMode);
    saveStorage('colorMode', cToggle)
    colorMode = cToggle
    document.body.classList.toggle("dark");
})

در آخر هم فانکشن زیر رو اضافه می کنیم :

function initThemeColorMode() {
    checkLocalStorageColorMode()
    setBodyClass()
}


و اون رو فراخوانی می کنیم :

initThemeColorMode()

وقتی صفحه اجرا بشه ما باید پردازش های اولیه رو با استفاده از فانکشن initThemeColorMode انجام بدیم برای همین اون رو فراخوانی میکنیم

کار این فانکشن اینه که بررسی میکنه رنگ فعلی تم باید دارک باشه یا که خیر و بعدش میاد بررسی میکنه باید کلاس dark به body اضافه بشه یا که خیر

ما در setBodyClass از toggle استفاده نکردیم چونکه در حالت اولیه body کلاسی نداره و ما اگه از toggle استفاده کنیم کلاس dark رو به اون اضافه می کرد

در حال حاضر کد ما به شکل زیره :


    let colorMode;
    let btn = document.getElementById("toggle");
    btn.addEventListener('click', function () {
        let cToggle = toggleColor(colorMode);
        saveStorage('colorMode', cToggle)
        colorMode = cToggle
        document.body.classList.toggle("dark");
    })

    function saveStorage(item, value) {
        localStorage.setItem(item, value)
    }

    function getStorage(item) {
        return localStorage.getItem(item)
    }

    function checkLocalStorageColorMode() {
        let mode = getStorage('colorMode');
        return mode == null ? colorMode = 'light' : colorMode = mode;
    }

    function initThemeColorMode() {
        checkLocalStorageColorMode()
        setBodyClass()
    }

    function toggleColor(color) {
        return color === 'dark' ? 'light' : 'dark'
    }

    function setBodyClass() {
        colorMode === 'dark' ? document.body.classList.add("dark") : document.body.classList.remove("dark")
    }

    initThemeColorMode()

الان اگه صفحه رو اجرا کنید و رنگ تم رو عوض کنید و رفرش کنید میبینید رنگ صفحه همون رنگیه که آخرین بار بود.

3-2 - تنظیم دارک مود براساس مرورگر کاربر

در مرحله اخر ما میخوایم کاری کنیم دارک مود صفحه براساس مرورگر کاربر تنظیم بشه.

پس ابتدا از طریق inpect به Application برید و روی local storage بزنید و storage صفحه رو خالی کنید (اگه دارید همزمان با مطلب کدارو تست میکنید داخل همون صفحه اینکارو کنید و storage ویرگول رو اشتباهی پاک نکنید!)

در ادامه کارمون متغییر زیر رو تعریف میکنیم :

let systemColorMode

بعد فانکشن checkLocalStorageColorMode رو به کد زیر تغییر میدیم :

function checkLocalStorageColorMode() {
    let mode = getStorage('colorMode');
    return mode == null ? colorMode = systemColorMode : colorMode = mode;
}

در فانکشن جدید ما میگیم اگر کاربر رنگ انتخاب نکرده بود بیاد و از رنگ مرورگر که درون متغیر systemColorMode میریزیم استفاده بکنه .

در ادامه فانکشن زیر رو تعریف میکنیم:

function checkSystemColorMode() {
    return systemColorMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}

در کد بالا میایم بررسی میکنیم مرورگر کاربر روی دارک مود قرار داره یا که خیر.

در ادامه فانکشن initThemeColorMode رو به کد زیر تغییر میدیم :

function initThemeColorMode() {
    checkSystemColorMode();
    checkLocalStorageColorMode()
    setBodyClass()
}

الان اگه وارد صفحه بشید رنگ رو براساس مرورگر کاربر تنظیم میکنه مگراینکه روی دکمه کلیک کنید که رنگ عوض بشه.


در حال حاضر کد ما به شکل زیره :


    let colorMode, systemColorMode;
    let btn = document.getElementById("toggle");
    btn.addEventListener('click', function () {
        let cToggle = toggleColor(colorMode);
        saveStorage('colorMode', cToggle)
        colorMode = cToggle
        document.body.classList.toggle("dark");
    })
    function checkSystemColorMode() {
        return systemColorMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
    }

    function saveStorage(item, value) {
        localStorage.setItem(item, value)
    }

    function getStorage(item) {
        return localStorage.getItem(item)
    }

    function checkLocalStorageColorMode() {
        let mode = getStorage('colorMode');
        return mode === null ? colorMode = systemColorMode : colorMode = mode;
    }

    function initThemeColorMode() {
        checkSystemColorMode();
        checkLocalStorageColorMode()
        setBodyClass()
    }

    function toggleColor(color) {
        return color === 'dark' ? 'light' : 'dark'
    }

    function setBodyClass() {
        colorMode === 'dark' ? document.body.classList.add("dark") : document.body.classList.remove("dark")
    }

    initThemeColorMode()


3-3 - تعریف رویداد تغییر رنگ مرورگر

الان ما باید کاری انجام بدیم در صورتی که کاربر رنگ انتخاب نکرده باشه , رنگ صفحه با تغییر رنگ مرورگر عوض بشه.

پس ما اول فانکشن زیر رو مینویسم :

function changeColor() {
    if (getStorage('colorMode') == null) {
        colorMode = checkSystemColorMode()
        setBodyClass()
    }
}

در کد بالا اول بررسی میکنیم کاربر رنگی انتخاب کرده یا خیر(چون تغییر رنگ باید وقتی باشه کاربر انتخابی نکرده باشه)

بعد رنگ مرورگر رو با فانکشن checkSystemColorMode میگیرم و با setBodyClass اون رو هندل میکنیم.

اما برای اجرا این فانکشن باید کد زیر رو بنویسیم :

window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
    changeColor()
});

و تمام! کد ما الان به شکل زیره :


    let colorMode, systemColorMode;
    let btn = document.getElementById("toggle");
    btn.addEventListener('click', function () {
        let cToggle = toggleColor(colorMode);
        saveStorage('colorMode', cToggle)
        colorMode = cToggle
        document.body.classList.toggle("dark");
    })

    function checkSystemColorMode() {
        return systemColorMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
    }

    function saveStorage(item, value) {
        localStorage.setItem(item, value)
    }

    function getStorage(item) {
        return localStorage.getItem(item)
    }

    function checkLocalStorageColorMode() {
        let mode = getStorage('colorMode');
        return mode === null ? colorMode = systemColorMode : colorMode = mode;
    }

    function initThemeColorMode() {
        checkSystemColorMode();
        checkLocalStorageColorMode()
        setBodyClass()
    }

    function toggleColor(color) {
        return color === 'dark' ? 'light' : 'dark'
    }

    function changeColor() {
        if (getStorage('colorMode') == null) {
            colorMode = checkSystemColorMode()
            setBodyClass()
        }
    }

    function setBodyClass() {
        colorMode === 'dark' ? document.body.classList.add("dark") : document.body.classList.remove("dark")
    }
    window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
        changeColor()
    });
    initThemeColorMode()

امیدوارم از این پست استفاده مفیدی ببرید و ببخشید اگه طولانی شد

برای مشاهده کد کامل میتونید به گیتهابم مراجعه کنید :

https://github.com/alirezax5/darkmode

اگه سوالی داشتید حتما کامنت کنید.