Creating an iPhone in CSS

For any project I can, I’ve been challenging myself to create assets I need in CSS — this is my attempt at the iPhone.

If you don’t want to read the whole thing, you can find this project on CodePen and Github.

Github — https://github.com/stobertg/iphone

CodePen — https://codepen.io/stobertg/pen/reQGRo

Shared Elements

First, we’ll set up our shared SCSS elements that we will @extend when needed.

// Absolute Positioning
%absolute{
position: absolute;
}
%margin-auto{
margin: auto;
}
%center-horizontal{
@extend %absolute;
right: 0px;
left: 0px;
@extend %margin-auto;
}
%center-vertical{
@extend %absolute;
top: 0px;
bottom: 0px;
@extend %margin-auto;
}
%center-all{
@extend %center-horizontal;
@extend %center-vertical;
}
// Global Color
$iphone-black: #1d1d1d;
// Pseudo Elements
%sudo{
content: ' ';
@extend %absolute;
}

Next, we’ll create our global containers — one for the whole phone and another for the “base” of the phone which we will position absolute bottom right.

<figure class="iphone">
  <div class="phone">
  </div>
</figure>

The CSS :

.iphone{
position: relative;
width: 281px;
height: 591px;
margin: 0px auto;
}
.phone{
@extend %absolute;
bottom: 0px;
right: 0px;
width: 278px;
height: 588px;
}

Creating the base of the phone.

Looking at our reference image, we know that we want to make this pretty scalable in the sense that this phone can be used for any type of interaction display. For example, if we have a slider with next and previous images exposed to the left and right, we would want images moving behind the phone when images transition — not over the phone. This type of interaction can’t be accomplished with overflow hidden. So to make this phone scalable, our “phone base” needs to have a transparent background and we need to create the structure with borders instead. Let’s create this part first and then move our way inward.

As we zoom into our reference image, we start to pick up on subtle details that make this such a well done asset. Take notice of the thin line — you can tell how the top part of the line is subtly lighter then the right side. Let’s start by using pseudo elements to create this and the thick border.

*quick note — creating this on a dark background will help you notice the details better, such as the thin line.

.phone{
@extend %absolute;
bottom: 0px;
right: 0px;
width: 278px;
height: 588px;
  // Thick Border
  &:before{
@extend %sudos;
width: 100%;
height: 100%;
border: 20px solid $iphone-black;
border-radius: 40px;
}
  // Thin Line
  &:after{
@extend %sudos;
@extend %center-all;
width: 270px;
height: 580px;
border: 3px solid;
border-top-color: #252525;
border-left-color: #252525;
border-right-color: #212121;
border-bottom-color: #212121;
border-radius: 35px;
}
}

With the thin line, we’re making the top and left border slightly lighter than the right and bottom border to give it the gradient effect.

Next, let’s work on the top and bottom. First, let’s concentrate on their similarities. We know that the screen is completely centered on the phone — meaning the top and bottom are the same height, as well as their width.

Let’s update the html :

<figure class="iphone">
  <div class="phone">
    <div class="top">
<div>
<span class="camera"></span>
<span class="speaker"></span>
</div>
</div>
    <div class="bottom">
<div></div>
</div>
  </div>
</figure>

The CSS :

.top, .bottom{
@extend %absolute;
height: 83px;
width: 100%;
background: $iphone-black;
}
.top{
top: 0px;
border-radius: 40px 40px 0px 0px;
overflow: hidden;
}
.bottom{
bottom: 0px;
border-radius: 0px 0px 40px 40px;
}

For the top, we set the overflow as hidden because we’ll need it for hiding the glare later on.

Creating the Speaker and Camera

For the top, the speaker and camera are nested in another div container. As we notice more detail about the top, we can see that the speaker and the camera each have three parts — the outside border, the inside border and the background. This means that we can accomplish these pieces with pseudo elements and no additional html.

The container height is 35px, providing easy placement for the speaker to be absolute positioned on the bottom at 100% width and the camera is being positioned absolute on the top, in the center.

.top{
top: 0px;
border-radius: 40px 40px 0px 0px;
overflow: hidden;
  span{
display: block;
}
  // Container for the speaker and camera
  div{
@extend %center-horizontal;
top: 23px;
width: 55px;
height: 35px;
}
}

For the camera and the speaker we can create the gradient by just using one pseudo element. If you look closely, the lighter border on the bottom is the same color as the background in the middle — all we have to do is create the middle border, make it a tiny bit smaller, and then absolute position the Pseudo element on the top right. This will give the illusion that it’s a gradient when it’s really not.

.camera{
@extend %center-horizontal;
top: 0px;
width: 14px;
height: 14px;
border-radius: 50%;
border: 1px solid;
border-top-color: #1e1e1e;
border-left-color: #262626;
border-right-color: #1e1e1e;
border-bottom-color: #262626;
  &:before, &:after{
@extend %sudos;
@extend %center-all;
border-radius: 50%;
}
  // Gradient layer on top of background
  &:before{
width: 12px;
height: 12px;
background: -webkit-linear-gradient(top, #0f0f0f, #1f1f1f);
background: -o-linear-gradient(bottom, #0f0f0f, #1f1f1f);
background: -moz-linear-gradient(bottom, #0f0f0f, #1f1f1f);
background: linear-gradient(to bottom, #0f0f0f, #1f1f1f);
}
  // Inside Border
  &:after{
width: 6px;
height: 6px;
border: 2px solid #2a2a2a;
background: $iphone-black;
}
}

For the speaker

.speaker{
@extend %absolute;
bottom: 0px;
width: 53px;
height: 13px;
background: #2a2a2a;
border-radius: 10px;
z-index: 10;
  &:after{
@extend %sudos;
@extend %center-horizontal;
width: 54px;
height: 12px;
border: 3px solid;
border-top-color: #181818;
border-left-color: #181818;
border-right-color: #111;
border-bottom-color: #1e1e1e;
border-radius: 10px;
}
}

Creating the Bottom Home Button and the Bottom Gradient

.bottom{
bottom: 0px;
border-radius: 0px 0px 40px 40px;
  // Outside Border (White Outline)
  div{
@extend %center-horizontal;
top: 18px;
width: 45px;
height: 45px;
border-radius: 50%;
border: 1px solid #484848;
    &:before{
@extend %sudos;
}
}
  // Bottom two gradient (on the floor)
  &:before, &:after{
@extend %sudos;
@extend %center-horizontal;
bottom: 0px;
height: 6px;
border-radius: 100%;
-moz-box-shadow: 0px 0px 5px rgba(0,0,0,.9);
-webkit-box-shadow: 0px 0px 5px rgba(0,0,0,.9);
box-shadow: 0px 0px 5px rgba(0,0,0,.9);
}
  &:before{
background: rgba(0,0,0,0.6);
bottom: -2px;
width: 76%;
opacity: 0.8;
}
  &:after{
background: rgba(0,0,0,0.5);
bottom: -3px;
width: 90%;
opacity: 0.3;
height: 5px;
}
}

Creating the Screen Section

Let’s first add the screen to the HTML markup

<figure class="iphone">
  <div class="phone">
    <div class="top">
<div>
<span class="camera"></span>
<span class="speaker"></span>
</div>
</div>
   <!-- Add the Screen -->
    <div class="screen">
<!-- img
<img src="http://www.tylerstober.com/img/cardiact/one.jpg">
-->
</div>
    <div class="bottom">
<div></div>
</div>
  </div>
</figure>

The screen part is now pretty easy, now that we’ve created the rest of the base, just absolute position it dead center.

.screen{
@extend %center-all;
top: 0px;
width: 242px;
height: 424px;
border-radius: 3px;
border: 3px solid;
border-top-color: #252525;
border-left-color: #252525;
border-right-color: #212121;
border-bottom-color: #252525;
&:after{
@extend %sudos;
@extend %center-all;
left: -1px;
width: 238px;
height: 421px;
border: 2px solid #000;
border-radius: 3px;
}
}

Creating the Top and Side Buttons

To create the top button, we’ll utilize the before pseudo on the iphone class.

.iphone{
  &:before{
@extend %sudos;
background: #1e1e1e;
width: 45px;
height: 4px;
top: 0px;
right: 47px;
border-radius: 2px;
}
}

Next, we’ll add the side buttons to the html

<figure class="iphone">
  <!-- Add the Side Button -->
  <div class="side-buttons">
<div></div>
</div>
  <div class="phone">
<div class="top">
<div>
<span class="camera"></span>
<span class="speaker"></span>
</div>
</div>
    <div class="screen">
<!-- img
<img src="http://www.tylerstober.com/img/cardiact/one.jpg">
-->
</div>
    <div class="bottom">
<div></div>
</div>
</div>
</figure>

Side Button CSS :

.side-buttons{
@extend %absolute;
height: 125px;
width: 4px;
top: 84px;
  div, &:before, &:after{
background: #1e1e1e;
width: 4px;
border-radius: 2px;
}
  &:before, &:after{
@extend %sudos;
background: $iphone-black;
}
  &:before{
height: 26px;
}
  div, &:after{
height: 20px;
bottom: 0px;
}
  div{
@extend %center-vertical;
top: 6px;
}
}

Creating the Glare

To create the glare, we will revisit the .top class and add a pseudo element. Remember that we attached overflow hidden to this class to be able to do this part.

.top{  

&:after{
@extend %sudos;
@extend %absolute;
top: -50px;
right: 0px;
width: 150px;
height: 160px;
    // Rotating the Shape
    @include transform(rotate(-20deg)); 
    // Transparent Gradient from left to right

background: -webkit-linear-gradient(left, rgba(255,255,255,0.02), rgba(255,255,255,0));
background: -o-linear-gradient(right, rgba(255,255,255,0.02), rgba(255,255,255,0));
background: -moz-linear-gradient(right, rgba(255,255,255,0.02), rgba(255,255,255,0));
background: linear-gradient(to right, rgba(255,255,255,0.02), rgba(255,255,255,0));
}
}

Adding the Image

Just make sure that you have the image set to 100% in the css and you’re all set.

img{ 
width: 100%
}

HTML should look like

<figure class="iphone">
<div class="side-buttons">
<div></div>
</div>
  <div class="phone">
<div class="top">
<div>
<span class="camera"></span>
<span class="speaker"></span>
</div>
</div>
    <div class="screen">
<!-- The Image -->
<img src="http://www.tylerstober.com/img/cardiact/one.jpg">
</div>
    <div class="bottom">
<div></div>
</div>
</div>
</figure>

You can download this project from Github — https://github.com/stobertg/iphone

Or view on CodePen — https://codepen.io/stobertg/pen/reQGRo