انتقال ورودی های لایه بالایی و ویژگی نمایش در CSS-مجله Smashing
انتشار: بهمن 10، 1403
بروزرسانی: 28 اردیبهشت 1404

انتقال ورودی های لایه بالایی و ویژگی نمایش در CSS-مجله Smashing


انیمیشن از و به display: none; چیزی بود که ما فقط با JavaScript برای تغییر کلاس ها یا ایجاد هک های دیگر به آن می رسیدیم. دلیل اینکه ما نتوانستیم این کار را در CSS انجام دهیم ، در مشخصات جدید CSS Transions سطح 2 توضیح داده شده است:

وی گفت: "در سطح 1 این مشخصات ، انتقال فقط می تواند در طی یک رویداد تغییر سبک برای عناصری که دارای یک سبک قبل از تغییر هستند که توسط رویداد تغییر سبک قبلی ایجاد شده است ، شروع شود. این بدان معناست که انتقال نمی تواند بر روی عنصری آغاز شود که برای رویداد تغییر سبک قبلی ارائه نشده است. "

به عبارت ساده ، این بدان معنی است که ما نتوانستیم انتقال را بر روی یک عنصر پنهان شروع کنیم یا به تازگی ایجاد شده است.

چه می کند transition-behavior: allow-discrete انجام دهید؟

allow-discrete آیا نام عجیب و غریب برای ارزش خاصیت CSS است ، درست است؟ ما در مورد انتقال هستیم display: none، پس چرا این نامگذاری نشده است transition-behavior: allow-display در عوض؟ دلیل این امر این است که این کار کمی بیشتر از رسیدگی به CSS است display املاک ، همانطور که سایر خصوصیات "گسسته" در CSS وجود دارد. یک قانون ساده این است که خصوصیات گسسته در حال انتقال نیست بلکه معمولاً بلافاصله بین دو حالت دور می شوند. نمونه های دیگر خصوصیات گسسته visibility وت mix-blend-modeبشر نمونه ای از این موارد را در پایان این مقاله درج می کنم.

برای خلاصه کردن ، تنظیم transition-behavior دارایی به allow-discrete به ما اجازه می دهد تا به مرورگر بگوییم که می تواند مقادیر یک خاصیت گسسته را عوض کند (به عنوان مثال ، displayبا visibilityوت mix-blend-mode) در 50 ٪ علامت به جای علامت 0 ٪ انتقال.

چه می کند @starting-style انجام دهید؟

در @starting-style قانون قبل از ارائه به صفحه ، سبک های یک عنصر را درست تعریف می کند. این در ترکیب با transition-behavior و به همین دلیل است:

هنگامی که یک مورد به DOM اضافه می شود یا در ابتدا تنظیم می شود display: none، به نوعی "شروع سبک" نیاز دارد که از آن نیاز به انتقال دارد. برای مثال بیشتر ، Popovers و عناصر گفتگو به یک لایه بالا اضافه می شوند که لایه ای است که خارج از جریان سند شما است ، می توانید به عنوان یک خواهر و برادر از آن نگاه کنید element in your page’s structure. Now, when opening this dialog or popover, they get created inside that top layer, so they don’t have any styles to start transitioning from, which is why we set @starting-styleبشر نگران نباشید اگر همه اینها کمی گیج کننده به نظر می رسد. نسخه های نمایشی ممکن است آن را واضح تر جلوه دهند. نکته مهمی که باید بدانیم این است که ما می توانیم به مرورگر چیزی بدهیم که انیمیشن را با آن شروع کند زیرا در غیر این صورت چیزی برای تحریک از آن ندارد.

یادداشتی در مورد پشتیبانی مرورگر

در لحظه نوشتن ، transition-behavior در Chrome ، Edge ، Safari و Firefox موجود است. این همان است @starting-style، اما Firefox در حال حاضر از انیمیشن پشتیبانی نمی کند display: noneبشر اما به یاد داشته باشید که همه چیز در این مقاله می تواند کاملاً به عنوان یک پیشرفت مترقی مورد استفاده قرار گیرد.

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

  • انیمیشن از و به display: none در Dom.
  • دیالوگ های انیمیشن و پاپورها که از لایه بالایی وارد و خارج می شوند.
  • "خواص گسسته" بیشتری می توانیم اداره کنیم.

انیمیشن از و به display: none در DOM

برای مثال اول ، بیایید نگاهی بیندازیم @starting-style تنها من این نسخه ی نمایشی را صرفاً برای توضیح جادو ایجاد کردم. تصور کنید که می خواهید دو دکمه در یک صفحه برای اضافه کردن یا حذف موارد لیست در داخل یک لیست بدون هماهنگ.

این می تواند HTML شروع شما باشد:

در مرحله بعد ، ما اقداماتی را اضافه می کنیم که موارد لیست را اضافه یا حذف می کنند. این می تواند هر روشی برای انتخاب شما باشد ، اما برای اهداف نمایشی ، من به سرعت کمی JavaScript را برای آن نوشتم:

document.addEventListener("DOMContentLoaded", () => {  const addButton = document.querySelector(".btn-add");  const removeButton = document.querySelector(".btn-remove");  const list = document.querySelector(\'ul(role="list")\');  addButton.addEventListener("click", () => {    const newItem = document.createElement("li");    list.appendChild(newItem);  });  removeButton.addEventListener("click", () => {    if (list.lastElementChild) {      list.lastElementChild.classList.add("removing");      setTimeout(() => {        list.removeChild(list.lastElementChild);      }, 200);    }  });});

هنگام کلیک بر روی addButton، یک مورد لیست خالی در داخل لیست بدون نظارت ایجاد می شود. هنگام کلیک بر روی removeButton، آخرین مورد جدید است .removing کلاس و سرانجام پس از 200 متر از DOM خارج می شود.

با این کار ، می توانیم برخی از CSS را برای موارد خود بنویسیم تا قسمت حذف را تحریک کنیم:

ul {    li {      transition: opacity 0.2s, transform 0.2s;      &.removing {        opacity: 0;        transform: translate(0, 50%);      }    }  }

این عالی است! ما .removing انیمیشن در حال حاضر عالی به نظر می رسد ، اما آنچه ما در اینجا به دنبال آن بودیم ، راهی برای تحریک ورود مواردی بود که در داخل DOM ما وارد می شود. برای این کار ، ما باید آن سبک های شروع و همچنین وضعیت نهایی موارد لیست خود را تعریف کنیم.

ابتدا بیایید CSS را به روز کنیم تا حالت نهایی در داخل آن مورد لیست باشد:

ul {    li {      opacity: 1;      transform: translate(0, 0);      transition: opacity 0.2s, transform 0.2s;      &.removing {        opacity: 0;        transform: translate(0, 50%);      }    }  }

تغییر زیادی نکرده است ، اما اکنون این وظیفه ماست که به مرورگر اطلاع دهیم که سبک های شروع باید چه باشد. ما می توانیم این را به همان روشی که انجام دادیم تنظیم کنیم .removing سبک هایی مانند این:

ul {    li {      opacity: 1;      transform: translate(0, 0);      transition: opacity 0.2s, transform 0.2s;      @starting-style {        opacity: 0;        transform: translate(0, 50%);      }      &.removing {        opacity: 0;        transform: translate(0, 50%);      }    }  }

اکنون ما به مرورگر اطلاع داده ایم که @starting-style باید شامل کدورت صفر باشد و با استفاده از a کمی به پایین گره خورده باشد transformبشر نتیجه نهایی چیزی شبیه به این است:

اما نیازی نیست که در آنجا متوقف شویم! ما می توانیم از انیمیشن های مختلف برای ورود و خروج استفاده کنیم. به عنوان مثال می توانیم سبک شروع خود را به موارد زیر بروز کنیم:

@starting-style {  opacity: 0;  transform: translate(0, -50%);}

با انجام این کار ، موارد از بالا وارد می شوند و از پایین خارج می شوند. مثال کامل را در این Codepen مشاهده کنید:

قلم (@@stary-sylede-up-in ، down-out (forked)) (https://codepen.io/smashingmag/pen/xjropgg) را توسط AltilityBend مشاهده کنید.

نمایش نسخه ی نمایشی به سبک شروع قلم @start-up-in ، down-out (forked) by ilitybend.

چه زمانی استفاده کنید transition-behavior: allow-discrete

در مثال قبلی مواردی را از DOM خود اضافه و حذف کردیم. در نسخه ی نمایشی بعدی ، ما موارد را با استفاده از CSS نشان می دهیم و پنهان می کنیم display خاصیت راه اندازی اساسی تقریباً یکسان است ، به جز ما هشت مورد لیست را به DOM خود اضافه خواهیم کرد .hidden کلاس متصل به آن:

    

یک بار دیگر ، برای اهداف نمایشی ، من کمی جاوا اسکریپت اضافه کردم که این بار ، .hidden کلاس مورد بعدی هنگام کلیک بر روی addButton و اضافه می کند hidden کلاس هنگام کلیک بر روی removeButton:

document.addEventListener("DOMContentLoaded", () => {  const addButton = document.querySelector(".btn-add");  const removeButton = document.querySelector(".btn-remove");  const listItems = document.querySelectorAll(\'ul(role="list") li\');  let activeCount = 0;  addButton.addEventListener("click", () => {    if (activeCount < listItems.length) {      listItems(activeCount).classList.remove("hidden");      activeCount++;    }  });  removeButton.addEventListener("click", () => {    if (activeCount > 0) {      activeCount--;      listItems(activeCount).classList.add("hidden");    }  });});

بیایید همه چیزهایی را که تاکنون آموخته ایم جمع کنیم ، اضافه کنیم @starting-style به موارد ما ، و تنظیم اولیه را در CSS انجام دهید:

ul {    li {      display: block;      opacity: 1;      transform: translate(0, 0);      transition: opacity 0.2s, transform 0.2s;      @starting-style {        opacity: 0;        transform: translate(0, -50%);      }      &.hidden {        display: none;        opacity: 0;        transform: translate(0, 50%);      }    }  }

این بار ، ما اضافه کرده ایم .hidden کلاس ، آن را تنظیم کنید display: none، و همان را اضافه کرد opacity وت transform اعلامیه هایی که قبلاً با .removing کلاس در آخرین مثال. همانطور که ممکن است انتظار داشته باشید ، ما برای موارد خود یک محو شدن خوب می گیریم ، اما حذف آنها هنوز هم ناگهانی است زیرا موارد خود را مستقیماً تنظیم می کنیم display: noneبشر

اینجاست transition-behavior ملک بازی می شود. برای شکستن آن کمی بیشتر ، بیایید آن را حذف کنیم transition ملک CSS قبلی ما و کمی آن را باز کنید:

ul {    li {      display: block;      opacity: 1;      transform: translate(0, 0);      transition-property: opacity, transform;      transition-duration: 0.2s;    }  }

تمام کاری که باید انجام شود انتقال است display دارایی و تنظیم transition-behavior دارایی به allow-discrete:

ul {    li {      display: block;      opacity: 1;      transform: translate(0, 0);      transition-property: opacity, transform, display;      transition-duration: 0.2s;      transition-behavior: allow-discrete;      /* etc. */    }  }

ما اکنون عنصر را از display: none، و نتیجه دقیقاً همانطور که ما می خواستیم:

ما می توانیم از transition خاصیت Shorthand برای ساختن کد ما کمی کمرنگ:

transition: opacity 0.2s, transform 0.2s, display 0.2s allow-discrete;

می توانید اضافه کنید allow-discrete در آنجا اما اگر این کار را کردید ، توجه داشته باشید که اگر بعد از آن یک انتقال کوتاه را اعلام کردید transition-behavior، آن را نادیده می گیرد. بنابراین ، به جای این:

transition-behavior: allow-discrete;transition: opacity 0.2s, transform 0.2s, display 0.2s;

... ما می خواهیم اعلام کنیم transition-behavior پس از در transition Shorthand:

transition: opacity 0.2s, transform 0.2s, display 0.2s;transition-behavior: allow-discrete;

در غیر این صورت ، transition املاک Shorthand غلبه می کند transition-behaviorبشر

به قلم (@starty-Style و Transition-Behavior: اجازه-تخریب (چنگال)) مراجعه کنید (https://codepen.io/smashingmag/pen/ggkpxda) توسط AltilityBend.

به Pen @Starty-Style و Transition-Behavior: اجازه دهید تا از طریق AtilityBend اجازه دهید.

دیالوگ های متحرک و پاپ ها وارد و خارج از لایه بالایی می شوند

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

آن لایه بالا چیست؟

ما قبلاً "لایه بالا" را به یک خواهر و برادر تشبیه کرده ایم element, but you might also think of it as a special layer that sits above everything else on a web page. It’s like a transparent sheet that you can place over a drawing. Anything you draw on that sheet will be visible on top of the original drawing.

The original drawing, in this example, is the DOM. This means that the top layer is out of the document flow, which provides us with a few benefits. For example, as I stated before, dialogs and popovers are added to this top layer, and that makes perfect sense because they should always be on top of everything else. No more z-index: 9999!

اما این بیش از این است:

  • z-index بی ربط است: عناصر موجود در لایه بالا ، صرف نظر از آنها ، همیشه در بالا هستند z-index ارزش
  • سلسله مراتب دام مهم نیست: موقعیت یک عنصر در DOM بر ترتیب انباشت آن در لایه بالا تأثیر نمی گذارد.
  • پس زمینه: ما به یک جدید دسترسی پیدا می کنیم ::backdrop شبه عنصر که به ما امکان می دهد منطقه بین لایه بالایی و DOM را در زیر آن سبک کنیم.

امیدوارم که شما شروع به درک اهمیت لایه بالا و چگونگی انتقال عناصر در داخل و خارج از آن کنیم ، همانطور که با Popovers و Dialogues انجام می دهیم.

انتقال عنصر گفتگو در لایه بالا

HTML زیر حاوی دکمه ای است که باز می شود

عنصر ، و آن عنصر حاوی دکمه دیگری است که بسته می شود بشر بنابراین ، ما یک دکمه داریم که باز می شود و یکی که آن را می بندد.

  

Hi, there!

اتفاقات زیادی در HTML با دستورات Invoker اتفاق می افتد که مرحله زیر را کمی آسان تر می کند ، اما در حال حاضر ، بیایید کمی JavaScript را اضافه کنیم تا این معین در واقع کار کند:

// Get all open dialog buttons.const openButtons = document.querySelectorAll(".open-dialog");// Get all close dialog buttons.const closeButtons = document.querySelectorAll(".close-dialog");// Add click event listeners to open buttons.openButtons.forEach((button) =< {  button.addEventListener("click", () =< {    const targetId = button.getAttribute("data-target");    const dialog = document.getElementById(targetId);    if (dialog) {      dialog.showModal();    }  });});// Add click event listeners to close buttons.closeButtons.forEach((button) =< {  button.addEventListener("click", () =< {    const targetId = button.getAttribute("data-target");    const dialog = document.getElementById(targetId);    if (dialog) {      dialog.close();    }  });});

من از سبک های زیر به عنوان نقطه شروع استفاده می کنم. توجه کنید که چگونه یک ظاهر طراحی می کنم ::backdrop به عنوان یک امتیاز اضافی!

dialog {  padding: 30px;  width: 100%;  max-width: 600px;  background: #fff;  border-radius: 8px;  border: 0;  box-shadow:     rgba(0, 0, 0, 0.3) 0px 19px 38px,    rgba(0, 0, 0, 0.22) 0px 15px 12px;      &::backdrop {    background-image: linear-gradient(      45deg in oklab,      oklch(80% 0.4 222) 0%,      oklch(35% 0.5 313) 100%    );  }}

این منجر به انتقال بسیار سخت برای ورود می شود ، به این معنی که خیلی صاف نیست:

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

dialog {  opacity: 0;  translate: 0 30%;  transition-property: opacity, translate, display;  transition-duration: 0.8s;  transition-behavior: allow-discrete;    &(open) {    opacity: 1;    translate: 0 0;    @starting-style {      opacity: 0;      translate: 0 -30%;    }  }}

هنگامی که یک گفتگو باز است ، مرورگر سیلی می زند open ویژگی در آن:

 ... 

و این چیز دیگری است که می توانیم با CSS هدف قرار دهیم ، مانند dialog(open)بشر بنابراین ، در این حالت ، ما باید تنظیم کنیم @starting-style برای وقتی که گفتگو در یک است open دولت

بیایید در حالی که در آن هستیم ، یک انتقال برای پس زمینه خود اضافه کنیم:

dialog {  /* etc. */  &::backdrop {    opacity: 0;    transition-property: opacity;    transition-duration: 1s;  }  &(open) {    /* etc. */    &::backdrop {      opacity: 0.8;      @starting-style {        opacity: 0;      }    }  }}

حالا احتمالاً فکر می کنید: هه اما شما باید اضافه کنید display خاصیت و transition-behavior: allow-discrete در پس زمینه!

اما نه ، اینگونه نیست. حتی اگر من پس زمینه شبه خود را به CSS زیر تغییر دهم ، نتیجه همان باقی می ماند:

 &::backdrop {    opacity: 0;    transition-property: opacity, display;    transition-duration: 1s;    transition-behavior: allow-discrete;  }

معلوم است که ما با یک کار می کنیم ::backdrop و هنگام کار با a ::backdrop، ما به طور ضمنی با CSS نیز کار می کنیم overlay ویژگی ، که مشخص می کند آیا عنصری که در لایه بالا ظاهر می شود در حال حاضر در لایه بالا ارائه شده است.

وت overlay به همین ترتیب اتفاق می افتد که یکی دیگر از ویژگی های گسسته است که ما باید در آن بگنجانیم transition-property اعلامیه:

dialog {  /* etc. */&::backdrop {  transition-property: opacity, display, overlay;  /* etc. */}

متأسفانه ، این در حال حاضر فقط در مرورگرهای کروم پشتیبانی می شود ، اما می توان از آن به عنوان یک پیشرفت مترقی استفاده کرد.

و ، بله ، ما باید آن را به dialog سبک ها نیز:

dialog {  transition-property: opacity, translate, display, overlay;  /* etc. */&::backdrop {  transition-property: opacity, display, overlay;  /* etc. */}

به قلم (گفتگوی: شروع سبک ، انتقال-behavior ، روکش (چنگال)) (https://codepen.io/smashingmag/pen/pvzqoge) را مشاهده کنید.

به گفتگوی قلم مراجعه کنید: به سبک شروع ، انتقال-رفتار ، روکش (چنگال) توسط AtilityBend.

به جای گفتگو ، برای یک پوپور تقریباً یکسان است. من از همین تکنیک استفاده می کنم ، فقط این بار با Popovers کار می کنم:

قلم (انتقال Popover با @stary-Style (Forked)) (https://codepen.io/smashingmag/pen/emoblxe) را توسط AltilityBend مشاهده کنید.

انتقال Pen Popover را با @start-stary (Forked) توسط AlilityBend مشاهده کنید.

سایر خصوصیات گسسته

علاوه بر مواردی که در اینجا پوشش داده ایم ، چند خاصیت گسسته دیگر نیز وجود دارد. اگر نسخه ی نمایشی دوم را به یاد دارید ، جایی که ما برخی از موارد را از و به آن منتقل کردیم display: none، با همین visibility در عوض خاصیت این می تواند برای مواردی که می خواهید مواردی را برای حفظ فضای جعبه عنصر حفظ کنید ، حتی اگر نامرئی باشد ، مفید باشد.

بنابراین ، در اینجا همان مثال ، فقط با استفاده از visibility به جای displayبشر

قلم (انتقال خاصیت دید (Forked)) (https://codepen.io/smashingmag/pen/lepmjqx) را توسط AltilityBend مشاهده کنید.

قلم را در حال انتقال خاصیت دید (FORKED) توسط AlilityBend مشاهده کنید.

CSS mix-blend-mode ملک یکی دیگر از مواردی است که گسسته تلقی می شود. برای اینکه کاملاً صادقانه بگویم ، من نمی توانم یک مورد استفاده خوب برای نسخه ی نمایشی پیدا کنم. اما من جلوتر رفتم و نمونه ای از این دست را ایجاد کردم که در آن دو mix-blend-modeS درست در وسط انتقال به جای فوراً تغییر دهید.

به قلم (https://codepen.io/smashingmag/pen/bnboxzp) به قلم (transitioning mix-mode (forked)) مراجعه کنید.

به استفاده از AlilityBend ، Mix-Mix Mix-Mix (Forked) را مشاهده کنید.

پیچیدن

این یک مرور کلی در مورد چگونگی انتقال عناصر به داخل و خارج از لایه بالا است! در یک دنیای ایده آل ، ما می توانیم بدون نیاز به یک ملک کاملاً جدید مانند transition-behavior فقط برای انتقال در غیر این صورت خواص "غیرقابل انتقال" ، اما ما در اینجا هستیم و خوشحالم که آن را داریم.

اما ما نیز باید در مورد آن بیاموزیم @starting-style و اینکه چگونه مجموعه ای از سبک ها را به مرورگرها ارائه می دهد که می توانیم برای شروع یک انتقال برای عنصری که در لایه بالایی قرار دارد ، استفاده کنیم. در غیر این صورت ، این عنصر هیچ چیزی برای انتقال از ابتدا ارائه نمی دهد ، و ما هیچ راهی برای انتقال آنها به راحتی در داخل و خارج از لایه بالا نداریم.

سرمقاله خرد کردن(GG ، YK)

منبع: https://smashingmagazine.com/2025/01/transitioning-top-layer-entries-display-property-css/