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

  • زمان را از دست می دهیم.
    وقتی باید نگران عوارض جانبی باشیم، تغییرات بیشتر طول می کشد.
  • ما باگ ایجاد می کنیم.
    نمونه مورد علاقه من یک فروشگاه آنلاین است که در آن دکمه های “خرید” به دلیل استفاده نادرست از واحدهای دید پنهان شده بودند.
  • ما ویژگی های کمتری می سازیم.
    وقتی تغییرات ترسناک و وقت گیر هستند، اغلب اتفاق نمی افتد.

بیایید ببینیم چگونه می‌توانیم بهترین شیوه‌ها و ایده‌ها را از نوشتن توابع جاوا اسکریپت خوب برای نوشتن CSS که استفاده آسان، عاری از عوارض جانبی ناخواسته و انعطاف‌پذیر در برابر تغییر است، وام بگیریم.

جلوگیری از عوارض جانبی ناخواسته

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

بیایید به عنوان مثال به این نماد فلش در یک دایره نگاه کنیم:

نماد پیکان سمت راست که در یک دایره نشسته است
(پیش نمایش بزرگ)

خوب به نظر می رسد، اما بیایید بگوییم که ما یک نماد فلش باریک تر می خواهیم:

فلش سمت راست در یک بیضی تخم مرغی شکل
(پیش نمایش بزرگ)

حالا دایره حاوی له شده است! این نمونه ای از عوارض جانبی ناخواسته است. استفاده از یک فلش باریکتر شکل دایره را خراب می کند.

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

فلش سمت راست در یک بیضی تخم مرغی شکل با راهنماهای پد نمایش داده شده است
(پیش نمایش بزرگ)

در حالت ایده آل، نماد داخلی نباید شکل دایره حاوی را تغییر دهد. در اینجا یک نسخه نمایشی از نحوه تعمیر نماد له شده آورده شده است:

قلم را ببینید [Arrow Icon Example [forked]](https://codepen.io/smashingmag/pen/OJBpNMv) توسط یافی.

قلم را ببینید مثال نماد پیکان [forked] توسط یافی.

دو پیشرفت در این مثال وجود دارد:

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

بهبودهای این مثال ممکن است برای هر موردی خوب نباشد. برای مثال، اگر به تغییر شکل و اندازه ظرف با نماد داخلی نیاز دارید، ممکن است نسخه «قبل از» کد برای شما مناسب‌تر باشد.

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

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

بیشتر بعد از پرش! ادامه مطلب زیر ↓

نوشتن کد راحت

پارامترهای تابع در جاوا اسکریپت راه مناسبی برای تعریف ورودی هایی که می خواهید کنترل کنید فراهم می کند. مثل این است که تصمیم بگیرید چه دستگیره هایی را روی تلویزیون قرار دهید.

ما می توانیم CSS بنویسیم که کنترل آن به همین راحتی باشد. برای انجام این کار، بیایید به نحوه جلوگیری از دو مشکلی که ممکن است در هنگام نوشتن یک تابع جاوا اسکریپت با آن مواجه شویم، نگاه کنیم:

  • پارامترهای خیلی زیاد
    تنظیمات بیشتر سربار بیشتری ایجاد می کند و استفاده از آن سخت می شود.
  • پارامترهای کافی نیست
    تنظیمات کمتر ممکن است کنترل کافی را برای موارد استفاده شما فراهم نکند.

پارامترهای خیلی زیاد

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

در اینجا یک عملکرد راحت وجود دارد که استفاده از آن آسان است:

switchLightbulb(ON);

آن را با این عملکرد پیچیده و دردناک مقایسه کنید:

switchLightbulb(getConnectedWires, isCompleteCircuit, setUpBattery, batteryStatus, isUsingWallOutlet, hasPowerOutage, isElectricityBillPaid, etc);

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

ایده مشابهی برای CSS اعمال می شود. فرض کنید کارتی با تصویر، متن عنوان، متن اصلی و یک دکمه داریم. ما می خواهیم به راحتی عرض کارت را تغییر دهیم.

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

.card {
  max-width: 300px;
}

یک روش کمتر راحت، تعریف صریح آن است max-width از هر .card جزء:

.card-image {
  max-width: 300px;
}
.card-title-text {
  max-width: 300px;
}
.card-body-text {
  max-width: 300px;
}
.card-button {
  max-width: 300px;
}

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

پارامترهای خیلی کم

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

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

setCarState({ speed: 60, turnAngleDegrees: 2 });

می‌توانیم مختصرتر باشیم و پارامترها را ترکیب کنیم:

setCarState({ speedAndTurnAngle: 60 });

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

در CSS موارد مشابهی وجود دارد که می خواهیم یک پارامتر را بدون تأثیرگذاری بر دیگری کنترل کنیم. به عنوان مثال، شاید ما یک جزء کارت دیگری داشته باشیم، این بار با یک عکس، نام، بیوگرافی کوتاه و دکمه «بیشتر بخوانید» و می‌خواهیم عرض کارت را بدون تأثیر بر ابعاد عکس تغییر دهیم.

متاسفانه، max-width رویکردی که قبلاً در ظرف کارت استفاده کردیم، پارامترهای بسیار کمی را برای نیازهای ما فراهم می کند:

.card {
  max-width: 300px;
}

همانطور که قبلاً اشاره کردیم، عناصر فرزند کارت با عرض ظرف کارت تا حداکثر سازگار می شوند 300px. این شامل تصویر است که با کوچک شدن عرض ظرف در زیر کوچک می شود 300px.

آنچه ما نیاز داریم یک پارامتر دیگر برای عکس است:

.card {
  max-width: 300px;
}
.photo {
  width: max(150px, 50%);
}

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

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

نوشتن سبک های انعطاف پذیر

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

ما می توانیم تغییراتی از همان سوال را در CSS بپرسیم، مانند:

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

فرض کنید یک طرح داریم با سه کارت که به صورت افقی در یک ظرف چیده شده اند.

طرح سه کارته
(پیش نمایش بزرگ)

مجموعه های CSS max-width: 900px بر روی ظرف، و هر کارت می شود اتاق تنفس کمی با padding: 5vw. این ممکن است در ظاهر خوب به نظر برسد، اما یک مشکل وجود دارد: ظرف دارای یک حاشیه بالایی است در حالی که لایه آن ندارد. با بزرگتر شدن صفحه، محتوا خرد می شود.

قلم را ببینید [Example of padding crushing content [forked]](https://codepen.io/smashingmag/pen/RwepaQQ) توسط یافی.

قلم را ببینید نمونه ای از محتوای خرد کردن لایی [forked] توسط یافی.

راه حل های ممکن عبارتند از:

  • استفاده از نما یا نقاط شکست کانتینر برای تحت کنترل نگه داشتن بالشتک،
  • با استفاده از CSS min() تابعی برای تنظیم یک کران بالای روی بالشتک، یا
  • استفاده از واحدهای ثابت مانند پیکسل ها که به طور نامحدود با پنجره رشد نمی کنند.

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

احمد شادید نام بسیار خوبی برای این تکنیک دارد: CSS دفاعی. ایده این است که ما می‌توانیم سبک‌های «مقاوم در آینده» را با در نظر گرفتن آن‌ها به‌عنوان ورودی‌هایی که یک UI را خروجی می‌دهند و پیش‌بینی موقعیت‌هایی که قابلیت استفاده خروجی را کاهش می‌دهند، در نظر بگیریم.

نتیجه

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

خوشبختانه، همان ایده هایی که به ما در نوشتن توابع خوب کمک می کنند می توانند به ما در نوشتن CSS خوب کمک کنند، یعنی:

  • از عوارض جانبی ناخواسته خودداری کنید.
  • از پارامترهای مناسب استفاده کنید.
  • در نظر بگیرید که چگونه ورودی ها خروجی ها را تغییر می دهند.

چه چیزی این ایده ها را به هم مرتبط می کند، سوالی است که امیدوارم دفعه بعد که CSS می نویسید از خود بپرسید. این طرح چگونه باید به تغییر پاسخ دهد؟

مطالعه بیشتر در SmashingMag

سرمقاله Smashing
(gg, yk, il)