ر هنگام کار با متغیرهای CSS ممکن است با همان مشکلاتی مواجه شویم که هنگام کار با خصوصیات CSS مواجه می شویم، منظور من از مشکلات خطرهایی است که هنگام کار با متغیرهای CSS در کمین ما هستند و ممکن است در دام آن ها بیفتیم. در این جلسه می خواهیم برخی از خطاهای رایج در متغیرهای CSS را بررسی کنیم.
مشکل اول: دستورات دوگانه
منظور من از دستورات دوگانه، دستورات CSS ای هستند که دو یا چند بار برای یک خصوصیت تعریف شده اند. به مثال زیر نگاه کنید:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/*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'smy color too?<p>color?</p>
</div>
|
پاراگراف اول (تگ p) آبی (blue) خواهد بود؛ طبق قوانین آبشاری CSS از آنجایی که هیچ مقدار color– مشخصی برای عنصر p تعریف نشده است، مقدار مورد نظر را از root: به ارث می برد:
اولین div نیز سبز (green) خواهد بود چرا که مستقیما مقدارش را تعیین کرده ایم:
آن div ای که آیدی alert دارد نیز قرمز (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 را به صورت زیر تعیین می کنید:
به آن single token می گوییم. در واقع 20px به عنوان یک واحد مستقل محسوب می شود بنابراین نمی توان آن را از هم جدا کرد. با این اوصاف هنگام کار با متغیرهای CSS مراقب باشید تا به تقلید از زبان های برنامه نویسی دیگر کد را به شکل زیر ننویسید:
|
:root{
--size:20
}
div{
font-size:var(--size)px/*WRONG*/
}
|
این کد کاملا غلط است چرا که نمی توان 20px را از هم جدا کرد. مرورگر این کد را به شکل px و 20 میبیند (یعنی بین px و 20 یک اسپیس قرار میگیرد). بنابراین در هنگام کار با single token ها باید کل آن را درون متغیر قرار دهید یا اینکه از تابع calc استفاده کنید:
در این دستور می توانید مقدار متغیر size را روی 20 خالی بگذارید.
پروژه های عملی
در پروژه ی اول میخواهیم دو دکمه بسازیم که با hover شدن رنگشان تغییر کند.
پروژه ی اول
اگر بخواهیم به روش عادی CSS عمل کنیم کدهایمان بدین شکل می شود:
- ابتدا به دکمه ی خود یک کلاس مانند btn. می دهیم.
- استایل های عادی btn را تعریف می کنیم.
- استایل های جداگانه ای برای حالت hover در نظر می گیریم.
یعنی:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
<!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:2rem4rem;
border:2pxsolidblack;
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><button class="btn red">Hello</button>
</body>
</html>
|
اگر همین کد را با متغیرها بنویسیم:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
<!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:2rem4rem;
border:2pxsolidvar(--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><button class="btn red">Hello</button>
</body>
</html>
|
مشاهده ی خروجی
آیا میدانید syntax این مورد چیست؟
background: var(–color, black)
در این حالت پارامتر دوم (black) حالت پیش فرض است؛ یعنی رنگ پس زمینه را روی color– تنظیم کن اما اگر این متغیر وجود ندارد مقدار black را در نظر بگیر. بنابراین رنگ دکمه به راحتی هنگام hover تغییر پیدا می کند.
پروژه ی دوم ما پیشرفته تر است. در این پروژه میخواهیم چنین چیزی بسازیم. یعنی هنگام تایپ یک رنگ، مربع همان رنگ را بگیرد و با تکان دادن Slider نیز مربع ها به حالت سه بعدی جا به جا شوند.
کدهای HTML شامل سه قسمت می شوند:
- یک input از نوع range
- یک container برای نگه داشتن دستورات
- یک section برای نگه داشتن مجموعه مستطیل ها به همراه input هایشان
بنابراین:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<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/></div><div class="color-box"id="5"><input/></div>
<div class="color-box"id="6">;<input/></div>
</section>
<footer class="instructions">??Move the slider<br/>??Write any color inthe red boxes</footer>
</main>
</body>
|
کدهای CSS نیز به طور خلاصه باید این کارها را انجام دهند:
- کلاس slider. و instructions. را به صورت absolute قرار دهید تا روی عناصر دیگر صفحه تاثیر نگذارند.
- به عنصر body عکس گل آفتاب گردان را می دهیم (برای زیباسازی)
- نگهدارنده ی color-boxes را به وسط صفحه می بریم.
- استایل های دلخواه را روی color-boxes پیاده می کنیم.
- مستطیل ها را با flexbox در وسط صفحه قرار دهیم.
بنابراین:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
@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')0100%/340pxno-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:1rem2rem;
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:10px10px30pxrgba(0,0,0,0.4);
border-radius:0.3rem;
transform:perspective(500px)rotateY(calc(var(--slider)*1deg));
transition:transform0.3s
}
.color-box{
padding:1rem3.5rem;
margin-bottom:0.5rem;
border:1pxsolid rgba(255,255,255,0.2);
border-radius:0.3rem;
box-shadow:10px10px30pxrgba(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) را گرفته و وضعیت مستطیل ها را به روز رسانی می کنیم:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
constinputs=document.querySelectorAll('.color-box > input')
constroot=document.documentElement
constrange=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)
})
functionhandleInputChange(e){
let value=e.target.value
let inputId=e.target.parentNode.id
let inputBg=`--bg-${inputId}`
root.style.setProperty(inputBg,value)
}
functionhandleSlider(e){
let value=e.target.value
root.style.setProperty('--slider',value)
}
|
امیدوارم مقاله بررسی خطاهای رایج در متغیرهای CSS به درک بهتر شما کمک کرده باشد.