Redesigning A Responsive Youtube with HTML5/CSS3 [Tutorial]

Note: This post was first published on the 18th Feb, 2013.

If you have seen YouTube recently, you may notice one glaring omission from their website layout. Their design lacks the ability to fold responsively as you resize the browser window. It’s strange how the layout does not even contract to a smaller width; YouTube is currently designed using a fixed-width webpage.

I want to bring in some modern web design techniques and give the YouTube homepage a nice redesign. In this tutorial, I’ll explain how we can build a custom mobile-responsive YouTube clone layout from scratch.

I’ll be using some newer HTML5 and CSS3 techniques supported in mostly all modern browsers.

If you want to see my code in action check out the live demo at the end of the article below.

Creating the Structure

To get us started we should create a single index.html page with the typical HTML5 doctype. Since this is a mobile responsive layout we need to include a few specific meta tags as well.

In this project, I’ll be separating our JavaScript and CSS code into different files, and you can see what that looks like in my codes below:

<!doctype html>
<html lang="en-US">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>Demo sliding menu test</title>
  <meta name="author" content="Jake Rocheleau">
  <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
  <link rel="shortcut icon" href="favicon.ico">
  <link rel="icon" href="favicon.ico">
  <link rel="stylesheet" type="text/css" href="css/styles.css">
  <link rel="stylesheet" type="text/css" href="css/responsive.css">
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.9.0/jquery-ui.min.js"></script>
  <script type="text/javascript" src="js/retina.js"></script>
  <script type="text/javascript" src="js/scripts.js"></script>
<!--[if lt IE 9]>
  <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>

So, along with the viewport meta tag, I include a series of external documents. The stylesheets styles.css and responsive.css contain the design rules for our typical layout and over-responsive media queries.

Additionally I am including two JS libraries from Google’s CDN hosting: jQuery and jQuery UI. Both will come in handy as the layout shrinks and we use a sliding animation to display the navigation menu.

This animation is tied to the scripts.js file where I’ll be keeping all our custom jQuery codes. Additionally, I have another 3rd party script named retina.js, which is by far the easiest way to work around retina display images.

If you visit the retina.js website you’ll find a download link for their minified library. Simply include this into your document and the script will auto-scan your images for @2x variations (when on retina devices).

More Responsive Tendencies

For this particular tutorial, I have gone with a more atypical approach to website design techniques.

When our layout is displaying in full at 950px, you’ll see two sidebars along with the center video content. However when you get down to the smallest frame, around 320px, you’ll only see the center column and a top toolbar area.

toogle youtube toolbar

This toolbar will have a menu toggle button which you can tap, to slide back and forth. None of the menu links work in my demo because we don’t have any pages with content right now. But you may update these anchor links with new HREF values to get them working on a real website.

Let me copy over just the top header & navigation code from our document body.

<body>
  <div id="w" class="clearfix">
    <header id="fulltop">
      <span id="logomini"><a href="index.html"><img src="design-responsive-youtube/logo-mini.png" alt="YouTube - Broadcast Yourself"></a></span>
      
      <span id="userlogin">
        <img src="design-responsive-youtube/avatar-sm.png" alt="default user pic" class="defaultphoto"> 
        <a href="javascript:void(0)">Log In</a>
      </span>      
      
      <div id="searchbox">
        <form id="searchform" name="searchform" action="#" method="get">
          <input type="text" name="s" id="s" class="searchbar" placeholder="" tabindex="1">
          <input type="submit" name="sbtn" id="sbtn" value="" tabindex="2">
        </form>
        
        <ul id="topsidelinks">
          <li><a href="javascript:void(0)">Browse</a></li>
          <li><a href="javascript:void(0)">Featured</a></li>
          <li><a href="javascript:void(0)">Upload</a></li>
        </ul>
      </div>
    </header>
    
    <nav>
      <ul id="sidenav">
        <li class="heading">User Account</li>
        <li><a href="#login" class="signin"><i></i>Sign In</a></li>
        <li><a href="#register" class="register"><i></i>Register</a></li>
        <li class="heading">Video Categories</li>
        <li><a href="#popular" class="popular"><i></i>Popular</a></li>
        <li><a href="#recent" class="recent"><i></i>Recently Uploaded</a></li>
        <li><a href="#comedy" class="comedy"><i></i>Comedy</a></li>
        <li><a href="#entertainment" class="entertainment"><i></i>Entertainment</a></li>
        <li><a href="#film" class="film"><i></i>Film & Animation</a></li>
        <li><a href="#gaming" class="gaming"><i></i>Gaming</a></li>
        <li><a href="#people" class="people"><i></i>People & Blogs</a></li>
      </ul>
    </nav><!-- end navigation menu -->

So all the content wrapped inside our body is inside another wrapper div with the ID #w. This is how we can fix the page content towards the center and limit the maximum width around 950px. But inside the header tag you’ll notice that many of the features are not displaying on smaller screens. We are using @media queries inside CSS to limit when the search bar and top links will be displayed.

Additionally the sliding nav menu will always appear hidden on smaller screens. Once your browser width passes about 600px then the side navigation is displayed naturally as a left column in the body container. This is the reason why these links should always work properly regardless of the responsive situation.

Common Webpage Styles

I want to jump into discussing a few important blocks of CSS code. To begin we need to understand how the core body is centered and why the two-column layout drops down as you resize the window.

Now these rules are separated into two documents as you saw earlier, so the easiest way to understand this is by downloading my source code directly.

/* page structure */
#w { 
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  max-width: 950px; 
  min-width: 300px; 
  height: 100%;
  margin: 0 auto; 
  overflow: hidden;
  position: relative; 
  display: block; 
  -webkit-box-shadow: 0px 0px 9px rgba(0,0,0,0.65);
  -moz-box-shadow: 0px 0px 9px rgba(0,0,0,0.65);
  box-shadow: 0px 0px 9px rgba(0,0,0,0.65); 
}

#pageWrapper { display: block; width: 100%; }
#page { 
  display: block; 
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  width: 100%;
  min-height: 650px;
  position: relative; 
  top: 0; 
  background: #fff; 
  z-index: 999;  
  padding: 0;
  -webkit-box-shadow: -4px 0px 9px -4px rgba(0,0,0,0.65);
  -moz-box-shadow: -4px 0px 9px -4px rgba(0,0,0,0.65);
  box-shadow: -4px 0px 9px -4px rgba(0,0,0,0.65);
}
#content { display: block; padding: 10px 14px; }

#fulltop { display: none; visibility: hidden; }
#secondary { display: none; visibility: hidden; }

Initially we are hiding the top header section and the secondary sidebar from view. All the HTML is still in our document, but none of this will be displayed until the width has surpassed 600px.

The secondary sidebar is actually hidden until 800px because there simply isn’t enough room in the layout.

/* header */
#topbar { 
  display: block; 
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  height: 60px;
  padding: 0px 6px;
  padding-top: 10px;
  text-align: center;
  border-bottom: 1px solid #677282;
  background-color: #6279a3;
  background-image: -webkit-gradient(linear, left top, left bottom, from(#8da1c2), to(#6279a3));
  background-image: -webkit-linear-gradient(top, #8da1c2, #6279a3);
  background-image: -moz-linear-gradient(top, #8da1c2, #6279a3);
  background-image: -ms-linear-gradient(top, #8da1c2, #6279a3);
  background-image: -o-linear-gradient(top, #8da1c2, #6279a3);
  background-image: linear-gradient(top, #8da1c2, #6279a3);
  -webkit-box-shadow: 0px 1px 0px rgba(255,255,255,0.5) inset;
  -moz-box-shadow: 0px 1px 0px rgba(255,255,255,0.5) inset;
  box-shadow: 0px 1px 0px rgba(255,255,255,0.5) inset;
}

#logo { position: relative; top: -5px; }

#slidelink { 
  display: block; 
  font-size: 0.01em; 
  line-height: 1.8em; 
  width: 50px; 
  height: 35px; 
  position: relative;
  top: 2px;
  left: 10px;
  background: url('../design-responsive-youtube/menu.png') top left no-repeat; 
  float: left; 
  z-index: 999;
}

All the header codes are pertaining to the responsive mobile top navigation toolbar with the blue gradient background. We are creating all of this through CSS3 except for the sliding button, which uses a background image.

For retina devices I have included an @2x copy of the menu icon, along with all of the sidebar icons which are from the Glyphish icon pack.

When using CSS background images we cannot rely on the retina.js script. That will only parse images which are loaded into the page using an HTML5 <img> tag. Instead we need to setup new responsive rules inside the stylesheet named responsive.css.

I’ve copied over my block of code below:

/* retina display devices only */
@media only screen and (-webkit-min-device-pixel-ratio: 2),	only screen and (min--moz-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) {
 
 #slidelink { background: url('../design-responsive-youtube/menu@2x.png') top left no-repeat; background-size: 50px 35px; }
 
 #sbtn { background: url('../design-responsive-youtube/search@2x.png'); background-size: 24px 24px; }
 
 #sidenav li a.signin i { background-image: url('../design-responsive-youtube/user@2x.png'); background-size: 24px 21px; } 
 #sidenav li a.register i { background-image: url('../design-responsive-youtube/gear@2x.png'); background-size: 26px 26px; }
 #sidenav li a.popular i { background-image: url('../design-responsive-youtube/star@2x.png'); background-size: 26px 26px; }
 #sidenav li a.recent i { background-image: url('../design-responsive-youtube/coffee@2x.png'); background-size: 24px 26px; }
 #sidenav li a.comedy i { background-image: url('../design-responsive-youtube/mic@2x.png'); background-size: 12px 24px; }
 #sidenav li a.entertainment i { background-image: url('../design-responsive-youtube/tv@2x.png'); background-size: 24px 24px; }
 #sidenav li a.film i { background-image: url('../design-responsive-youtube/film@2x.png'); background-size: 20px 25px; }
 #sidenav li a.gaming i { background-image: url('../design-responsive-youtube/joystick@2x.png'); background-size: 22px 20px; }
 #sidenav li a.people i { background-image: url('../design-responsive-youtube/pencil@2x.png'); background-size: 23px 23px; }
}

The background-size property along with an @2x copy is what performs all the magic here. We need to squeeze an image twice as large into the typical sizing constraints.

This will look a whole lot better on retina devices where your natural images would look blurry and upscaled in comparison.

Important Responsive CSS Blocks

Much of the responsive codes should be straightforward for web developers who are familiar with using the syntax. But I’ll copy over some other sections from my responsive.css document and explain the layout effects.

/* first responsive changes between mobile and desktop layout */
@media only screen and (min-width: 600px) {
  #sidenav { z-index: 999; width: 250px; }
  #page { z-index: 1; padding-left: 250px; }
  
  #topbar { display: none; visibility: hidden; }
  
  #fulltop { display: block; visibility: visible; height: 45px; padding: 8px 14px; border-bottom: 1px solid #d8d8d8; }
  #logomini { display: block; float: left; margin-right: 40px; }
  
  #searchform { display: block; float: left; }
  #s { 
    width: 310px; 
    border: 1px solid #ccc;
    padding: 8px 7px;
    color: #999;
    background: #f7f7f7;
    font-size: 1.45em;
    text-shadow: 0px 1px 0px #fff;
    outline: none;
    -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.5) inset;
    -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.5) inset;
    box-shadow: 0 1px 3px rgba(0,0,0,0.5) inset;
    -webkit-transition: all .4s linear;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    border-radius: 3px;
    -moz-transition: all .4s linear;
    transition: all .4s linear;
  }
  #s:focus { color: #666; background: #fff; border-color: #b8b8b8; }
  
  #sbtn { cursor: pointer; width: 24px; height: 24px; border: 0; background: none; background-image: url('../design-responsive-youtube/search.png'); position: relative; top: -4px; left: -35px; opacity: 0.7; }
  #sbtn:hover { cursor: pointer; }

Right when your browser viewport hits 600px the whole layout should change immediately. We are no longer using the toggle menu and now wish to display it openly as a left sidebar.

We also need to change the visibility of the older responsive toolbar and display the #fulltop header div instead.

Additionally you may get a kick out of the CSS3 transitions and box shadow effects I’m using on the search field. These effects should perform exactly the same in most browsers including Firefox, Opera, Safari, and even IE9-10.

It’s a nice additional touch giving this YouTube layout some modern aesthetics.

/* as the layout widens display a secondary sidebar and top user links */
@media only screen and (min-width: 810px) {
  #userlogin { display: block; float: right; margin-right: 35px; margin-top: 4px; height: 30px; line-height: 30px; }
  #userlogin .defaultphoto { display: block; float: left; border: 1px solid #ddd; margin-right: 3px; }
  #userlogin a { line-height: 35px; }
  
  #secondary { display: block; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; visibility: visible; width: 240px; padding: 10px 14px; z-index: 999; position: absolute; right: 0; }
  #secondary h2 { font-size: 1.3em; font-weight: bold; font-style: italic; line-height: 1.45em; color: #66666d; margin-bottom: 7px; }
  .videoblock { display: block; visibility: visible; width: 100%; }
  .videoblock a .vidimg { display: block; visibility: visible; }
  
  .videoblock a { display: block; width: 100%; margin-bottom: 7px; padding: 5px 0px; text-decoration: none; border-bottom: 1px solid #fff; }
  .videoblock a:hover { border-bottom: 1px solid #ebebeb; background: #f6f6f6; }
  
  .videoblock a .vidimg img { display: inline-block; visibility: visible; border: 1px solid #cdcdcd; }

  .videoblock a h4 { font-weight: bold; font-size: 1.3em; color: #333; margin-bottom: 1px; }
  .videoblock a:hover h4 { color: #5a7aaa; }

  .videoblock a .uploader { display: block; font-size: 1.1em; color: #666669; }
  .videoblock a .views { display: block; font-size: 1.1em; color: #666669; }
  .videoblock a:hover .uploader, .videoblock a:hover .views { color: #525252; }
  
  #page { padding-right: 240px; }
}

Now this last bit of responsive code takes effect once the browser window is slightly larger than 800px. I have included a secondary sidebar area which supports “featured videos”, among other similar blocks of code.

I haven’t included much dummy content since the focus of this tutorial is on working responsive codes. But this new secondary sidebar is perfect for extra page content which just can’t be fitted into the smaller layouts.

You may also notice these styles add a small set of links into the full top header display. When a user is logged in this is the perfect opportunity to present more impactful profile-related links. These could pertain to user account settings, favorite videos, channel subscriptions, or recent uploads.

Developing JS with jQuery

There are just two core functions I’ve built into the scripts.js asset file: whenever the user taps on our mobile responsive menu, it opens/closes the panel accordingly and if the user opens the menu and then resizes their browser, all the content is pushed over to the right.

In this scenario we need to handle if the menu is open and the browser is resized large enough to hide the menu, then reposition the main content area. I’ll break down each of these code snippets into two segments.

  var page = $("#page");

  // show and hide navigation menu
  $("a#slidelink").on("click", function(e){
    e.preventDefault();
    var position = page.position();
    var winwidth = $(window).width();
    
    if(position.left == 0) {
      $(page).animate(
        { left: '+=240px' },
        250,
        'easeOutBack',
        function() {
          // callback
      });
    } else {
      $(page).animate(
        { left: '-=240px' },
        400,
        'easeOutCirc',
        function() {
          // callback	
      });   
    }
  });

The #slidelink refers to our menu button which is displayed in the top mobile toolbar area. Whenever the user clicks on this link then we find the current position of our page content. If the left position returns a value of 0 then we know the menu is still closed, and we need to open it.

If the value is anything except 0 then we can assume the menu is already open and we’re looking to close it.

Both of these effects use the jquery .animate() method which is why we’re including a copy of the jQuery UI library as well. None of the callback functions are active, but it’s easy to add in your own codes.

Inside you can place anything you want to execute immediately after these animations are complete.

  // check content position on browser resize
  var resizeTimer;
  $(window).resize(function() {
    clearTimeout(resizeTimer);
    resizeTimer = setTimeout(resetPagePosition, 150);
  });  
  
  
  function resetPagePosition() {
    var position = page.position();
    var winwidth = $(window).width();
    
    if(winwidth <= 600 && position.left != 0) {
      // if the window is above 600px and the menu is open we need to reset back into position
      $(page).animate({left: "0"}, 110);
    }
  };

The second function will handle repositioning of our page content whenever the menu is open & the browser window gets resized wide enough to hide it. This event handler which is attached to the window object listens for jQuery’s .resize() method. I have set a timer for 150 milliseconds so the function isn’t firing immediately after the resize.

All the interactive code can be found inside my custom function resetPagePosition(). Inside the function I have created another position variable to determine where our page is located.

If the left value is not 0, then we know the menu was open and we have now passed the 600px threshold. It’s a simpler solution for cleaning up this annoying bug, which you will likely run into if you’re using any type of sliding mobile menu techniques.

Secondary Sidebar design - YouTube Responsive tutorial CSS3 media queries

Demo & Download

Feel free to play around with the live demo version and see if you can get a working solution on your desktop, laptop, tablet, or smartphone.

Final Thoughts

I hope this tutorial has demonstrated a few key traits for building responsive websites. The developers at YouTube could be drawing in more attention to the site if it was directly supported on mobile devices. YouTube does have their own mobile subdomain but it’s just not the same experience.

If you have any questions or comments about the tutorial, you can share with us in the post discussion area below.

WebsiteFacebookTwitterInstagramPinterestLinkedInGoogle+YoutubeRedditDribbbleBehanceGithubCodePenWhatsappEmail