راهنمای کامل rem و em در css

Em یا Rem؟ (قسمت اول)

در مطلب قبل توضیح داده شد که این واحدهای نسبی چه هستند و چگونه عمل می کنند. حال در این مطلب به دنبال جواب دادن به این سوال هستیم که “از کدام یک از این واحدها باید استفاده کنیم؟“. آیا اصلا این سوال درست است؟

 

پای سفره ماژولاریان!

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

به عنوان مثال دموی زیر را در نظر بگیرید:

 

See the Pen Circular Menu by Mojtaba Seyedi (@seyedi) on CodePen.

 

منوی بالا یه کامپوننت است (یا حداقل دوس داره که باشه 🙂 ) که می تواند در پروژه های مختلف مورد استفاده قرار بگیرد. شاید اندازه این منو و آیتم هایش در نظر شما کوچک و یا بزرگ باشد و بخواهید اندازه آن را تغییر دهید در اینجا اگر واحدهای اندازه px بودند شما با یک کار طاقت فرسا مواجه بودید به این دلیل که مکان تمام آیتم ها باید دوباره مشخص و اندازه گیری می شد. اما الان که واحدها em هستند کافی است اندازه فونت عنصر اصلی را تغییر دهید تا تمام منو و جزییاتش به صورت یکنواخت کوچک یا بزرگ شود. پس در اینجا تنها با اعمال یک خط قادر به تغییر اندازه خواهید بود.

فرض کنید می خواهیم منو را کمی کوچک تر کنیم کافی است بنویسیم:

 


.circular-menu {
  font-size: 13px;
}

 

ساخت این کامپوننت در این مطلب توضیح داده شده است.

حال متوجه قدرت واحدهای نسبی مثل em و rem می شویم.

 

کدام یک؟

بعضی از طراحان به هیچ عنوان از rem استفاده نمی کنند, آنها به این باور هستند که استفاده از rem باعث می شود تا کامپوننت هایشان کمتر ماژولار باشند به همین دلیل فقط از em استفاده می کنند. اما گروهی دیگر به دلیل اینکه کار با em کمی پیچیدگی محاسبه دارد, برای جلوگیری از این پیچیدگی فقط از rem استفاده می کنند.

Zell Liew در بلاگ خود نوشته است: “دوره ای در کارم فقط از em استفاده کردم و دوره ای فقط از rem که em به ماژولار نویسی خیلی کمک می کرد و rem به سادگی کار”. جالب است بدانید که وی هردوی این موارد را دام می داند.

پس از مدتی استفاده از این واحدها همه ما به این نتیجه می توانیم برسیم که هر کدام نقاط قوت و ضعف مخصوص به خود را دارند.

وی در این پست با بررسی چند مثال به دنبال روشن کردن این موضوع است که باید با استفاده مناسب از هر کدام بنا به شرایط موجود, از قدرت هر دو بهره ببریم. و روش کاری خود را با دو قانون بیان می کند:

  1. اگر ویژگی با توجه به font-size باید کوچک و یا بزرگ شود از em استفاده کنید.
  2. بقیه ویژگی ها را با rem بنویسید.

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

 

فقط با استفاده از Rem

فرض کنید یک عنصر شبیه به تصویر زیر داریم:

 
استفاده از rem
 

اگر بخواهیم فقط از rem استفاده کنیم, خواهیم داشت:

 


.header {
  font-size: 1rem;
  padding: 0.5rem 0.75rem;
  background: #7F7CFF;
}

 

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

 


<a href="#" class="header header--large">header!</a>

 

(به نحوه نوشتن کلاس ها توجه کنید. از روش BEM استفاده شده است که در آینده حتما بصورت مفصل در موردش بحث خواهیم کرد. اما بطور خلاصه: اگر بخواهیم پروژه را طوری پیاده سازی کنیم تا بتواند به راحتی گسترش پیدا کند و هر چه پروژه بزرگتر می شود کد نویسی راحتر شود نه سخت تر (از آنجا که خیلی از اجزا تکراری خواهند شد) باید یک روش مناسب برای انتخاب کلاس هایمان داشته باشیم. BEM یکی از این روش ها برای انسجام دادن به نام گذاری کلاس ها می باشد که به ماژولار نویسی هم کمک می کند. )

 

در CSS خواهیم داشت:

 


.header {
  font-size: 1rem;
  padding: 0.5rem 0.75rem;
  background: #7F7CFF;
}

.header--large {
  font-size: 2rem;
}

 

متاسفانه همانطور که در تصویر زیر می بینیم خروجی برای عنصر header--large. مناسب نشد. چرا که فاصله بین متن و لبه های عنصر خیلی کم شد:

 
استفاده از rem در css
 

اگر اصرار داشته باشیم که همچنان از rem استفاده کنیم باید ویژگی padding را هم برای عنصر جدید باز نویسی کنیم.

 


.header {
  font-size: 1rem;
  padding: 0.5rem 0.75rem;
  background: #7F7CFF;
}

.header--large {
  font-size: 2rem;
  padding: 1rem 1.5rem;
}

 

rem در css

 

بله به خروجی مناسب رسیدیم, اما به چه قیمتی؟

همانطور که ملاحظه می کنید مقادیر ویژگی های font-size و padding برای عنصر جدید دو برابر شدند. چه می شود اگر تعداد عناصر مشابه به این هدر که قرار است با اندازه متفاوت در پروژه ظاهر شوند بیشتر شود؟ بله, هر بار باید ویژگی های مختلف را برای هدر جدید دیگر باز نویسی کنیم.

پس واضح است که استفاده از rem باعث تکرار کد می شود و قانون Don’t Repeat Yourself) DRY (خودتو تکرار نکن دیگه 🙂 ) ) رعایت نخواهد شود. و همینطور پیچیدگی کد زیاد می شود.

اگر em را وارد بازی کنیم به راحتی می توانیم بدون باز نویسی ویژگی padding به خروجی مناسب برسیم:

 


.header {
  font-size: 1rem;
  padding: 0.5em 0.75em;
  background: #7F7CFF;
}

.header--large {
  font-size: 2rem;
}

 

(البته با توجه به خوندن این پست این مطلب رو می دونید ولی باز هم برای یادآوری میگم:)

زمانی که از em استفاده می کنیم اندازه عناصر, وابسته به font-size همان عنصر و اجداد آن می شود پس هر بار که font-size عنصر تغییر کند ویژگی هایی که با em نوشته شده اند به همان نسبت تغییر می کنند.

پس تا الان به مفید بود قانون اول (اگر ویژگی با توجه به font-size باید کوچک و یا بزرگ شود از em استفاده کنید) پی بردیم.

 

فقط با استفاده از Em

در این مورد پیاده سازی با آخرین کدی که دیدیم خیلی تفاوت ندارد جز اینکه باید remها تبدیل به em شوند:

 


.header {
  font-size: 1em;
  padding: 0.5em 0.75em;
  background: #7F7CFF;
}

.header--large {
  font-size: 2em;
}

 

در اینجا هر دو عنصر header. و header--large. کاملا شبیه به زمانی خواهند بود که از rem استفاده کردیم.

 

همین دیگه, تموم شد؟

 

نه 🙂

 

خیلی کم پیش می آید که در یک پروژه فقط یک هدر داشته باشیم, پس باید عناصر را در کنار هم نیز بررسی کنیم.

الگویی که در تصویر زیر مشاهده می کنید در صفحات وب کاملا رایج است

 

استفاده از em و rem در css

 

 


<div class="header header--large">A Header Element</div>
<p>A paragraph of text</p>
<p>A paragraph of text</p>
<div class="header">A Header Element</div>
<p>A paragraph of text</p>

 

برای استایل نیاز داریم تا کمی margin به سمت چپ و راست عنصر پاراگراف اضافه کنیم:

 


p {
  margin-left: 0.75em;
  margin-right: 0.75em;
}

 

خروجی بصورت زیر خواهد بود:

 

em در سی اس اس

 

🙁

متاسفانه padding سمت چپ و راست برای عنصر header--large. خیلی زیاد است و باعث شده است تا چیدمان زشت بنظر برسد, چراکه شروع خطوط در یک راستا نیستند.

اگر برای استفاده از em پافشاری کنیم باید padding-left و padding-right را برای عنصر بزرگتر بصورت جداگانه بازنویسی کنیم:

 


.header {
  font-size: 1em;
  padding: 0.5em 0.75em;
}

.header--large {
  font-size: 2em;
  padding-left: 0.375em;
  padding-right: 0.375em;
  margin: 0.75em 0; 
}

 

استفاده از em و rem در css
 

اما به دلیل نکاتی که در مورد بالا گفته شد این کار روش مناسبی نیست پس بهتر است به جای لجبازی از واحد عزیزی به نام rem کمک بگیریم:

 


.header {
  padding: 0.5em 0.75rem; /* Em   Rem */
  font-size: 1em;
  background: #7F7CFF;
}

.header--large {
  font-size: 2em;
}

 

همانطور که می دانید rem وابسته به font-size عنصر ریشه (html) است پس با تغییر اندازه font-size عنصر header--large. خروجی برای padding چپ و راست تغییر نخواهد کرد.

 

تا اینجا با دو کارآمد زیر آشنا شدیم که چون قانون های تجربی هستند احتمال اینکه موارد نقض پیدا کنند وجود دارد که بهتر است اگر موردی پیش آمد باهم به اشترک بگذاریم.

  1. اگر ویژگی با توجه به font-size باید کوچک و یا بزرگ شود از em استفاده کنید.
  2. بقیه ویژگی ها را با rem بنویسید.

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