القواعد اللي هنمشي عليها
Dropdown: يفتح من مكانه ويقفل بسرعة
القائمة بتطلع من الزرار نفسه: transform-origin: top، من scale(0.95) وشفافة لحجمها الطبيعي. والعناصر بتنزل ورا بعض بـ stagger، زي شرايح الدونت.
القفل عكس كده: ١٢٠ms بس، من غير نطة، ومن غير stagger.
.menu { transform-origin: top; /* مقفولة: سريعة ومن غير نطة */ opacity: 0; transform: translateY(-6px) scale(0.95); visibility: hidden; transition: opacity 0.12s var(--ease-in), transform 0.12s var(--ease-in), visibility 0s 0.12s; /* تستخبى بعد ما الحركة تخلص */}.dd.open .menu { opacity: 1; transform: none; visibility: visible; transition: opacity 0.18s var(--ease-out), transform 0.26s var(--ease-back), visibility 0s;}/* stagger: كل عنصر متأخر 28ms عن اللي قبله (OpenStagger في Filee) */.menu li { opacity: 0; transform: translateY(-4px);}.dd.open .menu li { opacity: 1; transform: none; transition: opacity 0.2s, transform 0.3s var(--ease-back); transition-delay: calc(var(--i) * 28ms);}في Avalonia الفكرة إنك تحط animation على الـ Border اللي جوه الـ popup، يشتغل لما الـ ComboBox يبقى :dropdownopen:
<Style Selector="ComboBox:dropdownopen /template/ Border#PopupBorder"> <Style.Animations> <Animation Duration="0:0:0.22" Easing="CubicEaseOut" FillMode="Forward"> <KeyFrame Cue="0%"><Setter Property="Opacity" Value="0" /></KeyFrame> <KeyFrame Cue="100%"><Setter Property="Opacity" Value="1" /></KeyFrame> </Animation> </Style.Animations></Style>
Select: السهم يلف، والقيمة تتبدّل بحركة
نفس الـ dropdown، وفوقه تلات حاجات صغيرة:
- السهم بيلف
180degبنطة لما تفتح (زي سهم الرئيسية في Filee اللي بيلف 90). - علامة ✓ بتظهر من
scale(0.4)بنطة على الاختيار الجديد. - القيمة في الزرار بتطلع من تحت لما تتغير، فتعرف إن حاجة اتغيرت.
.chev { transition: transform 0.3s var(--ease-back); }.open .chev { transform: rotate(180deg); }.check { opacity: 0; transform: scale(0.4); transition: opacity 0.15s, transform 0.3s var(--ease-back); }[aria-selected="true"] > .check { opacity: 1; transform: none; }.value.swap { animation: swap 0.3s var(--ease-back); }@keyframes swap { from { opacity: 0; transform: translateY(8px); } }
Tabs: مؤشر بيتزحلق، ومحتوى جاي من الناحية الصح
بدل ما الخط اللي تحت التاب يختفي ويظهر في مكان تاني، فيه مؤشر واحد بيتزحلق لمكان التاب الجديد بـ BackEaseOut. والمحتوى الجديد بيدخل من ناحية التاب اللي رحتله: لو رحت للي بعده، ييجي من ناحيته.
PNG · JPG · WEBP · AVIF
// المؤشر بيتحرك لمكان وعرض التاب الجديد. الحركة نفسها في CSSfunction place(tab: HTMLElement) { ink.style.setProperty("--x", `${tab.offsetLeft}px`); ink.style.setProperty("--w", `${tab.offsetWidth}px`);}// الصفحة RTL: التاب اللي بعده على الشمال، فالمحتوى ييجي من الشمالconst from = next > current ? "from-left" : "from-right";.ink { position: absolute; left: var(--x); width: var(--w); transition: left 0.35s var(--ease-back), width 0.35s var(--ease-back);}
في Avalonia ممكن تعمل نفس المؤشر بـ Border واحد فوق التابات، و DoubleTransition على Canvas.Left و Width، وتحسب مكان التاب في الـ code-behind.
Modal: الخلفية تغمق، والـ dialog ينط
حاجتين بيتحركوا مع بعض، بمدد مختلفة:
- الخلفية بتغمق بـ
opacityفي ٢٠٠ms، من غير نطة. - الـ dialog بيكبر من
scale(0.9)في ٣٢٠ms بنطة. - القفل للاتنين في ١٦٠ms بـ EaseInCubic، زي قفل الدونت بالظبط.
function open() { backdrop.hidden = false; // فريمين: الأول يرسم الحالة المقفولة، التاني يبدأ الحركة منها requestAnimationFrame(() => requestAnimationFrame(() => backdrop.classList.add("open")));}function close() { backdrop.classList.remove("open"); // استنى الحركة تخلص قبل ما تخفي (زي FinishClose في Filee) setTimeout(() => (backdrop.hidden = true), 170);}Switch: الزرار يتمط وانت دايس
الزرار الأبيض بيتزحلق بنطة، والخلفية بتتلوّن في ١٥٠ms. والتفصيلة الحلوة: وانت دايس، الزرار بيعرض شوية (width: 24px بدل 20px)، كأنه بيستعد يتنقل.
.switch { transition: background-color 0.15s; }.switch i { transition: transform 0.3s var(--ease-back), width 0.15s; }.switch:active i { width: 24px; }.switch[aria-checked="true"] i { transform: translateX(20px); }.switch[aria-checked="true"]:active i { transform: translateX(16px); } /* يتمط ناحية الشمال */
Tooltip: يستنى قبل ما يظهر، ويمشي علطول
الـ tooltip اللي بيظهر مع كل حركة ماوس مزعج. فـ:
- الظهور بعد
300msاستنى، وبعدين يطلع بنطة صغيرة. - الاختفاء فوري تقريبًا (١٠٠ms)، من غير استنى.
.tip { opacity: 0; transform: translate(-50%, 4px); transition: opacity 0.1s, transform 0.1s; /* الاختفاء */}.wrap:hover .tip { opacity: 1; transform: translate(-50%, 0); transition: opacity 0.18s 0.3s, transform 0.25s var(--ease-back) 0.3s; /* الظهور بعد 300ms */}
الحيلة: الـ transition اللي في الحالة الجديدة هو اللي بيتطبق. فتحط delay في الـ :hover بس، والاختفاء ياخد الـ transition العادي من غير delay. في Avalonia في ToolTip.ShowDelay جاهزة للتأخير.
Accordion: grid من صفر لواحد + سهم بيلف ٩٠
سهم الرئيسية في Filee بيلف من 0 لـ 90deg لما تفتح. ضيف عليه فتح القسم بـ grid-template-rows من 0fr لـ 1fr (اتشرحت بالتفصيل في مذكرة الـ Smooth Collapse).
PNG ← JPG ← WEBP. كلها جوه Magick.NET.
DOCX و PDF و HWPX. الأصعب بيروح LibreOffice.
كله على FFmpeg، وبيتنزّل أول ما تحتاجه.
.body { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.3s var(--ease-out); }.open .body { grid-template-rows: 1fr; }.body > div { overflow: hidden; } /* القص على الابن */.chev { transition: transform 0.3s var(--ease-back); }.open .chev { transform: rotate(90deg); }
في Avalonia الـ Expander عنده خاصية ContentTransition تحط فيها CrossFade مثلًا. ولصفحات كاملة فيه TransitioningContentControl مع PageSlide أو CrossFade.