I am trying to use more css and less Javascript for animation. I am running into an issue animating three different boxes. I have the boxes fade in with opacity by adding the fadeShow class to bring the opacity to 1. However, I am wanting the boxes to appear as if they are animating from the left side of the page to the right.
Here is a fiddle that shows it in action:
Click here to see
.info-box {
border: 1px solid black;
padding: 50px;
background: #00f;
color: #fff;
display: inline;
margin: 0 100px;
transition: 1s;
opacity: 0;
}
.info-box.fadeShow {
opacity: 1;
transform: translateX(150px);
}
I am trying to make the boxes animate over 150px OR if there is a better way to do this to put the boxes into their perminent state. What I mean by this is, if the boxes are supposed to be at left: 25%;, left: 45%; and left: 65%;, then I would want the boxes to be 150px to the left of that and then transition into place.
Firstly, to have the boxes slide over from the left, you should apply the negative transformation to the .info-box class:
transform:translatex(-150px);
And then reset it in the .fadeShow class:
transform:initial;
Secondly, you have the display property of the .info-box class set to inline, you'll need to change that as transformations can't be applied to inline elements.
Finally, for performance purposes, it's best to explicitly state which properties you want to apply transitions to:
transition:opacity 1s,transform 1s;
Or:
transition-duration:1s;
transition-property:opacity,transform;
Without CSS animations and calc function:
window.addEventListener("scroll", function(event) {
var top, green, red, yellow;
top = this.scrollY;
green = document.querySelector("#green"),
red = document.querySelector("#red"),
yellow= document.querySelector("#yellow");
if(top > 100){
green.classList.add("green", "active");
red.classList.add("red", "active");
yellow.classList.add("yellow", "active");
}
}, false);
*{box-sizing:border-box; height: 400vh}
body{margin: 0; padding-top: 200px}
.box{
width: 150px;
height: 150px;
opacity:0;
position: absolute;
transform: translateX(-150px);
opacity:0
}
#green{
background: green;
left: 25%;
}
#red{
background: red;
left: 45%;
}
#yellow{
background: yellow;
left: 65%;
}
#green.green{transition: all .3s ease}
#red.red{transition: all .6s ease}
#yellow.yellow{transition: all .9s ease}
#green.active,
#red.active,
#yellow.active{opacity: 1;transform: translateX(0);}
<section>
<article>
<div id=green class=box></div>
<div id=red class=box></div>
<div id=yellow class=box></div>
</article>
</section>
With CSS animations and calc function:
*{box-sizing:border-box}
body{margin: 0; padding-top: 20px}
.box{
width: 150px;
height: 150px;
position: absolute
}
#green{
background: green;
left: 25%;
animation:slideinGreen .3s ease
}
#red{
background: red;
left: 45%;
animation:slideinRed .6s ease
}
#yellow{
background: yellow;
left: 65%;
animation:slideinYellow .9s ease
}
#keyframes slideinGreen {
from {
left: calc(25% - 150px); opacity: 0
}
}
#keyframes slideinRed{
from {
left: calc(45% - 150px); opacity: 0
}
}
#keyframes slideinYellow {
from {
left: calc(65% - 150px); opacity: 0
}
}
<section>
<article>
<div id=green class=box></div>
<div id=red class=box></div>
<div id=yellow class=box></div>
</article>
</section>
Now you can add EventTarget.addEventListener() and Element.classList
window.addEventListener("scroll", function(event) {
var top, green, red, yellow;
top = this.scrollY;
green = document.querySelector("#green"),
red = document.querySelector("#red"),
yellow= document.querySelector("#yellow");
if(top > 100){
green.classList.add("green", "active");
red.classList.add("red", "active");
yellow.classList.add("yellow", "active");
}
}, false);
*{box-sizing:border-box; height: 400vh}
body{margin: 0; padding-top: 200px}
.box{
width: 150px;
height: 150px;
opacity:0;
position: absolute
}
#green{
background: green;
left: 25%;
}
#red{
background: red;
left: 45%;
}
#yellow{
background: yellow;
left: 65%;
}
#green.green{animation:slideinGreen .3s ease}
#red.red{animation:slideinRed .6s ease}
#yellow.yellow{animation:slideinYellow .9s ease}
#green.active,#red.active,#yellow.active{opacity: 1}
#keyframes slideinGreen {
from {
left: calc(25% - 150px);opacity:0
}
}
#keyframes slideinRed{
from {
left: calc(45% - 150px);opacity:0
}
}
#keyframes slideinYellow {
from {
left: calc(65% - 150px);opacity:0
}
}
<section>
<article>
<div id=green class=box></div>
<div id=red class=box></div>
<div id=yellow class=box></div>
</article>
</section>
you need to set css transition to: transition: all 1s;
since you need to tell what properties you need to animate.
and using all means animate all css properties. also you need to set display: inline-block
.info-box {
border: 1px solid black;
padding: 50px;
background: #00f;
color: #fff;
display: inline-block;
margin: 0 100px;
transition:all 1s;
opacity: 0;
}
The transform isn't working because the child divs are set to display:inline.
Change that to inline-block.
JSfiddle Demo
Related
I am trying to move an image when my mouse is over it.
Here's an exemple. When moving hover pictures, the text is smoothly following your mouse and this is what I'm looking for.
Do you have any idea ?
The problem with what I tried is that the image keeps moving when I get out of the violet box. (I would prefer to avoid having to create a box and recognize when I am over the image).
$("#containerScaled").on('mousemove', '.box', function (e) {
$("#followC").css("top", e.clientY)
.css("left", e.clientX);
});
<style>
#containerScaled, #followC {
transition: all 0.9s ease-out;
transform-origin: center;
transform: scale(1, 1);
}
.box {
height:50px;
width:50px;
left: 500px;
top: 50px;
background-color: blueviolet;
position: absolute;
}
.mouseFollow {
position: fixed;
width:70px;
height:20px;
font-size:12px;
pointer-events:none;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="containerScaled" class="container">
<div class="box">test</div>
</div>
<div id="followC" class="mouseFollow"><img src=" image "/></div>
I think you should begin with altering your position based on where your mose is positioned inside your rectangel like so:
if (e.clientX > width/2){
addX = 20;
}
if(e.clientX < width/2){
addX = -20;
}
if(e.clientY > height/2){
addY = 20;
}
if(e.clientY < height/2){
addY = -20;
}
This is the first step, that actually makes something "follow" your mouse.
I think you could do some optimization, so that the animation is more crispy, but basically thats the way to go.
I also added
$("#containerScaled").on('mouseleave', '.box', function(e) {
$("#followC").css("top", "50%").css("left", "50%");
});
so that your element will get back to its original position once you leave the :hover area
Because of this I also made you hover area transparent, any lay over the moving element, so that when you hover over the moving element, you wont leave the hover area, and trigger mouseleave
.box{
background-color: transparent;
}
.boxcolored{
position: absolute;
height: 100px;
width: 100px;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
background-color: green;
}
$("#containerScaled").on('mousemove', '.box', function(e) {
var left = parseFloat($(".box").css("left"));
var right = parseFloat($(".box").css("top"));
var width = parseFloat($(".box").css("widht"));
var height = parseFloat($(".box").css("height"));
var addX = 0;
var addY = 0;
if (e.clientX > width/2){
addX = 20;
}
if(e.clientX < width/2){
addX = -20;
}
if(e.clientY > height/2){
addY = 20;
}
if(e.clientY < height/2){
addY = -20;
}
$("#followC").css("top", e.clientY + addY)
.css("left", e.clientX + addX);
});
$("#containerScaled").on('mouseleave', '.box', function(e) {
$("#followC").css("top", "50%").css("left", "50%");
});
#containerScaled {
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 200px;
background-color: red;
}
#followC {
transition: all 0.9s ease-out;
transform-origin: center;
}
.box {
position: absolute;
height: 100px;
width: 100px;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
background-color: transparent;
}
.boxcolored{
position: absolute;
height: 100px;
width: 100px;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
background-color: green;
}
.mouseFollow {
position: relative;
height: 20px;
width: 75px;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="containerScaled" class="container">
<div class="boxcolored"></div>
<div id="followC" class="mouseFollow">HALLO</div>
<div class="box">mouse me</div>
</div>
The box outlined in a red dashed line is the hover area. The yellow box is the visual area which is the approximation of the limits to which the letters can move within.
There is a lag and an offset. The lag is due to transition: 0.9s and the offset is left and top. The lag can be decreased but at the cost of the smooth movement, There are four letters at varying transition times for comparison. Notice that they all stop at the same position (when the mouse is no longer moving within the dashed box), it just that the slower the transition the more movement occurs after the mouse has left the dashed box.
The offset is tougher since there is only two positions that will work: x: right or left and y: top or bottom. If keeping the letters within a box is a concern, then keep the hover area border and background to none and show the offset (visual area) instead.
Note: Do not review this demo in compact mode, view it in full page mode (normal dimensions)
$(".target").on('mousemove', function(e) {
$(".text").css({
"top": e.clientY,
"left": e.clientX
});
});
main {
position:relative;
font: 400 16px/1.2 Arial;
}
.zone {
position: absolute;
z-index: 1;
height: 120px;
width: 110px;
margin: 90px 0 0 90px;
background: gold;
color:white;
text-align:right;
}
.target {
position: absolute;
z-index: 2;
height: 100px;
width: 100px;
margin: 75px;
outline: 3px dashed red;
color:red
}
.text {
position: absolute;
z-index: 3;
top: 90px;
left: 90px;
font-size: 32px;
color:black
}
.A {
transition: all 0.9s ease-out;
}
.B {
transition: all 0.6s ease-out;
}
.C {
transition: all 0.3s ease-out;
}
<main>
<section class="target">Hover Area</section>
<aside class="text A">A</aside>
<aside class="text B">B</aside>
<aside class="text C">C</aside>
<aside class="text D">D</aside>
<section class='zone'><b>Visual Area</b></section>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Click on the image in snippet (expand full page) to run transform and look more closely at bottom right corner when animated card goes behind, you will see it overlaps slightly when it shouldn't. I happens when I apply z-index on each box div in CSS. If I remove z-index, there is no flash, but I need z-indexes on my box divs. Otherwise I cant have stack behave in such when I shuffle them (unless I change DOM order which I don't want). I have tried with some backface-visibility in CSS but with no luck. How could I get rid of such flash?
$('body').on('click', function() {
var box = $('#a2')
box.one("transitionend", function() {
box.css("zIndex", -1).one("transitionend", function() {
}).removeClass('t').addClass('t2')
}).addClass('t')
})
.box {
position: absolute;
width: 250px;
padding: 10px;
background: #fff;
box-shadow: 1px 1px 5px #484848;
left: 0;
top: 0;
height: 370px;
box-sizing: content-box;
transition-duration: 0.5s;
transition-timing-function: ease;
backface-visibility: hidden;
}
.box img {
display: block;
position: relative;
backface-visibility: hidden;
user-select: none;
}
#a1 {
z-index: 0;
transform: rotate(-4.5884deg);
}
#a2 {
z-index: 1;
transform: rotate(7deg);
}
.t {
transform: translateX(370px) rotate(23deg) !important;
}
.t2 {
transform: translateX(0) rotate(-7deg) !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="box" id="a1">
<img src="http://interactivepixel.net/tst/01.jpg" alt="" />
</div>
<div class="box" id="a2">
<img src="http://interactivepixel.net/tst/02.jpg" alt="" />
</div>
Happens in all browsers from what I can see.
The fix is actually simple - just add transition-property: transform because that is what you want to transform (transition-property: all is the default and z-index is also transitioned).
See demo below:
$('body').on('click', function() {
var box = $('#a2')
box.one("transitionend", function() {
box.css("zIndex", -1).removeClass('t').addClass('t2')
}).addClass('t')
});
.box {
position: absolute;
width: 250px;
padding: 10px;
background: #fff;
box-shadow: 1px 1px 5px #484848;
left: 0;
top: 0;
height: 370px;
box-sizing: content-box;
transition-duration: 0.5s;
transition-timing-function: ease;
backface-visibility: hidden;
transition-property: transform; /* added */
}
.box img {
display: block;
position: relative;
backface-visibility: hidden;
user-select: none;
}
#a1 {
z-index: 0;
transform: rotate(-4.5884deg);
}
#a2 {
z-index: 1;
transform: rotate(7deg);
}
.t {
transform: translateX(370px) rotate(23deg) !important;
}
.t2 {
transform: translateX(0) rotate(-7deg) !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="box" id="a1">
<img src="http://interactivepixel.net/tst/01.jpg" alt="" />
</div>
<div class="box" id="a2">
<img src="http://interactivepixel.net/tst/02.jpg" alt="" />
</div>
Why the flicker?
Note that z-index is an integer and it doesn't make much sense to transition it - the animation type is integer according to MDN:
When animated, values of the data type are interpolated
using discrete, whole steps. The calculation is done as if they were
real, floating-point numbers; the discrete value is obtained using the
floor function. The speed of the interpolation is determined by the
timing function associated with the animation.
See a sample of how you can animate z-index:
div {
position: absolute;
border: 1px solid;
}
.container div {
width: 100px;
height: 100px;
}
.container .box {
background-color: cadetblue;
z-index: 1;
animation: stack 5s infinite linear;
}
.box + div {
top: 10px;
left: 10px;
z-index: 1;
background-color: lightblue;
}
.box + div + div {
top: 20px;
left: 20px;
z-index: 2;
background-color: aliceblue;
}
#keyframes stack {
50% {
z-index: 3;
}
}
<div class="container">
<div class="box"></div>
<div></div>
<div></div>
</div>
This is why you have the flicker in your animation.
I think it is merely an order problem.
Just place the .css (" zIndex ", -1) next to the .addClass ('t'):
this way flash doesn't happen since z-index is applyed before the backward translation
$('body').on('click', function() {
var box = $('#a2')
box.one("transitionend", function() {
box.removeClass('t').addClass('t2')
}).css("zIndex", -1).addClass('t')
})
I just update your code with jQuery update. Actually i just move your box.css("zIndex", -1).addClass('t'); script in setTimeout method. Try this I hove it'll resolve your issue. Thanks
$('body').on('click', function() {
var box = $('#a2')
box.one("transitionend", function() {
box.one("transitionend").addClass('t2');
})
setTimeout(function(){
box.css("zIndex", -1).addClass('t');
})
})
.box {
position: absolute;
width: 250px;
padding: 10px;
background: #fff;
box-shadow: 1px 1px 5px #484848;
left: 0;
top: 0;
height: 370px;
box-sizing: content-box;
transition-duration: 0.5s;
transition-timing-function: ease;
backface-visibility: hidden;
}
.box img {
display: block;
position: relative;
backface-visibility: hidden;
user-select: none;
}
#a1 {
z-index: 0;
transform: rotate(-4.5884deg);
}
#a2 {
z-index: 1;
transform: rotate(7deg);
}
.t {
transform: translateX(370px) rotate(23deg) !important;
}
.t2 {
transform: translateX(0) rotate(-7deg) !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="box" id="a1">
<img src="http://interactivepixel.net/tst/01.jpg" alt="" />
</div>
<div class="box" id="a2">
<img src="http://interactivepixel.net/tst/02.jpg" alt="" />
</div>
I tried increasing the z-index of the succeeding image and it works.
$('body').on('click', function() {
var box = $('#a2')
var i=0;
box.one("transitionend", function() {
// increase the z-index
$("#a1").css("zIndex", 99);
box.css("zIndex", -1).one("transitionend", function() {
}).removeClass('t').addClass('t2')
}).addClass('t')
})
.box {
position: absolute;
width: 250px;
padding: 10px;
background: #fff;
box-shadow: 1px 1px 5px #484848;
left: 0;
top: 0;
height: 370px;
box-sizing: content-box;
transition-duration: 0.5s;
transition-timing-function: ease;
backface-visibility: hidden;
}
.box img {
display: block;
position: relative;
backface-visibility: hidden;
user-select: none;
}
#a1 {
z-index: 0;
transform: rotate(-4.5884deg);
}
#a2 {
z-index: 1;
transform: rotate(7deg);
}
.t {
transform: translateX(370px) rotate(23deg) !important;
}
.t2 {
transform: translateX(0) rotate(-7deg) !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="box" id="a1">
<img src="http://interactivepixel.net/tst/01.jpg" alt="" />
</div>
<div class="box" id="a2">
<img src="http://interactivepixel.net/tst/02.jpg" alt="" />
</div>
I have e.x 3 boxes, the red one should have at start a bigger size then the others (through css). Now, when I click on the green or yellow box the red gets smaller size same as green or yellow had before clicking. And the clicked one gets the CSS Style (size) of the red one. I want to make it with JQuery but don't know how?
.r1, .r2, .r3{
width: 80px;
height: 80px;
margin: 40px;
float: left;
}
.r1{
background-color: red;
position: inherit;
transform: scaleY(1.2);
transform: scale(1.2);
transform-origin: center;
border: 2px solid #15dc6e;
}
.r2{
background-color: green;
}
.r3{
background-color: yellow;
}
<div class="content">
<div class="r1"></div>
<div class="r2"></div>
<div class="r3"></div>
</div>
Fiddle: https://jsfiddle.net/cwx3ukra/16/
$(document).ready( () => {
$('.content div').click( e => {
// Remove zoom class from all elements
$('.content div').removeClass('big');
// Only apply to the clicked element
$(e.target).addClass('big');
});
})
.r1,
.r2,
.r3 {
width: 80px;
height: 80px;
margin: 40px;
float: left;
transform: scale(1);
transition: all 500ms ease-out;
}
.r1 {
background-color: red;
}
.r2 {
background-color: green;
}
.r3 {
background-color: yellow;
}
.big {
transform: scale(1.2);
border: 2px solid #15dc6e;
transform-origin: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="content">
<div class="r1 big"></div>
<div class="r2"></div>
<div class="r3"></div>
</div>
Working JSFiddle Here
You can achieve a smooth transition using pure CSS:
.r1,
.r2,
.r3 {
width: 80px;
height: 80px;
margin: 40px;
float: left;
transform: scale(1);
transition: all 500ms ease-out;
}
.big {
transform: scale(1.2);
border: 2px solid #15dc6e;
transform-origin: center;
}
The transition property will automatically transition from one rule to another. In this example, it transitions from transform: scale(1) to transform: scale(1.2).
Try this out:
Codepen: https://codepen.io/samandalso/pen/qKrLLM
$(function() {
$('.content div').on('click', function(){
$('.content div').not($(this)).removeClass('scaled');
$(this).toggleClass('scaled');
});
});
I am attempting to get a panel to slide up when a trigger is selected. This is working in my snippet. The issue is that the contents within the #proposal-panel are showing, even though I have #proposal-panel set to opacity: 0, until the trigger is clicked (.active is added). It is showing at the bottom of the page.
Also, for some reason on my actual site, the panel is not sliding up. I have multiple sections, just like the example. The panel just sets at the bottom of the page. The only thing that happens when the active class is added is the z-index takes effect.
I am wanting the panel to slide from the bottom to the top when triggered. That is what I am trying to do with translateYin the active class.
Does anyone know why the contents are showing and possibly why the panel is not sliding up?
Here is a fiddle.
$('#proposal-trigger').on('click', function () {
$('#proposal-panel').addClass('active');
});
#red {
height: 100vh;
width: 100%;
background: red;
}
#blue {
height: 100vh;
width: 100%;
background: blue;
}
#proposal-trigger {
background: #3B3B3B;
width: 100px;
height: 100px;
position: fixed;
bottom: 0;
right: 200px;
}
#proposal-panel {
background: #333333;
width: 58%;
height: 100vh;
position: fixed;
padding: 15px 0;
right: 0;
bottom: -100vh;
opacity: 0;
transition: ease 0.3s;-webkit-transition: ease 0.3s;
}
#proposal-panel.active {
transition: ease 0.3s;-webkit-transition: ease 0.3s;
transform: translateY(0vh);-webkit-transform: translateY(0vh);
bottom: 0;
top: 0;
z-index: 99;
opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<section id="red"></section>
<section id="blue"></section>
<div id="proposal-trigger">
<input>
<input>
</div>
<div id="proposal-panel"></div>
Assuming it's the little black box you see at the bottom, that's from #proposal-trigger. #proposal-panel is hidden. I removed the background color from #proposal-trigger to get rid of that.
And to have the element slide up, use transform: translate().
$('#proposal-trigger').on('click', function() {
$('#proposal-panel').addClass('active');
});
#red {
height: 100vh;
width: 100%;
background: red;
}
#blue {
height: 100vh;
width: 100%;
background: blue;
}
#proposal-trigger {
width: 100px;
height: 100px;
position: fixed;
bottom: 0;
right: 200px;
}
#proposal-panel {
background: #333333;
width: 58%;
height: 100vh;
position: fixed;
padding: 15px 0;
right: 0;
opacity: 0;
transition: 0.3s;
transform: translateY(100%);
bottom: 0;
}
#proposal-panel.active {
transform: translateY(0);
z-index: 99;
opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section id="red"></section>
<section id="blue"></section>
<div id="proposal-trigger">
<input>
<input>
</div>
<div id="proposal-panel"></div>
You don't need to use translateY to do this animations, just need to use top and bottom with the fixed position. And remove the background-color from #proposal-trigger so it doesn't show anymore
Here is a demo
$('#proposal-trigger').on('click', function () {
$('#proposal-panel').addClass('active');
});
<section id="red"></section>
<section id="blue"></section>
<div id="proposal-trigger">
<input>
<input>
</div>
<div id="proposal-panel"></div>
#red {
height: 100vh;
width: 100%;
background: red;
}
#blue {
height: 100vh;
width: 100%;
background: blue;
}
#proposal-trigger {
width: 100px;
height: 100px;
position: fixed;
bottom: 0;
right: 200px;
}
#proposal-panel {
background: #333333;
width: 58%;
position: fixed;
padding: 15px 0;
right: 0;
bottom: 0;
top: 100%;
opacity: 0;
transition: ease 0.3s;-webkit-transition: ease 0.3s;
}
#proposal-panel.active {
transition: ease 0.3s;-webkit-transition: ease 0.3s;
bottom: 0;
top: 0;
z-index: 99;
opacity: 1;
}
I want to create a toggle button that morphs its shape from a plus sign to a minus sign.
Using CSS only, without the use of pseudo-elements.
My desired effect is to have the vertical line in the "+" sign to shrink into the horizontal line.
I know it's possible but I'm not sure which is the best route to take. I was thinking of doing something with the height but I'm worried about the line-height of browsers changing its position in the element.
$('button').on("click", function(){
$(this).toggleClass('active');
});
button {
color: #ecf0f1;
background: #e74c3c;
width: 50px;
height: 50px;
border: 0;
font-size: 1.5em;
}
button span {
transition: all .75s ease-in-out;
}
button.active span {
/* Code to morph + to - */
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button><span>+</span></button>
Because of the simplicity of the shapes, the easiest way is just to make the + and - with elements. Using pseudo elements would be the cleanest solution, but you can also just use a DOM element and have a slightly messier document structure.
With that in mind, the actual solution is straightforward. We use CSS to position elements to resemble the desired characters, and then "morph" between them by animating that position.
Take a look over the following code, and try to understand what each rule is accomplishing.
button {
color: #ecf0f1;
background: #e74c3c;
width: 50px;
height: 50px;
border: 0;
font-size: 1.5em;
position: relative;
}
button span {
position: absolute;
transition: 300ms;
background: white;
border-radius: 2px;
}
/* Create the "+" shape by positioning the spans absolutely */
button span:first-child {
top: 25%;
bottom: 25%;
width: 10%;
left: 45%;
}
button span:last-child {
left: 25%;
right: 25%;
height: 10%;
top: 45%;
}
/* Morph the shape when the button is hovered over */
button:hover span {
transform: rotate(90deg);
}
button:hover span:last-child {
left: 50%;
right: 50%;
}
<button>
<span></span>
<span></span>
</button>
Note : please stop editing the question making the answers incorrect
CSS solution
$('button').on("click", function(){
$(this).toggleClass('active');
});
button {
color: #ecf0f1;
background: #e74c3c;
width: 70px;
height: 70px;
position: relative;
font-size: 50px;
cursor: pointer;
border: 0;
outline: 0;
padding: 0
}
.plus,
.minus {
color: #fff;
padding: 10px;
width: 70px;
height: 70px;
line-height: 50px;
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
text-align: center;
box-sizing: border-box;
transition: .5s all ease-out;
}
.plus {
opacity: 1;
transform: rotate(0deg);
}
button.active .plus {
opacity: 0;
transform: rotate(90deg);
}
.minus {
opacity: 0;
transform: rotate(-90deg);
}
button.active .minus {
opacity: 1;
transform: rotate(0deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" />
<button>
<span class="plus"><i class="fa fa-plus"></i></span>
<span class="minus"><i class="fa fa-minus"></i></span>
</button>
A (old) CSS solution:
Using pseudo element ::before with content property
$('button').on("click", function() {
$(this).toggleClass('active');
});
button {
color: #ecf0f1;
background: #e74c3c;
width: 50px;
height: 50px;
border: 0;
font-size: 1.5em;
}
button span {
transition: all .75s ease-in-out;
position:relative
}
button span::before {
content:"+"
}
button.active span::before {
content:"-"
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button><span></span></button>
A (old) jquery Solution:
no need for span, you can do this using text() with a if statement in jquery
$('button').on("click", function() {
$(this).toggleClass('active');
$(this).text() == "+" ? $(this).text("-") : $(this).text("+");
});
button {
color: #ecf0f1;
background: #e74c3c;
width: 50px;
height: 50px;
border: 0;
font-size: 1.5em;
transition: all .75s ease-in-out;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button>+</button>
Ah my bad I've overlooked that OP doesn't want to use any pseudo
elements. But the big advantage with pseudo elements would be that you have less HTML Code and a cleaner structure.
It's also a different morphing animation as OP wants but maybe someone else can use this.
So if you don't mind I'll let my suggestion there.
Maybe something like this?
HTML
<div class="button"></div>
CSS
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
}
body {
margin: 0;
background: #343838;
}
.button {
position: absolute;
width: 55px;
height: 55px;
background: #70975B;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(0deg);
border-radius: 50%;
cursor: pointer;
z-index: 100;
transition: 0.4s cubic-bezier(0.2, 0.6, 0.3, 1.1);
}
.button:after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 2px;
width: 50%;
background: white;
}
.button:before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 50%;
width: 2px;
background: white;
}
.button.clicked {
transform: translate(-50%, -50%) rotate(360deg);
background: #CC2A41;
}
.button.clicked:before {
width: 0;
}
jQuery
$(".button").click(function() {
$(this).toggleClass("clicked");
});
And here a working example
http://codepen.io/svelts/pen/LkyZoZ
try this
$('button').on("click", function() {
var $this = $(this);
$this.toggleClass('toggle');
if ($this.hasClass('toggle')) {
$this.text('+');
} else {
$this.text('-');
}
});
button {
color: #ecf0f1;
background: #e74c3c;
width: 50px;
height: 50px;
border: 0;
font-size: 1.5em;
transition: all .75s ease-in-out;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button class="toggle">+</button>