مفهوم Extend در CSS
ﺯﻣﺎﻥ ﻣﻄﺎﻟﻌﻪ: 8 دقیقه

مفهوم Extend در CSS

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

مفهوم پایه‌ای

وراثت! کاربرد این قابلیت در ارثبری ویژگی‌های css ای است. (من می‌خواهم که فلان انتخاب‌گر (selector) استایل‌های انتخاب‌گر دیگری را نیز به ارث ببرد و آن را نیز شامل شود.)

استفاده‌ی پایه‌ای

فعلا بیایید از پیش‌پردازنده‌ی SASS در مثال‌های خود استفاده کنیم.

.foo {
  color: red;
}
.bar {
  @extend .foo;
}

خروجی:

.foo, .bar {
  color: red;
}

به این نکته توجه داشته باشید که در مثال بالا، کلاس bar کدهای داخل کلاس foo را کپی پیست نمی‌کند؛ بلکه همان‌طور که در خروجی می‌بینید،‌ انتخاب‌گر foo را در کنار انتخا‌ب‌گر bar (با ویرگول) قرار داده و دیگر باعث جلوگیری از نوشتن کدهای تکراری استایل‌دهی می‌شود و البته که در نهایت هر دوی این کلاس‌های ویژگی‌های مورد نظر مشترک را دارا خواهند بود.

رابطه‌ی extend با mixin

 شما اغلب می‌توانید با استفاده از mixin نیز در موارد مشابه، به نتیجه‌ای یکسان و مطلوب به نسبت با extend برسید:

@mixin stuff {
  color: red;
}
.foo {
  @include stuff;
} 
.bar {
  @include stuff;
}

قطعه کد بالا منجر به وارد شدن استایل‌ها به درون هر دو انتخاب‌گر می‌شود و صادقانه باید بگوییم که مفهومی ساده‌تر و قابل‌ فهم‌تر نسبت به extend دارد؛ پس طبیعی‌ است که استفاده از mixin ها متدوال‌تر از extend باشد. با توجه به خروجی کد بالا که در زیر مشاهده می‌کنید، متوجه می‌شویم که استایل وارد شده در میکس‌این، درون انتخاب‌گر هر دو کلاس کپی شده است:

.foo {
  color: red;
}
.bar {
  color: red;
}

اما خیلی نگران زیاد‌تر شدن کدها در هنگام استفاده از mixin ها در برابر extend نباشید. (با توجه به این که کدهای تکراری توسط gzip قابل فشرده شدن‌اند)

میکس‌این می‌تواند کارهایی فراتر از توانایی اکستند انجام دهد؛ مثل چیزی که در زیر مشاهده می‌کنید؛ چیزی شبیه به کار فانکشن‌ها در هر زبان برنامه نویسی که می‌شناسید. (میکس‌این پارامتر می‌گیرد و با توجه به آن، قاعده‌ (rule) ی css را پردازش می‌کند)

@mixin padMasterJ ($param: 10px) {
  padding: $param;
}

این در حالیست که اکستند (extend) قابلیت انجام چنین کاری را ندارد. پس بیایید یک قانون ساده را به بهانه‌ی مطالب اشاره شده در این بخش، بیان کنیم:

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

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

راه و روش SASS ای

ما تا به این‌جای کار از SASS استفاده کرده‌ایم؛ پس بیایید کمی راجع به نحوه‌ی مدیریت کردن extend در این پیش‌پردازنده صحبت کنیم. SASS تمام انتخاب‌گرهای تودرتو (nested) را نیز در extend خود منتقل می‌کند.

.module {
  padding: 10px;
  h3 {
    color: red; 
  }
}

.news {
  @extend .module;
}

خروجی قطعه کد بالا:

.module, .news {
  padding: 10px;
}
.module h3, .news h3 {
  color: red;
}

یکی از محدودیت‌های موجود در SASS این است که شما نمی‌توانید انتخاب‌گرهای تودرتو را به تنهایی extend کنید. در زیر نیز می‌توانید مثال این مورد را مشاهده کنید:

.header {
  h3 {
    color: red; 
  }
}

.special-header {
  /* Error: can't extend nested selectors */
  @extend .header h3;
}

کد بالا ارور خواهد داد.

راه و روش LESS ای

LESS از &:extend برای پیاده‌سازی مثال بسیار ساده‌ی ما استفاده می‌کند:

.foo {
  color: red;
}
.bar {
  &:extend(.foo);
}

خروجی کد بالا:

.foo,
.bar {
  color: red;
}

نکته‌ی جالب این پیش پردازنده در این مورد نیز این است که به طور پیش‌فرض به extend کردن انتخاب‌گرهای تودرتو (nested) نمی‌پردازد.

.module {
  padding: 10px;
  h3 {
    color: red; 
  }
}

.news {
  &:extend(.module);
}

همان‌طور که در خروجی زیر می‌بینید، h3 گسترش پیدا نخواهد کرد و منتقل نخواهد شد:

.module,
.news {
  padding: 10px;
}
.module h3 {
  color: red;
}

البته می‌توانید با اضافه کردن کلیدواژه‌ی all این کار را امکان‌پذیر کنید:

.news {
  &:extend(.module all);
}

طبق خروجی زیر می‌بینید که با استفاده از کلید واژه‌ی all تمامی موارد extend شده‌اند:

.module,
.news {
  padding: 10px;
}
.module h3,
.news h3 {
  color: red;
}

راه و روش Stylus ای

Extend در Stylus بسیار شبیه به Sass کار می‌کند.

.module 
  padding 10px
  h3 
    color red

.news 
  @extend .module

خروجی قطعه کد بالا:

.module,
.news {
  padding: 10px;
}
.module h3,
.news h3 {
  color: #f00;
}

یک تفاوت کوچک میان این پیش پردازنده و sass، این است که stylus می‌تواند انتخاب‌گرهای تودرتو را به شکل زیر extend کند:

.header 
  padding 10px
  h3 
    color red

.special-header 
  @extend .header h3

خروجی کد بالا:

.header {
  padding: 10px;
}
.header h3,
.special-header {
  color: #f00;
}

Extend کردن placeholder ها

SASS و Stylus دارای انتخاب‌گرهای placeholder هستند. در SASS بدین شکل خواهیم داشت:

%grid-1-2 {
  float: left;
  width: 50%;
}

و در  Stylus نیز به این شکل خواهیم داشت:

$grid-1-2
  float left
  width 50%

باید توجه داشته باشید که شما نمی‌توانید از placeholder ها به تنهایی در css استفاده کنید و باید حتما آن‌ها را فقط extend کنید تا قابل استفاده باشند. نکته مفید در استفاده از این مورد در پیش‌پردازنده ها این است که شما می‌توانید از الگوی نام‌گذاری مانند grid-1-2 که زیاد در HTML مناسب نیستند و توصیه نمی‌شوند، به شکل درونی در خود پیش‌پردازنده استفاده کنید:

.main-content {
  @extend %grid-2-3;
}
.sidebar {
  @extend %grid-1-3;
}

مراقب ترتیب انتخاب‌گرها باشید

به دلیل بازنویسی انتخاب‌گرها (selectors)، ممکن است گاهی اوقات به مواردی بر بخورید که در آن‌ها به خروجی قابل انتظار خود نرسید. برای مثال به قطعه کد زیر توجه کنید تا این مفهوم را بهتر متوجه شوید:

.one {
   color: red;
}
.two {
   color: green;
}
.three {
   @extend .one;
}

اگر المنتی به مانند زیر در HTML خود داشته باشید، با خروجی متفاوت از انتظاراتتان مواجه خواهید شد:

<div class="three two">test</div>

شما ممکن است تصور کنید که کلاس با نام three برنده‌‌ی نوع رنگ متن این المنت باشد؛ چرا که در SASS بعد از تعریف کلاس two آورده شده است. اما به این نکته توجه داشته باشید که کلاس three در حال extend کردن کلاس one است. پس خروجی کامپایل شده‌ی قطعه کد SASS بالا، چیزی شبیه به کد زیر است:

.one, .three {
  color: red;
}

.two {
  color: green;
}

حال بهتر متوجه شدیم که چرا کلاس two اولویت بالاتری در استایل‌دهی نسبت به کلاس three دارد. پس در نهایت رنگ المنت HTML امان سبز خواهد بود.

مراقب خروجی‌های بسیار حجیم باشید

ما در این بخش می‌خواهیم به یک سناریو که ممکن است در استفاده‌ی شما از extend بروز دهد بپردازیم؛ این سناریو توسط Nicole Sullivan بررسی شده است:

  • شما برای clearfix یک کلاس placeholder تشکیل داده‌اید.
  • شما یک کلاس ماژول عمومی که کلاس clearfix را extend می‌کند، تشکیل داده‌اید.
  • شما کلاس‌های دیگری را تشکیل می‌دهید که هرکدام کلاس module را نیز extend کرده‌اند. (از extend های زنجیره‌وار استفاده می‌کنید)
%clearfix {
  &:before,
  &:after {
    content: " ";
    display: table;
  }
  &:after {
    clear: both;
  }
}

.module {
  padding: 10px;
  @extend %clearfix;
  h3 {
    color: red;
    @extend %clearfix;
    span {
      float: right; 
    }
  }
}

.sports {
  @extend .module;
}

.news {
  @extend .module; 
}

حال شما را به مشاهده‌ی خروجی حجیم قطعه کد بالا در css خام دعوت می‌کنم:

.module:before, .sports:before, 
.news:before, .module h3:before, 
.sports h3:before, .news h3:before, 
.module:after, .sports:after, 
.news:after, .module h3:after, 
.sports h3:after, .news h3:after {
  content: " ";
  display: table;
}
.module:after, .sports:after, 
.news:after, .module h3:after, 
.sports h3:after, .news h3:after {
  clear: both;
}

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

در این‌جا می‌شود یک قانون ساده‌ی کلی دیگر نیز معرفی کرد:

تکنیکی را استفاده کنید که کم‌ترین میزان خروجی کد CSS خام را به همراه خواهد داشت.

مراقب media query ها باشید

هیچ‌ یک از زبان‌ها به شما اجازه‌ی extend کردن از درون یک مدیا کوئری به یک انتخاب‌گر در بیرون آن مدیا کوئری را نمی‌دهند. در این مورد نیز نظر شما به مثال زیر جلب می‌کنم که به خوبی کار خواهد کرد:

@media (max-width: 100px) {
  .module {
    padding: 10px;
  }
  .news {
    @extend .module;
  }
}

اما قطعه کد زیر دچار مشکل خواهد شد و صحیح نیست:

.module {
  padding: 10px;
}

@media (max-width: 100px) {
  .news {
    @extend .module;
  }
}

آینده‌ی Extend

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

.module {
  padding: 10px;
}
.news {
  !extend .module;
}

در کد بالا از @extend استفاده نکرده‌ایم چرا که این علامت معنای خاص خود را در css دارد.

در قسمت نظرات این مطلب می‌توانید نظراتتان راجع به extend و تجریباتتان در استفاده از آن در پیش‌پردازنده‌های css را با ما به اشتراک بگذارید.

منبع

چه امتیازی برای این مقاله میدهید؟

خیلی بد
بد
متوسط
خوب
عالی
4.5 از 2 رای

1 سال پیش
css
/@BAbolfazl

Front-End

دیدگاه و پرسش

برای ارسال دیدگاه لازم است وارد شده یا ثبت‌نام کنید

ورود یا ثبت‌نام

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

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

ابوالفضل باغشاهی

Front-End