in Tutorials

Create a Full Screen Layout for (Mobile) Web Apps

Over the last year or so, I’ve noticed that I basically use the same starting layout for most of my web apps.

In developing the layout, I’ve gone through several iterations and many lessons learned, and landed on what I think is pretty decent boilerplate layout for (mobile) wep apps.

So, I thought I’d walk through how to create it.

The layout we’ll be creating

Here’s what the finished layout will look like.

Mobile view
Mobile view of a full screen web app layout

Mobile view of a full screen web app layout

Desktop view
Desktop view of full screen web app layout

Desktop view of full screen web app layout

Main “features” of this layout:

  • Fixed header with an internal 3-column layout, optimized for optional left/right-column icons.
  • Full height main content block with auto-scroll.
  • Layout is full width for smaller devices and centered for desktops and larger devices (or landscape views.)

This may not seem like much, but, as it turns out, even creating a layout like this is not that trivial.

Browser/Device Compatibility

This design will work on current versions of major browsers (Chrome/Safari/Firefox.)  It has not been tested on older browsers.

Get the code

While I recommend you follow the instructions and create this on your own, if you just want the code…


Before getting started, I recommend you have the following setup:

  • A local web server: I’m on a Mac and use MAMP.  If you are as well, install it, configure the server to point to the directory where you keep local dev files (I have a “dev” directory in the root of my home directory), then start the server and point your browser to “localhost:8888” (or whatever port your server uses.)  From there, you should be able to navigate to your specific project.
  • Something for auto-reloading your web pages while you work: I use the livereload npm package, with the corresponding Chrome extension.  This assumes you have node installed.  First install livereload globally with  npm i -g livereload  In your terminal, navigate to your project directory and type  livereload, then go back to your browser, make sure you’re at the URL corresponding to your project location and click on “Enable LiveReload.”  After this, your browser should refresh automatically every time a file is modified in the corresponding directory.

Create the HTML Page

Create a project folder and add the following:


This is the base markup.  Next, let’s view what we’ve added so far in a browser

View your work in device mode

Open up your browser, display your console (here’s how to do that in chrome) and toggle device mode to be for a mobile device.  You should now see something like this.

Default view without styling

Default view without styling

Why view your work in device mode?  Primarily to get in the habit of taking a Mobile First approach to implementing your app, ie we want to first make sure our design looks right on small devices before making sure we support larger devices and desktops.

Mobile Meta Tags

The first thing you might notice is that the text appears very small, despite being wrapped in an H1 tag.  A common mistake is to try to fix this using css.  The first time I was building a mobile web app, I remember spending hours trying to increase the font size for mobile views, only to find that it then would be ridiculously large on desktops.

Instead, you need to add mobile meta tags, which will scale our content based on the device in use.  Add the following to the <head>  block of your markup:

Your view should now update to display H1 in a size you’d expect:

Page with meta tags added

Page with meta tags added

Before adding styling, let’s discuss one detail about our markup.

Why IDs rather than class names?

You might have noticed that I am using ID tags for all my main selectors.

This is an intentional and a carefully considered choice.  In general, you should be using class names, eg <div class="some-css-class"></div>  but in this case, we want to explicitly say that these top-level blocks will be unique to the app, ie when it comes to our app-containerapp-header, and  main-content …

There can be only one, er, ID tag

There can be only one…ID tag

And for that purpose ID selectors are ideal.


Add this to your  <head>  block:

And add this file:


Add Normalize

Imo, you should always include normalize when building a web app, because, as stated in the project description…

Normalize.css makes browsers render all elements more consistently and in line with modern standards. It precisely targets only the styles that need normalizing.

A couple more pointers:

  • This should be the first css that loads.
  • Do not link directly to an online stylesheet, but instead copy and paste the current version of the raw normalize css into a local file.  You don’t want to risk the remote stylesheet not loading, or be updated, without you knowing it, since this could impact your entire design.

With this in mind, copy and paste normalize into a local file and import it at the beginning of the file.

If your web page now updates to be a sans serif font, then you know everything has been hooked up properly.

Set HTML and BODY to be full screen

Next, add the following styling to your css file (below the import statement):

This added css won’t make any visible updates to your page.   Think of this as the equivalent to a building foundation. It’s invisible to most, but essential to the structure of your layout.

Let’s look more closely at a couple items. First, we are applying a natural border box model, which you basically should be doing for all your layouts.

Second, let’s talk about why we are using min-height rather than height for our body block.

Why use min-height rather than just height?

Note the use of min-height: 100% for the body block.  Why not just set it to be height:100%?  How could something be more than 100%?  To understand the reason why, take a look at the following visual:

Content block that is more than 100% if window height

Content block that is more than 100% of window height

The content in this view is greater than 100% because it contains content that forces it to exceed the length of the current window size.  To support (dynamic) content that might be greater than that of the window we want to set the height of the containing block to be a minimum of a hundred percent rather than 100%, so that it is able to exceed the 100% mark if needed.

Add a App Container

Next, let’s create a full height container for our app.  Add the following below the css you just added earlier.

Here, we’ve set our app container to be full height and centered for larger viewports. You can confirm that it is centered by toggling out of device view and setting your window width to exceed 500px.

Full height centered app container

Full height centered app container

Note that the container is full height even if there is no content that pushes the layout to full height. We are achieving this by using the viewport height (vh) unit.

Please see the comments in the above css for more details.

NOTE: the width and padding values, such as  max-width: 31.25em are just for demo purposes.  You should choose the values that are appropriate for your specific app.

Add a Fixed Header

Next, let’s update the app header to be fixed to the top of the viewport and have a vertically and horizontally centered layout, with optional left/right blocks. Add the following below the css you just added earlier.

Your layout should now look like this:

Layout with app header added

Layout with app header added

This layout also supports optional left/right content blocks, which is great for icon-based buttons.

Add Icons (Left/Right Header Content)

Update your app header markup to be as follows:

You can use whatever icon package you prefer, but for the demo I’m using Google’s Material Design Icons.  One reason I like this package is that it selects the icon based on plain text, so if there is an issue with loading the font, it falls back on displaying the icon name instead. (If you refresh your page before adding the link below, you’ll see what I mean.)

Let’s add a link to the icon font. Add this to your  <head>  block:

Your layout should now look like this:

App Header with Icons Added

App Header with Icons Added

Update main content padding

We aren’t quite done with the fixed header.  The issue we need to address won’t be clear until we add some actual content.

Go ahead and add a large block of text to the main-content block.

For example, you could go to and grab several paragraphs of dummy text.

After doing that, your layout should look something like this:

App Header with Text Clipped

App Header with Text Clipped

After adding the dummy text, we can see that the top of the main content block is being covered up by the header.  Let’s fix that.

Add the following property to the end of the  #app-container block:

While I am using a hard-coded value here, this value should really be a calculated value, based on the sum of the general padding used for this container plus the height of  #app-header, which in my case is 4em, so it would be 1em + 4em or, abstractly, $app-padding + $app-header-height.  (In a production app, I would be using something like Sass variables to calculate this value.)

The app header now no longer covers the main content.

Mobile view of a full screen web app layout

The finished layout – mobile view

Our layout is done. Yay!

I hope you found this useful.  If you liked it, please let me know in the comments and/or tweet about it. Also, if you found any errors, definitely let me know in the comments.