Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to morph a plus sign to a minus sign using CSS transition?

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>
like image 980
yaserso Avatar asked Jul 01 '16 02:07

yaserso


2 Answers

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>
like image 103
Jacob Gray Avatar answered Oct 04 '22 02:10

Jacob Gray


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>
like image 28
dippas Avatar answered Oct 04 '22 02:10

dippas