راهنمای رنگ‌های CSS مدرن با RGB و HSL و HWB و LAB و LCH

خلاصه سریع: آیا می‌دانستید که پالت رنگی انتخابی شما می‌تواند بر میزان مصرف انرژی وب‌سایت شما تأثیر بگذارد؟ حتی انتخاب رنگ‌های سازگارتر با محیط، می‌تواند میزان تأثیر روی عمر باتری دستگاه‌های تلفن همراه را کاهش دهد. در این مقاله، میشل بارکر (Michelle Barker) در مورد چیزهای نه چندان واضحی که امروزه هنگام استفاده از رنگ‌ها در CSS باید در نظر داشته باشید، توصیه‌هایی را به اشتراک می‌گذارد.

رنگ‌ها در وب، بیشتر از آن هستند که به نظر می‌رسد و قرار است بسیار جالب‌تر شود! در این مقاله، به بهترین روش‌های استفاده از رنگ‌ها در یک سیستم طراحی، و آنچه می‌توانیم از رنگ‌های خود در آینده  انتظار داشته باشیم، نگاهی می‌اندازیم.

ارزش‌های رنگ شناخته شده

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

.my-element {
  background-color: red;
}

این رنگ‌ها بسیار محدود هستند و به ندرت با طرح‌هایی که می‌سازیم مطابقت دارند! همچنین می‌توانیم از مقادیر هگزادسیمال (hexadecimal) استفاده کنیم. کد زیر به المان مورد نظر ما (المان با کلاس my-element)، پس‌زمینه قرمز می‌دهد:

.my-element {
  background-color: #ff0000;
}

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

RGB

نمادگذاری RGB (قرمز، سبز، آبی) روشی جایگزین برای نوشتن رنگ‌ها است، که به ما امکان دسترسی به همان محدوده رنگ‌ها را با مقادیر هگزا، به شکلی بسیار خواناتر می‌دهد. ما یک تابع rgb() در CSS برای این کارداریم. رنگ‌ها در وب اضافی یا ادیتیو هستند، به این معنی که هر چه نسبت قرمز، سبز و آبی بیشتر باشد، رنگ حاصل روشن‌تر خواهد بود. اگر فقط از کانال قرمز استفاده کنیم، نتیجه قرمز است:

.my-element {
  background-color: rgb(255, 0, 0);
}

با تنظیم کانال‌های قرمز، سبز و آبی روی بالاترین مقدار، رنگ سفید ایجاد می‌شود:

.my-element {
  background-color: rgb(255, 255, 255);
}

همچنین می‌توانیم با استفاده از فانکشن rgba()، یک کانال آلفا (برای شفافیت) اضافه کنیم:

.my-element {
  background-color: rgba(255, 0, 0, 0.5); // transparency of 50%
}

فانکشن‌های rgb() و rgba() به ما این امکان را می‌دهند که رنگ‌ها را در کد ترکیب کنیم، اما نتایج می‌تواند تا حدودی غیرقابل‌پیش‌بینی باشد.

HSL

اخیراً، توانایی استفاده از مقادیر HSL (رنگ یا hue، اشباع یا saturation، روشنایی یا lightness) با فانکشن رنگی hsl() و hsla() را داریم. به‌عنوان یک توسعه‌دهنده، وقتی صحبت از تنظیم مقادیر رنگ به میان می‌آید، این موارد بسیار شهودی‌تر هستند. برای مثال، می‌توانیم با تنظیم پارامتر روشنایی، انواع تیره‌تر و روشن‌تر از یک رنگ را دریافت کنیم:

.my-element {
  background-color: hsl(0deg, 100%, 20%); // dark red
}

.my-element {
  background-color: hsl(0deg, 100%, 50%); // medium red
}

.my-element {
  background-color: hsl(0deg, 100%, 80%); // light red
}
ترکیب رنگ HSL

پارامتر hue موقعیت روی یک چرخ رنگ را نشان می‌دهد و می‌تواند هر مقداری بین 0 تا 360 درجه باشد. همچنین این فانکشن واحدهای چرخشی (به‌عنوان‌مثال 0.5 دور) و مقادیر بدون واحد را می‌پذیرد.

موارد زیر، همگی معتبر هستند:

.my-element {
  background-color: hsl(180deg, 50%, 50%);
}

.my-element {
  background-color: hsl(0.5turn, 50%, 50%);
}

.my-element {
  background-color: hsl(180, 50%, 50%);
}

نکته: نگه‌داشتن SHIFT و کلیک کردن روی نمونه رنگ در اینسپکتر کروم و ابزار توسعه فایرفاکس، مقدار رنگ را بین هگز، RGB و HSL تغییر می‌دهد!

همان‌طور که به‌زودی خواهیم دید، hsl() و hsla() به خوبی با ویژگی‌های سفارشی دست‌کاری می‌شوند.

currentColor

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

سینتکس رنگ مدرن

ماژول رنگی CSS لول 4، سینتکس راحت‌تری را برای فانکشن‌های رنگی در اختیار ما قرار می‌دهد، که به‌طور گسترده در مرورگرها پشتیبانی می‌شود. ما دیگر نیازی به جدا کردن مقادیر با کاما نداریم و فانکشن‌های rgb() و hsl() می‌توانند یک پارامتر آلفای اختیاری داشته باشند، که با یک فوروارد اسلش از هم جدا شوند:

.my-element {
  /* optional alpha value gives us 50% opacity */
  background-color: hsl(0 100% 50% / 0.5);
}

.my-element {
  /* With no alpha value the background is fully opaque*/
  background-color: hsl(0 100% 50%);
}

توابع رنگی جدید CSS

HWB

HWB مخفف رنگ (hue)، سفیدی (whiteness) و سیاهی (blackness) است. مانند HSL، رنگ می‌تواند هرجایی در محدوده 0 تا 360 باشد. دو آرگومان دیگر، میزان رنگ سفید یا سیاه را تا 100٪ کنترل می‌کنند (که منجر به یک رنگ کاملاً سفید یا کاملاً سیاه می‌شود). اگر مقادیر مساوی سفید و سیاه باهم میکس شوند، رنگ حاصل، خاکستری است. ما می‌توانیم این را شبیه به ترکیب کردن رنگ در نظر بگیریم، که برای ایجاد پالت‌های رنگی تک‌رنگ، مفید است.

پالت رنگی مونوکروم

با این نسخه‌ی نمایشی، آن را امتحان کنید (فقط در سافاری کار می‌کند):

کد HTML:

<div>
  <h1>HWB color explorer</h1>
  <p class="warning">
    Sorry, your browser doesn’t support HWB colors.
  </p>
  <code class="result" data-result>hwb(0 0 0)</code>
  <div class="controls" data-controls>
    <div class="input-group">
      <label for="h">Hue</label>
      <input id="h" type="range" min="0" max="360">
    </div>
    <div class="input-group">
      <label for="w">Whiteness</label>
      <input id="w" type="range" min="0" max="100" value="0">
    </div>
    <div class="input-group">
      <label for="b">Blackness</label>
      <input id="b" type="range" min="0" max="100" value="0">
    </div>
  </div>
</div>

کد SCSS:

* {
  box-sizing: border-box;
}

body {
  font-family: "Open Sans", sans-serif;
  margin: 0;
  min-height: 100vh;
  background: hsl(0, 50%, 80%);
  display: flex;
  justify-content: center;
  align-items: center;
  color: var(--text, #000000);
}

.controls {
  padding: 1.75rem;
  background: #ffffff;
  border-radius: 0.5rem;
  display: none;
  color: #000000;
  
  > * + * {
    margin-top: 0.75rem;
  }
}

.result {
  display: block;
  font-size: 1.4rem;
  margin: 0 0 1rem;
  text-align: center;
}

.input-group {
  display: flex;
  align-items: center;
  
  label {
    margin-right: 0.5rem;
    width: 6rem;
  }
  
  input {
    flex: 1 1 auto;
  }
}

@supports (color: hwb(0 0% 0%)) {
  body {
    background: hwb(var(--h, 0) calc(var(--w, 0) * 1%) calc(var(--b, 0) * 1%));
  }
  
  .controls {
    display: block;
  }
  
  .warning {
    display: none;
  }
}

کد JS:

const controls = document.querySelector('[data-controls]')
const inputs = [...document.querySelectorAll('input')]
const result = document.querySelector('[data-result]')

const setTextColor = () => {
  const wInput = inputs[1].value
  const bInput = inputs[2].value
  let textColor = '#ffffff'
  
  if (wInput > 50 && bInput <= 50) {
    textColor = '#000000'
  } else if (bInput > 50 && wInput <= 50) {
    textColor = '#ffffff'
  }
  
  document.body.style.setProperty('--text', textColor)
}

controls.addEventListener('input', (e) => {
  if (!e.target.id) return
  
  const { value } = e.target
  document.body.style.setProperty(`--${e.target.id}`, value)
  
  const results = inputs.map((input, i) => {
    return i === 0 ? `${input.value}%` : input.value
  }).join(' ')
  
  result.innerText = `hwb(${results})`
  
  // Change text color for accessibility
  setTextColor()
})

LAB

LAB و LCH به‌عنوان رنگ‌های مستقل از دستگاه تعریف شده‌اند. LAB یک فضای رنگی است که در نرم‌افزارهایی مانند فتوشاپ قابل‌دسترسی است، و هنگامی توصیه می‌شود که می‌خواهید یک رنگ، روی صفحه همان رنگی باشد. LAB از سه محور استفاده می‌کند: روشنایی (lightness) که به دنبال آن محور a (سبز به قرمز) و محور b (آبی به زرد) می‌آید.

روشنایی مانند HSL، به‌عنوان یک درصد بیان می‌شود، اما زمانی که با فانکشن رنگ ()lab استفاده می‌شود، می‌تواند از 100٪ فراتر رود. سفیدهای بسیار روشن می‌توانند تا 400 درصد استفاده کنند. مقادیر برای محورهای a و b می‌توانند از مثبت تا منفی متغیر باشند. دو مقدار منفی منجر به طیف رنگی سبز/آبی طیف می‌شوند، درحالی‌که دو مقدار مثبت می‌توانند رنگ نارنجی/قرمز بیشتری ایجاد کنند.

.my-element {
  background-color: lab(80% 100 50); // reddish pink
}

.my-element {
  background-color: lab(80% -80 -100); // blue/turquoise
}
orange red hue

کد HTML:

<div>
  <h1>LAB color explorer</h1>
  <p class="warning">
    Sorry, your browser doesn’t support LAB colors.
  </p>
  <code class="result" data-result>lab(50% 0 0)</code>
  <div class="controls" data-controls>
    <div class="input-group">
      <label for="l">L</label>
      <input id="l" type="range" min="0" max="100">
    </div>
    <div class="input-group">
      <label for="a">A</label>
      <input id="a" type="range" min="-160" max="160">
    </div>
    <div class="input-group">
      <label for="b">B</label>
      <input id="b" type="range" min="-160" max="160">
    </div>
  </div>
</div>

کد SCSS:

* {
  box-sizing: border-box;
}

body {
  font-family: "Open Sans", sans-serif;
  margin: 0;
  min-height: 100vh;
  background: hsl(0, 50%, 80%);
  display: flex;
  justify-content: center;
  align-items: center;
  color: var(--text, #000000);
}

h1 {
  text-align: center;
}

.controls {
  padding: 1.75rem;
  background: #ffffff;
  border-radius: 0.5rem;
  display: none;
  color: #000000;
  
  > * + * {
    margin-top: 0.75rem;
  }
}

.result {
  display: block;
  font-size: 1.4rem;
  margin: 0 0 1rem;
  text-align: center;
}

.input-group {
  display: flex;
  align-items: center;
  
  label {
    margin-right: 0.5rem;
    width: 1.5rem;
  }
  
  input {
    flex: 1 0 auto;
  }
}

@supports (color: lab(0% 0 0)) {
  body {
    background: lab(calc(var(--l, 50) * 1%) var(--a, 0) var(--b, 0));
  }
  
  .controls {
    display: block;
  }
  
  .warning {
    display: none;
  }
}

کد JS:

const controls = document.querySelector('[data-controls]')
const inputs = [...document.querySelectorAll('input')]
const result = document.querySelector('[data-result]')

controls.addEventListener('input', (e) => {
  if (!e.target.id) return
  
  const { value } = e.target
  document.body.style.setProperty(`--${e.target.id}`, value)
  
  const results = inputs.map((input, i) => {
    return i === 0 ? `${input.value}%` : input.value
  }).join(' ')
  
  result.innerText = `lab(${results})`
  
  // Change text color for accessibility
  if (e.target.id === 'l') {
    const textColor = value < 50 ? '#ffffff' : '#000000'
    document.body.style.setProperty('--text', textColor)
  }
})

LCH

LCH مخفف lightness، chroma و hue است. مانند LAB، درصد روشنایی می‌تواند بیش از 100 باشد. مشابه HSL، رنگ یا hue می‌تواند محدوده‌ای بین 0 تا 360 باشد. کروما میزان رنگ را نشان می‌دهد، و ما می‌توانیم آن را شبیه به اشباع در HSL در نظر بگیریم. اما chroma می‌تواند از 100 تجاوز کند و درواقع، از نظر تئوری نامحدود است. مثال استفاده:

.my-element {
  background-color: lch(80% 100 50);
}

.my-element {
  background-color: lch(80% 240 50); // this color would be outside of the displayable range of today’s browsers
}

بااین‌حال، محدودیتی در تعداد رنگ‌هایی که مرورگرها و مانیتورهای امروزی می‌توانند نمایش دهند وجود دارد (به‌زودی در مورد آن بیشتر توضیح خواهیم داد)، بنابراین بعید است مقادیر بالای 230، تفاوتی ایجاد کنند و Chroma تا زمانی که در رنج قرار نگیرد، کاهش می‌یابد.

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

چرا باوجود HSL، به LAB و LCH نیاز داریم؟ یک دلیل این است که استفاده از LAB یا LCH به ما امکان دسترسی به طیف وسیع‌تری از رنگ‌ها را می‌دهد. LCH و LAB طوری طراحی شده‌اند که به ما امکان دسترسی به‌کل طیف بینایی انسان را می‌دهند. علاوه بر این، HSL و RGB دارای چند کاستی هستند: آنها از نظر ادراکی یکنواخت نیستند و در HSL، افزایش یا کاهش روشنایی، بسته به رنگ، تأثیر کاملاً متفاوتی دارد.

با استفاده از کد زیر، می‌توانیم با زدن کلید سیاه و سفید، تضاد فاحشی بین LCH و HSL مشاهده کنیم. برای رنگ HSL و نوارهای اشباع، تفاوت‌های واضحی در روشنایی هر مربع وجود دارد، حتی اگر مؤلفه روشنایی یا لایتنس فانکشن HSL یکسان باشد! در همین حال، نوارهای رنگی کروما در سمت LCH، دارای روشنایی ادراکی تقریباً یکنواختی هستند.

کد HTML:

<!--Colors coverted using Lea Verou’s LCH coverter https://css.land/lch/-->
<div class="main-wrapper">
	<header>
		<h1>Comparing LCH and HSL colors</h1>
		<button data-toggle hidden role="switch" checked="false">
			Grayscale<span data-text aria-hidden>: Off</span>
		</button>
	</header>
	<div class="grid">
		<div class="wrapper">
			<h2>LCH</h2>
			<section>
				<h3>Lightness</h3>
				<div class="color-strip-wrapper">
					<ol class="color-strip color-strip--lightness">
						<li><p>0%</p></li>
						<li><p>10%</p></li>
						<li><p>20%</p></li>
						<li><p>30%</p></li>
						<li><p>40%</p></li>
						<li><p>50%</p></li>
						<li><p>60%</p></li>
						<li><p>70%</p></li>
						<li><p>80%</p></li>
						<li><p>90%</p></li>
						<li><p>100%</p></li>
					</ol>
				</div>
			</section>

			<section>
				<h3>Chroma</h3>
				<div class="color-strip-wrapper">
					<ol class="color-strip color-strip--chroma">
						<li><p>0</p></li>
						<li><p>10</p></li>
						<li><p>20</p></li>
						<li><p>30</p></li>
						<li><p>40</p></li>
						<li><p>50</p></li>
						<li><p>60</p></li>
						<li><p>70</p></li>
						<li><p>80</p></li>
						<li><p>90</p></li>
						<li><p>100</p></li>
					</ol>
				</div>
			</section>

			<section>
				<h3>Hue</h3>
				<div class="color-strip-wrapper">
					<ol class="color-strip color-strip--hue">
						<li><p>0</p></li>
						<li><p>36</p></li>
						<li><p>72</p></li>
						<li><p>108</p></li>
						<li><p>144</p></li>
						<li><p>180</p></li>
						<li><p>216</p></li>
						<li><p>252</p></li>
						<li><p>288</p></li>
						<li><p>324</p></li>
						<li><p>360</p></li>
					</ol>
				</div>
			</section>
		</div>

		<div class="wrapper">
			<h2>HSL</h2>
			<section>
				<h3>Hue</h3>
				<div class="color-strip-wrapper color-strip-wrapper--hsl">
					<ol class="color-strip color-strip--hue">
						<li><p>0</p></li>
						<li><p>36</p></li>
						<li><p>72</p></li>
						<li><p>108</p></li>
						<li><p>144</p></li>
						<li><p>180</p></li>
						<li><p>216</p></li>
						<li><p>252</p></li>
						<li><p>288</p></li>
						<li><p>324</p></li>
						<li><p>360</p></li>
					</ol>
				</div>
			</section>

			<section>
				<h3>Saturation</h3>
				<div class="color-strip-wrapper color-strip-wrapper--hsl">
					<ol class="color-strip color-strip--saturation">
						<li><p>0%</p></li>
						<li><p>10%</p></li>
						<li><p>20%</p></li>
						<li><p>30%</p></li>
						<li><p>40%</p></li>
						<li><p>50%</p></li>
						<li><p>60%</p></li>
						<li><p>70%</p></li>
						<li><p>80%</p></li>
						<li><p>90%</p></li>
						<li><p>100%</p></li>
					</ol>
				</div>
			</section>

			<section>
				<h3>Lightness</h3>
				<div class="color-strip-wrapper color-strip-wrapper--hsl">
					<ol class="color-strip color-strip--lightness-hsl">
						<li><p>0%</p></li>
						<li><p>10%</p></li>
						<li><p>20%</p></li>
						<li><p>30%</p></li>
						<li><p>40%</p></li>
						<li><p>50%</p></li>
						<li><p>60%</p></li>
						<li><p>70%</p></li>
						<li><p>80%</p></li>
						<li><p>90%</p></li>
						<li><p>100%</p></li>
					</ol>
				</div>
			</section>
		</div>
	</div>
</div>

کد SCSS:

* {
	box-sizing: border-box;
}

body {
	font-family: Helvetica, sans-serif;
	margin: 0;
	padding: 1rem;
	min-height: 100vh;
	
	&.is-grayscale {
		.grid {
			filter: grayscale(100%);
		}
	}
}

.main-wrapper {
	max-width: 115rem;
	margin: 0 auto;
}

button {
	margin-bottom: 1rem;
	font-size: 1.2rem;
	padding: 0.5rem 1rem;
	border-radius: 0.4rem;
	border: none;
	background: darkslategray;
	color: #ffffff;
	min-width: 12rem;
	
	span {
		pointer-events: none;
	}
	
	&:hover,
	&:focus {
		background: slategray;
	}
}

.grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 600px), 1fr));
	gap: 1rem;
	justify-content: center;
}

.wrapper {
	padding: max(1rem, 2vw);
	background: rgba(240, 240, 240);
	border-radius: 0.5rem;
	max-width: 60rem;
}

section + section {
	margin-top: 2rem;
}

.color-strip-wrapper {
	max-width: 100%;
	overflow-x: auto;
}

.color-strip {
	--c0: rgb(0% 0% 0%);
	--c1: rgb(0% 10.28% 27.62%);
	--c2: rgb(0% 18.2% 44.24%);
	--c3: rgb(15.43% 26.8% 54.94%);
	--c4: rgb(26.84% 35.94% 65.43%);
	--c5: rgb(37.58% 45.53% 76.21%);
	--c6: rgb(48.28% 55.51% 87.27%);
	--c7: rgb(59.1% 65.83% 98.58%);
	--c8: rgb(73.36% 76.85% 100%);
	--c9: rgb(86.98% 88.27% 100%);
	--c10: rgb(100% 100% 100%);
	
	width: max(50rem, 100%);
	height: 5rem;
	display: flex;
	margin: 0;
	padding: 0;
	
	> li {
		--color: var(--c0);
		width: calc(100% / 11);
		height: 100%;
		display: flex;
		justify-content: center;
		align-items: center;
		background: var(--color);
		
		&:nth-child(2) { --i: 1; }
		&:nth-child(3) { --i: 2; }
		&:nth-child(4) { --i: 3; }
		&:nth-child(5) { --i: 4; }
		&:nth-child(6) { --i: 5; }
		&:nth-child(7) { --i: 6; }
		&:nth-child(8) { --i: 7; }
		&:nth-child(9) { --i: 8; }
		&:nth-child(10) { --i: 9; }
		&:nth-child(11) { --i: 10; }
		
		&:nth-child(2) { --color: var(--c1); }
		&:nth-child(3) { --color: var(--c2); }
		&:nth-child(4) { --color: var(--c3); }
		&:nth-child(5) { --color: var(--c4); }
		&:nth-child(6) { --color: var(--c5); }
		&:nth-child(7) { --color: var(--c6); }
		&:nth-child(8) { --color: var(--c7); }
		&:nth-child(9) { --color: var(--c8); }
		&:nth-child(10) { --color: var(--c9); }
		&:nth-child(11) { --color: var(--c10); }
	}
	
	@supports (background: lch(0% 45 282)) {
		--CONSTANTS: 45 282;
		--c0: lch(0% var(--CONSTANTS));
		--c1: lch(10% var(--CONSTANTS));
		--c2: lch(20% var(--CONSTANTS));
		--c3: lch(30% var(--CONSTANTS));
		--c4: lch(40% var(--CONSTANTS));
		--c5: lch(50% var(--CONSTANTS));
		--c6: lch(60% var(--CONSTANTS));
		--c7: lch(70% var(--CONSTANTS));
		--c8: lch(80% var(--CONSTANTS));
		--c9: lch(90% var(--CONSTANTS));
		--c10: lch(100% var(--CONSTANTS));
	}
	
	p {
		background: #ffffff;
		padding: 0.18rem 0.25rem 0.125rem;
		border-radius: 0.2rem;
		line-height: 1;
	}
}

.color-strip--chroma {
	--c0: rgb(46.63% 46.63% 46.64%);
	--c1: rgb(45.59% 46.35% 53.16%);
	--c2: rgb(44.1% 46.08% 59.69%);
	--c3: rgb(42.05% 45.84% 66.26%);
	--c4: rgb(39.3% 45.63% 72.88%);
	--c5: rgb(35.59% 45.44% 79.56%);
	--c6: rgb(30.45% 45.28% 86.3%);
	--c7: rgb(22.7% 45.16% 93.11%);
	--c8: rgb(4.71% 45.07% 99.99%);
	--c9: rgb(4.63% 45.07% 100%);
	--c10: rgb(4.63% 45.07% 100%);
	
	@supports (background: lch(0% 45 282)) {
		--L: 50%;
		--H: 282;
		--c0: lch(var(--L) 0 var(--H));
		--c1: lch(var(--L) 10 var(--H));
		--c2: lch(var(--L) 20 var(--H));
		--c3: lch(var(--L) 30 var(--H));
		--c4: lch(var(--L) 40 var(--H));
		--c5: lch(var(--L) 50 var(--H));
		--c6: lch(var(--L) 60 var(--H));
		--c7: lch(var(--L) 70 var(--H));
		--c8: lch(var(--L) 80 var(--H));
		--c9: lch(var(--L) 90 var(--H));
		--c10: lch(var(--L) 100 var(--H));
	}
}

.color-strip--hue {
	--c0: rgb(75.62% 30.45% 47.57%);
	--c1: rgb(73.61% 34.24% 28.07%);
	--c2: rgb(61.78% 42.39% 12.8%);
	--c3: rgb(43.42% 49.22% 10.47%);
	--c4: rgb(16.41% 53.24% 25.54%);
	--c5: rgb(0% 52.88% 46.13%);
	--c6: rgb(0% 51.79% 59.01%);
	--c7: rgb(0% 50.07% 73.51%);
	--c8: rgb(41.25% 44.14% 78.68%);
	--c9: rgb(65.22% 35.59% 66.7%);
	--c10: rgb(75.62% 30.45% 47.57%);
	
	@supports (background: lch(0% 45 282)) {
		--CONSTANTS: 50% 50;
		--c0: lch(var(--CONSTANTS) 0);
		--c1: lch(var(--CONSTANTS) 36);
		--c2: lch(var(--CONSTANTS) 72);
		--c3: lch(var(--CONSTANTS) 108);
		--c4: lch(var(--CONSTANTS) 144);
		--c5: lch(var(--CONSTANTS) 180);
		--c6: lch(var(--CONSTANTS) 216);
		--c7: lch(var(--CONSTANTS) 252);
		--c8: lch(var(--CONSTANTS) 288);
		--c9: lch(var(--CONSTANTS) 324);
		--c10: lch(var(--CONSTANTS) 360);
	}
}

.color-strip-wrapper--hsl {
	.color-strip--hue {
		> li {
			--hue: calc(var(--i) * (360 / 10));
			background: hsl(var(--hue, 0) 50% 45%);
		}
	}
	
	.color-strip--saturation {
		> li {
			--s: calc(var(--i, 0) * 10);
			background: hsl(282 calc(var(--s) * 1%) 45%);
		}
	}
	
	.color-strip--lightness-hsl {
		> li {
			--l: calc(var(--i, 0) * 10);
			background: hsl(282 50% calc(var(--l) * 1%));
		}
	}
}

کد JS:

const button = document.querySelector('[data-toggle]')
const buttonText = document.querySelector('[data-text]')

button.hidden = false

button.addEventListener('click', (e) => {
	if (e.target.checked) {
		document.body.classList.remove('is-grayscale')
		buttonText.innerText = ': Off'
		e.target.checked = false
	} else {
		document.body.classList.add('is-grayscale')
		buttonText.innerText = ': On'
		e.target.checked = true
	}
})
اعمال فیلتر رنگ درجه خاکستری

همچنین می‌توانیم تفاوت بزرگی را هنگام استفاده از رنگ LCH برای گرادیان مشاهده کنیم. هردوی این گرادیان‌ها با یک رنگ شروع و پایان می‌یابند (با استفاده از این مبدل مقادیر LCH به معادل‌های HSL تبدیل می‌شوند). اما گرادیان LCH از میان سایه‌های آبی و بنفش عبور می‌کند، درحالی‌که گرادیان HSL، گل‌آلودتر به نظر می‌رسد.

کد HTML:

<div class="lch">LCH</div>
<div class="hsl">HSL</div>
<div class="rgb">RGB (P3 color)</div>

کد CSS:

* {
	box-sizing: border-box;
}

body {
	font-family: 'Helvetica', sans-serif;
	font-size: 1.6rem;
	color: #ffffff;
	min-height: 100vh;
	margin: 0;
}

body > div {
	width: 100%;
	min-height: 50vh;
	display: flex;
	justify-content: center;
	align-items: center;
}

.lch {
	background: linear-gradient(
		to right,
		lch(50% 100 200),
		lch(50% 100 0)
	);
}

.hsl {
	background: linear-gradient(
		to right,
		hsl(188 100% 34%),
		hsl(331 100% 50%)
	);
}

.rgb {
	background: linear-gradient(
		to right,
		color(display-p3 0 0.5188 0.631),
		color(display-p3 0.8596 0 0.4786)
	);
}
سایه‌های آبی و صورتی

با آنکه LAB و LCH شاید از لحاظ سینتکسی، وضوح کمتری داشته باشند، به‌گونه‌ای رفتار می‌کنند که برای چشم انسان منطقی‌تر باشد. مانند سایر فانکشن‌های رنگی، hwb() و lab() و lch() نیز می‌توانند یک پارامتر آلفا اختیاری داشته باشند.

.my-element {
  background-color: lch(80% 240 50 / 0.5); // Resulting color has 50% opacity
}

پشتیبانی مرورگر و فضاهای رنگی

hwb() و lab() و lch() فقط در سافاری پشتیبانی می‌شوند، اما می‌توان با تعریف یک فالبک برای مرورگرهای غیر پشتیبانی، از آنها استفاده کرد. مرورگرهایی که از فانکشن رنگ پشتیبانی نمی‌کنند، قانون دوم را نادیده می‌گیرند:

.my-element {
  background-color: lch(55% 102 360);

  /* LCH color converted to RGB using Lea Verou’s tool: https://css.land/lch/ */
  background-color: rgb(98.38% 0% 53.33%);
}

اگر استایل های دیگر به پشتیبانی از فانکشن های رنگ جدیدتر بستگی داشته باشند، می‌توانیم از یک فیچر کوئری استفاده کنیم:

.my-element {
  display: none;
}

/* Only display this element if the browser supports lch() */
@supports (background-color: lch(55% 102 360)) {
  .my-element {
    display: block;
    background-color: lch(55% 102 360);
  }
}

اگرچه صفحه نمایش‌های مدرن قادر به نمایش رنگ‌هایی فراتر از RGB هستند، اکثر مرورگرها در حال حاضر فقط از رنگ‌ها در فضای رنگی sRGB پشتیبانی می‌کنند. در نسخه‌ی نمایشی رنگ LAB ممکن است متوجه شوید که حرکت دادن اسلایدرها فراتر از یک نقطه خاص، تأثیری روی رنگ  نمی‌گذارد. استفاده از مقادیر خارج از محدوده sRGB تنها زمانی تأثیر خواهد داشت که سخت‌افزار و مرورگرها به‌اندازه کافی پیشرفت کنند.

اکنون سافاری از فانکشن color() پشتیبانی می‌کند، که ما را قادر می‌سازد رنگ‌ها را در فضای P3 نمایش دهیم، اما در حال حاضر به رنگ‌های RGB محدود شده‌اند و  همه مزایای LAB و LCH را به ما نمی‌دهند.

.my-element {
  background: rgb(98.38% 0% 53.33%); // bright pink
  background: color(display-p3 0.947 0 0.5295); // equivalent in P3 color space
}

دسترسی‌پذیری

هنگامی‌که آنها به‌طور گسترده پشتیبانی می‌شوند، شاید LAB و LCH بتوانند به ما در انتخاب ترکیب‌های رنگی در دسترس‌تر، کمک کنند. تا زمانی که مقدار روشنایی آن‌ها ثابت بماند، متن پیش‌زمینه (فورگراند) باید نسبت کنتراست یکسانی با رنگ‌های پس‌زمینه (بک‌گراند)، مقادیر متفاوت کروم یا hue داشته باشد.

مدیریت رنگ

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

ویژگی‌های سفارشی

ویژگی‌های سفارشی CSS به ما امکان می‌دهد مقادیر را برای استفاده مجدد در شیوه‌نامه‌های خود ذخیره کنیم. ازآنجایی‌که آنها مقادیر جزئی ویژگی را مجاز می‌کنند، می‌توانند برای مدیریت و دست‌کاری مقادیر رنگ، مفید باشند. HSL به دلیل شهودی بودن یعنی وضوع بالا، مناسب ویژگی‌های سفارشی است. در کد قبلی، از آنها برای تنظیم رنگ در هر بخش از نوار رنگ، با محاسبه یک مقدار hue بر اساس شاخص المنت، استفاده کردیم.

li {
  --hue: calc(var(--i) * (360 / 10));
  background: hsl(var(--hue, 0) 50% 45%);
}

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

مهاجرت از HEX/RGB به HSL

رنگ‌های RGB ممکن است تا حدی نیازهای شما را برآورده کنند، اما اگر به انعطاف‌پذیری نیاز دارید تا بتوانید سایه‌های جدیدی را از پالت رنگ پایه خود استخراج‌ کنید، بهتر است به HSL (یا LCH، پس از پشتیبانی) سوئیچ کنید. توصیه می‌کنیم برای این کار از ویژگی‌های سفارشی استفاده کنید.

شاید شما رنگ‌هایی را به عنوان متغیرهای Sass ذخیره کرده باشید:

$primary: rgb(141 66 245);

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

:root {
  --h: 265;
  --s: 70%;
  --l: 50%;
        
  --primary: hsl(var(--h) var(--s) var(--l));
  --primaryDark: hsl(var(--h) var(--s) 35%);
  --primaryLight: hsl(var(--h) var(--s) 75%);
}

همان‌طور که آدام آرگیل در مقاله ساخت طرح رنگی توضیح داده است، HSL می‌تواند برای ایجاد طرح‌های رنگی، فوق‌العاده مفید باشد. او در مقاله خود، طرح‌های رنگی روشن، تیره و کم‌نور را ایجاد می‌کند و از یک رنگ برند به‌عنوان پایه استفاده می‌کند. روش دوست داشتنی است، زیرا امکان کنترل دقیق بر روی نوع رنگ را فراهم می‌کند (به‌عنوان‌مثال، کاهش اشباع رنگ‌ها در طرح تاریک)، اما همچنان مزیت بزرگ ویژگی‌های سفارشی را حفظ می‌کند: به‌روزرسانی رنگ برند تنها در یک مکان، برای همه طرح‌های رنگی انجام می‌شود، بنابراین می‌تواند باعث صرفه‌جویی در کار شود.

 

فانکشن های رنگ Sass

وقتی صحبت از ترکیب و تنظیم رنگ‌ها به میان می‌آید، Sass، فانکشن‌های رنگی را ارائه می‌دهد تا بتوانیم این کار را سال‌ها انجام دهیم. می‌توانیم رنگ‌ها را اشباع یا غیراشباع، روشن یا تیره و حتی دو رنگ را باهم ترکیب کنیم. این‌ها در برخی موارد عالی عمل می‌کنند، اما محدودیت‌هایی نیز دارند: اولاً، فقط می‌توانیم از آنها در زمان کامپایل استفاده کنیم، و برای دست‌کاری رنگ‌های زنده در مرورگر، کاربردی ندارد. ثانیاً، آنها به RGB و HSL محدود می‌شوند، بنابراین از همان مسائل یکنواختی ادراکی رنج می‌برند. همان‌طور که در این نسخه نمایشی می‌بینیم، جایی که یک رنگ به‌طور فزاینده‌ای غیراشباع شده، وقتی به مقیاس خاکستری تبدیل می‌شود، روشن‌تر به نظر می‌رسد.

فیلتر درجه خاکستری

برای اطمینان از اینکه روشنایی، یکنواخت باقی می‌ماند، می‌توانیم از ویژگی‌های سفارشی با LCH به روشی مشابه HSL بالا استفاده کنیم.

li {
  --hue: calc(var(--i) * (360 / 10));
  background: lch(50% 45 var(--hue, 0));
}

ترکیب و تغییر رنگ

ترکیب رنگ

CSS هنوز به ما اجازه نمی‌دهد که رنگ‌ها را در مرورگر ترکیب کنیم. همه‌چیز در حال تغییر است: مشخصات رنگ لول 5 CSS (درافت کاری)، حاوی پیشنهادانی برای فانکشن های ترکیب رنگ است، که نسبتاً امیدوارکننده به نظر می‌رسد. اولین مورد، فانکشن color-mix() است که دو رنگ را بسیار شبیه فانکشن mix() سَس ترکیب می‌کند. اما color-mix() در CSS به ما امکان می‌دهد یک فضای رنگی را مشخص کنیم، و به‌طور پیش‌فرض از LCH استفاده می‌کند، که درنتیجه میکس بهتری دارد.

فانکشن‌های color-mix() و color-contrast() در حال حاضر بوسیله یک فلگ در سافاری 15 پشتیبانی می‌شوند.

زمانی که رنگ‌ها به‌عنوان آرگومان ارسال می‌شود، نباید LCH باشند، اما تناسب (interpolation) از فضای رنگی مشخص‌شده استفاده می‌کند. می‌توانیم مشخص کنیم که چه مقدار از هر رنگ باید شبیه به استاپ‌های گرادیان، ترکیب شوند:

.my-element {
  /* equal amounts of red and blue */
  background-color: color-mix(in lch, red, blue);
}

.my-element {
  /* 30% red, 70% blue */
  background-color: color-mix(in lch, red 30%, blue);
}

کنتراست رنگ و دسترسی‌پذیری

color-contrast()، یکی دیگر از فانکشن‌های پیشنهادی است که واقعاً پیامدهای زیادی برای انتخاب رنگ‌های در دسترس دارد. درواقع، با در نظر گرفتن قابلیت دسترسی‌پذیری، طراحی‌شده است. این فانکشن به مرورگر اجازه می‌دهد تا با مقایسه آن با رنگ دیگر، مناسب‌ترین مقدار را از فهرست انتخاب کند. ما حتی می‌توانیم نسبت کنتراست موردنظر را مشخص کنیم، تا مطمئن شویم که طرح‌های رنگی ما مطابق دستورالعمل‌های WCAG هستند. رنگ‌ها از چپ به راست ارزیابی می‌شوند و مرورگر اولین رنگی را از لیست انتخاب می‌کند که نسبت موردنظر را برآورده می‌کند. اگر هیچ رنگی با این نسبت مطابقت نداشته باشد، رنگ انتخابی، رنگی خواهد بود که بیشترین کنتراست را دارد.

.my-element {
  color: wheat;
  background-color: color-contrast(wheat vs bisque, darkgoldenrod, olive, sienna, darkgreen, maroon to AA);
}

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

 

پشتیبانی مرورگر

مشخصات رنگ لول 5 در حال حاضر در پیش‌نویس کار است، به این معنی که هیچ مرورگری هنوز ازفانکشن‌های color-contrast() و color-mix() پشتیبانی نمی‌کند و سینتکس آنها در معرض تغییر است. اما مطمئناً آینده روشنی برای رنگ در وب، به نظر می‌رسد!

تأثیر رنگ‌ها بر محیط

آیا می‌دانستید که پالت رنگی انتخابی شما می‌تواند بر میزان مصرف انرژی وب‌سایت شما تأثیر بگذارد؟ در صفحه‌نمایش‌های OLED (که بیشتر تلویزیون‌ها و لپ‌تاپ‌های مدرن را تشکیل می‌دهند)، رنگ‌های تیره‌تر انرژی کمتری نسبت به رنگ‌های روشن مصرف می‌کنند. رنگ سفید، بیشترین مصرف انرژی و رنگ سیاه، کمترین میزان مصرف را دارد. به گفته تام گرین‌وود، نویسنده Sustainable Web Design، آبی نیز انرژی بیشتری نسبت به رنگ‌های قرمز و سبز دارد. برای کاهش اثرات زیست‌محیطی اپلیکیشن‌های خود، رنگ تیره‌تر را در نظر بگیرید، از آبی کمتر استفاده کنید، یا گزینه حالت تاریک را برای کاربران خود فعال کنید. به‌عنوان یک امتیاز اضافی، انتخاب رنگ‌های سازگار با محیط‌زیست نیز می‌تواند میزان تأثیر روی عمر باتری دستگاه‌های تلفن همراه را، کاهش دهد.

فاطمه رسولی

فاطمه رسولی

دیدگاه‌ها


ثبت دیدگاه