چند وقته که مشغول ایجاد تغییرات کوچیکی روی کد های بخش فرانتاند اسنپفود شدم که قراره با نام جدید اسنپ اکسپرس منتشر بشه و دو تا از تسکهای مهم تیم فرانت این بود که کاربری سایت روی دسکتاپ بهبود پیدا کنه و همزمان با لانچ جدید، کمی از چیدمان ها رو پایین و بالا کنیم و سایز و کاربری اون رو برای کاربر دسکتاپ، بهبود بدیم. یه سری از المان ها با position:fixed نوشته شده بودن که همهی عرض صفحه رو بگیرن و (من اسم اونا رو میذارم المان های فیکس) مثل:
این جور کمپوننت ها، با چیدمان بقیه صفحه کاری ندارن و موقع استفاده کردن ازشون، حتما حواستون باشه که المانی که پشت هدرتون هست باید حتما یه فضای خالی (بسته به طول المان فیکس شده) براش جا در نظر بگیرین، چون قراره پشت المان فیکس ما پنهان بشه.
مشکل وقتی شروع میشه که تعداد کمپوننت های فیکس پروژه میره بالا. کمپوننتهایی مثل:
داشتن چند تا کمپوننت فیکس که هر کدوم بقیه رو به رسمیت بشناسه(!) کار بسیار پیچیدهایه و عموما منتهی میشه به فیکس کردن یه سری طول المان ها
مثلا:
قبل از این که ادامه بدیم، میخواستم این نکته رو تاکید کنم که وقتی برای یه تگ، position: fixed رو استفاده میکنید، هربار مرورگر مجبوره برای این تگ، یه stacking context تعریف کنه که کاملا جدیده و نسبت به چیزی نمیشه جابجاش کرد. برای همین مجبوریم یه سری متغیر برای خط ۸، تعریف کنیم. (یا از line-height استفاده کنیم)
برای جلوگیری از چنین مشکلاتی، واقعا چیکار میشه کرد؟
اول از همه بگم که من ننشستم که همه راه ها رو امتحان و مقایسه کنم. روشی هم که میخوام معرفی کنم لزوما بهترین روش (یا حتی روش خوبی) نیست. ولی چیزی بود که به عقل ناقص ما رسیده خلاصه. به بزرگی خودتون فلان... در نتیجه اگه پیشنهادی یا روش بهتری سراغ دارین بگین بهم حتما...
ریعکت پورتال (و دوستان) وارد میشوند!
اول مسئله رو با فرض یه هدر و یه فوتر میسازیم و بعد پشتیبانی از چند تا رو اضافه میکنیم (که میشه قسمت دوم)
function Layout({ children }) { return ( <div id="#app"> <header id="sticky-header" /> <section className={styles.container}> {children} </section> <footer id="sticky-footer" /> </div> ); }
تا اینجای کار چیز خاصی نداریم. دو تا تگ با آیدی های مخصوص خودشون تعریف کردیم که قراره بعدا هر کی دوست داشت پرشون کنه! بچه ها یا همون children اش هم که داخل container تعریف کردیم. حالا بریم سراغ کمپوننتهای فنسی ماجرا:
function StickyHeader({ children }) { const targetElem = document.querySelector('#sticky-header') if (!targetElem) return null return react.createPortal(children, targetElem) }
که البته یه دونه مشابه اینم واسه فوتر داریم دیگه.
به نظرتون قشنگ شد یا زشت؟
این کمپوننت میگه هر چی تو شکمم بذاری من میفرستم داخل sticky-header.
مثلا ما فاکتور خرید رو بالا نشون میدیم و پایین صفحه اینو میذاریم:
حالا شاید حدس بزنید که موقع استایلینگ میخوام اینطوری بنویسم:
که البته بیراه فکر نکردید در اون صورت میتونم مشکل خالی گذاشتن زیر المان فیکس رو اینطور حل کنم:
function Layout({ children }) { const headerRef = useRef(); const footerRef = useRef(); const headerHeight = headerRef.current?.clientHeight; const footerHeight = footerRef.current?.clientHeight; const containerStyles = { marginTop: headerHeight marginBottom: footerHeight } return ( <div id="#app"> <header id="#sticky-header" ref={headerRef} /> <section className={styles.container} style={containerStyles}> {children}</section> <footer id="#sticky-footer" ref={footerRef} /> </div> ); }
خط های اول Layout رو با اضافه کردن دو تا ریفرنس و گرفتن طولشون شروع کردم. و با این متغیرم، به کمپوننت اصلی صفحه، از بالا و پایین فضا دادم تا چیزی پایین صفحه گم نشه :))
...تا اینجا یه روش یاد گرفتیم.
یادتونه گفتم «شاید حدس بزنید که موقع استایلینگ بیام فیکس کنم؟» ها! نه دیگه. من از فیکس متنفرم.
به جاش:
تامام! هر سه تا (هدر، container و فوتر) داخل یه flex هستن که چون هدر و فوتر flex ندارن، height مورد نیاز خودشون رو اشغال میکنن و بقیه طول صفحه میرسه به containerمون.
اگه با لایک و کامنت تشویقم کنید ادامه پست رو میذارم و در مورد داشتن چند تا هدر و فوتر با ترتیب دلخواه صحبت میکنم. مثال یکم پیچیده ترش رو، داخل این صفحه از اسنپفود میبینید: