I see an annoying bug happening at the end of the animation loop, where it blinks for a fraction of a second, and makes the animation look choppy.
Here is the pen.
SCSS:
$dim: 60px;
$mult: 1.8;
$color: #bada55;
body, html {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
background-color: #36a;
}
.circle {
background-color: $color;
border-radius: 50%;
width: $dim;
height: $dim;
position: relative;
}
.circle:before {
content: "";
display: table;
background-color: $color;
border-radius: 50%;
position: absolute;
animation: notification 800ms ease-in infinite;
}
#keyframes notification{
0% {
opacity: 1;
width: $dim;
height: $dim;
left: 0;
top: 0;
}
90% {
opacity: 0;
left: -(($dim * $mult) - $dim)/2;
top: -(($dim * $mult) - $dim)/2;
width: $dim * $mult;
height: $dim * $mult;
}
100% {
opacity: 0;
width: $dim;
height: $dim;
left: 0;
top: 0;
}
}
I've tried adding another frame, but it doesn't really remove it. I also tried hiding the before div afterwards, but doesn't work. Neither with z-index.
Any suggestions?
The problem with the "choppy" behaviour is: You change the dimensions and the positioning of your element. This forces the browser to re-render the element (in this case your :before pseudo-element. This makes the calculation for the browser way harder than it has to be.
Instead of alternating the dimensions, you could use a simple transform. Transforming elements does not force a re-rendering of the element and therefore performs way smoother. Also, it makes the code a bit easier as well. I forked your CodePen and used the transform instead of the dimensions: http://codepen.io/HerrBertling/pen/NbrPJb
It's certainly not perfect concerning the animation and the dimensions, but it should run way smoother.
(Check e.g. this Medium post for further info about the browser's behaviour: https://medium.com/outsystems-experts/how-to-achieve-60-fps-animations-with-css3-db7b98610108#.sykm5uqyv)
Related
why animation can be reusable after im changing elemets display property with js
can some one explain i couldnt find any answer for this
can someone explain me this
my codes downbelow
`
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
aside {
display: none;
position: relative;
left: -100%;
height: 100vh;
background-color: red;
width: 20%;
animation: openit 800ms ease-in forwards ;
}
#keyframes openit {
to{
left: 0;
}
}
aside a {
display: block;
}
.open {
position: absolute;
z-index: -1;
}
</style>
`
I found this:
When we want to use transition for display:none to display:block, transition properties do not work. The reason for this is, display:none property is used for removing block and display:block property is used for displaying block. A block cannot be partly displayed. Either it is available or unavailable. That is why the transition property does not work.
form this link. I hope this help.
I am trying to make animation for the side menu. If I open the menu animation is working exactly how I want, the issue is, that I cannot make animation when I close it. Is there some property to make it animate back after the menu closes? Best would be if I could do it with css animations.
app.component.html
<app-menu *ngIf="showMenu"></app-menu>
Animation triggers when I toggle showMenu variable but it just disappear after I set it false.
menu.component.html
<div class="menu-panel" (click)="$event.stopPropagation();">
styles.scss
app-menu {
display: inline-block;
z-index: 100;
position: absolute;
height: 100vh;
width: 100vw;
}
#keyframes menu-panel {
0% {
background-color: #00FF9B;
left: -$menu-width;
}
100% {
background-color: #B290FF;
left: 0;
}
}
.menu-panel {
position: absolute;
display: inline-block;
width: $menu-width;
height: 100%;
background-color: #B290FF;
animation: menu-panel 500ms linear;
z-index: 100;
}
Try using transition instead. Control whether the panel is opened by a class .open. That's just the idea, try tweaking yourself to fits your need.
app-menu {
display: inline-block;
z-index: 100;
position: absolute;
height: 100vh;
width: 100vw;
}
.menu-panel {
position: absolute;
display: inline-block;
width: $menu-width;
height: 100%;
z-index: 100;
transition: all 500ms;
background-color: #00FF9B;
left: -$menu-width;
}
.menu-panel.open {
background-color: #B290FF;
left: 0;
}
I want to use a CSS transform to animate a video to display on a page, but I want the video to push the content down as it animates in, instead of the default situation where the space of the video already exists within the UI.
I created a jsfiddle to show what I mean here: https://jsfiddle.net/njpatten/198sh5ec/2/
I prefer to only transform the element for performance reasons, but I've tried modifying height as well to get the desired effect, but the result is a bit jumpy, and also not as performant as I'd like.
.video {
transform-origin: 0 0;
transform: scale(0, 0);
transition: 0.2s;
height: 0;
&.open {
transform: scale(1, 1);
height: 100%;
}
}
Is there a 'hack' that I'm missing that could solve this issue? How do animators deal with the element taking up space when trying to animate in an element while still keeping things performant (and therefore only animating transforms and opacity).
Thanks in advance!
Unfortunately, transform isn't going to cut it. It can't affect the layout of the document, which is what you're trying to achieve with pushing the text copy down. That said, I would approach this by first making the iframe container set its own dimensions based on an aspect ratio. Your video is at 560x315 which calculated as a percentage is 56.25% as tall as it is wide. The percentage is needed because it can be used with the "padding trick" to get an element that scales according to aspect ratio. So the first part is to make your video container based on aspect ratio:
.video {
position: relative;
max-width: 560px;
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
&:after {
content: '';
display: block;
padding-top: 56.25%;
}
}
As you'll notice you can now set the width of .video and it will always have the right height for the video. Next we need to add the transition. We'll be transitioning the padding-top property.
.video {
position: relative;
max-width: 560px;
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
&:after {
content: '';
display: block;
padding-top: 0%;
transition: padding 0.2s;
}
&.open:after {
padding-top: 56.25%;
}
}
Lastly, you can add a transition to your video so it scales up instead of opens like a shade:
.video {
position: relative;
max-width: 560px;
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transition: transform 0.2s;
transform-origin: 0 0;
transform: scale(0,0);
}
&:after {
content: '';
display: block;
padding-top: 0%;
transition: padding 0.2s;
}
&.open:after {
padding-top: 56.25%;
}
&.open iframe {
transform: scale(1,1);
}
}
The end result is similar but not exact to what you were wanting:
https://jsfiddle.net/jmarikle/kjd87was/
I will eventually have a grid of embedded YouTube videos on a grid that are each initially covered by an overlay that will contain information about the relevant video. On hovering over the overlay, it slides away, leaving the video visible.
The problem is that once the overlay is out of sight, the hover is no longer in effect, so the overlay returns if you even twitch the mouse over the video. I'm bound to be missing something stupid, but I can't for the life of me figure out what it is.
Here's the CSS
.vid-wrap {
position: relative;
padding-bottom: 56.25%;
/* 16:9 */
padding-top: 0px;
height: 0;
overflow: hidden;
}
.vid-wrap iframe, .vid-wrap .vid-overlay {
cursor: pointer;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
.vid-wrap .vid-overlay {
z-index: 1;
background-color: green;
}
.vid-wrap .vid-overlay:hover {
top: -100%;
transition: all .5s;
}
You can just add this CSS to fix your issue
.vid-wrap:hover .vid-overlay{
top: -100%
}
This should fix your problem.
As I was in the process of trying to make an animated figure (transitions on hover), I found out that the background of my <figure> is showing near the edges when I apply border-radius: 50% to it, even though my image should be taking up all available space.
For a quick demo that illustrates the problem, please look at http://codepen.io/anon/pen/KwMMKz
HTML
<figure>
<img src="http://placehold.it/400x400" alt>
<figcaption>Demo</figcaption>
</figure>
CSS
figure {
background-color: red;
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
position: relative; /* For caption */
}
img {
border-radius: 50%; /* Forced on image for smooth transition */
width: 100%;
transition: opacity 1s ease-out;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
}
figure:hover img {
opacity: 0;
}
figure:hover figcaption {
top: 50%;
}
Please note: I know that placing the background-color on figure:hover is a work-around, but I am more interested in the reason why this "jagged border"-like look is appearing.
My guess is that it has to do with AA rendering (or something related) of the browser and that it treats theĀ <figure> element differently than a media element such as <img>, but I can't find any proof of this online. Is this a bug, is it a "feature", or is it something I can actually fix?
Lastly, I also know that I could have used transform: translateY(); here for the animation, but that's not part of my question so please don't provide it as an answer.
UPDATE 17/12 14:03
It appears that this issue is not exclusive to border-radius: 50%. The issue can occur when any wrapping element uses border-radius in combination with overflow: hidden, when the wrapper contains content that is equal or bigger than the wrapper's dimensions.
UPDATE 17/12 14:14
Neither the usage of overflow: hidden on the wrapper element, nor the usage of border-radius on the contained image (or any other child element) seem to be the cause of this as they can be interchanged and the pixelated edge will still appear.
This seems to indicate that this issue is solely caused by 2 DOM elements being in exactly the same place, when any sort of border-radius is applied to the wrapper element and the visible area of the child is limited to that of the parent's.
I've been having same issue and ended up using pseudo element instead of background, kinda like that:
figure::before {
content: '';
display: block;
background-color: red;
width: 400px;
height: 400px;
transform: scale(0.997);
border-radius: 50%;
}
This allowed me to create 'pseudo background' which I later shrinked a little bit with transform: scale(0.997); so it will be just the same size but a bit below visible edge. Of course in your case you would also need to position image absolutely so it is not pushed below by this ::before.
It appears that it is indeed a "feature" of how the browser handles border-radius to give a smooth edge to the rounded corners of a container. The image background is anti-aliased in the same way (but as it is transparent has no effect) as can be seen by setting the img background color.
When the border is anti-aliased it "bleeds" into the background to soften the edges and so you are seeing that around the image as a "jaggy" ring in much the same way you would see a corona around the moon during a full solar eclipse.
the issue is always there, whether the anti-aliased object is covered or not, if you were to draw a circle then anti-alias it, you would see the circle is marginally narrower than the anti-aliased version. Most anti-aliasing algorithms aggregate the surrounding pixels of the object rather than those contained within it.
To overcome it, you'd either need to make your image large enough to cover the space taken up by the anti-aliased edge or reduce the container such that the anti-aliased area is smaller than the image.
You could add a new tag with an opacity of 0 then have that fade in with the image fading out.
figure {
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
position: relative; /* For caption */
}
background {
background-color: red;
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
opacity: 0;
position: fixed;
z-index: 5;
transition: opacity 1s ease-out;
}
img {
border-radius: 50%; /* Forced on image for smooth transition */
width: 100%;
transition: opacity 1s ease-out;
position: relative;
z-index: 100;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
z-index: 10000;
}
figure:hover img {
opacity: 0;
}
figure:hover background {
opacity: 1;
}
figure:hover figcaption {
top: 50%;
}
<figure>
<background></background>
<img src="http://placehold.it/400x400" alt>
<figcaption>Demo</figcaption>
</figure>
Notice I added the background tag and removed background-color from figure
http://codepen.io/marczking/pen/KwMgaR
So after playing around (used background-image and pseudo-elements, changes nothing...) you notice that this light border is only visible if you apply round corners. So I am assuming here it has to do how the Browser renders the CSS, nothing wrong with the CSS-rules ^^)
<figure>
<figcaption>Demo</figcaption>
</figure>
figure {
background-color: red;
width: 400px;
height: 400px;
border-radius: 100px;
position: relative; /* For caption */
}
figure::before {
content: "";
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: url("http://placehold.it/400x400") no-repeat;
border-radius: 100px; /* Forced on image for smooth transition */
transition: opacity 1s ease-out;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
}
figure:hover::before {
opacity: 0;
}
figure:hover figcaption {
top: 50%;
}