CSS transition

CSS allows us to control the transition of certain element properties as they change (read more here). When combined with the :hover selector, we can create a unique animation when the user hovers over an element.

Setting up a basic HTML page, we create a series of divs as follows.

<!DOCTYPE html>
<html>
<head>
  <title>CSS Animations and Transitions</title>
  <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
  <div class="sun-wrapper">
    <div class="sun"></div>
  </div>
</body>
</html>

In order to create our sun element, we first define the height and width of our sun element. Applying a border-radius of half the width makes the square into a circle (try removing or changing this to get a better understanding).

.sun-wrapper {
  height: 200px;
  width: 200px;
  overflow: hidden;
  border: 1px solid blue;
  background-color: lightblue;
}

.sun {
  width: 200px;
  height: 200px;
  background-color: orange;
  border-radius: 100px;
}

you can see our sun below:

Using the :hover selector, we can make add rules to change the background-color of sun and sun-wrapper, as well as a transform rule that causes sun to move out of the wrapper div. The wrapper has overflow set to hidden in order to hide anything that extends beyond view. Notice the selector we are using for sun-wrapper. What it says is “when you hover over sun-wrapper, the rule for anything inside named sun is background-color: red and transform: translateY(200px)

.sun-wrapper:hover {
  background-color: #ff2b0f;
}

.sun-wrapper:hover .sun {
  background-color: red;
  transform: translateY(200px);
}

Combining these, we get the below result:

This happens way too fast! So we’re going to add a transition for our properties. We need to tell the browser what property (or properties) to transition (transition-property), how long to take (transition-duration), which easing function to use (transition-timing-function), and (if any) how much delay before the transition begins (transition-delay). Notice how on sun, we have two different properties to transition, separated by commas. We do the same with duration and timing function to match.

.sun-wrapper {
  height: 200px;
  width: 200px;
  overflow: hidden;
  border: 1px solid blue;
  transition: background 4s ease-in-out;
  background-color: lightblue;
}

.sun-wrapper:hover {
  background-color: #ff2b0f;
}

.sun-wrapper:hover .sun {
  background-color: red;
  transform: translateY(200px);
}

.sun {
  width: 200px;
  height: 200px;
  background-color: orange;
  border-radius: 100px;
  transition-property: background-color, transform;
  transition-duration: 4s, 4s;
  transition-timing-function: ease-in-out, linear;
}

assembled, we get the following. Try mousing over it!

CSS animation

Now what if we want this to continually animate, without user interaction? The best way to do this is with CSS animations. Just like transition, animation allows us to define a property to be animated. It differs in that it allows us more fine grained control over the animation process through the @keyframes property.

To begin, we add a more elements to our HTML to create a moon.

<!DOCTYPE html>
<html>
<head>
  <title>CSS Animations and Transitions</title>
  <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
  <div class="sun-wrapper">
    <div class="sun"></div>
  </div>
  <div class="moon-wrapper">
    <div class="moon"></div>
  </div>
</body>
</html>

and we give it similar properties to the sun element

.moon-wrapper {
  height: 200px;
  width: 200px;
  border: 1px solid blue;
  background-color: black;
  overflow: hidden;
}

.moon {
  height: 200px;
  width: 200px;
  border-radius: 100px;
  background-color: lightyellow;
}

Our result should look like the below:

In order to use the animation property, we must first define our @keyframe. @keyframe allows us to define the behavior of our animation at specific points. One way we can do this is by defining from and to points - the beginning and end. Another way we can do this (with much finer control) is to set the different properties at various percentages of the animation. Below we can see riseandset simply defines the beginning and end, whereas the moonsky keyframe defines three points - beginning, middle, and end. Both are valid and allow different levels of control.

@keyframes riseandset {
  from {
    transform: translateY(-200px);
  }

  to {
    transform: translateY(200px);
    background-color: yellow;
  }
}

@keyframes moonsky {
  0% {
    background-color: black;
  }

  50% {
    background-color: red;
  }

  100% {
    background-color: lightblue;
  }
}

We now need to tell our moon elements what animation to do. We do this with the animation-name property. Like the transition property, we also set the duration and timing function via the similarly named animation-duration and animation-timing-function properties. New to the scene are animation-iteration-count, where you can specify how many times the animation should repeat, and animation-direction, where you can specify reverse, alternate, and more. We use alternate in order to

.moon-wrapper {
  height: 200px;
  width: 200px;
  border: 1px solid blue;
  background-color: black;
  overflow: hidden;
  animation-name: moonsky;
  animation-duration: 4s;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
  animation-direction: alternate;
}

.moon {
  height: 200px;
  width: 200px;
  border-radius: 100px;
  background-color: lightyellow;
  animation-name: riseandset;
  animation-duration: 4s;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
  animation-direction: alternate;
}

Putting this all together, we end up with the below sketch:

Final CSS file:

.sun-wrapper {
  height: 200px;
  width: 200px;
  overflow: hidden;
  border: 1px solid blue;
  transition: background 4s ease-in-out;
  background-color: lightblue;
}

.sun-wrapper:hover {
  background-color: #ff2b0f;
}

.sun-wrapper:hover .sun {
  background-color: red;
  transform: translateY(200px);
}

.sun {
  width: 200px;
  height: 200px;
  background-color: orange;
  border-radius: 100px;
  transition-property: background-color, transform;
  transition-duration: 4s, 4s;
  transition-timing-function: ease-in-out, linear;
}

.moon-wrapper {
  height: 200px;
  width: 200px;
  border: 1px solid blue;
  background-color: black;
  overflow: hidden;
  animation-name: moonsky;
  animation-duration: 4s;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
  animation-direction: alternate;
  margin-bottom: 50px;
}

.moon {
  height: 200px;
  width: 200px;
  border-radius: 100px;
  background-color: lightyellow;
  animation-name: riseandset;
  animation-duration: 4s;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
  animation-direction: alternate;
}

@keyframes riseandset {
  from {
    transform: translateY(-200px);
  }

  to {
    transform: translateY(200px);
    background-color: yellow;
  }
}

@keyframes moonsky {
  0% {
    background-color: black;
  }

  50% {
    background-color: red;
  }

  100% {
    background-color: lightblue;
  }
}