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

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

در ادامه قسمت اول این مطلب به دنبال این هستیم تا با بررسی کامپوننت ها در کنار هم در یک سیستم گرید (grid) با نحوه استفاده مناسب از دو واحد em و rem بیشتر آشنا شویم.

در مطلب قبل چند عنصر را در کنار هم قرار داده و نکاتی را در مورد آنها بررسی کردیم. در اینجا از همان عناصر کامپوننت زیر را می سازیم:

 
ایجاد یک کامپوننت
 

HTML برای این کامپوننت بصورت زیر است:

 


<div class="component">
  <div class="component__header">A header element</div>
  <p>Some paragraph text</p>
</div>

 

استایل های اولیه در زیر نمایش داده شده اند:

 


.component {
  background: white;
  border: 2px solid #7F7CFF;
}

.component__header {
  font-size: 2em;
  padding: 0.5em 1.5rem;
  background: #7F7CFF;
  margin: 0;
}

.component p {
  padding-left: 1.5rem;
  padding-right: 1.5rem;
  margin: 1.5rem 0;
}

 

همانطور که در تصویر زیر نشان داده شده است, این کامپوننت می تواند در قسمت های مختلف سایت مثل قسمت محتوای اصلی, sidebar و یا در قسمت های چند ستونه و غیره نمایش داده شود:

 
مکان های ممکن برای نمایش کامپوننت
 

شاید بهتر باشد عنصر مربوط به عنوان کامپوننت (هدر) زمانی که در قسمت sidebar قرار می گیرد, چون محیط اطرافش باریک تر است, کمی کوچک تر ظاهر شود:

 
قرار دادن کامپوننت در sidebar
 

می توانیم برای رسیدگی به این کار, یک گونه دیگر از این کامپوننت را با استفاده از یک کلاس مخصوص به خود بوجود آوریم:

 


<div class="component component--small">
  <!-- محتوای کامپوننت -->
</div>

 

و استایل برای کامپوننت با ظاهر کوچک بصورت زیر خواهد بود:

 


.component--small .component__header {
  font-size: 1em;
}

 

تا الان دو قانونی که در مطلب قبل بررسی کردیم باز هم اعمال شده اند.

همانطور که برای عنصر عنوان (component__header.) مشاهده می کنید ویژگی هایی با em مقدار دهی شدند که با بقیه اجزا صفحه تعامل دارند.

ساخت کامپوننت بر اساس این دیدگاه با دو روش انجام می شود:

  1. ویژگی های همه عناصر داخلی کامپوننت بر اساس font-size کامپوننت بزرگ یا کوچک می شوند.
  2. ویژگی های برخی عناصر داخلی کامپوننت بر اساس font-size کامپوننت بزرگ یا کوچک می شوند.

در ادامه کامپوننت منظور را بر اساس دو مورد بالا می سازیم تا مطلب روشن شود:

 

مورد اول: ویژگی های همه عناصر داخلی کامپوننت بر اساس font-size کامپوننت تغییر می کنند

اول ببینیم که چنین کامپوننتی به چه شکل است:

 

تغییر اندازه اجزا کامپوننت در شرایط مختلف

 

توجه کنید که چگونه padding, font-size و margin همه اجزا و عناصر کامپوننت تغییر می کند. اگر می خواهیم که کامپوننت ما در صفحه نمایش های مختلف اینگونه رفتار کند باید همه چیز را em مقدار دهی کنیم:

 


.component {
  background: white;
  border: 2px solid #7F7CFF;
}

.component__header {
  font-size: 2em;
  padding: 0.5em 0.75em; /* Rem --> Em */
  background: #7F7CFF;
  margin: 0;
}

.component p {
  padding-left: 1.5em; /* Rem --> Em */
  padding-right: 1.5em; /* Rem --> Em */
  margin: 1.5em 0; /* Rem --> Em */
}

// شکل کوچک کامپوننت 
.component--small .component__header {
  font-size: 1em;
  padding-left: 1.5em; /* Added em padding */
  padding-right: 1.5em; /* Added em padding */
}

 

و فقط برای تغییر اندازه اجزا کامپوننت در صفحه نمایش مختلف کافی است بصورت زیر عمل کنیم:

 


.component {
  // Other styles
  @media (min-width: 800px) {
    font-size: 1.5em;
  }
}

 

تغییر اندازه اجزا کامپوننت در شرایط مختلف
 

تا الان همه چی ظاهر خوبی دارد. پس بیاییم کمی کار را پیچیده تر کنیم:

فرض کنید گریدی شبیه به گرید زیر داریم و می خواهیم تمام فاصله های بین آیتم های گرید در همه صفحه نمایش ها و دستگاه ها یکسان بماند (به دلیل زیباسازی)

 
گرید ساده برای مثال
 

HTML برای این گرید بصورت زیر خواهد بود:


 


<div class="grid">
  <div class="grid-item"> 
    <div class="component"> <!-- component --> </div> 
  </div>

  <div class="grid-item">
    <div class="component component--small"> <!-- A --> </div>
    <div class="component component--small"> <!-- B --> </div>
  </div>
</div>

 

می خواهیم فاصله 2em بین آیتم های A و B داشته باشیم. از آنجایی که در طرح em را برابر با 16 پیکسل یعنی همان اندازه فونت عنصر ریشه می دانیم, پس در نتیجه فاصله باید 32 پیکسل باشد. چالش اینجا است که کامپوننت ها در اندازه کوچکشان نیز باید این فاصله 32 پیکسلی را داشته باشند, پس داریم:

 


.component {
  /* Other styles */
  @media (min-width: 800px) {
    font-size: 1.25em;
  }
}

.component + .component {
  margin-top: 2em;
}

 

اما نکته اینجا است که فاصله بین دو کامپوننت کوچک در صفحه نمایش بزرگتر از 800px بیشتر از 32 پیکسل می شود.

 
فاصله بین گرید a و b
 

چرا؟

چون ما از emی استفاده کردیم که وابسته به font-size کامپوننت است و اندازه فونت کامپوننت نیز در صفحات بزرگتر از 800px دیگر 1em یعنی همان 16 پیکسل نخواهد بود بلکه بیشتر است (1.25em)

به همین دلیل 2em در اینجا برابر با 2 (1.25 × 16) = 40 پیکسل می شود نه 32 پیکسل.

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

 


.component + .component {
  margin-top: 2rem;
}

 

رفع مشکل فاصله گرید در این مثال
 

دموی زیر برای بررسی بیشتر آماده شده است:

 

See the Pen REM vs EM – Case 1 by Mojtaba Seyedi (@seyedi) on CodePen.

 

در ضمن برای ساخت این گرید از فلکس باکس استفاده شده است که می توانید در همین سایت آموزش فلکس باکس را مطالعه کنید.

و در ضمن این ایده که اندازه فونت عنصر ریشه px باشد و در سطح کامپوننت از rem و برای متن از em استفاده شود در این پست توسط chris coyier بیان شده است.

 

مورد دوم: ویژگی های برخی عناصر داخلی کامپوننت بر اساس font-size کامپوننت تغییر می کنند

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

گاهی نیاز است فقط یک جز از کامپوننت تغییر اندازه داشته باشد و نه همه اجزا آن به عنوان مثال شاید فقط بخواهیم هدر یا عنوان کامپوننت مورد مثال را در صفحه نمایش ها بزرگ کمی بزرگتر نمایش دهیم:

 
بررسی مورد دوم
 

از آنجایی که در مورد دوم فقط می خواهیم عنوان در صفحه نمایش های بزرگتر از 1200px کمی بزرگتر شود با خیال راحت می توانیم همه ویژگی ها را با rem اندازه دهی کنیم به غیر از دو ویژگی padding-top و padding-bottom برای عنصر عنوان این کامپوننت.

 


.component {
  background: white;
  border: 2px solid #7F7CFF;
}

.component__header {
  font-size: 2rem; /* em --> rem */
  padding: 0.5em 1.5rem; /* em --> rem البته نه همه */
  background: #7F7CFF;
}

.component p {
  padding-left: 1.5rem; /* em --> rem */
  padding-right: 1.5rem; /* em --> rem */
  margin: 1.5rem 0; /* em --> rem */
}

.component--small .component__header {
  font-size: 1rem; /* em --> rem */
}

 

به راحتی می توانیم با استفاده از مدیا کوئری اندازه فونت عنصر عنوان را در صفحه نمایش های متفاوت کنترل کنیم:

 


.component__header {
  font-size: 2rem;
  @media (min-width: 1200px) {
    font-size: 3rem
  }
}

.component--small .component__header {
  font-size: 1rem;
  @media (min-width: 1200px) {
    font-size: 1.5rem
  }
}

 

بررسی مورد دوم

 

همانطور که مشاهده می کنید در زمانی که مرورگر را کوچک بزرگ می کنیم فقط عنصر هدر اندازه اش تغییر می کند.

بله این نحوه ساخت کامپوننت بر اساس مورد دوم است :)

دموی زیر را بررسی کنید:

 

See the Pen REM vs EM – Case 2 by Mojtaba Seyedi (@seyedi) on CodePen.


 

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

اگر از پیش پردازنده ها استفاده می کنید بهتر است همیشه font-size را بصورت انتزاعی تنظیم کنید و از آن در کامپوننت ها استفاده کنید:

 


h2 { 
  font-size: 2rem;
  @media (min-width: 1200px) {
    font-size: 3rem
  } 
}

h3 { 
  font-size: 1rem; 
  @media (min-width: 1200px) {
    font-size: 1.5rem
  }
}

.component__header { @extend h2; }
.component--small .component__header { @extend h3; }

 

همچنین نویسنده این مطلب توضیح می دهد که اگر بپرسید کدام یک از این دو روش بهتر است؟ جواب این خواهد بود که کاملا وابسته به طرح و ظاهر پروژه دارد.

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

 

حرف آخر

زمان این رسیده است که جواب این سوال که از کدام یک از واحدهای em و rem باید استفاده کنیم را بیان کنیم.

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

همچنین همیشه مراقب پشتیبانی مرورگرها در مورد rem باشید. البته خالی از لطف نیست تا پلی فیلی برای مرورگرهایی که این واحد را پشتیبانی نمی کنند معرفی کنیم:

10 دیدگاه برای “Em یا Rem؟ (قسمت دوم)

  1. عالی عالی.
    استفاده از واحد‌های نسبی واقعا کاربردی و دل‌چسبه.
    یکی‌دو روز برای درک کامل و کاربردهای em و rem وقت گذاشتم.
    خیلی باهاشون حال می‌کنم.
    سپاس از آموزش‌های خوب آقای سیدی.
    من کدهای سایتتونو در بخش بازرسی عناصر(inspector) مرورگر فایرفاکس نگاه و دست‌کاری می‌کنم .. این‌جوری هم مطالب گفته‌شده رو درک می‌کنم و هم با کد نویسی استاندارد آشنا می‌شم و الگو می‌گیرم.
    .
    .
    لطفا اگر وقت دارید آموزش sass.scss رو پی بگیرید.

  2. سلام خسته نباشید مطالب بسیار خوبی بود.
    سوالی که برای من همیشه وجود داشته اینه که آبا در زمان تبدیل طرح گرافیکی به طراحی ریسپانسیو ، باید ارتفاع کامپوننت ها رو تنظیم کنیم ؟ یا فقط از padding-top , padding-bottom برای تنظیم ارتفاع استفاده کرد؟
    چون این ارتفاع باید در اندازه ابزار های مختلف متغیر باید و نمیتواند ثابت باشد ؟

    1. سلام، در کل به عنوان یک قانون عمومی (یعنی به غیر از موارد خاص) ارتفاع رو آزاد بذارید، یعنی اجازه بدید ارتفاع رو محتوای داخل یک کامپوننت مشخص کنه.
      ولی در طرح ها و عناصر خاص بسته به موقعیت می تونید از خود ارتفاع و یا حتی padding برای کنترل این موضوع استفاده کنید.

  3. سپاس از آموزش‌های خوبتون!
    یه پرسش
    بنظرتون برای همین ماژولار بودن طراحی بخصوص برای یکساننگه داشتن اندازه های المان ها استفاده از واحد vw برای ویژگیهای font-size,matgin,width و…چه مزایا و معایبی نسبت به em و rem داره؟

    1. بسته به طرحتون داره، در حالت کلی استفاده از واحدهای مربوط به viewport برای ماژولار کردن کار جالبی نیست چون اونجا انتخاب بین عرض یا ارتفاع viewport هم وجود داره و دو تا مجهول دارید. اون واحدها زمانی به کار میان که میخواین طرح سیالی داشته باشید که مثلا با عرض صفحه اندازش تغییر کنه. اون موقع خوب هستش که از واحدهای viewport استفاده کنید.

  4. اندازه فونت کامپوننت نیز در صفحات بزرگتر از 800px دیگر 1em یعنی همان 16 پیکسل نخواهد بود بلکه بیشتر است (1.25em). میشه اینو یه کم بیشتر توضیح بدید؟ من فکر می کردم همیشه فونت سایز پیش فرض 16 پیکسل هست 0o. (کلا اگر مطلب خوبی درباره ی صفحات با سایزهای مختلف توی سایتتون دارید لینک بدید). ممنون از مطالب خوبتون.

سوال داری؟ برو به پنل پرسش و پاسخ

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *