در هر پروژهای، به خصوص پروژههای بزرگ یا پروژههایی که افراد مختلفی روی آن کار میکنند خیلی مهم است که ساختار درست و استاندارد، پیاده سازی شود که با گسترش پروژه و یا تغییر تیم ضربهایی به پروژه وارد نشود و بتوان پروژه را به راحتی گسترش داد و بروزرسانی کرد. البته خاصیت دیگر درست کردن ساختار فایلها و نوع نوشتار کدها، سرعت بارگذاری و پردازش فایلها در مرورگر است، که قطعا وقتی بحث موبایل هم مطرح باشد خیلی خیلی مهم میشود.
این راهها شامل موارد مختلفی میشود مانند ساختاربندی فولدرهای پروژه، نام گذاری کلاس ها و قوانین استفاده از کلاسها و IDها، شیوه و ترتیب نوشتن و خیلی چیزهای دیگر که دوست دارم وقت بشود راجب این موارد در صحبت کنیم.
یکی از این کارهای موثر، پیادهسازی مفاهیم Object Oriented CSS است که به طور خیلی ساده، OOCSS یعنی جدا کردن قسمتهای مختلف: ساختار، طراحی و … و پرهیز از تکرار کدها.
خیلی وقتها پیش میآید که قسمت زیادی در کدها و یا حتی پروژههای مختلف تکرار میشود. این موضوع اصلی این مطلب هست که روشهای مختلفی برای حل این مسله داریم.
دو راه حل کلی برای حذف تکرار کدهای CSS وجود دارد:
- ایجاد تغییرات در نامهای کلاسها در فایل HTML
- تغیر در ساختار نوشتار CSS
یک مثال ساده مطرح میکنم: من برای نمایش لوگو سایتها عکس را به عنوان بکگراند المان(در هدر مثلا h1 و در فوتر span) قرار میدهم و با این کار میتونم نام سایت را هم درون تگ HTML بنویسم. و سپس با استفاده از CSS آن نام را از نمایش کاربر مخفی نگه میدارم و تنها برای موتورهای جستجو خوانایی دارد.
خب برای هر عکسی که بخواهم این کار را بکنم (لوگو هدر، لوگو فوتر و …) باید این کد HTMLنوشته:
<h1 class="header__logo">Header Logo</h1> <span class="footer__logo">Footer Logo</span>
و این کدهای CSS تکرار شود:
.header__logo {
background: url("header-orginal-logo.png") no-repeat 0 0;
width: 150px;
height: 113px;
text-indent: -9999px;
line-height: 1px;
font-size: 1px;
overflow: hidden;
display: block;
}
.footer__logo {
background: url("footer-black-logo.png") no-repeat 0 0;
width: 75px;
height: 56px;
text-indent: -9999px;
line-height: 1px;
font-size: 1px;
overflow: hidden;
display: block;
}
ایجاد تغییرات در نامهای کلاسها در فایل HTML
همانطور که میبینید قسمت زیادی از این کد تکرار شده و هم کار توسعه و بروزرسانی پروژه را سخت میکند و هم حجم فایل را زیاد میکند.
در روش اول ما میتوانیم استایلهای مشترک را در یک کلاس جدا به عنوان مثال helper–text-hidden قرار دهیم و سپس در جاهای مختف آن را صدا بزنیم. اول استایل جدید را مینویسیم:
.helper--text-hidden {
text-indent: -9999px;
line-height: 1px;
font-size: 1px;
overflow: hidden;
display: block;
}
.header__logo {
background: url("header-orginal-logo.png") no-repeat 0 0;
width: 150px;
height: 113px;
}
.footer__logo {
background: url("footer-black-logo.png") no-repeat 0 0;
width: 75px;
height: 56px;
}
سپس فایل مارکآپ را تغیر میدهیم به:
<h1 class="header__logo helper--text-hidden">Header Logo</h1> <span class="footer__logo helper--text-hidden">Footer Logo</span>
این روش، روش خوبیست ولی باز بستگی به پروژه دارد. معمولا برای ما تغییرات زیاد در ساختار HTML به دلیل استفاده از CMSها و دردسرهایی که ممکن است بوجود بیاید خیلی امکانپذیر نیست و ترجیح میدیم از روش دوم یعنی تغییر در ساختار CSS استفاده کنیم که محدودیتی در استفاده از آن نداریم.
تغیر در ساختار نوشتار CSS
در اولین روش این قسمت، با استفاده از CSS خالص قسمت مشترک را جدا میکنیم:
.header__logo,
.footer__logo {
text-indent: -9999px;
line-height: 1px;
font-size: 1px;
overflow: hidden;
display: block;
}
.header__logo {
background: url("header-orginal-logo.png") no-repeat 0 0;
width: 150px;
height: 113px;
}
.footer__logo {
background: url("footer-black-logo.png") no-repeat 0 0;
width: 75px;
height: 56px;
}
این روش درستی است که بدون نیاز به تغیر نام کلاسها در HTML مشکل را حل می کند. اما در پروسه توسعه مشکلی که بوجود می آورد این است که اگر از این کد جاهای مختلفی استفاده شود این اتفاق گیج کننده خواهد افتاد:
.header__logo,
.footer__logo,
.class-name__x,
.class-name__y,
.class-name__z {
/* Repeated styles */
}
برای حل این مشکل در پروسه توسعه قابلیت فوقالعادهای در Sass وجود دارد به نام Extend که همین کار را به زیبایی انجام میدهد و به صورتهای خیلی پیچیدهتری هم میشود ازش استفاده کرد(باید مراقب استفاده از خاصیت @extend باشید! استفاده غلط و نابجا از این باعث ایجاد کدهای زیاد میشود). با استفاده از این روش کلاسها میتوانند از ویژگیهای یک کلاس ارث ببرند. کد بالا را میتوانیم به این صورت بنویسیم:
.helper--text-hidden {
text-indent: -9999px;
line-height: 1px;
font-size: 1px;
overflow: hidden;
display: block;
}
.header__logo {
background: url("header-orginal-logo.png") no-repeat 0 0;
width: 150px;
height: 113px;
@extend .helper--text-hidden;
}
.footer__logo {
background: url("footer-black-logo.png") no-repeat 0 0;
width: 75px;
height: 56px;
@extend .helper--text-hidden;
}
که بعد از کامپایل فایل scss خروجی زیر برگردانده میشود:
.helper--text-hidden,
.header__logo,
.footer__logo {
text-indent: -9999px;
line-height: 1px;
font-size: 1px;
overflow: hidden;
display: block;
}
.header__logo {
background: url("header-orginal-logo.png") no-repeat 0 0;
width: 150px;
height: 113px;
}
.footer__logo {
background: url("footer-black-logo.png") no-repeat 0 0;
width: 75px;
height: 56px;
}
در این روش فقط کافی هست هرجا بخواهیم استایلهای مشترک اعمال شود عبارت @extend به علاوه اسم کلاس را درون کلاس مورد نظر بنویسیم و اینطوری نام آن کلاس در کنار کلاسهای قرار میگیرد که آن ویژگی مشترک خاص را دارند.

اما همانطور که میبینید یک کلاس اضافه ایجاد شده است(.helper–text-hidden) که جایی استفاده نخواهد شد. برای حذف این کلاس و استفاده از قابلیت اکستند به سراغ ویژگی دیگری در Sass به نام Placeholder Selectors میرویم یا کلاسهای خاموش. این نوع Selector برای حل همین مشکل درست شده است در واقع اگر شما به این روش کدی را تعریف کنید آن کد مستقیم در خروجی نمایش داده نمیشود مگر از آن @extend شود.
برای تعریف Placeholder Selectors فقط کافی است همانند تعریف کلاس یا ID عمل کنید با این تفاوت که به جای نقطه یا # از علامت % استفاده کنید. مثال بالا را با این تغییر بروز میکنم:
%helper--text-hidden {
text-indent: -9999px;
line-height: 1px;
font-size: 1px;
overflow: hidden;
display: block;
}
.header__logo {
background: url("header-orginal-logo.png") no-repeat 0 0;
width: 150px;
height: 113px;
@extend %helper--text-hidden;
}
.footer__logo {
background: url("footer-black-logo.png") no-repeat 0 0;
width: 75px;
height: 56px;
@extend %helper--text-hidden;
}
تغیری که در کد خروجی ایجاد میشود، حذف کلاس اضافهی helper–text-hidden است:
.header__logo,
.footer__logo {
text-indent: -9999px;
line-height: 1px;
font-size: 1px;
overflow: hidden;
display: block;
}
.header__logo {
background: url("header-orginal-logo.png") no-repeat 0 0;
width: 150px;
height: 113px;
}
.footer__logo {
background: url("footer-black-logo.png") no-repeat 0 0;
width: 75px;
height: 56px;
}
این بهترین روش برای جدا کردن CSSهای مشترک است اما همه چیز اینجا تمام نمیشود!
ما بر اساس نوع کد و پروژه میتوانیم از خلاقیت خودمون برای ساختارمندتر کردن کدها استفاده کنیم به عنوان مثال، در کد بالا قسمت مشترک دیگری وجود دارد که برای تعریف لوگو ها استفاده شده است. آن ویژگیهای width و height است که از الزامات کد برای مخفی نمودن متن و نمایش عکس است.
اما ویژگیهای مشترک width و height بر اساس اندازه عکسها در کلاسهای مختلف متفاوت هست و نمیتوان آنها را در کلاسهای خاموش اکستند استفاده کرد.(به دلایل متفاوتی background را جز ویژگیهای مشترک در نظر نگرفتم. شما میتونید بر اساس کد خود ایدهی این میکسین را پیاده سازی کنید)
کاری که میخواهم بکنم تعریف یک Mixin و استفاده از اکستند درون آن است. کد هیجان انگیز زیر را ببینید:
%helper--text-hidden {
text-indent: -9999px;
line-height: 1px;
font-size: 1px;
overflow: hidden;
display: block;
}
@mixin text-hidden($width, $height) {
@extend %helper--text-hidden;
width: $width;
height: $height;
}
.header__logo {
background: url('header-orginal-logo.png') no-repeat 0 0;
@include text-hidden(150px, 113px);
}
.footer__logo {
background: url('footer-black-logo.png') no-repeat 0 0;
@include text-hidden(75px, 56px);
}
همانطور که در کد بالا میبینید قسمتی که کاملا تکراری است درون یک Placeholder Selector قرار گرفته است و ویژگیهای مشترکی که تنها مقدار آنها فرق دارد درون میکسین قرار داده شده است و مقدرا ها به عنوان ورودی میکسین گرفته میشود. و قسمت تکرار شده(Placeholder Selector: %helper–text-hidden) درون خود میکسین فقط @extend میشود.
در آخر میتوان این میکسین را درون کلاسها include کرده و خروجی دقیقا همانند کد CSS قبلی میشود با این تفاوت که کار توسعه ساختار مرتبتری پیدا کرده است.
- برای تست کدها به این صفحه مراجعه کنید: استفاده از @extend درون @mixin
- و فایلهای نهایی این مطلب را از این صفحه دانلود کنید:
Using @extend in a @mixin for OOCSS Structre
خیلی خوب بود، البته less هم اکستند رو داره :)
مطلب بسیار خوبی بود
موفق باشی
پیرشی جوون. مطمئنن من از کلی فک زدن نجات دادی با این مطلبت :)(تنبلی ما در مستند کردن و تنبلی دوستان در گوگل کردن)
راستی نیستی دیگه!؟ انقدر عمیق نشو توی این پروژه ها، اونایی که رفتن، برگشتنا! :دی
:)) من مخلصم درگیر جای زندگانی و کار بودم، کم کم پیدام میشه دوباره :)
خیلی خیلی خوب بود
مرسی پرهام ! واقعا خوب بود !
هر روز دارم بیشتر میفهمم که sass چی داره که less نداره !
خیلی خوب بود مرسی پرهام. جالب ترین جاش هم اون قسمتی بود که توی یه mixin یه class رو extend کردی !!! تا الان فکر میکردم برای mixin ها فقط باید متغیر تعریف کرد و ورودی ارسال کرد.
خیلی عالی بود
ممنون
مطالب به روز و کامله