متغیرهای CSS برای توسعه React

آفلاین
user-avatar
عرفان حشمتی
25 دی 1399, خواندن در 10 دقیقه

این نظر جنجالی است که من بیشتر طرفدار CSS-in-JS هستم. همچنین CSS را هم خیلی دوست دارم و معتقدم که استفاده از CSS-in-JS شما را از یادگیری چیزهای دیگر بی نیاز نمی‌کند. مهم نیست که CSS خود را در کجا قرار دهید، مهم این است که بر آن تسلط داشته باشید. حرفه‌ای شدن در CSS شما را به یک توسعه دهنده فرانت-اند کارآمد تبدیل می‌کند. در این آموزش می‌خواهیم ببینیم که چگونه می‌توان از جذاب‌ترین تحولات جدید در CSS مانند متغیرهای CSS و ویژگی‌های سفارشی AKA بهره برد. خواهیم دید که چگونه می‌توان از آنها در برنامه‌های React خود برای بهبود گردش کار و کارهای بسیار زیبا استفاده کرد.

به عنوان یک توسعه دهنده React، ممکن است فکر کنید که نیازی به متغیرها در CSS ندارید و یک موتور جاوااسکریپت کامل در اختیار دارید.

برای سویچ کردن به متغیرهای CSS در برنامه React دو دلیل وجود دارد:

  • ارگونومی آن خوب است.
  • امکانات جدیدی در اختیارمان قرار می‌دهد. به این صورت که می‌توانید کارهایی را با متغیرهای CSS انجام دهید که با JS امکان‌پذیر نیست.

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

مقدمه کوتاه

متغیرهای CSS به شرح زیر است:

html {
  --color-text: black;
  --color-background: lightgray;
  --color-primary: rebeccapurple;
  --gutter: 16px;
}
p {
  color: var(--color-text);
  margin-bottom: var(--gutter);
}
.title {
  color: var(--color-primary);
}

نکته جالب این است که ظاهری کاملا شبیه به پروپرتی‌ها دارند. در حقیقت دلیل اینکه آنها به طور رسمی "CSS Custom Properties" نامیده می‌شوند، ویژگی آنها مانند موقعیت یا رنگ است. اکنون می‌توانیم پروپرتی‌های خود را تعریف کنیم.

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

آموزش‌ها اغلب نشان می‌دهند متغیرهای CSS به یک سلکتور عجیب root: پیوست شده‌اند:

:root {
  --color-text: black;
  --color-background: lightgray;
}

این یک روش فانتزی برای انجام همان کار است. root: یک شبه کلاس است که به عنصر سطح بالای HTML اشاره دارد.

در اینجا برخی دیگر از مواردی که باید درباره متغیرهای CSS بدانید، ذکر شده اند:

  • می‌توانید مقدار متغیر را با کلمه کلیدی var صدا کنید که مانند متدgetter  عمل می‌کند:
    var(--color-primary)، در این حالت تبدیل به rebeccapurple می‌شود.
  • خصوصیات سفارشی باید با دو خط تیره شروع شوند. این همان چیزی است که آنها را از خصوصیات سنتی CSS متمایز می‌کند.
  • آنها می‌توانند هر نوع مقداری را نگه دارند، نه فقط رنگ‌ها و پیکسل‌ها.
  • می‌توانید آنها را به هر سلکتور وصل کنید، نه فقط به تگ html.
  • اگر متغیر CSS تعریف نشده باشد، می‌توانید یک مقدار پیش فرض تعیین کنید:
    var(--primary-color, pink) در صورت لزوم به رنگ صورتی برمی‌گردد.

برنامه React

بیایید ببینیم این حالت در React چگونه به نظر می‌رسد. در این آموزش از styled-components استفاده می‌شود، اما دستورالعمل ها بدون در نظر گرفتن کتابخانه CSS-in-JS باید تقریبا مشابه باشند.

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

const COLORS = {
  text: 'black',
  background: 'white',
  primary: 'rebeccapurple',
};
const SIZES = [
  8,
  16,
  24,
  32,
  /* And so on */
];

در یک برنامه React ممکن است آنها را مستقیما وارد کامپوننت مورد نیاز خود کنید:

import { COLORS } from '../constants';
const Button = styled.button`
  background: ${COLORS.primary};
`;

یا ممکن است از یک تم استفاده کنید:

// components/App.js
import { ThemeProvider } from 'styled-components';
import { COLORS } from '../constants';
// This element wraps our entire application,
// to make the theme available via context.
const App = ({ children }) => {
  return <ThemeProvider theme={{ colors: COLORS }}>{children}</ThemeProvider>;
};
// Elsewhere…
const Button = styled.button`
  background: ${(props) => props.theme.colors.primary};
`;

در اینجا همان کد وجود دارد، اما با استفاده از متغیرهای CSS تنظیم می‌شود:

import { createGlobalStyle } from 'styled-components';
// Create a `GlobalStyles` component.
// I usually already have this, to include a CSS
// reset, set border-box, and other global concerns.
const GlobalStyles = createGlobalStyle`
  html {
    --color-text: black;
    --color-background: white;
    --color-primary: rebeccapurple;
  }
`;
const App = ({ children }) => {
  return (
    <>
      <GlobalStyles />
      {children}
    </>
  );
};

ما برخی از متغیرها را ایجاد کرده و آنها را در روت پیوست کرده‌ایم. اکنون می‌توانیم در اجزای خود به آنها دسترسی پیدا کنیم:

const Button = styled.button`
  background: var(--color-primary);
`;

به نظر من این یک پیروزی کوچک است. امکان دستیابی به مقادیر تم بدون ایمپورت کردن یا تابع درون خطی، یک کار مفید است. شما برخی از مزایای نوع استاتیک را از دست می‌دهید - بعدا در این باره بیشتر می‌خوانید - اما به نظر من کار بسیار خوبی است.

این تفاوت نسبتا جزئی است. بیایید یک چیز جالب‌تر را بررسی کنیم.

تغییر مقادیر، نه متغیرها

فرض کنید که ما یک کامپوننت دکمه (button) داریم.

const Button = styled.button`
  height: 32px;
  padding: 0 32px;
  border-radius: 16px;
  border: none;
  color: white;
  font-size: 13px;
  font-weight: 600;
  text-shadow: 1px 1px 0px #3a00df;
  background: linear-gradient(170deg, #359eff 5%, #3a00df 95%);
`;

render(<Button width={60}>Hello World</Button>);

به نظر زیبا می‌رسد، اما بازخورد ما این است که محدوده کلیک در دستگاه‌های تلفن همراه بسیار کوچک است. دستورالعمل استاندارد این است که عناصر تعاملی باید از 44 پیکسل تا 48 پیکسل ارتفاع داشته باشند. برای سهولت در ضربه زدن روی تلفن باید اندازه آن را متناسب کنیم.

بیایید از یک راه‌حل ساده استفاده کنیم، نه از متغیرهای CSS.

const Button = styled.button`
  /* Omitted other styles */
  /* Mobile height */
  height: 48px;
  /* Desktop height */
  @media (min-width: ${(props) => props.theme.bp.desktop}) {
    height: 32px;
  }
`;

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

سپس به سرعت می‌فهمیم که کار ما انجام نشده است. دکمه ها تنها عناصر قابل لمس در برنامه‌های ما نیستند و ورودی متن نیز وجود دارد.

بیایید کامپوننت TextInput خود را نیز به روز کنیم و اندازه‌های خود را بر اساس تم خود ذخیره می‌کنیم:

const App = ({ children }) => {
  return (
    <ThemeProvider
      theme={{
        colors: COLORS,
        mobileTapHeight: 48,
        desktopTapHeight: 32,
      }}
    >
      {children}
    </ThemeProvider>
  );
};

ما از این مقادیر در هر دو کامپوننت خود استفاده می‌کنیم:

const Button = styled.button`
  height: ${(props) => props.theme.mobileTapHeight}px;
  @media (min-width: ${(props) => props.theme.bp.desktop}) {
    height: ${(props) => props.theme.desktopTapHeight}px;
  }
`;
const TextInput = styled.input`
  height: ${(props) => props.theme.mobileTapHeight}px;
  @media (min-width: ${(props) => props.theme.bp.desktop}) {
    height: ${(props) => props.theme.desktopTapHeight}px;
  }
`;

این نکته قابل توجهی از CSS است که بتوانید به هر عنصر قابل لمس دسترسی پیدا کنید.

به نظر می‌رسد متغیرهای CSS یک راه‌حل بسیار جذاب برای این مشکل ارائه می‌دهند، اما به یک تغییر مدل ذهنی نیاز دارد.

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

const GlobalStyles = createGlobalStyle`
  html {
    --min-tap-target-height: 48px;
    @media (min-width: ${(props) => props.theme.bp.desktop}) {
      --min-tap-target-height: 32px;
    }
  }
`;

با استفاده از این متغیر جادویی CSS، کامپوننت‌های واکنشی ما بسیار ساده‌تر می‌شوند:

const Button = styled.button`
  height: var(--min-tap-target-height);
`;
const TextInput = styled.input`
  height: var(--min-tap-target-height);
`;

داخل کامپوننت‌ها ارتفاع همیشه به یک متغیر اشاره دارد، صرف نظر از اندازه نمایش. تفاوت در این است که متغیر با تغییر عرض پنجره مقدار خود را تغییر می‌دهد.

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

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

این به ما اجازه می‌دهد در مورد دلیل انجام کار صریح‌تر عمل کنیم. ما در حال دادن یک نام به آن هستیم - min-tap-target-height - که بیان می‌کند چرا در وهله اول باید مقدار ارتفاع را تنظیم کنیم.

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

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

یک مثال سریع دیگر: ما می‌توانیم همین را برای اندازه قلم انجام دهیم، به طوری که هر viewport مقیاس خاص خود را داشته باشد.

const GlobalStyles = createGlobalStyle`
  html {
    --font-size-small: 16px;
    --font-size-medium: 22px;
    @media (min-width: 1024px) {
      --font-size-small: 21px;
      --font-size-medium: 24px;
    }
  }
`;
// Elsewhere...
const Paragraph = styled.p`
  font-size: var(--font-size-small);
`;
const OpeningParagraph = styled.p`
  font-size: var(--font-size-medium);
`;

کامپوننت‌ها اندازه‌ای را از مقیاس انتخاب می‌کنند و ما بسته به اندازه viewport مقیاس را عوض می‌کنیم.

سایر امکانات جدید

متغیرهای CSS حداقل دو در دیگر را باز می‌کنند:

1 – متحرک کردن هر خصوصیت

برخی از ویژگی‌های CSS وجود دارد که به راحتی نمی‌توان آنها را متحرک کرد. به عنوان مثال اگر تا به حال سعی کرده‌اید یک شیب خطی یا شعاعی را متحرک کنید، خیلی سریع متوجه شده‌اید که کار نمی‌کند.

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

به عنوان مثال، در اینجا یک انیمیشن گرادیان وجود دارد که با متغیرهای CSS امکان‌پذیر شده است:

2 – رفع مشکل حالت تاریک

اگر سعی کرده‌اید "حالت تاریک" را اجرا کنید، احتمالا این وضعیت برایتان مشکل‌ساز شده است. به این صورت که برای لحظه‌ای کوتاه، رنگ‌های اشتباه چشمک می‌زنند:

"حالت تاریک" به خصوص در زمینه ارائه شده توسط سرور (مانند Gatsby یا Next.js) بسیار شگفت آور است. مشکل این است که HTML مدت‌ها قبل از رسیدن به دستگاه کاربر تولید می‌شود، بنابراین راهی وجود ندارد که بدانید کاربر کدام تم رنگی را ترجیح می‌دهد.

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

Getting و Setting

در مثال بالا مقادیر تم خود را در یک کامپوننت GlobalStyles قرار می‌دهیم:

const GlobalStyles = createGlobalStyle`
  html {
    --color-text: black;
    --color-background: white;
    --color-primary: rebeccapurple;
  }
`;

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

در صورت تمایل می‌توانید آنها را در یک فایل constants.js ذخیره کنید که از آنها برای نمونه سازی متغیرهای CSS استفاده می‌شود. سپس در هر کجا که به مقادیر خام در جاوااسکریپت نیاز دارید وارد می‌شود:

const GlobalStyles = createGlobalStyle`
  html {
    --color-text: ${COLORS.text};
    --color-background:  ${COLORS.background};
    --color-primary:  ${COLORS.primary};
  }
`;

با کمی کد جاوااسکریپت می‌توانید به مقادیر دسترسی پیدا کنید:

getComputedStyle(document.documentElement).getPropertyValue('--color-primary');

همچنین می‌توانید این مقادیر را از داخل جاوااسکریپت نیز تنظیم کنید:

// Try changing the value of this CSS variable,
// and check out the blog's logo!
document.documentElement.style.setProperty(
  '--color-primary',
  'hsl(245deg, 100%, 60%)'
);

getting و setting متغیرهای CSS یک میانبر است. شاید تعجب کنید که چقدر به آن نیاز دارید. حتی می‌توانید از متغیرهای CSS در SVG ها استفاده کنید.

معایب

بدون type

احتمالا بزرگترین نقطه ضعف استفاده از متغیرهای CSS این است که راهی برای تایپ استاتیک (از طریق Typescript یا Flow) وجود ندارد.

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

همچنین فکر می‌کنم مهم است که بررسی‌های compile-time را در سایت خود انجام دهید، اما به نظر من ابزارهایی مانند Chromatic یک بررسی قابل اطمینان‌تر هستند. آنها در CI اجرا می‌شوند و هرگونه اختلاف را در خروجی تصویر ثبت می‌کنند.

اگر type-safety یک امر ضروری است، پس مجبور نیستید آن را کنار بگذارید. شما فقط باید استایل‌های خود را در یک شی جاوااسکریپت نگه دارید و از آنها استفاده کنید.

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

متغیرهای CSS از پشتیبانی در 4 مرورگر اصلی برخوردار هستند، اما پشتیبانی IE را ندارند:

کاربرد

هنگام استفاده از styled-component می‌توانید متغیرها را در هر کجا که می‌خواهید قرار دهید، از جمله در مدیا کوئری‌ها:

const Ymca = styled.abbr`
  font-size: 18px;
  @media (max-width: ${(p) => p.bp.desktop}) {
    font-size: 22px;
  }
`;

اما از متغیرهای CSS در هر کجای مدیا کوئری‌ها نمی‌توان استفاده کرد. این امکان وجود دارد که به کاربران اجازه داده شود متغیرهای اطراف را با env() توصیف کنند، اما هنوز محقق نشده است.

جمع بندی

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

بسیاری از ابزارهای محبوب مانند Theme UI توسط متغیرهای CSS ساخته شده‌اند.

تصمیم به استفاده از متغیرهای CSS در پروژه بعدی خود را دارید؟ دانستن نحوه استفاده از آنها ارزشش را دارد. هیچ وقت نمی‌دانید چه زمانی با مشکلی روبه رو می‌شوید که متغیرهای CSS می‌توانند راه حل آن باشند.

منبع

چه امتیازی به این مقاله می دید؟
خیلی بد
بد
متوسط
خوب
عالی

دیدگاه‌ها و پرسش‌ها

برای ارسال دیدگاه لازم است، ابتدا وارد سایت شوید.

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

آفلاین
user-avatar
عرفان حشمتی @heshmati74
مهندس معماری سیستم های کامپیوتری، طراح و توسعه دهنده وب سایت
دنبال کردن

گفتگو‌ برنامه نویسان

بخشی برای حل مشکلات برنامه‌نویسی و مباحث پیرامون آن وارد شو