سال ۲۰۱۸ رسیده است: دیگر نباید در حال نوشتن Vanilla CSS باشید

css
13 خرداد 1398, خواندن در 10 دقیقه

یک اشتباه رایج در میان توسعه دهندگان، این است که به استایل‌بندی در مقایسه با باقی بخش‌های کد، اهمیت کمتری می‌دهند.

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

این یک فلسفه بسیار ساده است:

  • اگر می‌خواهید چیزی را استایل‌بندی کنید، فقط آن را در انتهای فایل style.css قرار دهید.
  • وقتی که در انجام یک کار در زمینه ویژگی‌ها به مشکلی بر خورده‌اید، نیازی به خطایابی کد نیست. این کار احمقانه است، فقط CSS خالی است و یک !imortant ساده کار را برای شما انجام خواهد داد. محض احتیاط، شما می‌توانید از آن برای همه چیز استفاده کنید، پس قطعا کار خواهد کرد.
  • اگر همچنان کار نکند، یک انتخاب کننده به شدت مشخص یک راه مطمئن است. چیزی به مانند :«body>header#main_header.main-header>img.logo+div.links>a.link»
  • آیا شما مقداری زیادی کد تکرار شده دارید؟ این طبیعی است؛ فقط کمی استفاده مجدد از کد به روش قدیمی.
  • الگوها، بهترین شیوه‌ها، متدلوژی‌ها؟ برای چه؟ این موارد فقط CSS هستند، به یاد دارید؟

خوشبختانه در سال‌های اخیر، این روش فکر کردن همینطور منسوخ‌تر و منسوخ‌تر شده است.

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

تکامل CSS متداوم است. امکاناتی مانند طرح توری CSS (CSS Grid Layout)، Flexbox، ویژگی‌های سفارشی، حالت نوشتن و برخی موارد دیگر به سرعت در حال ظاهر شدن و پشتیبانی شدن هستند. با این حال، نگهداری ظاهر یک وب‌اپلیکیشن پیچیده فقط با Vanilla CSS یک کار سخت است؛ چه بهترین روش‌ها را دنبال کنید یا چه نکنید.

واقعیت این است که هر پروژه‌ای، به استثنای چند مورد، می‌تواند با چند ابزار پیش و پس پردازنده یا کتابخانه‌های CSS-in-JS موفق شود. در این مقاله، هر دوی آن‌ها، نحوه کارشان و برتری‌هایشان را خواهیم دید.

پیش پردازنده‌ها (preprocessors)

پیش پردازنده CSS ابزاری است که یک کد در زبان داده شده را به CSS خالص تبدیل می‌کند. معروف‌ترین پیش پردازنده‌ها Sass، Stylus و LESS هستند. در میان آن‌ها، تفاوت‌هایی در مجموعه امکانات و سینتکس زبان وجود دارد.

هدف این مقاله این نیست که یک مقایسه به همراه جزئیات بین گزینه‌های موجود انجام دهد، بلکه هدف این است که پیش پردازنده‌ها را به روشی عمومی معرفی کنیم. برای مثال، من Stylus، ابزاری نوشته شده در JavaScript را انتخاب می‌کنم که بر روی Node.js اجرا می‌شود.

نگاهی به این قطعه کد داشته باشید:

$base-color = #2DD;
$base-color--dark = darken($base-color, 30%);

.menu {
    background-color: $base-color--dark;
    &::before {
        color: $base-color;
    }
}

در ابتدای کد نمایش داده شده در بالا، من دو متغیر را تعریف کردم که مقادیرشان چند رنگ‌ هستند. اولین مورد یک مقدار حرفی دارد، و دومین مورد از یک تابع Stylus بومی به نام darken استفاده می‌کند تا رنگ ذخیره شده در متغیر $base-color را به مقدار ۳۰ درصد تیره‌تر کند.

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

نکته: استفاده از علامت دلار ($) به عنوان یک پیشوند برای نام متغیرها، یک کار بسته به ترجیح شخصی شما است و در Stylus ضروری نیست. من در طی سال‌های کار با Sass به این کار عادت کردم و امروزه از آن در Stylus استفاده می‌کنم. به این صورت، متغیرها قابل رویت‌تر می ‌شوند، و با کلمات کلیدی CSS اشتباه گرفته نمی‌شوند.

مثال بالا امکاناتی دارد که توسط مرورگر پشتیبانی نشده‌اند؛ مانند تو در تویی انتخاب کنننده و متغیرها. یک روند تلفیقی در جهت تفسیر صحیح کد Sass، Stylus یا LESS توسط مرورگر ضروری است. خروجی پس از کمپایل شدن، CSS خالص است:

.menu {

  background-color: #189b9b;

}

.menu::before {

  color: #2dd;

}

همانطور که می‌توانید ببینید، نتیجه نهایی انتخاب کننده‌های تو در تو را به عنوان قوانین جداگانه گسترش می‌دهد و هر ارجاع متغیر را با مقدار مربوطه جایگزین می‌کند. همین!

امکانات رایج در پیش پردازنده‌ها

امکانات پشتیبانی شده در پیش پردازنده‌ها متنوع هستند. در میان موارد اصلی، Sass و Stylus همه کاره‌ترین‌ها و کامل‌ترین‌ها هستند. یک بار دیگر، من از Stylus برای توضیح دان هر مفهوم استفاده خواهم کرد.

متغیرها

یک متغیر می‌تواند چیزهایی مانند این موارد را در خود ذخیره کند:

رنگ‌ها:

  • $base-color = blue;
  • $cta-color = #D32;
  • $link-color = rgb(15, 200, 25);

مقادیر عددی + واحد:

  • $container-padding = 2rem;
  • $rotation-increment = 15deg;
  • $default-transition-duration = 20ms;

لیست مقادیر، مانند:

  • اعداد: $sequence = 1, 2, 3;
  • رنگ‌ها: $colors = blue, #F00, hsla(120,100%,30%,0.5);
  • و غیره: $font-stack: “Helvetica Neue”, Helvetica, Arial, sans-serif;

تو در تویی

این که انتخاب کننده‌ها را در جهت جلوگیری از تکرار کد تو در تو کنید و قوانین همبسته را به روشی واضح‌تر با هم group کنید، ممکن است:

.main-navbar {
    ul {
        list-style-type: none;
    }
        a {
            color: #D22;
            &::after {
                margin-left: 1rem;
            }

            &:hover{
                opacity: 0.8;
            }
        }
}

پیشنهاد: مهم است که اشاره کنم که این ویژگی باید با دقت در نظر گرفته شود؛ زیرا اگر از آن بیش از حد استفاده شود، دوست دارد که به مشکل بر خورد؛ مثلا: استایل‌شیت‌هایی که به شدت با ساختار وراثتی HTML جفت شده‌اند، انتخاب کننده‌هایی با مشخص بودن بالا و خروجی CSSای که بی دلیل بسیار بزرگ است.

وراثت تکی و چندگانگی

به مانند زبان‌های OO، پیش پردازنده‌ها قابلیت استفاده مجدد از کد را از طریق وراثت فراهم می‌کنند.

یک کلاس X می‌توانند یک کلاس Y دیگر را گسترش دهد، تمام ویژگی‌هایش را به ارث ببرد و ویژگی‌های مختص خود را داشته باشد:

.btn {

    border-radius: 0.3rem;

    border: 0.1rem solid #222;

    &:hover {

        opacity: 0.9;

    }

}

.btn--blue {

    @extend .btn;

    background-color: #22D;

}

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

.btn {

    border-radius: 0.3rem;

    border: 0.1rem solid #222;

    &:hover {

        opacity: 0.9;

    }

}

.big-btn {

    font-size: 1.8rem;

    padding: 1rem 2rem;

}

.big-btn--blue {

    @extend .btn, .big-btn;

    background-color: #22D;

}

جانگهدارها (کلاس‌های چکیده)

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

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

$btn {

    border-radius: 0.3rem;

    border: 0.1rem solid #222;

    &:hover {

        opacity: 0.9;

    }

}

.btn--blue {

    @extend $btn;

    background-color: #22D;

}

در Stylus، جانگهدارها یک علامت دلار را به عنوان پیشوند خود دارند. در کد بالا، کلاس btn--blue کل بدنه جانگهدار $btn را به ارث خواهد برد، اما در عوض در CSS کمپایل شده حاضر نخواهد بود.

شروط و حلقه‌ها

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

$colors = 'blue', 'black', 'yellow', 'aqua';

$dark-colors = 'blue', 'black';

for $color in $colors {

    .btn--{$color} {

        background-color: unquote($color);

        

        if $color in $dark-colors {

            color: white;  

        } else {

            color: #222;

        }

    }

}

نسخه کمپایل شده به CSS هم اینجاست:

.btn--blue {

  background-color: blue;

  color: #fff;

}

.btn--black {

  background-color: black;

  color: #fff;

}

.btn--yellow {

  background-color: yellow;

  color: #222;

}

.btn--aqua {

  background-color: aqua;

  color: #222;

}

توابع

توابع، امکاناتی هستند که در پیش پردازنده‌های اصلی هم شامل شده‌اند. یک تابع، دقیقا به روشی از یک زبان دیگر که شما به آن عادت دارید رفتار می‌کند، و صفر تا n‌ آرگومان را دریافت کرده، و یک مقدار را بر می‌گرداند:

repeat($str, $qty) {

    if ($qty < 1) {

        return '';

    }

  

    $ret = '';

  

    for $i in 1..$qty {

        $ret += $str;

    }

  

    $ret;

}

h1:before{

    content: repeat(ha, 5);

}

خروجی CSS:

h1:before {
  content: 'hahahahaha';
}

مخلوط‌ها

مخلوط‌ها بسیار شبیه به توابع هستند، اما با این تفاوت‌ها:

  • هیج مقدار برگشتی‌ای ندارند.
  • با توجه به این که بازگشتی ندارند، نمی‌توانند به عنوان مقدار برای یک متغیر یا ویژگی استفاده شوند.
  • یک مخلوط می‌تواند ویژگی‌های CSS در بدنه خود داشته باشد، که در جایی که مخلوط فراخوانی شده است رندر خواهد شد.
square($side) {

    width: $side;

    height: $side;

}

.card{

    square(20rem);

    background-color: #3C3;

}

خروجی CSS:

.card {

  width: 20rem;

  height: 20rem;

  background-color: #3c3;

}

Importها

احتمالا از قبل قانون @import را در CSS می‌شناسید، که استایل‌شیت X را قادر می‌سازد تا استایل‌شیت Y خارجی را شامل شود. این توسط مرورگر و در طی تفسیر استایل‌شیت ساخته می‌شود، و یک درخواست HTTP را فعال می‌کند.

پیش پردازنده‌ها از این که مرورگر مجبور باشد این درخواست‌های اضافی را برای هر CSS شامل شده انجام دهد، جلوگیری می‌کنند. وقتی که شما یک فایل Sass، Stylus یا LESS را import می‌کنید، استایل‌شیت شامل شده و استایل‌شیتی که آن را شامل می‌شود، (پس از کمپایل شدن) تبدیل به یک فایل CSS bundle تکی می‌شوند تا در برنامه شما بارگذاری شود.

برای واضح‌ کردن این مسئله، در اینجا یک مثال را مشاهده می‌کنید:

// color-scheme.styl

$base-color = #555;

$cta-color = #D22;

// another-thing.styl

.whatever {

    padding: 2rem;

    background-color: $cta-color;

}

// example.styl

@import 'color-scheme';

@import 'another-thing';

.footer {

    background-color: $base-color;

    color: white;

}

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

.whatever {

  padding: 2rem;

  background-color: #d22;

}

.footer {

  background-color: #555;

  color: #fff;

}

به طور طبیعی، bundle آخر قبل از این که به کاربر تحویل داده شود، کوچک شده و GZip می‌شود.

توابع بومی

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

  • رنگ‌ها (مثلا: تیره کردن، اشباع، آلفا، روشنایی)
  • لیست‌ها (مثلا: push، pop، index، shift، keys)
  • انواع مختلف مقادیر و واحدها (مثلا: typeof، unit)
  • عملیات‌های ریاضی (مثلا: round، sin، floor، abs)
  • رشته‌ها (مثلا: split، substr، slice)

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

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

منبع

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

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

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

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

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