Weekly EncodeUI № 1: Create a Responsive Login Page with PureCSS

This is a part of a new weekly feature where we would build a simple webpage with different CSS and JavaScript techniques. I would pick a random #dailyui shot from Dribbble and show you how you can convert it to functional HTML page. I am not going to use SCSS or LESS, Pug or any other preprocessors. We would build these pages with just plain HTML, CSS and (mostly) vanilla JavaScript. At the end of the tutorials, we would create a list of key takeaways. I would try to explain in as simple a way as I can.

What we will build

daily ui

This week I chose this shot by Kola Popoola. Although it’s titled ‘Landing Page’, it’s more like a login page. I specially liked the simplicity in the design and how everything is stacked in perfect order. The designer didn’t provide any mockup for mobile devices, so I took the liberty to build it in my way. Also, I didn’t find the image used in the mockup, so I used this photo from Unsplash.

You can try the demo here. You can also check the GitHub repository for all the HTML, CSS and JavaScript files.

1. Getting Started

Let’s start with a new html file: index.html

<!doctype html>
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1">
     <title>Landing page</title>

Nothing special here. Note the <meta name="viewport">. This line ensures the viewport is set to the device’s width.

2. PureCSS

For this tutorial we would use PureCSS, one of the many bloat-free CSS frameworks. Add these lines before the closing </head> tag:

<link rel='stylesheet' href='https://unpkg.com/[email protected]/build/pure-min.css'/>
<!--[if lte IE 8]>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/build/rids-responive-old-ie-min.css">
<!--[if gt IE 8]><!-->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/build/grids-responsive-min.css">
<link rel='stylesheet' href='css/style.css'/>

Here, we added PureCSS base stylesheet. Then, the grid system (By default PureCSS does not include this). Finally, our own style.css file, which we will create next.

Create a directory named css and add style.css inside it. Add these inside style.css:

@import url('https://fonts.googleapis.com/css?family=Roboto|Raleway');

html, button, input, select, textarea, .pure-g [class *= "pure-u"] {
    font-family: 'Raleway', sans-serif !important;

body {
    background: #f1efef;

a {

Nothing fancy here. We are using Roboto and Raleway fonts from Google Fonts. The background is set to a slightly off white color. Worthwhile to note here that we have overridden the fonts. This is because PureCSS uses a different set of fonts. Do not worry about the classnames here, more about them in a moment.

3. HTML for the left section

Next add these lines inside <body> tag in index.html:

<main class='pure-g'>
    <section id='l_section' class='pure-u-1-1 pure-u-md-1-2'>
    <section id='r_section' class='pure-u-1-1 pure-u-md-1-2'>

PureCSS grid system works this way: each row should be .pure-g. Immediate child of .pure-g must be .pure-u-. Here <main> is our container and the <section> tags are left and right part of the page, identified with l_section and r_section.

Now, about the numbers after pure-u-, here is how it works: the classnames represent the widths of the elements. For example, .pure-u-1-4 will have a width of 25% (because 1/4=0.25 or 25%). Similarly, .pure-u-1-1 means it will take 100% width of the parent container, which is .pure-g.

Also, important to note, .pure-u-md- classnames. These are device width specific and uses min-width media query. Go through this part of the documentation to understand how it works. We have set .pure-u-md-1-2 in both <section> tags. This is because we want the layout to show two halves (i.e. 50% each) for devices with medium width.

Next, we add these lines inside the first <section>, i.e. the one with l_section id:

<img class='pure-img brand' src="img/logo.png"/>
<h1>We are <span class='brand-name'>vintage cars</span></h1>
<p>Welcome Back, please login to your account.</p>

<form class="pure-form pure-form-stacked">

 <div class='input-group'>
  <label for="email">Email</label>
  <input id="email" type="email">

 <div class='input-group last'>
  <label for="password">Password</label>
  <input id="password" type="password" >

 <div class='pure-g form-footer'>
  <div class='pure-u-1-2'>
    <label for="remember" class="pure-checkbox">
       <input id="remember" type="checkbox"> Remember me
  <div class='pure-u-1-2'>
      <a href='#' class='pure-checkbox'>Forgot password</a>

 <div class='pure-g'>
  <div class='pure-u-1-2 pure-u-md-1-3'>
      <input type="submit" class="pure-button pure-button-primary vc-btn" value="Login" />
  <div class='pure-u-1-2 pure-u-md-1-3'>
      <a class='pure-button pure-button-large vc-btn'>Sign Up</a>

<p class='toc-notice'>By signing up, you agree to Vintage Car's <a href='#'>Terms and Conditions</a> & <a href='#'>Privacy Policy</a></p>

Not too complicated markup: we created a heading (with h1), added some text (with <p>), and finally added the login form. For the form’s markup, I followed the documentation at PureCSS and created a stacked form.

At this point, the page looks like this:

weekly mockup to html
Ugly, isn’t it? Let’s put on some styles.

4. Styling the left section

Let’s come back to style.css and insert these lines:

main {
    margin:3em auto 0;
    color: #8c8787;
    -webkit-box-shadow: 1px 1px 10px 2px rgba(0,0,0,0.33);
    -moz-box-shadow: 1px 1px 10px 2px rgba(0,0,0,0.33);
    box-shadow: 1px 1px 10px 2px rgba(0,0,0,0.33);

#l_section img.brand {
  margin:2rem 0 0 2rem;

#l_section h1 {
    margin:5rem 0 1rem 2rem;
    font-family: 'Roboto', sans-serif;

#l_section h1 span.brand-name {

#l_section p {
    font-size:  1.25rem;
    margin:0 0 2rem 2rem;

#l_section fieldset {
  border: 0px;
  margin:0 2rem;

.input-group {
    border:1px solid #e2e1e1;
    transition-duration: 0.1s

Here, we set the maximum width of <main> to 960px, and box-shadow too. For all units here, I am using rem. You can read about it here. PureCSS’ base font-size is 16px; so 2rem is 32px and so on.

Note that we added border to each .input-group, the element that contains <input> fields. So, now it looks something like this:

weekly mockup to html
Okayish, but needs more care. Note that the border between the two form fields is 2px, because both have a 1px border on all sides. Let’s fix this with:

.input-group.last {

Next, we need to fix the pesky borders in <input> tags.

.input-group input[type='email'], .input-group input[type='password'] {

We also removed the box-shadow. Next, take a look at the mockup once again. Both the form fields have a yellow border the left. To achieve this effect:

.input-group:focus-within {
    border-left:4px solid #f6e122;

Let me explain. Recall that in our markup, we had each <input> field inside .input-group. We want to add a border on corresponding .input-group when we click on any of the <input> fields. :focus-within does the magic. The above is equivalent to saying: Add a 4px left border on each .input-group whenever the focus is at any of its children.

So now, we have this:

weekly mockup to html
Cool, we are getting there. Next, add these in style.css

.form-footer {
    margin:2rem 0 1rem;

.form-footer a {

.vc-btn {
  border:2px solid #100F0B;

.vc-btn:hover {

.vc-btn.pure-button-primary {
  background: #100F0B;

#l_section p.toc-notice {

Well, these are pretty self-explanatory. Here, we styled the two buttons with background and rounded border. .pure-button-primary is taken from PureCSS’ button classes. The .toc-notice class is styled with a larger line-height, to match the mockup.

5. HTML for right section

Insert the following lines inside <section id='r_section'>

<a href="#" class="custom-menu-toggle" id="toggle"><s class="bar"></s><s class="bar"></s></a>
<div class="pure-menu pure-menu-horizontal pure-menu-scrollable custom-menu custom-menu-bottom custom-menu-tucked" id="tuckedMenu">
    <ul class="pure-menu-list">
        <li class="pure-menu-item"><a href="#" class="pure-menu-link">About Us</a></li>
        <li class="pure-menu-item"><a href="#" class="pure-menu-link">Showcase</a></li>
        <li class="pure-menu-item"><a href="#" class="pure-menu-link">Letters</a></li>
        <li class="pure-menu-item"><a href="#" class="pure-menu-link">Contact</a></li>
        <li class="pure-menu-item"><a href="#" class="pure-menu-link">Blog</a></li>

I have taken the entire markup from this page on PureCSS examples section. On mobile devices, our menu on the right would look similar to the one at the demo page. On larger devices, it just show as a horizontal list of items. (I encourage you to go through the documentation on menus to have a better understanding of what’s happening here.)

6. Styling the right section

At this point, the right section looks like this:

weekly mockup to html
Let’s add some styles so that it looks more like our mockup. Add these in style.css:

#r_section {
  background:url('../img/bg.jpg') no-repeat center;
  background-size: cover;

.custom-menu-wrapper {
    background-color: #808080;
    margin-bottom: 2.5em;
    white-space: nowrap;
    position: relative;

.custom-menu {
    display: inline-block;
    width: auto;
    vertical-align: middle;
    -webkit-font-smoothing: antialiased;

.custom-menu .pure-menu-link {
    color: white;
    border:2px solid transparent;
    transition:all 0.4s ease-out;

.custom-menu .pure-menu-link:hover, .custom-menu .pure-menu-link:focus {
    background-color: transparent;
    border:2px solid #ffffff;

.custom-menu-toggle {
    width: 44px;
    height: 44px;
    display: block;
    position: absolute;
    top: 3px;
    right: 0;
    display: none;

.custom-menu-toggle .bar {
    background-color: white;
    display: block;
    width: 20px;
    height: 2px;
    border-radius: 100px;
    position: absolute;
    top: 22px;
    right: 12px;
    -webkit-transition: all 0.5s;
    -moz-transition: all 0.5s;
    -ms-transition: all 0.5s;
    transition: all 0.5s;

.custom-menu-toggle .bar:first-child {
    -webkit-transform: translateY(-6px);
    -moz-transform: translateY(-6px);
    -ms-transform: translateY(-6px);
    transform: translateY(-6px);

.custom-menu-toggle.x .bar {
    -webkit-transform: rotate(45deg);
    -moz-transform: rotate(45deg);
    -ms-transform: rotate(45deg);
    transform: rotate(45deg);

.custom-menu-toggle.x .bar:first-child {
    -webkit-transform: rotate(-45deg);
    -moz-transform: rotate(-45deg);
    -ms-transform: rotate(-45deg);
    transform: rotate(-45deg);

Here, we added the background to the Unsplash image, which I saved as bg.jpg inside img directory. I have taken the styles for the menu directly from the earlier demo page, with a few modifications: I changed the background color, added a bit of margin on top and left to suit our requirements. I also set all the text in menus to uppercase, and added a 2px solid border when the items are hovered or clicked.

Here it worthwhile to note that .custom-menu-toggle is the two-lined hamburger styled element that opens the menu when clicked. But its display is set to none. Because we don’t need it on larger devices.

At this point, our page looks almost exactly like the mockup.

weekly mockup to html
Now, it’s time we make it responsive.

7. Building for mobile devices

Our aim would be to make the page look like this:

weekly mokup to html
The important thing to note here is that the right section goes to the top and left section goes beneath. But our HTML markup has left section before the right section. So we need to re-order the elements.
The .pure-u- classes are actually flexbox items. Flexbox items can be re-ordered by setting order property. So, let’s insert the following lines in style.css:

@media screen and (max-width: 48em){
    main {

    #l_section {

    #r_section {


So, we removed the top-margin on <main> tag, set the page to 100% width and height. We re-ordered left and right sections by setting order. This styles are for devices whose width is maximum 48rem (which is 48×16 or 768px)

At this point, if you resize the window to mimick smaller devices, you would notice that the toggler for the menu is not showing up and there’s a horizontal scrollbar. To fix this, insert these line inside @media screen block:

.custom-menu {
     display: block;

 .custom-menu-toggle {
     display: block;
     display: none\9;

 .custom-menu-bottom {
     position: absolute;
     width: 95%;
     background-color: transparent;
     z-index: 100;

 .custom-menu-bottom .pure-menu-link {
     opacity: 1;
     -webkit-transform: translateX(0);
     -moz-transform: translateX(0);
     -ms-transform: translateX(0);
     transform: translateX(0);
     -webkit-transition: all 0.5s;
     -moz-transition: all 0.5s;
     -ms-transition: all 0.5s;
     transition: all 0.5s;

 .custom-menu-bottom.custom-menu-tucked .pure-menu-link {
     -webkit-transform: translateX(-140px);
     -moz-transform: translateX(-140px);
     -ms-transform: translateX(-140px);
     transform: translateX(-140px);
     opacity: 0;
     opacity: 1\9;

 .pure-menu-horizontal.custom-menu-tucked {
     z-index: -1;
     top: 45px;
     position: absolute;
     overflow: hidden;

Here we set the toggler’s display to block. This part of the code I copied from the demo page, as earlier. It sets animation properties and positions the toggler and the menu items one above another.

Now, our page looks good on mobile as well as desktop. But the toggler does not open the menu. To fix this, add a new JavaScript file menu-switch.js inside js/ directory and insert these lines:

(function (window, document) {
         document.getElementById('toggle').addEventListener('click', function (e) {
 })(this, this.document);

And we are done!

Key takeaways

  1. :focus-within: sets properties of parent element when focus is on any of its children.
  2. order CSS property: lets you re-order flexbox elements.


I hope this first edition of the weekly feature has been helpful to you. If you have a question, please use the comment section below. You can fork the GitHub repository and send a pull request if you want to add something to it. You can follow us on Twitter for more useful content.