Continue Transition from where Animation Ended - css

See the following button animation:
html {
background: white;
font-family: Arial;
}
.button {
position: relative;
display: inline-block;
color: #000;
border: 2px solid #000;
padding: 10px 24px;
font-size: 20px;
font-weight: 600;
text-align: center;
text-decoration: none;
transition-property: color, background, border-color;
transition-duration: 0.3s;
}
.button:hover {
color: #fff;
}
.button:hover ._background:after {
transform: translateX(0);
animation: fill-horizontal 0.3s linear 0s 1;
}
.button ._background {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: -1;
overflow: hidden;
}
.button ._background:after {
content: "";
position: absolute;
display: block;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: #000;
transform: translateX(100%);
transition: transform .3s;
}
#keyframes fill-horizontal {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}
<a class="button" href="javascript:">
<div class="_background"></div>
Button
</a>
The intended animation is to sweep the ._background:after element in from the left, and then out to the right like so:
translateX(-100%)
translateX(0) - Hover
translateX(100%) - Remove Hover
Whilst the animation works as intended when the user hovers for the duration of the CSS animation (.3s), it looks terrible if the user 'unhovers' before the CSS animation completes.
I would like the transition to translateX(100%) to continue from where the animation finished. Is this even possible?
NOTE - I am aware that the div._background element is not necessary, this has additional functionality that is not relevant to this question.

You can consider the same effect differently in order to avoid this bad effect:
Here is an idea using background animation where the trick is to change the position only after the size has changed.
.button {
position: relative;
display: inline-block;
color: #000;
border: 2px solid #000;
padding: 10px 24px;
font-size: 20px;
font-weight: 600;
text-align: center;
text-decoration: none;
background-image:linear-gradient(#000,#000);
background-size:0% 100%;
background-position:left;
background-repeat:no-repeat;
background-origin:border-box;
transition:color 0.3s, background-size 0.3s, background-position 0s 0.3s;
}
.button:hover {
color:#fff;
background-size:100% 100%;
background-position:right;
}
<div class="button">Some text</div>
Using this method, you will have a transition back in case you unhover rapidly.
A hacky idea to force the animation to complete is to consider a pseudo element that will make the hover area bigger and be sure you will keep the hover until the end:
.button {
position: relative;
display: inline-block;
color: #000;
border: 2px solid #000;
padding: 10px 24px;
font-size: 20px;
font-weight: 600;
text-align: center;
text-decoration: none;
background-image:linear-gradient(#000,#000);
background-size:0% 100%;
background-position:left;
background-repeat:no-repeat;
background-origin:border-box;
transition:color 0.3s, background-size 0.3s, background-position 0s 0.3s;
}
.button:hover {
color:#fff;
background-size:100% 100%;
background-position:right;
}
.button:hover:before {
content:"";
position:fixed;
top:0;
left:0;
right:0;
bottom:0;
z-index:99;
animation:remove 0s 0.3s forwards;
}
#keyframes remove {
to {
top:100%;
}
}
<div class="button">Some text</div>

Related

How to create button scaling effect in CSS?

I need a button whose after selector expands and gets disappeared when clicked. I need this effect via CSS.
When i click this button it's after selector expands.
Like
#button::after{
transform: scale(2);
}
But this is not happening for me. Please help me. When clicked the after selector button should expand then should disappear. In a nutshell, i need button scaling effect.
Do you mean something like this?
As far as I know you can't get an onclick event with CSS only and without using JavaScript. You can use :active, but this will only apply the style when the mouse button is held down. See Bojangles answer on "Can I have an Onclick effect in CSS".
#button {
display: block;
border: none;
position: relative;
color: red;
background-color: white;
font-size: 30px;
padding: 15px 30px;
}
#button:after {
content: '';
position: absolute;
display: block;
height: 100%;
width: 100%;
top: 0;
left: 0;
border: 4px solid red;
color: black;
font-size: 8px;
opacity: 1;
transition: transform .3s ease, opacity .5s ease;
}
#button:active:after {
transform: scale(5);
opacity: 0;
}
<button id="button">BUTTON</button>
**The code snippet is built upon on benedikt's answer.
#button:after's border color is set to transparent, adds border-color during the animation. this creates the illusion that it disappears. I hope this helps.
#button {
display: block;
border: 4px solid red;
position: relative;
color: red;
background-color: white;
font-size: 30px;
padding: 15px 30px;
}
#button:after {
content: '';
position: absolute;
display: block;
width:100%;
height:100%;
top:0;
left:0;
border: 4px solid transparent;
color: black;
font-size: 8px;
opacity: 1;
transition: transform 0.3s ease, opacity 0.5s ease, border-color 0.1s ease;
}
#button:active:after {
transform: scale(2);
border-color:red;
opacity: 0;
}
<button id="button">BUTTON</button>

How to create a pop up animation with a modal using css?

I have already created the modal in css, but when I try changing the transition so that it pops more like a modal instead of fading in, it doesn't work. I've tried changing the duration and the transition type but it doesn't seem to apply. Am I using the wrong transition?
See fiddle: https://jsfiddle.net/mtbh24uL/
.popup {
margin: 70px auto;
padding: 20px;
background: #fff;
border-radius: 5px;
width: 30%;
position: relative;
transition: all 5s ease-in-out;
}
My goal: to have more of a pop up effect like a real javascript modal. I basically need to create a modal like you see in the following picture. I'm not sure what the best approach is or the best plugin.
You could define a CSS animation for that and call this animation when you are clicking on the button. You can achieve this with adding the following CSS code. This is only an example to give you a rough idea of how your effect could look like. From this point you can even optimize and finetune the animation.
CSS
.overlay:target .popup{
animation: popup 0.7s;
}
#keyframes popup {
0%{
transform: scale(1);
}
50%{
transform: scale(1.4);
}
60%{
transform: scale(1.1);
}
70%{
transform: scale(1.2);
}
80%{
transform: scale(1);
}
90%{
transform: scale(1.1);
}
100%{
transform: scale(1);
}
}
body {
font-family: Arial, sans-serif;
background: url(http://www.shukatsu-note.com/wp-content/uploads/2014/12/computer-564136_1280.jpg) no-repeat;
background-size: cover;
height: 100vh;
}
h1 {
text-align: center;
font-family: Tahoma, Arial, sans-serif;
color: #06D85F;
margin: 80px 0;
}
.box {
width: 40%;
margin: 0 auto;
background: rgba(255, 255, 255, 0.2);
padding: 35px;
border: 2px solid #fff;
border-radius: 20px/50px;
background-clip: padding-box;
text-align: center;
}
.button {
font-size: 1em;
padding: 10px;
color: #fff;
border: 2px solid #06D85F;
border-radius: 20px/50px;
text-decoration: none;
cursor: pointer;
/* transition: all 0.3s ease-out; */
}
.button:hover {
background: #06D85F;
}
.overlay {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.7);
transition: opacity 500ms;
visibility: hidden;
opacity: 0;
}
.overlay:target {
visibility: visible;
opacity: 1;
}
.popup {
margin: 70px auto;
padding: 20px;
background: #fff;
border-radius: 5px;
width: 30%;
position: relative;
transition: all 5s ease-in-out;
}
.popup:after {
content: '';
position: absolute;
bottom: 100%;
width: 0;
height: 0;
border-style: solid;
border-width: 0 20px 20px 20px;
border-color: transparent transparent white transparent;
}
.overlay:target .popup {
animation: popup 0.7s;
}
.popup h2 {
margin-top: 0;
color: #333;
font-family: Tahoma, Arial, sans-serif;
}
.popup .close {
position: absolute;
top: 20px;
right: 30px;
transition: all 200ms;
font-size: 30px;
font-weight: bold;
text-decoration: none;
color: #333;
}
.popup .close:hover {
color: #06D85F;
}
.popup .content {
max-height: 30%;
overflow: auto;
}
#media screen and (max-width: 700px) {
.box {
width: 70%;
}
.popup {
width: 70%;
}
}
#keyframes popup {
0% {
transform: scale(1);
}
50% {
transform: scale(1.4);
}
60% {
transform: scale(1.1);
}
70% {
transform: scale(1.2);
}
80% {
transform: scale(1);
}
90% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
<h1>Popup/Modal Windows without JavaScript</h1>
<div class="box">
<a class="button" href="#popup1">Let me Pop up</a>
</div>
<div id="popup1" class="overlay">
<div class="popup">
<h2>Here i am</h2>
<a class="close" href="#">×</a>
<div class="content">
Thank to pop me out of that button, but now i'm done so you can close this window.
</div>
</div>
</div>
In answer to getting the curved arrow, you can use the :after or :before pseudo element. Something like this will achieve the desired effect:
CSS
.popup:after {
content: "";
position: absolute;
border: 0 solid transparent;
border-left: 24px solid white;
border-radius: 33px 0;
top: -18px;
left: 20px;
width: 30px;
height: 34px;
}

Transform Scale Causing Gaps/Lines

I'm building a website currently and am experiencing issues with transform: scale. I've got a button, and when a user hovers over it, two things happen:
A background "sweeps" in diagonally
The button label colour changes
The button grows slightly
I have got this working, and it looks really nice, but after implementing point 3, I'm seeing a weird gap to the left hand side when the button grows.
Here is my code: click for demo
HTML
Hover
CSS
body {
text-align: center;
padding-top: 10%;
}
.button {
display: inline-block;
text-transform: uppercase;
font-size: 1.1em;
font-weight: 600;
background: transparent;
transition: all ease .25s;
border: 3px solid green;
color: green;
position: relative;
overflow: hidden;
z-index: 2;
font-family: sans-serif;
padding: 20px 35px;
text-decoration: none;
}
.button:before {
content: ' ';
transition: all ease-out .25s;
width: 200%;
height: 100%;
position: absolute;
top: 0;
left: 0;
transform-origin: 0 0;
z-index: -1;
transform: skewX(-45deg) translateX(-100%);
background: green;
}
.button:hover:before {
transform: translateX(0);
}
.button:hover {
color: white;
transform: scale(1.1);
}
And here's a screenshot of the gap I'm seeing. This issue occurs in Chrome and Safari (I haven't tested Firefox or IE as I can't download them at work).
Screenshot of weird gap
It "only" appears in Chrome but not Firefox (edit: worse in Edge: first it's on the left then on bottom...). Not sure if a rounding error or something else is the cause of that gap, but I find that replacing border by a box-shadow improves the rendering.
There's still a gap that can be seen near the end of the transition but finally disappears so I added 2 box-shadows on :hover: the new one is inset and fills the gap between "border/box-shadow" and content box faster.
Codepen: http://codepen.io/PhilippeVay/pen/oYjZzK?editors=0100
body {
text-align: center;
padding-top: 10%;
}
.button {
display: inline-block;
text-transform: uppercase;
font-size: 1.1em;
font-weight: 600;
background: transparent;
transition: all ease .25s;
box-shadow: 0 0 0 3px green; /* replaces border which caused a gap in Chr, not Fx */
color: green;
position: relative;
overflow: hidden;
z-index: 2;
font-family: sans-serif;
padding: 19px 34px;
text-decoration: none;
}
.button:before {
content: ' ';
transition: transform ease-out .25s;
width: 200%;
height: 100%;
position: absolute;
top: 0;
left: 0;
transform-origin: 0 0;
z-index: -1;
transform: skewX(-45deg) translateX(-100%);
background: green;
}
.button:hover:before {
transform: translateX(0);
}
.button:hover {
color: white;
box-shadow: 0 0 0 3px green, inset 0 0 0 1px green; /* improves end of transition in Chrome */
transform: scale(1.1);
}
Hover
EDIT: playing with the size of the transitioned :pseudo
.button:before {
content: ' ';
transition: all ease-out .25s;
width: calc(200% + 6px);
height: calc(100% + 6px);
position: absolute;
top: -3px;
left: -3px;
transform-origin: 0 3px;
z-index: -1;
transform: skewX(-45deg) translateX(-100%);
background: green;
}
to take into account the border but that doesn't change anything because of overflow: hidden.
So here's my third try: by adding a container (or having the A element as a container) and keeping the border on the child element, it makes that gap disappear (overflow is around the border).
Codepen: http://codepen.io/PhilippeVay/pen/ZBbKWd
body {
text-align: center;
padding-top: 10%;
}
a {
display: inline-block;
overflow: hidden;
background: transparent;
transition: all ease .25s;
color: green;
position: relative;
z-index: 2;
font-family: sans-serif;
text-decoration: none;
}
a > span {
display: inline-block;
text-transform: uppercase;
font-size: 1.1em;
font-weight: 600;
border: 3px solid green;
padding: 20px 35px;
}
a:before {
content: ' ';
transition: all ease-out .25s;
width: 200%;
height: 100%;
position: absolute;
top: 0;
left: 0;
transform-origin: 0 0;
z-index: -1;
transform: skewX(-45deg) translateX(-100%);
background: green;
}
a:hover:before {
transform: translateX(0);
}
a:hover {
color: white;
transform: scale(1.1);
}
<span class="bd">Hover</span>
Fx transitions till the end flawlessly... and "corrects" the width by adding 2px on the right. But it's already visible in your jsbin so it's another story (and less annoying I guess as user will have clicked by then imho)

Animation not working both on and off hover

My animation does not seem to want to go both on and off the hover. I have tried putting the animation line on the LI:before itself and swapping the 0% and 100% but then nothing happens at all. I've been messing around with it for hours to no avail.
EDIT: Updated link, code
JSFiddle
ul {
display: flex;
flex-direction: row;
align-items: center;
list-style-type: none;
background-color: $base-gray-t;
margin: 1em;
padding: .25em 0 0 0;
height: 3em;
border-bottom: 0.375em solid $secondary-color;
overflow: hidden;
box-shadow: .05em .05em 1em 0;
}
li {
position: relative;
color: $base-gray-light;
padding: 0.40em;
font-size: 1.5em;
font-family: 'Montserrat', sans-serif;
cursor: pointer;
z-index: 2;
}
li:not(.active):not(:first-child):before {
content: '';
display: block;
position: absolute;
bottom: .01em;
width: 100%;
height: 2em;
margin-left: -.4em;
border-radius: .25em .25em 0 0;
z-index: -1;
}
li:hover:before {
background: $primary-color;
animation: splash .3s ease;
bottom: .01em
}
#keyframes splash {
0% {
bottom: -2em;
border-radius: 100%;
}
100% {
bottom: .01em;
}
}
If you are trying to complete the animation which you created on hover then for that add forwards along-with your animation properties as below,
li:hover:before {
background: $primary-color;
animation: splash .3s ease forwards;
bottom: .01em
}
Check this working jsfiddle link.
The transition method is much less involved and has less scope for problems so i edited your fiddle to use that instead:
https://jsfiddle.net/6t8xLssv/1/
I simply transitioned the :before element on hover, except in the case of the active li.
li:before{
content:'';
display:inline-block;
position:absolute;
bottom:0;
right:0;
left:0;
height:0;
transition:height 0.2s linear;
background:pink;
border-radius:5px 5px 0 0;
z-index:-1;
}
li:hover:before{
transition:height 0.2s linear;
height: 2em;
}
li.active:before{
display:none;
}
I hope this helps

animating pseudo element when passing to another element

I got a pseudo-element that marks the user's current choice in a navigation bar. It's a small upward triangle, an icon font from Font-Awesome. here's a jsFiddle DEMO of it (you need to stretch the result panel so everything will be lined).
.subnav > ul > li.active > a:after {
position: relative;
text-align: center;
font-family: FontAwesome;
top: 25px;
right: 50%;
content: "\f0de";
color: #c1c1c1;
}
I've added some basic jQuery function that switches the .active class, and I'm wondering if there's a way to animate the transition of the pseudo element so it'll move horizontally to the new position.
I know pseudo-elements transition are a thing, but searching and googling around I couldn't find anything similar to what I'm looking for. Is this even possible?
In this solution I used the :target pseudo class to switch states, but I recommend you stick with the jQuery function that switches the .active class.
FIDDLE
Markup
<div class="page" id="one">page one</div>
<div class="page" id="two">page two</div>
<div class="page" id="three">page three</div>
<div class="top">
<div class="arrow"></div>
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
</div>
CSS
.top
{
background: #eee;
position:relative;
overflow: hidden;
}
.arrow
{
border-bottom: 1px solid #c2c2c2;
height: 50px;
}
.arrow:before
{
content: '';
display: block;
width: 14px;
height: 14px;
border: 1px solid #c2c2c2;
border-radius: 3px;
position:absolute;
bottom:-9px;
left: 30px;
background: #fff;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-transition: left, 0.5s;
-moz-transition: left, 0.5s;
-o-transition: left, 0.5s;
transition: left, 0.5s;
}
ul
{
position: absolute;
top: 0;
list-style: none;
padding-left: 20px;
margin-top: 15px;
}
li
{
display: inline-block;
text-decoration: none;
font-size: 18px;
color: #676767;
margin-right: 40px;
}
.page
{
width: 100%;
height: 200px;
position: absolute;
top: 80px;
opacity: 0;
background: yellow;
-webkit-transition: opacity, 0.5s;
-moz-transition: opacity, 0.5s;
-o-transition: opacity, 0.5s;
transition: opacity, 0.5s;
}
.page:target
{
opacity: 1;
}
#two
{
background: pink;
}
#three
{
background: brown;
}
#one:target ~ .top .arrow:before
{
left: 30px;
}
#two:target ~ .top .arrow:before
{
left: 105px;
}
#three:target ~ .top .arrow:before
{
left: 189px;
}

Resources