خطاهای رایج در متغیرهای CSS + سورس کد پروژه ها

30 مرداد 1398
خطاهای رایج در متغیر های CSS + سورس کد پروژه ها

در هنگام کار با متغیرهای CSS ممکن است با همان مشکلاتی مواجه شویم که هنگام کار با خصوصیات CSS مواجه می شویم، منظور من از مشکلات خطرهایی است که هنگام کار با متغیرهای CSS در کمین ما هستند و ممکن است در دام آن ها بیفتیم. در این جلسه می خواهیم برخی از خطاهای رایج در متغیرهای CSS را بررسی کنیم.

مشکل اول: دستورات دوگانه

منظور من از دستورات دوگانه، دستورات CSS ای هستند که دو یا چند بار برای یک خصوصیت تعریف شده اند. به مثال زیر نگاه کنید:

/*define the variables*/

:root {
    --color: blue;
}

div {
    --color: green;
}

#alert {
    --color: red;
}

/*use the variable */

* {
    color: var(--color);
}

در اینجا برای متغیر رنگ 3 مقدار مختلف تعریف شده است. این اتفاق برخی اوقات در CSS نیز رخ میدهد. مسئله این است که متغیرها نیز پیرو قوانین آبشاری CSS هستند بنابراین به نظر شما عناصر زیر چه رنگی میگیرند؟

<p>What's my color?</p>
<div>and me?</div>
<div id='alert'> What's my color too? <p>color?</p>
</div>

پاراگراف اول (تگ p) آبی (blue) خواهد بود؛ طبق قوانین آبشاری CSS از آنجایی که هیچ مقدار color-- مشخصی برای عنصر p تعریف نشده است، مقدار مورد نظر را از root: به ارث می برد:

:root { --color: blue; }

اولین div نیز سبز (green) خواهد بود چرا که مستقیما مقدارش را تعیین کرده ایم:

div { --color: green; }

آن div ای که آیدی alert دارد نیز قرمز (red) خواهد بود:

#alert { --color: red; }

طبق قوانین آبشاری CSS آیدی (id) بالاترین اولویت را دارد و بنابراین متغیر تعریف شده در آن نیز فقط مختص به آن است و دیگر مقادیر را override میکند.

عنصر p داخل alert# نیز قرمز می شود. از آنجایی که برای این عنصر مقدار مستقیمی تعریف نشده است احتمالا فکر میکردید که رنگ این عنصر آبی شود (از root: ارث بری کند) اما اینطور نیست. طبق قوانین آبشاری CSS عناصر از پدر خود ارث بری دارند بنابراین p نیز از alert# ارث بری میکند.

دستورات دو گانه و حل آن ها
دستورات دو گانه و حل آن ها

مشکل دوم: وابستگی های چرخه‌ای

cyclic dependency یا وابستگی های چرخه‌ای (یعنی به شکل یک چرخ یا حلقه) به دو شکل عمده اتفاق می افتند:

1- زمانی که متغیر به خودش وابسته باشد؛ یعنی از ()var استفاده کنیم که به خودش اشاره می کند:

:root {
    --m: var(--m)
}

body {
    margin: var(--m)
}

2- زمانی که یک یا دو متغیر به یکدیگر اشاره می کنند:

:root {
    --one: calc(var(--two) + 10px);
    --two: calc(var(--one) - 10px);
}

شما باید همیشه از این دو حالت دوری کنید و گرنه در کدهایتان با خطا مواجه می شوید.

سوال: متغیرهای غیرمعتبر به چه چیزی تبدیل می شوند؟

پاسخ: همانطور که می دانید خطاهای مربوط به syntax (طرز نوشتار کدها) توسط مرورگر نادیده گرفته می شود اما متغیرها و ()var های غیرمعتبر به مقدار initial یا inherit برمیگردند.

این مثال را در نظر بگیرید:

:root {
    --color: 20px;
}

p {
    background-color: red;
}

p {
    background-color: var(--color);
}
روش اشتباه استفاده از متغیر ها
روش اشتباه استفاده از متغیرها

در چنین مثالی مقدار رنگ پس زمینه برابر با 20 پیکسل می شود که معنی ندارد و از آنجایی که background-color خصوصیت قابل وراثتی نیست مقدار آن به initial یا transparent برمیگردد.

اگر همین کد را به شکل background-color: 20px بنویسید (بدون متغیر و به شکل ساده) مقدار رنگ پس زمینه غیرمعتبر محسوب می شد اما از دستور قبلی برای آن استفاده شده و رنگ آن قرمز (red) می‌شد.

مشکل سوم: single token ها

زمانی که مقدار یک خصوصیت CSS را به صورت زیر تعیین می کنید:

font-size: 20px

به آن single token می گوییم. در واقع 20px به عنوان یک واحد مستقل محسوب می شود بنابراین نمی توان آن را از هم جدا کرد. با این اوصاف هنگام کار با متغیرهای CSS مراقب باشید تا به تقلید از زبان های برنامه نویسی دیگر کد را به شکل زیر ننویسید:

:root {
    --size: 20
}

div {
    font-size: var(--size)px/*WRONG*/
}

این کد کاملا غلط است چرا که نمی توان 20px را از هم جدا کرد. مرورگر این کد را به شکل px و 20 میبیند (یعنی بین px و 20 یک اسپیس قرار میگیرد). بنابراین در هنگام کار با single token ها باید کل آن را درون متغیر قرار دهید یا اینکه از تابع calc استفاده کنید:

calc(var(--size) * 1px(

در این دستور می توانید مقدار متغیر size را روی 20 خالی بگذارید.

پروژه های عملی

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

پروژه ی اول
پروژه ی اول

اگر بخواهیم به روش عادی CSS عمل کنیم کدهایمان بدین شکل می شود:

  • ابتدا به دکمه ی خود یک کلاس مانند btn. می دهیم.
  • استایل های عادی btn را تعریف می کنیم.
  • استایل های جداگانه ای برای حالت hover در نظر می گیریم.

یعنی:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>

    <style>
        .btn {
            padding: 2rem 4rem;
            border: 2px solid black;
            background: transparent;
            font-size: 0.6em;
            border-radius: 2px;
        }

        /*on hover */
        .btn:hover {
            cursor: pointer;
            background: black;
            color: white;
        }
    </style>
</head>

<body>

    <button class="btn">Hello</button&gt;<button class="btn red">Hello</button>

</body>

</html>

اگر همین کد را با متغیرها بنویسیم:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>

    <style>
        .btn {
            padding: 2rem 4rem;
            border: 2px solid var(--color, black);
            background: transparent;
            font-size: 0.6em;
            border-radius: 2px;
        }

        /*on hover*/
        .btn:hover {
            cursor: pointer;
            background: var(--color, black);
            color: white;
        }
    </style>
</head>

<body>

    <button class="btn">Hello</button&gt;<button class="btn red">Hello</button>

</body>

</html>

مشاهده ی خروجی

آیا میدانید syntax این مورد چیست؟

background: var(--color, black)

در این حالت پارامتر دوم (black) حالت پیش فرض است؛ یعنی رنگ پس زمینه را روی color-- تنظیم کن اما اگر این متغیر وجود ندارد مقدار black را در نظر بگیر. بنابراین رنگ دکمه به راحتی هنگام hover تغییر پیدا می کند.

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

کدهای HTML شامل سه قسمت می شوند:

  1. یک input از نوع range
  2. یک container برای نگه داشتن دستورات
  3. یک section برای نگه داشتن مجموعه مستطیل ها به همراه input هایشان

بنابراین:

<body>

    <main class="booth">
        <aside class="slider"> <label>Move this ? </label> <input class="booth-slider" type="range" min="-50" max="50"
                value="-50" step="5" /> </aside>
        <section class="color-boxes">
            <div class="color-box" id="1"><input value="red" /></div>
            <div class="color-box" id="2"><input /></div>
            <div class="color-box" id="3"><input /></div>
            <div class="color-box" id="4"><input/&gt; </div&gt; <div class="color-box" id="5"><input /></div>
            <div class="color-box" id="6">;<input />&lt;/div>
        </section>
        <footer class="instructions"> ?? Move the slider<br /> ?? Write any color in the red boxes </footer>
    </main>

</body>

کدهای CSS نیز به طور خلاصه باید این کارها را انجام دهند:

  1. کلاس slider. و instructions. را به صورت absolute قرار دهید تا روی عناصر دیگر صفحه تاثیر نگذارند.
  2. به عنصر body عکس گل آفتاب گردان را می دهیم (برای زیباسازی)
  3. نگهدارنده ی color-boxes را به وسط صفحه می بریم.
  4. استایل های دلخواه را روی color-boxes پیاده می کنیم.
  5. مستطیل ها را با flexbox در وسط صفحه قرار دهیم.

بنابراین:

@import url('https://fonts.googleapis.com/css?family=Shadows+Into+Light+Two');
  
:root {
  --primary-color: rgba(241,196,15 ,1);
  --secondary-color: teal;
  
  --slider: 0;
}

body {
  margin: 0;
  color: rgba(255,255,255,0.9);
  background: url('http://bit.ly/2FiPrRA') 0 100%/340px no-repeat, var(--primary-color);
  font-family: 'Shadows Into Light Two', cursive;
}

main.booth {
  min-height: 100vh;
  
  display: flex;
  justify-content: center;
  align-items: center;
}



/* Slider */
.slider,
.instructions {
  position: absolute;
  background: rgba(0,0,0,0.4);
  padding: 1rem 2rem;
  border-radius: 5px
}
.slider {
  right: 10px;
  top: 10px;
}
.slider > * {
  display: block;
}


/* Instructions */
.instructions {
  text-align: center;
  bottom: 0;
  background: initial;
  color: black;
}

/* Color Boxes */
.color-boxes {
  background: red;
  box-shadow: 10px 10px 30px rgba(0,0,0,0.4);
  border-radius: 0.3rem;
    
  transform: perspective(500px) rotateY( calc(var(--slider) * 1deg));
  transition: transform 0.3s
}


.color-box {
  padding: 1rem 3.5rem;
  margin-bottom: 0.5rem;
  border: 1px solid rgba(255,255,255,0.2);
  border-radius: 0.3rem;
  box-shadow: 10px 10px 30px rgba(0,0,0,0.4); 
}

/* Handle colors for each color box */
.color-box:nth-child(1) {
  background: var(--bg-1)
}
.color-box:nth-child(2) {
  background: var(--bg-2)
}
.color-box:nth-child(3) {
  background: var(--bg-3)
}
.color-box:nth-child(4) {
  background: var(--bg-4)
}
.color-box:nth-child(5) {
  background: var(--bg-5)
}
.color-box:nth-child(6) {
  background: var(--bg-6)
}

در آخر با استفاده از جاوا اسکریپت مقدار عنصر input (همان range) را گرفته و وضعیت مستطیل ها را به روز رسانی می کنیم:

const inputs = document.querySelectorAll('.color-box > input')
const root = document.documentElement
const range = document.querySelector('.booth-slider')

//as slider range's value changes, do something 
range.addEventListener('input', handleSlider)

//as the value in the input changes, do something.
inputs.forEach(input => {
  input.addEventListener('input', handleInputChange)
})

function handleInputChange (e) {
  let value = e.target.value
  let inputId = e.target.parentNode.id 
  let inputBg = `--bg-${inputId}` 
  root.style.setProperty(inputBg, value)
}

function handleSlider (e) {
  let value = e.target.value 
  root.style.setProperty('--slider', value)
}

امیدوارم مقاله بررسی خطاهای رایج در متغیرهای CSS به درک بهتر شما کمک کرده باشد.

نویسنده شوید

دیدگاه‌های شما (1 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

ماهان
21 آذر 1398
بابت این مقاله و مقاله قبلی در خصوص متغیرها در css سپاسگزارم. درخواستم از شما: مقایسه ای بین متغیرهای css و متغیرهای sass داشته باشید. کدوم یکی بهتره؟ کاربرد هر کدام چیست؟ ایا میتوان آنها را باهم ترکیب کرد؟

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

امیر زوارمی
27 آذر 1398
سلام دوست عزیز، پیشنهاد خیلی خوبی هست، ان شاء الله سعی می کنم در آینده چنین مقاله ای رو آماده کنم.

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.