Animate from display none
HTML-код
- Опубликовано: 2 июн 2024
- A common problem people ask me about is animating from, or to display: none, since it's not an animatable property.
After making my recent video on the dialog element, I got a lot of questions about animating it in and out, and it just so happens to use `display: none` when it's closed, so I saw it as a good opportunity to take a look at it.
🔗 Links
✅ The video on the dialog element: • dialog = the easiest w...
✅ The CodePen: codepen.io/kevinpowell/pen/QW...
✅ Open Props: open-props.style/
✅ Video introducing Open Props: • Supercharge your CSS w...
⌚ Timestamps
00:00 - Introduction
01:32 - What we're starting with
01:59 - Adding the animation on open
02:52 - The problem with backdrop
03:53 - Getting the backdrop to fade in
04:31 - Why it's easy to animate on open but not on close
05:28 - A quick fix for animating the close
06:37 - the problems with this solution
08:37 - Making a "closing" state
09:15 - Making the closing state work
14:06 - The problem with different animations on close
15:01 - Closing when we click outside the modal
19:36 - fixing the backdrop shadow effect
#css
--
Come hang out with other dev's in my Discord Community
💬 / discord
Keep up to date with everything I'm up to
✉ www.kevinpowell.co/newsletter
Come hang out with me live every Monday on Twitch!
📺 / kevinpowellcss
---
Help support my channel
👨🎓 Get a course: www.kevinpowell.co/courses
👕 Buy a shirt: teespring.com/stores/making-t...
💖 Support me on Patreon: / kevinpowell
---
My editor: VS Code - code.visualstudio.com/
---
I'm on some other places on the internet too!
If you'd like a behind the scenes and previews of what's coming up on my RUclips channel, make sure to follow me on Instagram and Twitter.
Twitter: / kevinjpowell
Codepen: codepen.io/kevinpowell/
Github: github.com/kevin-powell
---
And whatever you do, don't forget to keep on making your corner of the internet just a little bit more awesome!
This video is well worth the watch for the tip about "{once:true}" event listener parameter. 🙏
Right! I normally would just do a "removeEventListener" inside the event listener 😅
@@gilneyn.mathias1134 followed by 38 minutes of debugging why the fuck the stupid thing won't stop once I click it ITS SUPPOSED TO STOP NOW WHY
Faking the dialog::backdrop with a box-shadow is brilliant. Wonderful tip!
😂
Wow, that is what i've been looking for so long, to spice up my boring Modal boxes a bit XD
i'm literally writing in a youtube comment section for the second time of my life, but i have to say it. I was looking for exactly this kind of problem and exactly you @Kevin Powell had an video about it. The nice thing about it is, that all your other videos are just equally helpful, so it's just amazing !!!
Have run into this issue multiple times in the past and appreciate your insight here!
This is awesome! Another option would be to create an open and close class with opacity transitions. Then add or remove the classes with JS and use a setTimeout to “display:none” after the object finishes fading.
Kevin, I just want to say thank you for all the information you giving to us and for discord community, there are so many friendly, pleasant and ready to help people! Today one of them helped me a lot with my problem👍😉
I really really like your thorough explanation on how everything works. High quality content!!!
It would make me much less frustrated of css if you have a solution for animating height between auto and 0 without an arbitrary max-height, that causes an pause at the beginning/end of the animation.
One of the most annoying things about modern-day CSS and front-end web development.
@Grayson Peddie only works for static content, and not in responsive ... i have cms where the customers put whatever they want - so that's not a working solution for me
You don’t want to animate height. It’s bad for performance. It depends on your use case but maybe transform: scaleY() can fit your needs
@@roye7304 it’s fine to animate height as long as it’s done properly
It's a pain. I get around the issue by:
1. Add an inner wrapper element
2. Detect height of inner wrapper
3. Apply height of inner wrapper as max height of outer wrapper
4. Animate max-height (and visibility for accessibility) when opening & closing.
The browser doesn't always detect the correct height though, adding a time out delay to the max-height calculation often helps but it typically doesn't completly eliminate the issue.
Also, if the screen size changes you need to update the max-height setting to accommodate the new content height.
THANK YOU. I have been working through Frontend Mentor projects, trying to add my own flair as I go, and this had been the feature no one has been able to help me with. Idk how you read my mind, but you did.
Kevin, I have an issue "I can't do it opacity or visible it's gotta be displayed: none but same time it has to be with the transition. It has to be some way but I cant figured out." but then you came out and show us how precious you are. THANK YOU KEVIN. For making web more enjoyable and easy. Thank you mentoring us.
Literally was going to tackle this problem today, thanks for the timely video!
This was perfect timing for my current project!
I love it that you always bring the content that I didn't know that I needed it 😍
Always when I have a problem at work, Kevin uploads a video solving it... U r the best
The box-shadow trick worked well! I would never have thought to do that. Nice one, Kevin!
I've been a web developer for 19 years, professionally for 4 years, and this is the first time I've ever heard of the animationend event! Just goes to show we're all always learning, especially in tech fields 🙂
Holy Crap!! I've been searching for a solution to this for a bit. Thanks for the timely video. You Rock!
Excellent breakdown wish I had seen your video this morning, would have been a big help today.
If only I had known about the animationend event... I've always used some complex JS code snippet to pull the value of a CSS variable to calculate when a transition/animation was over. Thanks a ton!!
Btw. there's also a transitionend event, in case you're working with a transition instead :)
yeah, I have spent a couple of days trying to code this functionality in JS and after I finished it I found out about the animationend and transitionend events
Thank you for keeping my request and creating this video ❤️❤️❤️
I used the same solution for animating the / from display none. giving it a temporary closing state is a great solution :)
I always get so confused about which video to watch first. You have a lot of knowledgeable videos. Thanks a lot.
I was waiting for this so for so long , Thanks
Kevin, your videos are amazing and help me a lot!
What a beast. Thank you for these tips, really cool StuffIt.
I've been searching for this solution for almost 24hours, Never knew display properties were not animatable...Thanks Kevin :)
youre videos are spot on man! keep up the great work!
wanted to let you know that you inspired me like half a year ago to get back to coding again, i never studied web development before, but after seeing a couple of your videos i was instantly hooked.
with your help i got good with css and html, but i didnt stop there, i learned A LOT more, js for dom manipulation, and after that came serverside nodejs and now i host my own web application thats actually useful to a company.
and now this video, i was just thinking about how can i animate display:flex to display:grid, to make the change smoother. did google implement mindreading algorithm or what?
That's amazing, many thanks for your lessons
That was full of knowledge. Thanks.
About 5 months later, I've already got a 7 in my web dev class, but I can't be mad at you Kevin. Great video dude, thanks for this.
Awesome video! had the same issue multiple times. Thanks for the solution.
I literally thought this was impossible. Thanks!
What makes it complicated is that the backdrop is not in the DOM when the open is off. I found out using the developer tools that there is no browser style sheet for it, even though my own styling does apply. (...to an element that isn't there.)
If it was in the DOM when open is off, the opacity-transition would work. Although that would still leave it in the way of the regular content as well.
Having made quite a few dialogs myself (the one from bootstrap kept acting up in the complex designs our designer came up with) I usually make the backdrop a container with the dialog itself inside. That makes it behave much like a single thing. Way easier to make it look nice, and play nice with the rest of the page. Opening and closing is as simple as adding and removing a css class. Or checking/unchecking a checkbox.
I think I will keep doing that, considering the tricks needed to do it with dialog.
The solution here seems needlessly complex, with animations and javascript timed classes. With the backdrop not removed, it can be done with transitions and no javascript at all.
I have a codepen showing it. But I can't post that in a comment here.
Same problem i have been facing, and your just published this video😍
I never knew you could add additional properties like 'once' to event listener, very cool!
Wow this is what I was looking for damn, thank you!
For some reason, I find I like the ending animation to be quicker. Even just seeing the modal drop away looks better to me than the same length animation as opening. It looks more energetic in taking you back to the main content. It particularly looks good when the modal actually has options and changes something about the underlying document.
I'd suggest playing around with the speed of the closing animation is, and seeing if it feels better. Heck, maybe even make each animation speed into a variable.
For fading out, I usually create something like 'active' class but for modal with opacity: 1; & display: block; but with each separate class (and default modal styles is opacity: 0; & display: none;)
and later, ill just remove the 'modal--active-opacity' first, then use setTimeout for removing the the 'modal--active-display'.
You could use the same duration as how long your transition-duratiom goes for the timeout.
And the same goes for activating the modal but reverse the action with much lower duration timeout (let's say 50ms).
same been using this approach since i was starting to learn DOM
I thought I was the only person dealing with this issue... thank you so much 😭😭😭😭
Wow!
Thats once: true was especially eye poppingly gorgeous and elegant!
**that
It's helpful Thanks Kevin
I think you're the best web developer ever existed 👏👏👌👍💪
this is quite useful, Thank you
I was almost certain you were going to do this pure CSS!
You make me fall in love with css❤
Also, in details tag in HTML, there is an 'open' attribute, which can be used to animate as well.))
after a couple years of health challenges making my brain too foggy for words, I'm binging all the KP vids I've missed. I also, this month, for the first time ever, heard your gretting correctly. (After finding zero references to "Canadian slang friend and friends")
dang it!! Was just dealing with this issue a few days ago.(transitioning views though). You're a day late and a dollar short Kevin!! :) And i'm busy regrowing the hair i ripped out of my head. Thanks hoss, love your vids.
I’ve found the visibility: collapse or hidden (don’t remember which one lol) rule to be really useful here as a replacement for display: none, as the element still exits but is not visible and can be animated from
From intellisense...
visibility: collapse; "Table-specific. If used on elements other than rows, row groups, columns, or column groups, 'collapse' has the same meaning as 'hidden'."
You are CSS KING!!!
Just gave up on that problem, thank you!
There is also an event "transitionend", so you can do the same thing with transitions.
well, snap! i had no idea you could do all that (i knew about modals, but not all that fancy stuff wow)! very nice.
I think `vmax` is safer in the firefox workaround, for tall narrow devices with little content in the dialog, the backdrop will use the width for the backdrop but it may not be enough to cover the screen, with vmax it will use the largest of both sides so it will always cover the screen no matter the size
FYI, visibility: hidden will hide an element from screen readers and it’s animatable so you don’t need to use display none.
@@Zakum that's also true
@@Zakum - I have not found that to be true. Maybe it depends on what you’re placing the visibility hidden on. I’ve usually put it on custom modals wrapped in a div or section element.
@@Zakum if it is set to "visibility: hidden;" it will not be interactive. It will technically take up space on the page which is what you are probably thinking of. A dialog is not in the regular document flow though so that's a mute point. Visibility is the best way to achieve this effect.
You guys are right. I mixed it up with opacity since visibility hidden still takes space as Daniel said.
But it keep the element maintains it's size.
If I am not mistaken, transitions on the backdrop don't work because the backdrop is part of the dialog element which initially has display: none; on it. And that display: none; causes the dialog element not to create a box. So the ::backdrop pseudo-element also doesn't create a box. And if an element doesn't create a box, no transitions apply.
very nice, thanks!
BTW: display: none does _not_ remove the element from the dom. No css does ever change the dom. It only appears as if.
Amazing
Great video, I would love to see a video explaining how to do those "drawers" that people usually use in FAQ sections
you mean detail tag in HTML?
finaly found!! thx
Was this inspired by Adam Argyle Dialog GUI challenges video, uploaded yesterday? Cause it seems really similar.
i think we can overcome the issue with customising the two animations by using event.animationName to know when to remove the attr & close the modal. we'll also have to remove the once and manage that ourselves
6:38 - At this point in the video, add "visibility: hidden" to "visibility: visible" in the fade-in animation, and "visibility: visible" to "visibility: hidden" in the fade-out animation.
That will fix the accessibility issues and still achieve the desired affect with *no JavaScript*!
Ok yeah, it's not animating "display: none" but you don't have to.
but the element stays..in the DOM with this approach and still takes up it's width In the DOM
@@samuelokoli6584 yes but if you are doing a dialogue sort of thing, it is already taken out of the document flow due to the fixed positioning. So having it still take up space isn't actually a problem. You will need to add pointer-events: none; to the closed view to prevent people clicking on it though.
99% of the time, this is enough.
So nice
ur channel is great
Great!
This video helps me a lot! I now have a lot of refactoring to do hahaha. About the backdrop with box-shadow though - 100vw won’t work on mobile, will it? Because 100vw won’t cover the height of the viewport.
Thank you
OH MAN! How didn't I know that {once:true} trick before now??? HOW??? Thanks!
Hi, Kevin. Can we also use the method once you had shown in the 'space tourism navigation bar' RUclips video? Like if the browser supports, it will run a particular code, otherwise another one
Hey Kevin: question (or suggestion??): would 100vmax on the 2nd box shadow (eg @21:08) be preferable? I haven't played with it (clever, btw!) but, would there be issues with 100vw in situations where height > width? (eg, portrait mode mobiles, maybe rotated monitors)?
You're correct (I was going to write the same thing).
Great stuff, as usual. How do you stay up to date on CSS?
U r just amazing 🙏
Thank you 🙌
thank you
I think, animating opacity would be much more convenient and performant. If setting the opacity to 0 to hide the modal prevents users from clicking anywhere, pointer-events: none; does the job then setting it to all when the modal is open.
@Grayson Peddie Well, I don't think placing the markup for the modal dialog then just showing/hiding like the video shows or what Bootstrap does is a good idea for this exact reason. I prefer making a small Dialog object that works the same way as Sweetalert. So it's just one markup for everything, the modal title, body contents and click events are dynamically changed with JS. Much better.
I know what I'm saying has nothing to do with what the video shows though, not trying to foreshadow it but I just think this is a better approach specially because opacity is cheap to animate.
I wonder if there is a simpler way to do this by triggering a reflow / animation name change. Also maybe something like splitting animation into 0% to 99.99% and then 100% for the actual state change or something. btw maybe take a look at light brush? it's a very nice web painting application made in javascript, I think you'd enjoy pondering it.
Huh. I had thought there was a move towards treating opacity:0 as if it were visiblity:hidden.
I'd say the bigger problem with animating display:none is how you would handle objects that are actually within the main page layout, where other elements will move around to accommodate. I suspect you'd have to animate height and width.
Pretty good ! Thanks. - Animation with JQuery is a bit easier. Just add some code before the show and after the close - command - and you are done.. Then you do not need the solution with css and js.
🔥 content
Instead of using display:none and display:block you can use visibility:collapse and visibility:visible and this lets you animate with just transitions and there is no need for animations
Even though it’s in the name, I didn’t realize keyboards could still interact with a pointer-events: none; oops. Very very good to know
couldn't you just add visibility: hidden as part of your animation for fading out the modal? As for the fade-out on page load, is there no way to control that with animation-fill ?
I thought this too, I use visibility all of the time to animate between visible and hidden, are there any issues caused by the use of this?
The only issue I can think of off the top of my head is that "visibility: hidden" doesn't remove the element from the DOM's flow the way "display: none", which might cause layout issues if you don't explicitly account for it.
@@georgewoodman839 there are no issues with doing this. I use visibility all the time for stuff like this. It removes the element for keyboard and screen reader users and is designed to be used in animations.
Yes, visibility does not remove an element from the document flow, but we are talking about a dialog here. A dialog is ALREADY outside the document flow so it's a mute point.
I use aos scroll animations but was wondering if there's a way to make the elements stay loaded on the page after they have their little scroll-based animation play out. Currently, once the element is off screen its unloaded, and when I scroll from bottom to top of the page it'll replay those animations again which doesn't look good as I've laid them out for looking nice on scroll down. Any help is appreciated, thanks
How do you come up with these things that we need? Thanks Kevin
Kevin Powell, isn't it better use mouseX and bounds of dialog (offsetTop and clientHeight) instead of matching by tagName? (17:04)
In this moment we all are hating the CSS design team who made the display property unanimable.
For your next live build, you should make your video opener in CSS
Great video as always. I don’t understand when the display:none gets removed
Instead of javascript and "closing" attribute, a position: fixed; with top: -10000; left: -10000; would work as well, I guess?!? (I have to test it)
What JS book would you suggest to go along with CSS? (And forms)
All in all it's a pain in the a... I solved the problem with a setTimeout function which sets the display attribute to none after my fadeout animation finished which needs less workarounds for it to work.
Is there any chance to get to the backdrop-element via Javascript ? - For example to make it programatically blur. Seems that nobody knows an approach.
7:46 how about adding visibility: visible and hidden to fade-out? This prevents element from being focus or clicked I believe and it can be animated easily :)
I tried using it, but ran into an issue with it, though I forget exactly what it was right now. I didn't spend a ton of time trying to solve it though, so it might have been something silly I did.
I think the problem regarding visibility is, that the element is still getting rendered in the page. So you will have some elements already rendered without them being visible/used. Maybe it doesn't affect the performance by a lot, but I still think its worth thinking about
@@alexkawa6167 Yea, I agree. I think it will be nearly impossible to find perfect solution without javascript. But hey! CSS is evolving, who knows what we will get in the future! :D
@@Tysian full css w/o JavaScript? Hell yea haha
@@Tysian It's definitely exciting :D
Hi Kevin where's the flex box gallery with horizontal scroll video? thanks
FYI, instead of using the 'animationend', if you use Promise.all(modal.getAnimations().map(a => a.finished).then(() => { /* dialog close code */ }) then it will only run the dialog close code once all of the animations have finished.
Instead of adding a “close” attribute, you could add a “loaded” attribute on page load, then apply the animation effect to that attribute.
This only needs to run once so you don’t need to listen for animation end.
I don't think setting the shadow spread to 100vw is a good idea as it won't work as intended on screens that has portrait orientation because in that case the width is always smaller than the height thus on mobile devices the shadow won't be enough to reach to the top and bottom edge of the screen since it's limited to the devices viewport width which is smaller than the height as mentioned at the beginning, great video though.
Since you are using Javascript, why do you prefer to add attributes for the states instead of adding/removing classes?
Any hack to make css collapse/expand animation on height or width?