یک ترکیب حیله‌گر – مجله Smashing

یک ترکیب حیله‌گر - مجله Smashing

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

در اینجا یک نسخه نمایشی بصری از جلوه مورد نظر برای وضوح وجود دارد.

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

قبل از غواصی، اجازه دهید نگاهی گذرا به نشانه گذاری اولیه و CSS بیندازیم تا ببینیم با چه چیزی کار می کنیم:


  
  
Hero Content
Main Content
.header {
  position: sticky;
  top: 0; /* Offset, otherwise it won't stick! */
}

/* etc. */

با آن اعلامیه ها، .header به بالای صفحه می چسبد. و با این حال .hero عنصر زیر آن به طور ذاتی اندازه باقی می ماند. این چیزی است که ما می خواهیم تغییر دهیم.

میوه کم آویزان

اولین انگیزه ای که ممکن است داشته باشید، همانطور که من انجام دادم، این است که هدر و قهرمان را در نوعی کانتینر والد محصور کنید و آن ظرف را بدهید. 100vh تا آن را به نمای درت باز کند. پس از آن، می‌توانیم از Flexbox برای توزیع بچه‌ها استفاده کنیم و قهرمان را بزرگ کنیم تا فضای باقی‌مانده را پر کند.


  

Hero Content

Main Content
.container {
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.hero {
  flex-grow: 1;
}

/* etc. */

این در نگاه اول درست به نظر می رسد، اما مراقب باشید که هنگام عبور از قهرمان چه اتفاقی می افتد.

به قلم (تلاش شماره 1: ظرف + Flexbox (چنگال شده)) (https://codepen.io/smashingmag/pen/yLdQgQo) توسط فیلیپ مراجعه کنید.

به تلاش قلم شماره 1: ظرف + فلکس باکس (چنگال شده) توسط فیلیپ مراجعه کنید.

هدر چسبنده در ظرف اصلی خود به دام می افتد! اما.. چرا?

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

الف position: fixed عنصر به والدی که در آن قرار دارد یا هیچ یک از اجدادش اهمیتی نمی دهد. از جریان عادی سند خارج می‌شود و خود را مستقیماً از درگاه دید خارج می‌کند، گویی در فاصله معینی از لبه صفحه در جای خود چسبانده شده است.

برعکس، الف position: sticky عنصر همراه با لبه‌های درگاه دید (یا نزدیک‌ترین محفظه پیمایشی بعدی) هل داده می‌شود، اما هرگز از مرزهای والد مستقیم خود فرار نخواهد کرد. خوب، حداقل اگر از نظر بصری حساب نکنید transform-داشتن آن بنابراین راه بهتری برای فکر کردن در مورد آن ممکن است، دزدی از کریس کویر باشد position: sticky به یک معنا، یک محدوده محلی است position: fixed” این یک تصمیم طراحی عمدی است، تصمیمی که اجازه می‌دهد هدرهای چسبناک مخصوص بخش مانند آنهایی که توسط فهرست‌های الفبایی در رابط‌های تلفن همراه معروف شده‌اند، وجود داشته باشد.

به قلم (Sticky Section Headers (چنگال شده)) (https://codepen.io/smashingmag/pen/OJeaWrM) توسط فیلیپ مراجعه کنید.

سربرگ بخش چسبنده قلم (چنگال شده) توسط فیلیپ را ببینید.

خوب، پس این رویکرد برای مصیبت ما ممنوع است. ما باید راه حلی پیدا کنیم که شامل یک ظرف در اطراف هدر نباشد.

ثابت شد، اما حل نشد

شاید بتوانیم زندگی خود را کمی ساده تر کنیم. به جای یک ظرف، چه می شود اگر ما به .header عنصر الف ثابت شده است ارتفاع مثلاً 150px? سپس، تنها کاری که باید انجام دهیم این است که آن را تعریف کنیم .hero ارتفاع عنصر به عنوان height: calc(100vh - 150px).

به قلم (تلاش شماره 2: ارتفاع ثابت + محاسبه () (چنگال شده)) (https://codepen.io/smashingmag/pen/yLdQgGz) توسط فیلیپ مراجعه کنید.

تلاش قلم شماره 2: ارتفاع ثابت + کالک() (فشار) توسط فیلیپ را ببینید.

این رویکرد یه جورایی کار می کند، اما جنبه های منفی موذیانه تر از تلاش قبلی ما هستند، زیرا ممکن است بلافاصله آشکار نشوند. احتمالاً متوجه شدید که هدر خیلی بلند است و ما می‌خواهیم کمی ریاضی انجام دهیم تا در مورد ارتفاع بهتر تصمیم بگیریم.

کمی به آینده فکر کنیم،

  • چه می شود اگر .headerکودکان باید در اندازه‌های مختلف صفحه نمایش خود را بپیچند یا دوباره مرتب کنند یا برای حفظ خوانایی در تلفن همراه رشد کنند؟
  • اگر جاوا اسکریپت محتوا را دستکاری کند چه؟

همه این چیزها می تواند به طور ماهرانه ای را تغییر دهد .headerاندازه ایده‌آل، و تعقیب مقادیر مناسب ارتفاع برای هر سناریو، این پتانسیل را دارد که به یک کابوس نگهداری از نقاط شکست غیرقابل مدیریت و اعداد جادویی تبدیل شود – به خصوص اگر در نظر بگیریم که این کار نه تنها برای .header بلکه همچنین .hero عنصری که به آن بستگی دارد.

من استدلال می کنم که این راه حل نیز فقط احساس می کند اشتباه ارتفاع ثابت یکی از قابلیت‌های اصلی چیدمان CSS را می‌شکند – روشی که عناصر به طور خودکار رشد می‌کنند و برای انطباق با محتویاتشان کوچک می‌شوند – و عدم اتکا به آن معمولاً زندگی ما را می‌سازد. سخت تر، ساده تر نیست.

بنابراین، ما با…

رویکردی بدیع

اکنون که محدودیت‌هایی را که در حال کار با آن‌ها هستیم فهمیدیم، راه دیگری برای بیان مشکل این است که می‌خواهیم .header و .hero به به صورت جمعی دهانه 100vh بدون اینکه عناصر را به وضوح اندازه بگیرید یا آنها را در یک ظرف بپیچانید. در حالت ایده آل، ما پیدا می کنیم چیزی که در حال حاضر است 100vh و آنها را با آن تراز کنید. اینجاست که به ذهنم رسید که display: grid ممکن است فقط آنچه را که ما نیاز داریم فراهم کند!

بیایید این را امتحان کنیم: ما اعلام می کنیم display: grid بر روی body عنصر و قبل از .header که ما تماس خواهیم گرفت .above-the-fold-spacer. این عنصر جدید ارتفاع می گیرد 100vh و تمام عرض شبکه را در بر می گیرد. در مرحله بعد، به فاصله‌گذار خود می‌گوییم که باید دو ردیف شبکه را اشغال کند و آن را به بالای صفحه متصل می‌کنیم.

این عنصر باید کاملاً خالی باشد زیرا ما هرگز نمی‌خواهیم قابل مشاهده باشد یا در صفحه‌خوان‌ها ثبت شود. ما فقط از آن به عنوان عصا استفاده می کنیم تا به شبکه بگوییم چگونه رفتار کند.


  
  

  
  
  
Hero Content
Main Content
body {
  display: grid;
}

.above-the-fold-spacer {
  height: 100vh;
  /* Span from the first to the last grid column line */
  /* (Negative numbers count from the end of the grid) */
  grid-column: 1 / -1;
  /* Start at the first grid row line, and take up 2 rows */
  grid-row: 1 / span 2; 
}

/* etc. */

این ماده جادویی است

با اضافه کردن فاصله‌گذار، دو ردیف شبکه ایجاد کرده‌ایم که با هم دقیقا بردار 100vh. اکنون، در اصل تنها کاری که باقی مانده است، گفتن آن است .header و .hero عناصر برای تراز کردن خود با آن ردیف های موجود. ما باید به آنها بگوییم که از همان خط ستون شبکه شروع کنند .above-the-fold-spacer عنصر به طوری که آنها سعی نمی کنند در کنار آن بنشینند. اما با انجام آن… تا-دا!

به قلم (راه حل: تراز شبکه (چنگال شده)) (https://codepen.io/smashingmag/pen/YzoRNdo) توسط فیلیپ مراجعه کنید.

به قلم The Solution: Grid Alignment (چنگال شده) توسط فیلیپ مراجعه کنید.

دلیل این کار این است که یک محفظه شبکه‌ای می‌تواند دارای چندین کودک باشد که یک سلول مشابه را روی هم قرار می‌دهند. در موقعیتی مانند آن، بلندترین عنصر فرزند، ارتفاع کلی ردیف شبکه را تعیین می کند – یا در این مورد، ارتفاع ترکیبی دو ردیف (100vh).

برای کنترل اینکه دو عنصر قابل مشاهده دقیقا چگونه فضای موجود را بین خود تقسیم می کنند، می توانیم از آن استفاده کنیم grid-template-rows دارایی من آن را طوری ساختم که ردیف اول استفاده می کند min-content به جای 1fr. این امر ضروری است تا .header به اندازه فضا را اشغال نمی کند .hero اما در عوض فقط آنچه را که نیاز دارد می گیرد و به قهرمان اجازه می دهد بقیه را داشته باشد.

راه حل کامل ما در اینجا آمده است:


body {
  display: grid;
  grid-template-rows: min-content 1fr;
}

.above-the-fold-spacer {
  height: 100vh;
  grid-column: 1 / -1;
  grid-row: 1 / span 2;
}

.header {
  position: sticky;
  top: 0;
  grid-column-start: 1;
  grid-row-start: 1;
}

.hero {
  grid-column-start: 1;
  grid-row-start: 2;
}

و voila: یک هدر چسبنده با اندازه دلخواه بالای یک قهرمان که رشد می کند تا فضای قابل مشاهده باقیمانده را پر کند!

هشدارها و افکار نهایی

شایان ذکر است که ترتیب HTML عناصر در اینجا مهم است. اگر تعریف کنیم .above-the-fold-spacer بعد از ما .hero بخش، آن را پوشش داده و دسترسی به عناصر زیر را مسدود می کند. ما می توانیم با اعلام هر یک از این موارد کار کنیم order: -1، z-index: -1، یا visibility: hidden.

به خاطر داشته باشید که این یک مثال ساده است. برای مثال، اگر می خواهید یک نوار کناری در سمت چپ صفحه خود اضافه کنید، باید تنظیم کنید که عناصر از کدام ستون شروع می شوند. با این حال، در اکثر موارد، استفاده از یک رویکرد CSS Grid احتمالاً نسبت به وظیفه سیزیفی مدیریت دستی و هماهنگ کردن مقادیر ارتفاع چندین عنصر، دردسر کمتری دارد.

یکی دیگر از مزایای این رویکرد این است که آن است سازگار. اگر تصمیم دارید که یک گروه از سه عنصر به جای دو عنصر، ارتفاع صفحه را بگیرد، باید فاصله‌دهنده نامرئی را در سه ردیف قرار دهید و عناصر قابل مشاهده را به ردیف مناسب اختصاص دهید. حتی اگر محتوای عنصر قهرمان باعث افزایش ارتفاع آن شود 100vh، شبکه بدون شکستن چیزی سازگار می شود. حتی در تمام مرورگرهای مدرن به خوبی پشتیبانی می شود.

هر چه بیشتر در مورد این تکنیک فکر می کنم، بیشتر متقاعد می شوم که در واقع کاملاً تمیز است. سپس دوباره، شما می دانید که چگونه وکلا می توانند خود را در مورد استدلال های خود صحبت کنند؟ اگر می‌توانید راه‌حل ساده‌تری را که من نادیده گرفته‌ام بیاندیشید، با خیال راحت تماس بگیرید و به من اطلاع دهید!

سرمقاله Smashing
(gg, yk)

منبع: https://smashingmagazine.com/2024/09/sticky-headers-full-height-elements-tricky-combination/