I have a sidebar that gets bigger on hover. In that sidebar, I have divs that contains extra-content which is only displayed when the sidebar is hovered. The code below works well:
HTML file
<!--Sidebar-->
<div class="group w-16 bg-blue-700 hover:w-44">Sidebar
<div>Item 1
<span class="hidden group-hover:inline">Item 1: Details</span>
</div>
<div>Item 2
<span class="hidden group-hover:inline">Item 2: Details</span>
</div>
</div>
CSS file
#tailwind base;
#tailwind components;
#tailwind utilities;
tailwind.config.js
module.exports = {
purge: [],
darkMode: false, // or 'media' or 'class'
theme: {},
extend: {},
variants: {
extend: {
width: ['hover'],
display: ['group-hover'],
},
},
plugins: [],
}
However, I would like to create a nice transition when the sidebar is hovered so that it gets bigger smoothly. I do this by changing the HTML file to -->
New HTML file
<!--Sidebar-->
<div class="group w-16 bg-blue-700 hover:w-44 transition-all">Sidebar
<div>Item 1
<span class="hidden group-hover:inline">Item 1: Details</span>
</div>
<div>Item 2
<span class="hidden group-hover:inline">Item 2: Details</span>
</div>
</div>
Doing so, now, there is small bug when the sidebar is hovered: the extra content is displayed before the sidebar reaches its full-size.
I need to add a delay to the display of the extra content. Ideally, the sidebar would first gets bigger smoothly and reach its full-size, and only then the extra-content would appear. Is there a way to do so in native tailwind css?
To achieve this I did a simple hack for it.
As you may find yourself, tailwindcss-> group-hover:visible class represents:
.group:hover .group-hover\:visible {
visibility: visible;
}
So I changed group-hover:visible to xgroup-hover:visible and added some animation instead of original tailwindcss:
#keyframes tooltip-show {
0% {opacity: 0;}
5% {visibility: visible;}
25% {opacity: 50;}
50% {opacity: 75;}
100% {opacity: 100;}
}
.group:hover .xgroup-hover\:visible {
animation-delay: 0.7s;
animation-name: tooltip-show;
animation-duration: 2s;
}
this simple hack worked for me :)
So you can follow same way for your desired group-hover:inline class and add your own animation keyframes as you like.
Thanks to Ali javanmardi hints, I managed to achieve what I wanted. The main findings are:
Need to use Absolute positioning for Items Details in the sidebar
Adding a delay on a transition such as group-hover:visible delay-150 does not work in this specific case because this would lead the details to disappear after the sidebar is closed (because delay is applied at Start and End)
Instead, I created a custom animation of 1s, where the first "transition" keyframes happens at 15%, thus creating effectively a delay from 0% to 15%, combined with animation-fill-mode: forwards; Below is my code.
HTML file
<!--Sidebar-->
<div class="group w-16 bg-blue-700 hover:w-44 transition-all">Sidebar
<div class="relative">Item 1
<span class="absolute opacity-0 invisible group-hover:animate-tooltip_show ml-2">Item 1: Details</span>
</div>
<div class="relative">Item 2
<span class="absolute opacity-0 invisible group-hover:animate-tooltip_show ml-2">Item 2: Details</span>
</div>
</div>
tailwind.config.js
module.exports = {
purge: [],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {
keyframes: {
tooltip_show: {
'0%' : { visibility: 'hidden', opacity: '0'},
'15%' : { visibility: 'hidden', opacity: '0'},
'100%' : { visibility: 'visible', opacity: '100'},
}
},
animation: {
tooltip_show: 'tooltip_show 1s ease forwards',
}
},
},
variants: {
extend: {
width: ['hover'],
animation: ['group-hover'],
},
},
plugins: [],
}
Here's my implementation without using custom animation. You just need to add a delay when the parent is hovered, and reset the delay back to zero when the parent is not hovered.
<script src="https://cdn.tailwindcss.com"></script>
<style type="text/tailwindcss">
#layer components {
#container {
#apply flex flex-col items-center gap-2 mt-4;
};
#button {
#apply bg-blue-400 text-white p-1 rounded;
};
#tooltips {
#apply bg-green-400 p-0.5 w-24 left-1/2 -translate-x-1/2
translate-y-10 transition-opacity rounded;
};
};
</style>
<!-- Ignore previous code block, it's just for styling -->
<div id='container'>
<h1>Hover with delay tailwindcss<h1>
<button id='button' class='relative group'
>Hover me
<span id='tooltips' class='absolute
opacity-0
delay-0
group-hover:opacity-100
group-hover:delay-300'
>I'm here 👋</span>
</button>
</div>
Recently I have implemented some animations but I am having some problems when the animation ends. I have a div structure for responsiveness, that shows a menu button when the screen size is smaller than X.
When someone clicks on the menu button a left side bar, which is default set to display:none, is being shown by removing the display: none property immediately and then adding an animation class, this all works fine.
However, when the sidebar is collapsed again (by clicking on a close button), a new animation (for removing the menu) is being added, when this animation ends I need to set the display back to display:none (I don't want the sidebar take up any space).
In the current situation I accomplished this by setting some boolean variables that add display:none on false and removes it on true. My animation takes up to 300MS so I added a Task.Delay of 300MS to set the boolean. Sadly this doesn't create a perfect 'flow', you can see the screen hiccup because the setting of the display:none happens just a few MS to late. Of course I can decrease the Task.Delay to 290MS~ but this isn't a great solution.
Any ideas how I can accomplish this using Blazor?
Below the code:
HTML:
<!-- The mobile side bar, display: none default on screen sizes > X -->
<div class="md:hidden" style=#mobileSideBarDisplay>
<div class="fixed inset-0 flex z-40">
<! this sets the opacity of tyhe space to the right (grayed out) -->
<div class="fixed inset-0 #sidebarOverlayAnimation">
<div class="absolute inset-0 bg-gray-600 opacity-75"></div>
</div>
<!-- the actual side bar with it's buttons -->
<div class="relative flex-1 flex flex-col max-w-xs w-full pt-5 pb-4 bg-gray-800 #sidebarMenuAnimation">
<!-- Close button with which the sidebar menu can be closed -->
<button class=".." aria-label="Close sidebar" #onclick="ToggleSidebar"></button>
... Left out for readability
</div>
</div>
</div>
<!-- Static sidebar for desktop -->
<div class="hidden md:flex md:flex-shrink-0">
.. Left out for readability
</div>
<!-- menu button div which becomes visible at screensize < X
<div class="flex flex-col w-0 flex-1 overflow-hidden">
<!-- Menu button with which the sidebar menu can be opened -->
<button class=".. md:hidden" aria-label="Open sidebar" #onclick="ToggleSidebar">
.. Left out for readability
</div>
C# backend code:
#code {
// used to set display: none; (or empty)
private bool showMobileSideBar = false;
// Used to show / toggle animations
private bool showMobileSideBarAnimation = false;
// toggle animation and display classes
private string mobileSideBarDisplay => showMobileSideBar ? "" : "display: none;";
private string sidebarOverlayAnimation => showMobileSideBarAnimation ? "sidebar-overlay-animation-entering" : "sidebar-overlay-animation-leaving";
private string sidebarMenuAnimation => showMobileSideBarAnimation ? "sidebar-menu-animation-entering" : "sidebar-menu-animation-leaving";
// Function to display entering or leaving animation depending on the boolean value)
private async Task ToggleSidebar()
{
showMobileSideBarAnimation = !showMobileSideBarAnimation;
if (showMobileSideBar == true) // only delay when we need to set div to display: none;
{
await Task.Delay(300); // this works kinda clunky now
}
showMobileSideBar = !showMobileSideBar;
}
}
The CSS / animations:
/*
Animations for setting the right-space opacity (when the sidebar is shown / hidden)
*/
.sidebar-overlay-animation-entering {
animation-name: sidebar-overlay-entering;
animation-duration: 300ms;
animation-timing-function: linear;
}
#keyframes sidebar-overlay-entering {
from { opacity: 0; }
to { opacity: 1; }
}
.sidebar-overlay-animation-leaving {
animation-name: sidebar-overlay-leaving;
animation-duration: 300ms;
animation-timing-function: linear;
}
#keyframes sidebar-overlay-leaving {
from { opacity: 1; }
to { opacity: 0; }
}
/*
Animations for displaying the sidebar (in- and out)
*/
.sidebar-menu-animation-entering {
animation-name: sidebar-menu-entering;
animation-duration: 300ms;
animation-timing-function: ease-in-out;
}
#keyframes sidebar-menu-entering {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
.sidebar-menu-animation-leaving {
animation-name: sidebar-menu-leaving;
animation-duration: 300ms;
animation-timing-function: ease-in-out;
}
#keyframes sidebar-menu-leaving {
from { transform: translateX(0); }
to { transform: translateX(-100%); }
}
P.S. I tried using https://github.com/dazinator/BlazorDeferredRemove but I cant get it this to work. There is also not an example using animations (only transition with visibility) or using display: none; (But perhaps the library can work if someone could give a few pointers)
I have a dynamic span with dynamic class in my smarty template. The problem here is that the CSS assigned to those classes are not rendered. Everything works if I set things to static but when changed to dynamic it will not work anymore. I'm guessing the CSS is loaded first before the elements are rendered. What would be a good workaround for this?
Smarty:
<div id="wrapper">
<div id="word">
{counter start=9 print=false}
{foreach from=$currentUser item=name}
<span class="{counter}">{$name}</span>
{/foreach}
</div>
</div>
CSS that is not rendered:
#word span.l0 {
animation-delay: 0s;
}
#word span.l1 {
animation-delay: 0.375s;
}
#word span.l2 {
animation-delay: 0.75s;
}
#word span.l3 {
animation-delay: 1.125s;
}
#word span.l4 {
animation-delay: 1.5s;
}
Try this HTML code:
<div id="wrapper">
<div id="word">
{foreach from=$currentUser item=name key=i}
<span class="span.l{i}">
{$name}
</span>
{/foreach}
</div>
</div>
I was trying to do a page fade in when my app initially loads using appear; however, I am already using a routing css animation that does a fade in and fade out when going from page to page, but it still leaves me with an abrupt display of my page when it initially loads. So far, my attempts to add another transition tag around the routing transition in a outer nested way has failed. It still loads with an abrupt display of page. Any suggestions?
<template>
<div id="app">
<v-app>
<main>
<transition name="appearPageFadeIn" appear><!-- new appear tag -->
<cq-nav-mobile></cq-nav-mobile>
<cq-nav-desktop></cq-nav-desktop>
<transition name="interPageFadeOutIn" mode="out-in">
<router-view></router-view>
</transition>
<cq-footer></cq-footer>
</transition>
</main>
</v-app>
</div>
</template>
<!-- CSS -->
/* appear page animation */
.appearPageFadeIn-appear {
opacity: 0;
}
.appearPageFadeIn-appear-active {
transition: opacity 1s;
}
/* inter page routing animation */
.interPageFadeOutIn-enter {
opacity: 0;
}
.interPageFadeOutIn-enter-active {
transition: opacity 1s;
}
.interPageFadeOutIn-leave {
opacity: 1; //default
}
.interPageFadeOutIn-leave-active {
transition: opacity 1s;
opacity: 0;
}
I have a troublesome task. Image should be hidden and button showed by default. I want to show image and hide button, but when one animation ends, secound should start. transition should peroid 1 second. How to make it?
All code:
https://jsfiddle.net/169vuuk8/
HTML code:
<div class="showSingle" itemprop="1">
<img src="https://img.thegearpage.net/board/data/avatars/m/47/47608.jpg?1487188345" alt="logo">
<button class="button">button </button>
</div>
Looks like you just need transition-delay css property for second animation: https://developer.mozilla.org/en/docs/Web/CSS/transition-delay
You can either use transitionend event in js, but it is not really needed here: https://developer.mozilla.org/en/docs/Web/Events/transitionend
Not sure what you need exactly but below the image fades in the first second and the button out after 2 seconds delay.
.showSingle img {
opacity: 0;
animation: fadeInImage 1s ease-out forwards;
}
.showSingle button {
opacity: 1;
animation: fadeOutButton 1s ease-out 2s forwards;}
#keyframes fadeInImage {
to {
opacity: 1
}
}
#keyframes fadeOutButton {
to {
opacity: 0
}
}
<div class="showSingle" itemprop="1">
<img src="https://img.thegearpage.net/board/data/avatars/m/47/47608.jpg?1487188345" alt="logo">
<button class="button">button </button>
</div>