I am currently trying to create a CSS ripple effect. When I scale the button the ripple don't reach the edges of the button. The speed of the growth of the ripple is the same for every button size. It is a regular button. The CSS is added when the button is pressed.
This is my CSS code:
position: absolute;
background: #000;
border-radius: 50%;
width: 5px;
height: 5px;
animation: ripple 0.88s linear;
opacity: 0;
pointer-events: none;
#keyframes ripple {
from {
transform: scale(1);
opacity: 0.4
}
to {
transform: scale(100);
opacity: 0;
}
}
Thanks in advance!
Separate the ripple effect from the button element. Use a span element to execute the animation. Like so:
$(document).ready(function(){
$('button').on('click',function(){
$(this).find('.ripple').remove();
$(this).append($('<span class="ripple"></span>'));
});
});
button{
position: relative;
overflow: hidden;
width: 100px;
height: 25px;
}
button.big{
width: 200px;
height: 50px;
}
button.bigger{
width: 400px;
height: 100px;
}
.ripple{
position: absolute;
background: #000;
border-radius: 50%;
width: 5px;
height: 5px;
opacity: 0;
pointer-events: none;
animation: ripple 0.88s linear;
transform: scale(1);
top: 50%;
left: 50%;
}
#keyframes ripple {
from {
transform: scale(1);
opacity: 0.4
}
to {
transform: scale(100);
opacity: 0;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="">Ripple!</button>
<button class="big">Ripple!</button>
<button class="bigger">Ripple!</button>
Keep in mind that, since you're scaling to a 100x size, the biggest buttons your effect will support is a little under 500px wide (because of the ripple's borders)
Related
I have made a little animation that add a line under the box from the left to the right when it's hovered and the line go back from the left to the right when the mouse isn't hovering the box, but the issue is that the line goes back from the left to the right when I refresh the page. Is there a solution to disable the animation when I open the page or when I refresh it (if possible without JavaScript)
body {
background-color: black;
}
.box {
width: 100px;
height: 100px;
margin: 40px auto;
background-color: #f44336;
position: relative;
}
.box::after {
content: '';
position: absolute;
bottom: -7px;
width: 100%;
height: 3px;
background-color: #fff;
animation: out 400ms linear forwards;
transform-origin: right center;
}
.box:hover::after {
animation: in 400ms linear;
transform-origin: left center;
}
#keyframes in {
from {
transform: scaleX(0);
}
to {
transform: scaleX(1);
}
}
#keyframes out {
from {
transform: scaleX(1);
}
to {
transform: scaleX(0);
}
}
<div class="box"></div>
I changed your animation to a transition instead. Is this what you're after?
body {
background-color: black;
}
.box {
width: 100px;
height: 100px;
margin: 40px auto;
background-color: #f44336;
position: relative;
}
.box::after {
content: '';
position: absolute;
bottom: -7px;
width: 100%;
height: 3px;
background-color: #fff;
transform: scaleX(0);
transform-origin: right center;
transition: transform 400ms linear;
}
.box:hover::after {
transform: scaleX(1);
transform-origin: left center;
}
<div class="box"></div>
I don't believe this is possible using only css - you can use a css declaration when a mouse-over ends, however it will always trigger upon load.
You can however use simple JS using classes "on" and "off" to differentiate 'page load' and 'hover off'.
The code in this instance would be:
demo
$(".box").hover(
function () {
$(this).removeClass('off').addClass('on');
},
function () {
$(this).removeClass('on').addClass('off');
}
);
body {
background-color: black;
}
.box {
width: 200px;
height: 200px;
margin: 40px auto;
background-color: #f44336;
position: relative;
}
.box::after {
content: '';
position: absolute;
bottom: -7px;
height: 3px;
background-color: #fff;
}
.box.off::after {
width: 100%;
animation: out 400ms linear forwards;
transform-origin: right center;
}
.box.on::after {
width: 100%;
animation: in 400ms linear;
transform-origin: left center;
}
#keyframes in {
from {
transform: scaleX(0);
}
to {
transform: scaleX(1);
}
}
#keyframes out {
from {
transform: scaleX(1);
}
to {
transform: scaleX(0);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="box"></div>
I have a ripple effect set to a CSS class using a pseudo selector.
I'd like that animation to run from behind the element itself, but I can't manage to find how to do so.
.button {
width: 50px;
height: 50px;
background: lightblue;
position: absolute;
top: 50px;
left: 50px;
}
i.ripple:before {
content: "";
position: absolute;
border-radius: 50%;
width: 30px;
height: 30px;
background: darkorange;
animation: ripple 2s ease-in infinite;
}
#keyframes ripple {
0% {transform: scale(1);opacity: .5;}
100% {transform: scale(8);opacity: 0;}
}
<i class="ripple button">test</i>
If you run the example, you will see that the orange circle is on top of the blue box from the .button class, I'd like it to be behind.
I think this issue is related to this other question:
::before pseudo-element stacking order issue
But can't figure out much of it.
Set its z-index to -1 and you should be good.
.button {
width: 50px;
height: 50px;
background: lightblue;
position: absolute;
top: 50px;
left: 50px;
}
i.ripple:before {
content: "";
position: absolute;
border-radius: 50%;
width: 30px;
height: 30px;
background: darkorange;
animation: ripple 2s ease-in infinite;
z-index:-1;
}
#keyframes ripple {
0% {transform: scale(1);opacity: .5;}
100% {transform: scale(8);opacity: 0;}
}
<i class="ripple button">test</i>
Update the Z-Index.
.button {
width: 50px;
height: 50px;
background: lightblue;
position: absolute;
top: 50px;
left: 50px;
}
i.ripple:before {
content: "";
position: absolute;
border-radius: 50%;
width: 30px;
height: 30px;
background: darkorange;
animation: ripple 2s ease-in infinite;
z-index: -1;
}
#keyframes ripple {
0% {transform: scale(1);opacity: .5;}
100% {transform: scale(8);opacity: 0;}
}
<i class="ripple button">test</i>
.button {
width: 50px;
height: 50px;
background: lightblue;
position: absolute;
top: 50px;
left: 50px;
}
i.ripple:before {
content: "";
position: absolute;
border-radius: 50%;
width: 30px;
height: 30px;
background: darkorange;
animation: ripple 2s ease-in infinite;
}
#keyframes ripple {
0% {transform: scale(1);opacity: .5;}
100% {transform: scale(8);opacity: 0;}
}
<i class="ripple button">test</i>
Here's the CodePen.
The square changes to a circle as expected when it slides to the right, but when it returns back to the left, it stays a circle instead of changing to a square.
Also, I can only click the <a> once. If I try to click multiple times, it doesn't work.
Trying to do this with only CSS (if possible).
body {
margin-top: 30px;
background: gainsboro;
}
.container {
margin: auto;
width: 100%;
}
.path {
position: relative;
overflow: hidden;
width: 100%;
height: 80px;
x-background: white;
}
#keyframes ani {
0% {
left: 0;
}
50% {
left: 95%;
}
100% {
left: 0;
}
}
.shape:target {
border-radius: 50%;
transition: all .7s ease-in-out;
animation-name: ani;
animation-duration: 2s;
animation-direction: alternate;
animation-fill-mode: none;
}
.shape {
position: absolute;
left: 0;
background-color: slateblue;
width: 80px;
height: 80px;
display: block;
border-radius: none;
transition: border-radius .4s ease-out;
}
<div class="container">
<div class="path">
<span id="elem" class="shape"></span>
</div>
</div>
The closest you can get with just CSS is this, as far as I know:
body {
margin-top: 30px;
background: gainsboro;
}
.container {
margin: auto;
width: 100%;
}
.path {
position: relative;
overflow: hidden;
width: 100%;
height: 80px;
x-background: white;
}
#keyframes ani {
0% {
left: 0;
}
50% {
left: 95%;
}
100% {
left: 0;
}
}
.path a:focus .shape {
border-radius: 50%;
transition: all .7s ease-in-out;
animation-name: ani;
animation-duration: 2s;
animation-direction: alternate;
animation-fill-mode: none;
}
.shape {
position: absolute;
left: 0;
background-color: slateblue;
width: 80px;
height: 80px;
display: block;
border-radius: none;
transition: border-radius .4s ease-out;
}
<div class="container">
<div class="path">
<span id="elem" class="shape"></span>
</div>
</div>
The problem before was triggering the state with :target:. This is tough to debug with sites like Codepen or other embedded editors, since you can't see the hash change. Basically, clicking the link would append #elem to the URL, apply the :target styles to .shape, and stay like that until the hash changes.
This solution uses :focus, which gets you closer to your goal, but not all the way. To repeat the animation, you need to defocus/blur the circle, then click it again.
I'm usually all for CSS-only effects, but I'm pretty sure you'll need Javascript for this. Something as simple as applying a class on click, waiting 2 seconds, then removing the class would accomplish the same effect more reliably.
I'm trying to create a menu that is hidden off screen on the top of the document. There is a little portion showing that will be hoverable which will bring the rest of the menu into view. Trying to animate bottom to auto but it isn't working. Was wondering if someone knows how or better way to create a menu off screen similar to my codepen.
http://codepen.io/anthony-dandrea/pen/EjqYqj
.hud is the class that's giving me the animation problem.
.hud {
position: absolute;
width: 100%;
text-align: center;
transition: all 1s;
bottom: calc(100% - 39px);
}
.hud:hover {
bottom: 80%;
bottom: auto;
}
As already mentioned by Patrick Allen in comments, you cannot animate/transition from or to an "auto" value using CSS. For your case, you could replace it with transform: translate() like in the below snippet and achieve the same effect.
Below is the relevant SCSS code and what it does:
The transform: translateY(-100%) moves the elements content upwards by the exact height of the container element. This would hide the whole container.
A top: 39px is added such that the chevron icon is still shown and only the content is hidden.
On hover the transform is nullified by doing transform: translateY(0%). This puts the element back in its original position.
But because of the top: 39px present in the unhovered state, the position of the container would be offset a bit and that can be nullified by adding top: 0px on hover.
.hud {
position: absolute;
width: 100%;
text-align: center;
transition: all 1s;
top: 39px;
transform: translateY(-100%);
&:hover {
top: 0px;
transform: translateY(0%);
}
}
body {
background: #121111;
}
.hud {
position: absolute;
color: red;
width: 100%;
text-align: center;
-webkit-transition: all 1s;
transition: all 1s;
top: 39px;
-webkit-transform: translateY(-100%);
-ms-transform: translateY(-100%);
transform: translateY(-100%);
}
.hud:hover {
top: 0px;
-webkit-transform: translateY(0%);
-ms-transform: translateY(0%);
transform: translateY(0%);
}
.pull-down {
color: #e6e6e6;
-webkit-transition: all 0.2s;
transition: all 0.2s;
cursor: pointer;
height: 24px;
margin-top: 15px;
font-size: 1.5em;
}
.pull-down:hover {
color: #fff;
}
.hud:hover .pull-down {
color: #fff;
-ms-transform: rotate(-180deg);
-webkit-transform: rotate(-180deg);
transform: rotate(-180deg);
}
<link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" />
<div class="hud">
<div class="hud-internal">
<p>foobar</p>
</div>
<i class="fa fa-chevron-down pull-down" data-hud-toggle></i>
</div>
$('#click').click(function () {
var windowHeight = $(window).height();
var lineHeight = $('#line').height();
var desiredBottom = 100;
var newPosition = windowHeight - (lineHeight + desiredBottom);
$('#line').animate({top:newPosition},1000,function () {
$('#line').css({
bottom: desiredBottom,
bottom: 'auto'
});
});
});
Here jsfiddle
Give top: 0; to .hud element and it will work fine. Here is the codepen: http://codepen.io/anon/pen/KpOKdE
Is it possible to use CSS transitions to animate something between a position set as left: 0px to right: 0px so it goes all the way across the screen? I need to accomplish the same thing with top to bottom. Am I stuck calculating the screen width / object-size?
#nav {
position: absolute;
top: 0px;
left: 0px;
width: 50px;
height: 50px;
-webkit-transition: all 0.5s ease-out;
}
.moveto {
top: 0px;
right: 0px;
}
and then I use jQuery's .addClass
You can animate the position (top, bottom, left, right) and then subtract the element's width or height through a CSS transformation.
Consider:
$('.animate').on('click', function(){
$(this).toggleClass("move");
})
.animate {
height: 100px;
width: 100px;
background-color: #c00;
transition: all 1s ease;
position: absolute;
cursor: pointer;
font: 13px/100px sans-serif;
color: white;
text-align: center;
}
/* ↓ just to position things */
.animate.left { left: 0; top: 50%; margin-top: -100px;}
.animate.right { right: 0; top: 50%; }
.animate.top { top: 0; left: 50%; }
.animate.bottom { bottom: 0; left: 50%; margin-left: -100px;}
.animate.left.move {
left: 100%;
transform: translate(-100%, 0);
}
.animate.right.move {
right: 100%;
transform: translate(100%, 0);
}
.animate.top.move {
top: 100%;
transform: translate(0, -100%);
}
.animate.bottom.move {
bottom: 100%;
transform: translate(0, 100%);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Click to animate
<div class="animate left">left</div>
<div class="animate top">top</div>
<div class="animate bottom">bottom</div>
<div class="animate right">right</div>
And then animate depending on the position...
For elements with dynamic width it's possible to use transform: translateX(-100%); to counter the horizontal percentage value. This leads to two possible solutions:
1. Option: moving the element in the entire viewport:
Transition from:
transform: translateX(0);
to
transform: translateX(calc(100vw - 100%));
#viewportPendulum {
position: fixed;
left: 0;
top: 0;
animation: 2s ease-in-out infinite alternate swingViewport;
/* just for styling purposes */
background: #c70039;
padding: 1rem;
color: #fff;
font-family: sans-serif;
}
#keyframes swingViewport {
from {
transform: translateX(0);
}
to {
transform: translateX(calc(100vw - 100%));
}
}
<div id="viewportPendulum">Viewport</div>
2. Option: moving the element in the parent container:
Transition from:
transform: translateX(0);
left: 0;
to
left: 100%;
transform: translateX(-100%);
#parentPendulum {
position: relative;
display: inline-block;
animation: 2s ease-in-out infinite alternate swingParent;
/* just for styling purposes */
background: #c70039;
padding: 1rem;
color: #fff;
font-family: sans-serif;
}
#keyframes swingParent {
from {
transform: translateX(0);
left: 0;
}
to {
left: 100%;
transform: translateX(-100%);
}
}
.wrapper {
padding: 2rem 0;
margin: 2rem 15%;
background: #eee;
}
<div class="wrapper">
<div id="parentPendulum">Parent</div>
</div>
Demo on Codepen
Note: This approach can easily be extended to work for vertical positioning. Visit example here.
This worked for me on Chromium. The % for translate is in reference to the size of the bounding box of the element it is applied to so it perfectly gets the element to the lower right edge while not having to switch which property is used to specify it's location.
topleft {
top: 0%;
left: 0%;
}
bottomright {
top: 100%;
left: 100%;
-webkit-transform: translate(-100%,-100%);
}
In more modern browsers (including IE 10+) you can now use calc():
.moveto {
top: 0px;
left: calc(100% - 50px);
}