Skip to main content
Photography of Alvaro Montoro being a doofus
Alvaro Montoro

CSS Aficionado

Recreating the iPad Commercial Animation with CSS

css html tutorial webdev

Browsing the Internet, I saw the commercial for the new iPad Pro, and I really liked the animated words at the beginning:

I tried to recreate a similar animation just using HTML and CSS, and it happened to be really simple to develop while still remaining visually impactful:

Or you can add a little "something" to mimic the rotating tablet on the commercial.

My first thought was, "I may be able to build that animation with just one HTML element," and, although it may be possible, the code may also not be accessible and could present compatibility problems. So I decided to go for something slightly more verbose.

The idea would be to have a container with two elements that occupy all its height (50% each of them). They both will have overflow: hidden to hide anything outside of their visible area, and the text will then be positioned outside of that visible area, only sliding up/down when it's the right time in the animation.

The top element will have its text at the bottom, and it will slide up. The bottom element will have its text at the top and it will slide down:

Explanation of how the layers and text are positioned
The two layers hide the text by positioning it outside of their visible area

With this structure in mind, the HTML code could look something like this:

<div class="animated-title">
<div class="text-top">
<span>Apple's design</span>
<div class="text-bottom">
<div>for the win!</div>

Where .animated-title is the container, .text-top and .text-bottom are the elements that will have the text, which will be inside a div moved outside of the view via CSS. Let's put all together, and view the CSS step-by-step.

First, .animated-title (the main container of the animation) is placed in the center of the screen:

For this demo, we are going to position the animation at the center of the screen, but potentially you could put it wherever you want. The important part is that it has a position and height/width defined.

.animated-title {
color: #222;
font-family: Roboto, Arial, sans-serif;
height: 90vmin;
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 90vmin;

Now the direct children of this container must be positioned absolutely to the parent (that's why it required a position), and occupy half of it's height. The first child, .text-top, will go at the top of the container, and the second child, .text-bottom, will go at the bottom of the container.

.animated-title > div {
height: 50%;
overflow: hidden;
position: absolute;
width: 100%;

.animated-title > div.text-top {
border-bottom: 1vmin solid #000;
top: 0;

.animated-title > div.text-bottom {
bottom: 0;

You may have noticed that .text-top has a border-bottom. It is there to generate the middle line. The same thing could be achieved using other methods such as pseudo-elements, border-shadows, or borders on the main container or the children.

Before we define the text, let's add the animations that will control the text sliding. Initially the text will be outside of the visible area by translating it 100% of its height, and it will slide by animating that value to 0.

The text of the bottom section will be translated 100% up so it slides down, while the text of the top section will be translated 100% down so it can slide up (plus we need to add a short pause for it!):

@keyframes showTopText {
0% { transform: translate3d(0, 100%, 0); }
40%, 60% { transform: translate3d(0, 50%, 0); }
100% { transform: translate3d(0, 0, 0); }

@keyframes showBottomText {
0% { transform: translate3d(0, -100%, 0); }
100% { transform: translate3d(0, 0, 0); }

This effect can be achieved in different ways, but we opted for using 3D translations to trigger hardware acceleration (which would result in a smoother and less choppy transition).

At this point we have the styles of the parent container, the elements that will host the text, and the animations that will create the effect. Let's include the styles for the text itself.

In the HTML we have a <div> inside both .text-top and .text-bottom. It will contain the text of each section, so we need to position it in an absolute way and move it outside of their parents.

How you place the text outside of the visible area will depend on the method you used to create the animation. In this case we used transformations.

We assign the animations and play a little bit with the timing values so the slide happens when/how we want:

.animated-title > div div {
font-size: 12vmin; /* for demo purposes */
padding: 2vmin 0;
position: absolute;

.animated-title > div.text-top div {
animation: showTopText 1s;
animation-delay: 0.5s;
animation-fill-mode: forwards;
bottom: 0;
transform: translate(0, 100%);

.animated-title > div.text-bottom div {
animation: showBottomText 0.5s;
animation-delay: 1.75s;
animation-fill-mode: forwards;
top: 0;
transform: translate(0, -100%);

Finally we just need to add a couple of details to complete the design: the <span> will need to be converted to blocks, so each of them occupy a line. Adjust the color of the first line so it is lighter than the others:

.animated-title > div div span {
display: block;

.animated-title > div.text-top div span:first-child {
color: #767676;

You may wonder, "If you want a block element why not use a <div> instead of a styled <span>?" What a great question! The answer is related to usability/accessibility. Using screen readers with a <div>, the text will be read "Mimicking. Apple's design. For the win!", but with a <span> it will be read more fluidly: "Mimicking Apple's design. For the win!" We could even argue that the whole text should be inside a bunch of <span>s.

And just like that, our animation is complete. After putting it all together, the result will look like what we saw before:

Article originally published on