محاسبات مستقیم داخل CSS: calc()، min()، max() و clamp()

وارد فصل پانزدهم شدیم؛ فصلی که به توابع مهم CSS اختصاص داره. در فصل‌های قبل، بارها از calc() و clamp() استفاده کردیم، بدون این‌که مستقل و کامل بررسی‌شون کنیم. حالا وقتشه این چهار تابع پایه‌ای، که همگی برای محاسبات عددی طراحی شدن، رو دقیق و مستقل ببینیم.

calc(): انجام محاسبات ریاضی مستقیم در CSS

.box {
  width: calc(100% - 40px);
}

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

در این مثال، عرض جعبه، دقیقاً برابر «۱۰۰٪ عرض والد، منهای ۴۰ پیکسل» است؛ یعنی مثلاً اگه والد ۵۰۰ پیکسل عرض داشته باشه، این جعبه، ۴۶۰ پیکسل خواهد بود.

چهار عملگر پشتیبانی‌شده در calc()

.a { width: calc(100% - 20px); }  /* تفریق */
.b { width: calc(50% + 10px); }   /* جمع */
.c { width: calc(100% / 3); }     /* تقسیم */
.d { width: calc(20px * 2); }     /* ضرب */

calc() از چهار عملگر پایه ریاضی (+، -، *، /) پشتیبانی می‌کنه.

یک قانون Syntax مهم: فاصله دور + و -

.correct {
  width: calc(100% - 20px); /* درست */
}

.wrong {
  width: calc(100% -20px); /* نادرست؛ خطا ایجاد می‌کند */
}

یکی از رایج‌ترین اشتباهات نحوی: عملگرهای + و -، حتماً باید یک فاصله خالی، هم قبل و هم بعدشون داشته باشن؛ در غیر این‌صورت، مرورگر، عبارت رو نامعتبر تشخیص می‌ده و کل Declaration، نادیده گرفته می‌شه. عملگرهای * و /، این محدودیت رو ندارن.

ترکیب واحدهای مختلف: قدرت اصلی calc()

.sidebar {
  width: calc(25% + 2rem);
}

.full-height-minus-header {
  height: calc(100vh - 80px);
}

در مثال اول، عرضی که ترکیبی از درصد (نسبی به والد) و rem (نسبی به فونت ریشه، از فصل ۶) است؛ در مثال دوم، ارتفاعی که کل صفحه (100vh، از فصل ۶) رو می‌گیره، منهای یک هدر ثابت ۸۰ پیکسلی. این نوع ترکیب، دقیقاً همون چیزیه که بدون calc()، اصلاً امکان‌پذیر نبود.

min(): کوچک‌ترین مقدار از میان چند گزینه

.box {
  width: min(90%, 600px);
}

تابع min()، چند مقدار می‌گیره و همیشه، کوچک‌ترین اون‌ها رو، در هر لحظه، انتخاب می‌کنه. در این مثال، عرض جعبه، همیشه هرکدوم از این دو مقدار (۹۰٪ عرض والد، یا ۶۰۰ پیکسل ثابت) که کوچیک‌تره رو می‌گیره؛ یعنی در صفحه‌نمایش‌های کوچک، ۹۰٪ برنده می‌شه (چون عدد کوچیک‌تریه)، ولی در صفحه‌نمایش‌های بزرگ، همون ۶۰۰ پیکسل ثابت، سقف رو تعیین می‌کنه (چون از ۹۰٪ کوچیک‌تر می‌شه).

max(): بزرگ‌ترین مقدار از میان چند گزینه

.box {
  width: max(300px, 50%);
}

تابع max()، برعکس min()، همیشه بزرگ‌ترین مقدار رو انتخاب می‌کنه. در این مثال، عرض جعبه، هیچ‌وقت از ۳۰۰ پیکسل کمتر نمی‌شه؛ حتی اگه ۵۰٪ عرض والد، کمتر از این مقدار باشه.

clamp(): ترکیب min() و max() در یک تابع

.box {
  width: clamp(300px, 50%, 600px);
}

همون‌طور که در فصل‌های ۸ و ۱۴ کامل دیدیم، clamp(min, preferred, max)، در واقع، معادل نوشتن max(min, min(preferred, max)) است؛ یعنی مقدار وسط رو انتخاب می‌کنه، ولی هیچ‌وقت اجازه نمی‌ده از حداقل کمتر یا از حداکثر بیشتر بشه.

یک جدول مقایسه‌ای برای این سه تابع

تابع رفتار تعداد پارامتر
min() کوچک‌ترین مقدار را انتخاب می‌کند دو یا بیشتر
max() بزرگ‌ترین مقدار را انتخاب می‌کند دو یا بیشتر
clamp() مقدار وسط را، بین یک حداقل و حداکثر مشخص، محدود می‌کند دقیقاً سه (حداقل، ترجیحی، حداکثر)

تودرتو کردن این توابع در calc()

.box {
  width: calc(min(600px, 90%) - 20px);
}

می‌شه این توابع رو، داخل هم یا داخل calc()، تودرتو کرد. در این مثال، ابتدا کوچک‌ترین مقدار بین ۶۰۰ پیکسل و ۹۰٪ محاسبه می‌شه، و بعد، ۲۰ پیکسل از اون کم می‌شه.

یک کاربرد عملی: فاصله‌گذاری واکنش‌گرا بدون Media Query

.container {
  padding-inline: max(16px, 5%);
}

این الگو، تضمین می‌کنه که Padding افقی، هیچ‌وقت از ۱۶ پیکسل کمتر نشه (حتی در صفحه‌نمایش‌های خیلی کوچک)، ولی در صفحه‌نمایش‌های بزرگ‌تر، به‌طور نسبی (با ۵٪)، رشد کنه.

نکات مهم

  • calc() اجازه ترکیب واحدهای متفاوت (مثل درصد و پیکسل) را، در یک عبارت ریاضی واحد، می‌دهد؛ عملگرهای + و -، حتماً باید فاصله داشته باشند.
  • min() کوچک‌ترین و max() بزرگ‌ترین مقدار را از میان چند گزینه انتخاب می‌کنند.
  • clamp(min, preferred, max) در واقع ترکیبی از min() و max() است و مقدار وسط را بین یک حداقل و حداکثر محدود می‌کند.

اشتباهات رایج

  • فراموش کردن فاصله قبل و بعد از عملگرهای + و - داخل calc()، که باعث نامعتبر شدن کل عبارت می‌شود.
  • قاطی کردن min() و max()؛ اولی کوچک‌ترین، دومی بزرگ‌ترین مقدار را انتخاب می‌کند.
  • فراموش کردن این‌که clamp() دقیقاً سه پارامتر می‌پذیرد، نه دو یا بیشتر.

جمع‌بندی

calc() امکان انجام محاسبات ریاضی مستقیم، حتی با ترکیب واحدهای متفاوت، را در CSS فراهم می‌کند. min() و max()، به‌ترتیب، کوچک‌ترین و بزرگ‌ترین مقدار را از میان چند گزینه انتخاب می‌کنند، و clamp()، با ترکیب این دو، یک مقدار را بین یک حداقل و حداکثر مشخص محدود می‌کند؛ این چهار تابع، ابزارهای پایه‌ای برای محاسبات پویا و واکنش‌گرا در CSS مدرن هستند.