اگر بتوانیم اندازه های مشارکت طراحان را بدون دردسر پیاده سازی کنیم چه؟ اگر بتوانیم نقاط لنگر سفارشی را تنظیم کنیم تا یک مقدار کاملاً پاسخگو ایجاد کنیم و با رویکرد اندازه سیال، گزینه های بیشتری به ما بدهد؟ اگر یک فرمول جادویی داشتیم که کل پروژه را کنترل و هماهنگ می کرد، چه می شد؟
اغلب اتفاق می افتد که من دو قالب را از طراح دریافت می کنم: یکی برای موبایل و دیگری برای دسکتاپ. اخیراً از خودم میپرسم چگونه میتوانم فرآیند را خودکار کنم و نتیجه را بهینه کنم. چگونه اندازه های مشخص شده را به بهترین نحو پیاده سازی کنم؟ چگونه از یک نمای تبلت راحت اطمینان حاصل کنم؟ چگونه می توانم خروجی را برای صفحه نمایش های بزرگ بهینه کنم؟ چگونه می توانم به نسبت های شدید واکنش نشان دهم؟
من دوست دارم بتوانم دو مقدار اندازه های مختلف (فونت، فاصله و غیره) را در پیکسل بخوانم و آنها را به عنوان آرگومان در تابعی وارد کنم که همه کارها را برای من انجام دهد. من میخواهم فرمول جادویی پاسخگو، FabUnit خود را ایجاد کنم.
وقتی در بهار شروع به کار روی این موضوع کردم و FabUnit را راه اندازی کردم، با این مقاله جالب آدریان مواجه شدم. در این میان روسلان و برشت نیز در این راستا تحقیق کرده و اندیشه های جالبی ارائه کرده اند.
چگونه می توانم قالب های طراحی را به بهترین نحو پیاده سازی کنم؟
من از نوشتن درخواست های رسانه ای برای هر مقدار خسته شده ام و می خواهم از جهش های طراحی جلوگیری کنم. تعمیر و نگهداری و نتیجه رضایت بخش نیست. بنابراین بهترین راه برای اجرای مشارکت طراح چیست؟
در مورد اندازه مایعات چطور؟ ماشین حساب های دستی مانند وجود دارد اتوپیا یا حداقل – حداکثر – ماشین حساب.
اما برای پروژه هایم، معمولاً به گزینه های تنظیمات بیشتری نیاز دارم. نمای تبلت اغلب خیلی کوچک به نظر می رسد و من نه می توانم به درگاه های دید بزرگتر و نه نسبت تصویر واکنش نشان دهم.
و خوب است که یک هماهنگی متناسب در کل پروژه داشته باشیم. من میتوانم متغیرهای سراسری را با مقادیر محاسبهشده تعریف کنم، اما همچنین میخواهم بدون هیچ تلاشی بتوانم یک مقدار درونیابی شده را به صورت محلی در مؤلفهها ایجاد کنم. من می خواهم خط پاسخگوی خودم را ترسیم کنم. بنابراین من به ابزاری نیاز دارم که ارزش کامل را بر اساس چندین نقطه لنگر (تعریف صفحه) نشان دهد و فرآیندهای اکثر پروژه های من را خودکار کند. ابزار من باید سریع و آسان برای استفاده باشد و کد باید قابل خواندن و نگهداری باشد.
محاسبات ما باید بر اساس چه ثابت هایی از مشخصات طراحی باشد؟
بیایید نگاهی دقیق تر به مثال قبلی خود بیندازیم:
اندازه فونت بدنه باید باشد 16px
روی موبایل و 22px
روی دسکتاپ (در ادامه با راهنمای سبک کامل می پردازیم). اندازه تلفن همراه باید از شروع شود 375px
و به طور مداوم به 1024px
. تا 1440px
، اندازه ها باید به صورت ایستا در حد مطلوب باقی بمانند. پس از آن، مقادیر باید به صورت خطی تا مقیاس بندی شوند 2000px
، پس از آن max-wrapper اعمال می شود.
این به ما ثابت های زیر را می دهد که برای کل پروژه اعمال می شود:
Xf 375px global screen-min
Xa 1024px global screen-opt-start
Xb 1440px global screen-opt-end
Xu 2000px global screen-max
اندازه فونت بدنه باید حداقل باشد 16px
، در حالت ایده آل 22px
. حداکثر اندازه فونت در 2000px
باید به طور خودکار محاسبه شود:
Yf 16px local size-min
Ya 22px
Yb 22px local size-opt
Yu auto
بنابراین، در پایان روز، تابع من باید بتواند دو آرگومان بگیرد – در این مورد، 16
و 22
.
fab-unit(16, 22);
محاسبات
اگر علاقه ای به استخراج ریاضی فرمول ندارید، به راحتی به بخش “پرش کنید”چگونه از FabUnit استفاده کنیم؟“.
بنابراین، بیایید شروع کنیم!
گیره های اصلی را تعریف کنید
ابتدا باید بفهمیم که کدام گیره اصلی را می خواهیم تنظیم کنیم.
clamp1: clamp(Yf, slope1, Ya)
clamp2: clamp(Yb, slope2, Yu)
گیره ها را ترکیب و لانه کنید
حالا باید دو گیره را با هم ترکیب کنیم. این ممکن است کمی مشکل باشد. باید در نظر بگیریم که دو خط، slope1
و slope2
، بسته به میزان شیب آنها می توانند روی یکدیگر بازنویسی کنند. از آنجایی که ما می دانیم slope2
باید 45 درجه یا 100٪ (m = 1) باشد، ما می توانیم پرس و جو کنیم که آیا slope1
بالاتر از 1 است. به این ترتیب بسته به نحوه تلاقی خطوط می توانیم یک گیره متفاوت تنظیم کنیم.
اگر slope1
تندتر از slope2
، گیره ها را به این صورت ترکیب می کنیم:
clamp(Yf, slope1, clamp(Yb, slope2, Yu))
اگر slope1
صاف تر از slope2
، این محاسبه را انجام می دهیم:
clamp(clamp(Yf, slope1, Ya), slope2, Yu)
ترکیب شده:
steep-slope
? clamp(Yf, slope1, clamp(Yb, slope2, Yu))
: clamp(clamp(Yf, slope1, Ya), slope2, Yu)
Maximum Wrapper را به صورت اختیاری تنظیم کنید
اگر ماکزیمم لفافی نداشته باشیم که طرح را بالاتر از عرض معینی منجمد کند چه؟
ابتدا باید بفهمیم که کدام گیره اصلی را می خواهیم تنظیم کنیم.
clamp1: clamp(Yf, slope1, Ya)
max: max(Yb, slope2)
اگر slope1
تندتر از slope2
:
clamp(Yf, slope1, max(Yb, slope2))
اگر slope1
صاف تر از slope2
:
max(clamp(Yf, slope1, Ya), slope2)
محاسبه بدون لفاف – الاستیک به سمت بالا:
steep-slope
? clamp(Yf, slope1, max(Yb, slope2))
: max(clamp(Yf, slope1, Ya), slope2)
ترکیبی، با بسته بندی حداکثر اختیاری (اگر صفحه نمایش حداکثر باشد Xu
تنظیم شده است):
Xu
? steep-slope
? clamp(Yf, slope1, clamp(Yb, slope2, Yu))
: max(clamp(Yf, slope1, Ya), Yu)
: steep-slope
? clamp(Yf, slope1, max(Yb, slope2))
: max(clamp(Yf, slope1, Ya), slope2)
بنابراین ما ساختار اصلی فرمول را ساخته ایم. حالا کمی عمیق تر شیرجه می زنیم.
مقادیر گمشده را محاسبه کنید
بیایید ببینیم که کدام مقادیر را به عنوان آرگومان دریافت می کنیم و اکنون باید کدام مقادیر را محاسبه کنیم:
steep-slope
? clamp(Yf, slope1, clamp(Yb, slope2, Yu))
: max(clamp(Yf, slope1, Ya), Yu)
شیب تند
بله = Yb = 22 پیکسل
Yf = 16 پیکسل
شیب 1 = Mfa
شیب 2 = امبو
یو
steep-slope
بررسی کنید که آیا شیبYf → Ya
بالای شیب استYb → Yu
(m = 1) :
((Ya - Yf) / (Xa - Xf)) * 100 > 1
Mfa
درون یابی خطی، از جمله محاسبه شیبYf → Ya
:
Yf + (Ya - Yf) * (100vw - Xf) / (Xa - Xf)
Mbu
درون یابی خطی بینYb
وYu
(شیب m = 1):
100vw / Xb * Yb
Yu
محاسبه موقعیتYu
:
(Xu / Xb) * Yb
همه را با هم قرار دهید
Xu
? ((Ya - Yf) / (Xa - Xf)) * 100 > 1
? clamp(Yf, Yf + (Ya - Yf) * (100vw - Xf) / (Xa - Xf), clamp(Yb, 100vw / Xb * Yb, (Xu / Xb) * Yb))
: max(clamp(Yf, Yf + (Ya - Yf) * (100vw - Xf) / (Xa - Xf), Ya), (Xu / Xb) * Yb)
: ((Ya - Yf) / (Xa - Xf)) * 100 > 1
? clamp(Yf, Yf + (Ya - Yf) * (100vw - Xf) / (Xa - Xf), max(Yb, 100vw / Xb * Yb))
: max(clamp(Yf, Yf + (Ya - Yf) * (100vw - Xf) / (Xa - Xf), Ya), 100vw / Xb * Yb)
بهتر است برخی از محاسبات را در متغیرها ذخیره کنیم:
steep-slope = ((Ya - Yf) / (Xa - Xf)) * 100 > 1
slope1 = Yf + (Ya - Yf) * (100vw - Xf) / (Xa - Xf)
slope2 = 100vw / Xb * Yb
Yu = (Xu / Xb) * Yb
Xu
? steep-slope
? clamp(Yf, slope1, clamp(Yb, slope2, Yu))
: max(clamp(Yf, slope1, Ya), Yu)
: steep-slope
? clamp(Yf, slope1, max(Yb, slope2))
: max(clamp(Yf, slope1, Ya), slope2)
شامل نسبت ابعاد
از آنجا که ما اکنون می بینیم که گربه چگونه می پرد، خود را با یک کلوچه دیگر پذیرایی می کنیم. در مورد یک فرمت بسیار گسترده، به عنوان مثال چشم انداز دستگاه تلفن همراه، می خواهیم دوباره اندازه ها را کاهش دهیم. اینطوری دلپذیرتر و خواندنی تر است.
پس چه می شود اگر بتوانیم نسبت تصویر را در محاسبات خود لحاظ کنیم؟ در این مثال، می خواهیم اندازه ها را زمانی که صفحه نمایش از نسبت تصویر 16:9 عریض تر است، کوچک کنیم.
aspect-ratio = 16 / 9
screen-factor = min(100vw, 100vh * aspect-ratio)
در هر دو درونیابی شیب، ما به سادگی جایگزین می کنیم 100vw
با فاکتور صفحه نمایش جدید
slope1 = Yf + (Ya - Yf) * (screen-factor - Xf) / (Xa - Xf)
slope2 = screen-factor / Xb * Yb
پس بالاخره تمام شد. بیایید اکنون به کل فرمول جادویی نگاه کنیم.
فرمول
screen-factor = min(100vw, 100vh * aspect-ratio)
steep-slope = ((Ya - Yf) / (Xa - Xf)) * 100 > 1
slope1 = Yf + (Ya - Yf) * (screen-factor - Xf) / (Xa - Xf)
slope2 = screen-factor / Xb * Yb
Yu = (Xu / Xb) * Yb
Xu
? steep-slope
? clamp(Yf, slope1, clamp(Yb, slope2, Yu))
: max(clamp(Yf, slope1, Ya), Yu)
: steep-slope
? clamp(Yf, slope1, max(Yb, slope2))
: max(clamp(Yf, slope1, Ya), slope2)
عملکرد
اکنون می توانیم فرمول را در راه اندازی خود ادغام کنیم. در این مقاله به نحوه پیاده سازی آن در Sass خواهیم پرداخت. دو تابع کمکی تضمین میکنند که مقادیر rem را به درستی خروجی میدهیم (من به جزئیات آن نمیپردازم). سپس نقاط لنگر و نسبت ابعاد را به عنوان ثابت (به ترتیب متغیرهای Sass) قرار می دهیم. در نهایت، نقاط مختصات فرمول خود را با نام متغیرها جایگزین می کنیم و FabUnit آماده استفاده است.
_fab-unit.scss
@use "sass:math";
/* Helper functions */
$rem-base: 10px;
@function strip-units($number) {
@if (math.is-unitless($number)) {
@return $number;
} @else {
@return math.div($number, $number * 0 + 1);
}
}
@function rem($size){
@if (math.compatible($size, 1rem) and not math.is-unitless($size)) {
@return $size;
} @else {
@return math.div(strip-units($size), strip-units($rem-base)) * 1rem;
}
}
/* Default values fab-unit 🪄 */
$screen-min: 375;
$screen-opt-start: 1024;
$screen-opt-end: 1440;
$screen-max: 2000; // $screen-opt-end | int > $screen-opt-end | false
$aspect-ratio: math.div(16, 9); // smaller values for larger aspect ratios
/* Magic function fab-unit 🪄 */
@function fab-unit(
$size-min,
$size-opt,
$screen-min: $screen-min,
$screen-opt-start: $screen-opt-start,
$screen-opt-end: $screen-opt-end,
$screen-max: $screen-max,
$aspect-ratio: $aspect-ratio
) {
$screen-factor: min(100vw, 100vh * $aspect-ratio);
$steep-slope: math.div(($size-opt - $size-min), ($screen-opt-start - $screen-min)) * 100 > 1;
$slope1: calc(rem($size-min) + ($size-opt - $size-min) * ($screen-factor - rem($screen-min)) / ($screen-opt-start - $screen-min));
$slope2: calc($screen-factor / $screen-opt-end * $size-opt);
@if $screen-max {
$size-max: math.div(rem($screen-max), $screen-opt-end) * $size-opt;
@if $steep-slope {
@return clamp(rem($size-min), $slope1, clamp(rem($size-opt), $slope2, $size-max));
} @else {
@return clamp(clamp(rem($size-min), $slope1, rem($size-opt)), $slope2, $size-max);
}
} @else {
@if $steep-slope {
@return clamp(rem($size-min), $slope1, max(rem($size-opt), $slope2));
} @else {
@return max(clamp(rem($size-min), $slope1, rem($size-opt)), $slope2);
}
}
}
چگونه از FabUnit استفاده کنیم؟
کار تمام شده است، اکنون ساده است. راهنمای سبک از مثال ما را می توان در کوتاه ترین زمان اجرا کرد:
ما مقادیر مرتبط را از راهنمای سبک می خوانیم و آنها را به عنوان آرگومان به FabUnit ارسال می کنیم: fab-unit(16, 22)
.
style.scss
@import "fab-unit";
/* overwrite default values 🪄 */
$screen-max: 1800;
/* Style guide variables fab-unit 🪄 */
$fab-font-size-body: fab-unit(16, 22);
$fab-font-size-body-small: fab-unit(14, 16);
$fab-font-size-h1: fab-unit(60, 160);
$fab-font-size-h2: fab-unit(42, 110);
$fab-font-size-h3: fab-unit(28, 60);
$fab-space-s: fab-unit(20, 30);
$fab-space-m: fab-unit(40, 80);
$fab-space-l: fab-unit(60, 120);
$fab-space-xl: fab-unit(80, 180);
/* fab-unit in action 🪄 */
html {
font-size: 100% * math.div(strip-units($rem-base), 16);
}
body {
font-size: $fab-font-size-body;
}
.wrapper {
max-width: rem($screen-max);
margin-inline: auto;
padding: $fab-space-m;
}
h1 {
font-size: $fab-font-size-h1;
border-block-end: fab-unit(2, 10) solid plum;
}
…
p {
margin-block: $fab-space-s;
}
…
/* other use cases for calling fab-unit 🪄 */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(fab-unit(200, 500), 1fr));
gap: $fab-space-m;
}
.thing {
flex: 0 0 fab-unit(20, 30);
height: fab-unit(20, 36, 660, 800, 1600, 1800); /* min, opt, … custom anchor points */
}
اکنون می توانیم با فراخوانی خط پاسخگو را رسم کنیم fab-unit()
و فقط دو اندازه، حداقل و بهینه را مشخص کنید. میتوانیم اندازههای فونت، بالشتکها، حاشیهها و شکافها، ارتفاعها و عرضها را کنترل کنیم، و حتی اگر بخواهیم ستونهای شبکهای و طرحبندیهای انعطافپذیر را با آن تعریف کنیم. همچنین می توانیم نقاط لنگر از پیش تعریف شده را به صورت محلی جابجا کنیم.
بیایید به خروجی کامپایل شده نگاهی بیندازیم:
…
font-size: clamp(clamp(1.3rem, 1.3rem + 2 * (min(100vw, 177.7777777778vh) - 37.5rem) / 649, 1.5rem), min(100vw, 177.7777777778vh) / 1440 * 15, 2.0833333333rem);
…
و خروجی محاسبه شده:
font-size: 17.3542px
نگرانی های دسترسی
برای اطمینان از دسترسی خوب، توصیه میکنم در هر مورد آزمایش کنید که آیا همه اندازهها به اندازه کافی قابل بزرگنمایی هستند یا خیر. استدلال هایی با تفاوت زیاد ممکن است آنطور که می خواهید رفتار نکنند. برای اطلاعات بیشتر در مورد این موضوع، می توانید مقاله “نوع واکنشگرا و زومنوشته آدریان روزلی.
نتیجه
اکنون ما یک تابع ایجاد کرده ایم که همه کارها را برای ما انجام می دهد. این یک مقدار حداقل و بهینه را می گیرد و با در نظر گرفتن عرض صفحه، نسبت ابعاد و نقاط لنگر مشخص، یک محاسبه را به ویژگی CSS ما می اندازد – یک فرمول واحد که کل پروژه را هدایت می کند. بدون درخواست رسانه، بدون نقطه شکست، بدون جهش طراحی.
FabUnit ارائه شده در اینجا بر اساس تجربه شخصی من است و برای اکثر پروژه های من بهینه شده است. من در زمان زیادی صرفه جویی می کنم و از نتیجه راضی هستم. ممکن است شما و تیمتان رویکرد دیگری داشته باشید و بنابراین نیازهای دیگری برای FabUnit داشته باشید. خیلی خوب است اگر اکنون بتوانید FabUnit خود را مطابق با نیاز خود ایجاد کنید.
خوشحال می شوم اگر رویکرد من ایده های جدیدی را به شما القا کند. مفتخرم اگر مستقیماً از آن استفاده کنید بسته npm از FabUnit از این مقاله برای پروژه های شما.
متشکرم! 🙏🏻
پیوندهای FAB-UNIT
مرسی الی، رومن، پاتریک، فیدی.
(yk, il)