Building a Killer iPhone Layout with CSS

Landon Schropp
7 min readJan 18, 2016

It’s a permanent fixture in your pocket. Its bluish glow is the first thing you look at in the morning and the last thing you see before you go to bed. It connects you with friends and family. You use it to play games, read news and keep up with everything else in your life.

So what is it? Your phone! And in this article, we’re going to be taking a look at how to build the awesome iPhone layout you see above with HTML and CSS. We’ll be digging into some advanced topics in CSS, such as flexbox, the vh unit, CSS animations and Sass’s random to make this layout happen!

Unboxing

Let’s start with the iPhone’s markup. You’ll use a <div> container for the iPhone, and anther <div> for the screen. Inside of that, you’ll add 28 <button> elements for the icons.

<div class="iphone">
<div class="screen">
<button class="icon"></button>
...
<button class="icon"></button>
</div>
</div>

Since we’re using Sass for this layout, let’s define the variables for the colors. (If you’re curious how I came up with these names, check out this article.)

$white: #fff;
$athens-gray: #f7f8fa;
$shuttle-gray: #525c6b;
$indigo: #3f74ca;

Next, let’s stretch the <html> and <body> elements so they fill the height of the viewport. We’ll also center the iPhone horizontally and vertically inside the <body> element with flexbox.

html, body {
height: 100%;
}

body {
display: flex;
align-items: center;
justify-content: center;
}

Finally, let’s dump those default button styles so we can build something more streamlined and make the <span> elements border boxes.

button {
border: none;
padding: 0;
outline: none;
background-color: transparent;
user-select: none;
}

span {
box-sizing: border-box;
}

The Retina Display

In order to size the iPhone, we’ll be using the vh unit. The vh unit is a way specifying the size of something in terms of the viewport’s height. If we were to set an element’s height to 50vh, then it would take up half of the viewport.

So why bother with vh? As long as we size everything correctly, we can ensure the iPhone layout never gets smaller than the viewport’s height.

Let’s set 6vh for the width and height of the icons. We’ll also add background colors to the screen and icons so we can see them.

.screen {
background-color: $indigo;
}

.icon {
width: 6vh;
height: 6vh;
border-radius: 1.5vh;
background-color: $athens-gray;
}

.icon:active {
opacity: 0.75;
}

Next, let’s add a little space around the icons.

.icon {
...
margin: 1.5vh;
}

In order to create rows of icons, let’s make the screen a flex container and set its flex-wrap property to wrap. We’ll also restrict the width of the screen so the icons will wrap to the next line.

.screen {
...
display: flex;
flex-wrap: wrap;
padding: 1.5vh;
width: 36vh;
}

The Dock

If you look closely at the finished iPhone, you’ll notice the space between the icons in the last row and the one above it is larger than 3vh to accommodate the dock. We can add it by targeting the last four icons and making their margin top a little bigger.

.icon:nth-last-of-type(-n+4) {
margin-top: 3vh;
}

To get that light bar at the bottom, we’ll use a linear gradient. Since the gradient is pointing to the top, we can use a color stop of 11.5vh to create the line. We’ll also use Sass’s lighten function to lighten up the $indigo color.

.screen {
background: linear-gradient(to top,
lighten($indigo, 8%) 11.5vh, $indigo 11.5vh);
...
}

Woohoo! It’s starting to look like an iPhone!

The Body

Creating the shape of the iPhone is pretty simple. We’ll add padding to the container and add borders to the screen and the container. We’ll also round the corners of the iPhone.

.iphone, .screen {
border: 0.5vh solid $shuttle-gray;
}

.iphone {
padding: 10vh 1.5vh;
border-radius: 6vh;
}

We also need to add all of the little buttons and doohickeys on the iPhone. First, let’s add them to the HTML as <button> and <span> elements.

<div class="iphone">
...

<button class="home" title="Home"></button>
<span class="speaker" title="Speaker"></span>
<span class="camera" title="Camera"></span>
<span class="proximity" title="Proximity Sensor"></span>

<button class="silence" title="Silence Switch"></button>
<button class="volume-up" title="Volume Up"></button>
<button class="volume-down" title="Volume Down"></button>
<button class="sleep" title="Sleep"></button>
</div>

Styling these is pretty straight-forward — we’ll use good old absolute positioning. Let’s set the position of the iPhone container to relative so the other elements can be positioned off of it.

.iphone {
...
position: relative;
}

Next, we’ll size and position all the buttons and spans. There’s no magic here — just a whole lot of styles.

.home, .camera, .proximity, .speaker, .silence, .volume-up, .volume-down, .sleep {
position: absolute;
}

.home, .camera, .proximity {
border-radius: 50%;
}

.speaker, .silence, .volume-up, .volume-down, .sleep, .proximity {
background-color: $shuttle-gray;
}

.home, .speaker, .camera, .proximity {
left: 50%;
}

.home, .speaker {
margin-left: -3vh;
width: 6vh;
}

.home, .camera {
border: 0.5vh solid $shuttle-gray;
}

.home {
height: 6vh;
bottom: 2vh;
}

.speaker {
top: 4.75vh;
height: 0.5vh;
border-radius: 0.5vh;
}

.camera {
width: 1.5vh;
height: 1.5vh;
top: 4.25vh;
margin-left: -6.5vh;
}

.proximity {
width: 1vh;
height: 1vh;
top: 2vh;
margin-left: -0.5vh;
}

.silence, .volume-up, .volume-down, .sleep {
width: 0.5vh;
}

.volume-up, .volume-down, .sleep {
height: 5vh;
}

.silence, .volume-up, .volume-down {
left: -0.75vh;
}

.silence {
height: 3vh;
top: 10vh;
}

.volume-up, .sleep {
top: 17vh;
}

.volume-down {
top: 24vh;
}

.sleep {
right: -0.75vh;
}

One More Thing

Our iPhone layout is done, but there’s one more thing we can add to make it really special. Let’s make the buttons wiggle when we hold down an icon.

$(function() {
var timeout;

$(".icon")
.on("mousedown touchstart", function() {
timeout = setTimeout(function() {
$(".iphone").addClass("wiggle");
}, 1000);
})
.on("mouseup touchend", function() {
clearTimeout(timeout);
});

$(".home").click(function() {
$(".iphone").removeClass("wiggle");
});
});

Let’s break this down step by step. First, we have a function contained inside of $, which tells jQuery to run the function after the document is ready. Next, we bind to the mousedown and touchstart events on the icons and set a timeout for one second. If a mouseup or touchend event occurs before that second is up, then we cancel the timeout and nothing happens. Otherwise, we’ll add a wiggle class to the iPhone container. When the user clicks on the home button, the wiggle class is removed and the animation is stopped.

Next, let’s add that wiggle animation.

@keyframes wiggle {
25% {
transform: rotate(3.5deg);
}

75% {
transform: rotate(-3.5deg);
}
}

.wiggle .icon {
animation: wiggle 0.25s linear infinite;
}

Well, that’s something! Of course, the icons don’t synchronize like that on an actual iPhone. We can make it more true to life by using Sass’s random function. This function returns a random value greater than or equal to 0 and less than 1. We’ll use it to change the animation’s delay for each icon. We’ll also use a Sass for loop and the nth-of-type selector to style each icon individually.

@for $i from 1 through 28 {
.wiggle .icon:nth-of-type(#{$i}) {
animation: wiggle 0.25s linear infinite 0.25s * random();
}
}

We can make it even nicer by randomizing the rotation animation’s origin.

@for $i from 1 through 28 {
.wiggle .icon:nth-of-type(#{$i}) {
animation: wiggle (0.2s + 0.1s * random()) linear infinite 0.25s * random();
transform-origin: (25% + random() * 50%) (25% + random() * 50%);
}
}

That’s It!

You’ve seen everything you need to build an iPhone layout from scratch. You’ve learned several techniques, including wrapping with flexbox, making use of the vh unit and some nifty animation techniques with Sass. Hopefully, you can take what you’ve learned and apply it to some new layouts. Let me know what you come up with!

Want to learn more about flexbox? Check out my book, Unraveling Flexbox.

Don’t miss the next article! Subscribe here to get new web development tricks and tips delivered straight to your inbox.

--

--

Landon Schropp

I'm a developer, designer and entrepreneur based in Seattle.