The Basics of HTML and CSS - Part Two

Reading this tutorial post will help you learn about the fundamentals of classic HTML and CSS. This post builds upon the previous post, in which you can learn about how to create simple layouts with multiple columns. The components and patterns from the last chapter will be the basis of this post, so I highly recommend you read the previous article first.

In the last chapter of this tutorial series I tried to emphasize that I find it crucial to think in patterns and components. That's the way how people can be efficient. That naturally leads us to frameworks. With frameworks it's much easier to think in patterns, since the framework forces you to do so.

By the end of this lesson you will have your own small site building framework which you can modify and extend in the way you want. I hope that you will be able to apply it to many of your projects. Also, it will be a good basis in the subsequent posts to talk about the differences between classic HTML & CSS and email HTML.

In the example codes of the last post, I made two major mistakes. I forgot to add the following two lines to the head of the HTMLs:

<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

The first is telling the browser that the character encoding is utf-8, which is crucial if you want to use special characters. If you don't set the character set properly, then you can count on your browser to make some character rendering errors.

I find the second line even more critical. Without that line mobile clients do not apply the media queries, they just zoom out until the page is scaled down so much that the content fits to the screen. I hadn't have realized this issue until one of my friends showed me that the multi-columns don't stack on each other on his smart phone. I only tested those templates by resizing the screen. That way it worked perfectly, but not on mobile devices. Actually, it depends on the implementation of the browser if they will apply the media queries or not. That is why it worked in my browser, bot not on my friend's smart phone.

I felt so embarrassed, that I fixed it immediately. I did not include the meta charset line to the examples of the previous lesson, but I included both of the lines above to the examples of this lesson. If any of you finds any mistake or error in this post or in the examples, please let me know either via email or in the comments section in the bottom of this page.

Since I have started to work on this tutorial series, a lot of interesting ideas came into my mind. These are only slightly related to the core topic, so I have decided to include those as "extras". These type of posts are going to be shorter and they will be related to one or few of the core blog posts.

Just to give you a better understanding of what kind of posts I'm thinking about, I give you a few examples right now... The first type is that we can use CSS preprocessors (eg.: SASS) and task runners (eg.: Grunt or Gulp). Another is that sometimes I don't want to show you complicated solutions for certain problems. For example in this chapter of the tutorial series there will be a rather simple menu component. Originally I was planning a more complicated and fancier version, but I realized that that would not be a good showcase and I could not get to the point. These solutions will be great posts in the "extras" section.


This article is focusing on building the static HTML from scratch that you can see below. We are going to use all of the patterns learnt in the previous tutorial post.

Probably you have observed it from the preview, but I would like to emphasize a few things we are going to create:

  • A top menu, which will re-appear after you scrolled to the content.
  • A zig-zag multicolumn with proper stacking on small screens.
  • A "new decorator" which you can see in the featured section above the first product.
  • Icons with CSS image sprites in the footer of the page.

Fundamental CSS Properties in This Lesson

This lesson's primary CSS properties are the position and the z-index. In a way they are related to each other. If you override the default position of DOM elements, then you might need to use the z-index property to ensure that the elements are rendered in the order you wanted them to be rendered.

The Position CSS Property

The four most important values of the position property are static, relative, absolute, and fixed.

The position: static; is the default behaviour. The elements will be rendered where they should be.

The position: relative; tells the browser that it can be positioned somewhere else than the original position but there will be a gap in the original position.

The position: absolute; differs in a way from the previous one that the empty gap won't stay in the original position. The absolute positioned elements will be positioned relative to their closest non-static ancestor. It is very typical to use it together with a relative positioned ancestor.

The position: fixed; elements won't change their places when the page is scrolled. Just like absolute positioned elements, it does not leave space in the original position.

MDN reference

The Z-index CSS Property

This property specifies the order in which the elements in the same stacking context should be rendered. The stacking context can be tricky in some cases. It might happen that you give a huge z-index at the beginning of the DOM and another element at the end of the page with lower z-index will be rendered over the first element. A good rule of thumb is that you set the z-index values in the same level in the DOM.

You will often need to set the z-index if you position your elements. In fact z-index is only applied to positioned elements. So basically relative, absolute, and fixed positioned elements can have z-index, but static elements can't.

For example if you want to create a fixed menu across the top of your page and you have positioned elements within the page then you will want the menu to be rendered over the other elements.

MDN reference

Building Our Example

During the last lesson we learnt some patterns which are very general, so we can use them in this lesson as well. I grabbed the whole source code from the last lesson and reused it here. I did not modify the CSS files, I just deleted everything from the HTML's body. You can find the source code on GitHub.

As I mentioned previously, I added the following two lines to the head of the HTML:

<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

Besides that I set the font-family of the paragraphs to Georgia. The reason is that this font is easy to read and even though it's rather very simple, I'm starting to like it very much.

By the time you have finished this tutorial post, you will be able to create a static page you can see below.

Different Container Widths

The first thing you might have noticed is that the first two containers (the menu and the hero unit) are wider than the others. To achieve this, you need to introduce a new container type. Let's call it .container800. Since this container type is exactly 200 pixels wider than the previously introduced .container600, different media queries should be applied on it. Let's take a look at layout.css:

.container600 {
	width: 600px;
	margin: 0 auto;
}

.container800 {
	width: 800px;
	margin: 0 auto;
}

...

@media all and (max-width: 799px) {
	.container800 {
		width: 100%;
	}
}

@media all and (max-width: 599px) {
	.container600 {
		width: 100%;
	}

	.reorder .w33p {
		width: 100%;
	}

	.reorder .w66p {
		width: 100%;
	}
}

As you can see, the wider containers will turn to 100% width containers right below 800 pixels whereas the narrower containers will stay as they were. The other thing is that reordering (or stacking) is only applied when the actual width of the viewport is less than 600 pixels. In most of the cases it should be an okay behaviour, but you always need to check the results.

The corresponding markup is rather simple:

<body class="bg-gray">
	<div class="container800 bg-white">
		wide container
	</div>
	<div class="container600 bg-blue">
		narrow container
	</div>
</body>

You can see the results here:

Check the source code of the actual step on GitHub.

Adding Full Width Colored Rows

The main characteristic of the template we are building right now is that it is built up from full width colored sections running from the left hand side to the right hand side. The 800 and 600 wide content is centered in these full width containers.

To achieve this, you simply need to modify your markup in the following way:

<body class="bg-gray">
	<div class="bg-white">
		<div class="container800">
			wide container
		</div>
	</div>
	<div class="bg-blue">
		<div class="container600">
			narrow container
		</div>
	</div>
</body>

You need to wrap a div around each of your containers. These wrapper divs should get the background related classes.

Check the source code of the actual step on GitHub.

Introducint New Column Types

Throughout this tutorial post we will need more column widths than in the previous one. That is why it's a good idea to introduce them right now. Let's take a look at layout.css:

.container600 {
	width: 600px;
	margin: 0 auto;
}

.container800 {
	width: 800px;
	margin: 0 auto;
}

.cols .w33p {
	width: 33.33%;
	float: left; 
}

.cols .w66p {
	width: 66.66%;
	float: left;
}

.cols .w50p {
	width: 50%;
	float: left;
}

.cols .w25p {
	width: 25%;
	float: left;
}

.cols:after {
	content: "";
	display: block;
	clear: both;
}

...

@media all and (max-width: 799px) {
	.container800 {
		width: 100%;
	}
}

@media all and (max-width: 599px) {
	.container600 {
		width: 100%;
	}

	.reorder .w33p {
		width: 100%;
	}

	.reorder .w66p {
		width: 100%;
	}

	.reorder .w50p {
		width: 100%;
	}

	.reorder .w25p {
		width: 50%;
	}
}

In the previous post I used a separate class for applying clear: both; after multicolumns. In many cases you might have seen the cols:after implementation of it. This selector selects a pseudo element after the real element. If you set the content of it and you set it to display: block; then it behaves exactly like a div right after the real element. By doing this, your markup can stay cleaner.

Another thing which you might have noticed is that the .reorder .w25p elements under 600 pixels won't be 100% wide, but 50%. The originally 25% wide elements might have enough space even on mobile devices to keep two of them in one row. Let's try it and see what happens.

I did not include the markdown of this step here. Based on the preview I hope it's obvious what you have to do.

Check the source code of the actual step on GitHub.

Multi-Columns in Multi-Columns

The .w25p column works pretty well in the previous example, but if you take into account that you can combine multi-columns, then it does not seem that great idea any more to set its width only to 50% under 600 pixels.

You can achieve the same thing if you put multi-columns into each other and you don't let the multi-columns inside to be reordered. The structure should look like this:

			<div class="cols reorder">
				<div class="w50p">
					<p>Header left</p>
				</div>
				<div class="w50p">
					<p>Header right</p>
				</div>
			</div>
			<div class="cols reorder">
				<div class="w50p">
					<p>Header left2</p>
				</div>
				<div class="w50p cols">
					<div class="w50p">
						<p>Header right2_1</p>
					</div>
					<div class="w50p">
						<p>Header right2_2</p>
					</div>
				</div>
			</div>

The problem with this is that if you have CSS rules like below, then those rules will be applied all of the .w50p elements with .reorder ancestors, no matter how far they are from the actual element.

@media all and (max-width: 599px) {
	.reorder .w50p {
		width: 100%;
	}
}

It means that the multi-column in the other multi-column will be stacked on small screens no matter that you intended something else.

You can change the CSS in a way that the rules will only be applied when the .reorder element is the direct parent of the .w50p.

@media all and (max-width: 599px) {
	.container600 {
		width: 100%;
	}

	.reorder > .w33p {
		width: 100%;
	}

	.reorder > .w66p {
		width: 100%;
	}

	.reorder > .w50p {
		width: 100%;
	}

	.reorder > .w25p {
		width: 100%;
	}
}

As you can see, child selectors are extremely useful in these situations. If you want to learn more about them, please check the MDN reference. With (direct) child selectors, each of our .wXXp classes can be 100% wide.

From now on, you can combine multi-columns in a way you want.

Check the source code of the actual step on GitHub.

Creating the Header Menu

Now that we have the basic building blocks defined in the previous section, the next few steps will be very easy.

If you look at the header menu in the original preview, it can be composed from a 50%-50% multi-column with another multi-column in the right column. The second multi-column has three equal columns.

It's a relatively easy step, so I don't include any HTML or CSS here. I let you think about the solution yourself! :)

Check the source code of the actual step on GitHub.

Creating the Header Buttons

In the previous lesson, we created buttons with hover effect. You can do something similar with the links in the header menu. Let's add the followings to the button.css:

.header-button {
	display: block;

	color: #58585A;

	font-size: 20px;
	line-height: 35px;

	text-align: center;
	text-decoration: none;

	transition: all .5s;
}

.header-button:hover {
	background: #C72518;
	color: #FFFFFF;
	transition: all .5s;
}

If you apply these classes to the <a> tags in the header, then they will look pretty well. Their font-size and line-height are aligned to the height of the menu.

My biggest problem with this code is that there are colors in it. In my mind, colors should be in a separate file and they should be able to be applied to many components. If you organize your code in that way, then you will be able to combine your components with any of the color classes.

For now, let's leave it like it is, and we will deal with the problem later, when we clean up our code.

Check the source code of the actual step on GitHub.

Creating Product Blocks

This step should also be very, very easy. You only need to introduce a multi-column with three equal columns in them. You also need to create "cards" inside the columns. Let's take a look at the markup.

	<div class="bg-blue sm-padding-tb">
		<div class="container600">
			<h1>Featured Products</h1>
			<div class="cols reorder">
				<div class="w33p">
					<div class="sm-padding">
						<a class="header-button sm-padding bg-white product" href="http://edmdesigner.com" target="_blank">
							<img src="img/product01.jpg"/>
							<p>iPad Mega Cool</p>
						</a>
					</div>
				</div>
				<div class="w33p">
					<div class="sm-padding">
						<a class="header-button sm-padding bg-white product" href="http://edmdesigner.com" target="_blank">
							<img src="img/product02.jpg"/>
							<p>iPhone X</p>
						</a>
					</div>
				</div>
				<div class="w33p">
					<div class="sm-padding">
						<a class="header-button sm-padding bg-white product" href="http://edmdesigner.com" target="_blank">
							<img src="img/product03.jpg"/>
							<p>iMekk Elek</p>
						</a>
					</div>
				</div>
			</div>
		</div>
	</div>

In the code above you can see that I used the .sm-padding class quite a lot. As it's name suggests it adds a small padding to the actual element. Similarly the sm-padding-tb adds a small padding to the top and to the bottom of the element.

In the last post I used classes like padding30, but I have been told that it's ugly to include the exact amount in the name of the class. And indeed it feels much better to have small (sm), medium (m), and large (l) of something. This way you can create your own framework and you can change these values from project to project.

I also added the header-button class to the product blocks. Well, I wanted to have some hover effect quickly, but you can introduce your own product class. Feel free to do things differently! :)

You can find the padding related classes in the layout.css file.

Check the source code of the actual step on GitHub.

Zig-zag Multi-Columns

This kind of multi-columns are my favorite. If your images resolution if high enough they will look great. In this example I use low resolution images (200x200 pixels) so they are distorted even on the desktop view, but if you switch to the mobile view, they look even worse.

It's very easy to create these zig-zag multi-columns. You need at least two 50%-50% multi-colums after each other with an image in the left and then in the right column.

If you switch to the mobile view, you can see that they are stacked in a disturbing order. In my mind there should be an image followed by a text then followed by an image and a text again. But there are two images after each other.

This problem is actually easy to solve. I will show it to you a few steps later.

Check the source code of the actual step on GitHub.

Fixed Menu

If you want to create a menu, which is always visible - even when you scroll down - you have to set its position CSS property to fixed. I added the following code to a new file called main.css:

#menu {
	position: fixed;

	width: 100%;

	top: 0;
	left: 0;
}

Fixed elements don't have a parent container to inherit their width from. That is why you need to set it's width (in our case to 100%). You should also indicate where it's originated. In our case it's the top left hand side corner. I could also set the right: 0; and then I can skip the width: 100%; declaration.

After you linked the new css to your HTML file, you only need to add the id to the corresponding HTML tag:

...
	<link rel="stylesheet" href="main.css">
</head>
<body>
	<div id="menu" class="bg-white sm-padding-tb">
		<div class="container800">
...

As mentioned previously fixed elements don't consume any space at their original position. This is why you need to adjust the padding-top or margin-top of the next element or the <body> itself. I added 80 pixels of top-margin to the body in the defaults.css:

body {
	margin-top: 80px;
	
	font-size:10px;
	line-height:10px;
}

You can see from the preview, that there is a gap between the hero unit and the menu!

Check the source code of the actual step on GitHub.

Proper Spacings With the Fixed Menu

If you give it a second thought it's not a great idea to put something new in the defaults.css file, because you won't be able to use it as generally. You will need to change that margin-top from project to project.

That is why I decided to move that spacing to the next element in the DOM. That element is basically a hero unit, so I set its id to hero.

	<div id="menu" class="bg-white sm-padding-tb">
		<div class="container800">
			<div class="cols reorder">
				<div class="w50p">
					<img class="w200" src="img/logo.png" />
				</div>
				<div class="w50p cols">
					<div class="w33p">
						<a class="header-button" href="http://edmdesigner.com" target="_blank">API</a>
					</div>
					<div class="w33p">
						<a class="header-button" href="http://blog.edmdesigner.com" target="_blank">Blog</a>
					</div>
					<div class="w33p">
						<a class="header-button" href="http://edmdesigner.com/jobs" target="_blank">Jobs</a>
					</div>
				</div>
			</div>
		</div>
	</div>
	<div id="hero" class="bg-white l-padding-tb">
		<div class="container800">
			<h1>Modern Email HTML Tutorial</h1>
			<p>
				Strength does not come from winning. Your struggles develop your strengths. When you go through hardships and decide not to surrender, that is strength.
			</p>
		</div>
	</div>

The main.css also changed a little bit, I added the hero-unit related declarations to it:

#menu {
	position: fixed;

	width: 100%;

	top: 0;
	left: 0;
}

#hero {
	margin-top: 30px;

	text-align: center;
}

Check the source code of the actual step on GitHub.

Appearing Fixed Menu

It is very typical on the web that you can scroll away the header menus, but when you scrolled to the content they re-appear with some effect.

It is very easy to create something like that. The first thing you have to do is to change the position to absolute. Absolute positioning is similar to fixed in the sense that absolutely positioned elements also don't leave any space in their original position.

Why does it help us? Well, when you reach the content while scrolling, you need to change the position to fixed. That's it.

(function() {
	function getScrollTop(){
		if(typeof pageYOffset!= 'undefined'){
			//most browsers except IE before #9
			return pageYOffset;
		} else {
			var B= document.body; //IE 'quirks'
			var D= document.documentElement; //IE with doctype
			D= (D.clientHeight)? D: B;
			return D.scrollTop;
		}
	}

	function getCoords(elem) { // crossbrowser version
		var box = elem.getBoundingClientRect();

		var body = document.body;
		var docEl = document.documentElement;

		var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
		var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;

		var clientTop = docEl.clientTop || body.clientTop || 0;
		var clientLeft = docEl.clientLeft || body.clientLeft || 0;

		var top  = box.top +  scrollTop - clientTop;
		var left = box.left + scrollLeft - clientLeft;

		return { top: Math.round(top), left: Math.round(left) };
	}

	var menu = document.getElementById("menu");
	var content = document.getElementById("content");

	var contentTop = getCoords(content).top;

	addEventListener("scroll", function() {
		var scrollTop = getScrollTop();

		if (scrollTop > contentTop) {
			menu.style.position = "fixed";
			menu.classList.add("bg-white");
		} else {
			menu.style.position = "absolute";
			menu.classList.remove("bg-white");
		}
	});
}());

As you can see from the code, we need to specify the content element in our HTML.

<body>
	<div id="header" class="bg-white">
		<div id="menu" class="sm-padding-tb">
			<div class="container800">
				...
			</div>
		</div>
		<div id="hero" class="l-padding-tb">
			<div class="container800">
				<h1>Modern Email HTML Tutorial</h1>
				...
			</div>
		</div>
	</div>
	<div id="content">
		<div class="bg-brown">
			<div class="container600">
				...
			</div>
		</div>
		<div class="bg-blue sm-padding-tb">
			<div class="container600">
				<h2>Featured Products</h2>
				...
			</div>
		</div>
		<div class="bg-white sm-padding-tb">
			<div class="container600">
				<h2>Other Products</h2>

				...
			</div>
		</div>
	</div>
	<div id="footer" class="bg-gray sm-padding-tb center">
		<div class="container600">
			...
		</div>
	</div>
	<script src="main.js"></script>
</body>

I wrapped the menu and the hero unit with a new div with id="header". I also introduced the content and the footer ids in the markup. The final thing you can observe is that the main.js file is included at the end of the file. This ensures that the referenced DOM elements has been created already.

Check the source code of the actual step on GitHub.

Header Background Image

In our case, the header = menu + hero unit. This is great, because you can add a background image to the whole element. I think it generally looks great on web pages (although I'm far from being a designer.)

#header {
	z-index: 2;

	background-image: url(img/email-pattern-white.png);
}

#header #menu {
	position: absolute;

	width: 100%;

	top: 0;
	left: 0;

	transition: 1s all;
}

#header #hero {
	padding-top: 130px;

	text-align: center;
}

#content {
	z-index: 1;
}

#footer {
	z-index: 1;
}

In the main.css above I added z-indexes (and the background image). What do you think? Will these z-indexes work properly? What can be the problem with this code?

In the previous script you can see that the .bg-white class is added to the menu when it reached the content and it's removed when you scroll up. This ensures that the menu will be visible when you scroll down.

As you can see in the preview I added a small transition to the header menu when it's appearing.

Check the source code of the actual step on GitHub.

Stacking the Zig-zag Columns on Small Screens

The main problem with the zig-zag multi-columns was that the order of stacking on mobile is not correct. Images should not come after each other on mobile devices. To achieve this, have to have fixed order of the elements in each multi-columns and we can float each second to the right instead of to the left.

			<div class="container600">
				<div class="cols-r reorder">
					<div class="w50p">
						<img src="img/code.jpg"/>
					</div>
					<div class="w50p">
						<div class="sm-padding">
							...					
						</div>
					</div>
				</div>
				<div class="cols reorder">
					<div class="w50p">
						<img src="img/code2.jpg"/>
					</div>
					<div class="w50p">
						<div class="sm-padding">
							...					
						</div>
					</div>
				</div>
			</div>

In the markup above you can see that the natural order of the elements is image-text-image-text. This will be their order on mobile devices.

I introduced a new class called .cols-r. The -r postfix indicates that the columns are floated to the right hand side. The corresponding part of the layout.css looks like this:

.cols > .w33p {
	width: 33.33%;
	float: left; 
}

.cols > .w66p {
	width: 66.66%;
	float: left;
}

.cols > .w50p {
	width: 50%;
	float: left;
}

.cols > .w25p {
	width: 25%;
	float: left;
}

.cols:after {
	content: "";
	display: block;
	clear: both;
}

.cols-r > .w33p {
	width: 33.33%;
	float: right; 
}

.cols-r > .w66p {
	width: 66.66%;
	float: right;
}

.cols-r > .w50p {
	width: 50%;
	float: right;
}

.cols-r > .w25p {
	width: 25%;
	float: right;
}

.cols-r:after {
	content: "";
	display: block;
	clear: both;
}

I used the child selector everywhere to make sure that these rules are only applied to the direct children of the .cols and .cols-r elements.

The other problem was that the pictures I used had too low resolution. So I changed the images to two higher resolution ones.

Check the source code of the actual step on GitHub.

Absolute Positioned Decorators

It's very typical to see some kind of decorators around certain elements on the web. For example if you have a new product you might want to indicate it with a new label on one of the corners of the element.

To put a decorator to the top left hand side corner of a product element is very easy. You just have to set its position to absolute and set a small negative margin on the top and on the left.

.new-decorator {
	position: absolute;
	width: 100px;
	height: 100px;
	margin-left: -7px;
	margin-top: -5px;
}

If you set the position of the element to absolute but you don't declare neither of the top, right, bottom or right elements, then the element stays where it originally was but it does not take up any space on its original position. Also, it will be rendered over the next element in the DOM.

			<div class="sm-padding">
				<img class="new-decorator" src="img/new.png" />
				<a class="header-button sm-padding bg-white product" href="http://edmdesigner.com" target="_blank">
					<img class="w200" src="img/product01.jpg"/>
					<p>iPad Mega Cool</p>
				</a>
			</div>

Probably you have noticed that something is wrong with the z-indexes. If you scroll down in the preview above, you will see this:

The problem is that previously I set the z-index of static elements. Rule number one is that only positioned elements have z-indexes. This means that in our case these indices were not applied to our header and content elements. (So they were not applied to their child elements.)

There are two ways to resolve this issue. The first is to specify the z-index of the menu element and the product decorator elements. In our case neither of them have positioned ancestors, so their z-index will be calculated relative to the body.

The problem with this solution is that every time you introduce a new positioned element, you will have to specify its z-index. Would it not be easier to specify the z-index of the whole header and content elements generally? Just as we originally intended?

Of course it would. And it's easy to do so. You only have to add positioning to those main elements. It's best if their positioning is relative. If you don't set other positioning properties (eg.: left or top) then they will stay in their original position and the original size will be preserved.

#header {
	position: relative;
	z-index: 2;

	background-image: url(img/email-pattern-white.png);
}

#header #menu {
	position: absolute;

	width: 100%;

	top: 0;
	left: 0;

	transition: 1s all;
}

#header #hero {
	padding-top: 130px;

	text-align: center;
}

#content {
	position: relative;
	z-index: 1;
}

#footer {
	position: relative;
	z-index: 1;
}

This way, the header, content and footer elements z-index will be calculated relative to the body. The menu element will be on a different stacking context since it has a positioned (in our case relative) parent, the header. It means that even if you set the z-index of the decorator image to 10000, and the z-index of the menu to 1, the menu will be rendered over the decorator image.

I did not create a separate step for this, but I will apply the modification in the next step.

Check the source code of the actual step on GitHub.

CSS Image Sprites

The final thing we want to do is to add some social icons to the footer of our template. The only trick we are going to commit is that we are going to use only one image with all of the social icons on it. This way our browser won't need to open that many connections to the server.

How can we show different parts of the image with the different links we added? It's not that hard actually. You can set it as the background of a certain element and then you can position the background in a way that only the needed part of the image will be visible. You can achieve it with background-position and overflow: hidden;.

#footer a {
    display: inline-block;
    width: 28px;
    height: 28px;
    overflow: hidden;
    text-indent: -999px;
    background: url(img/socials.png) 0 0 no-repeat;
}

#footer a#f-fb {
	background-position: 0 -50px;
}
#footer a#f-tw {
	background-position: 0 -73px;
}
#footer a#f-ln {
	background-position: 0 -97px;
}
#footer a#f-gp {
	background-position: 0 -123px;
}
#footer a#f-rss {
	background-position: 0 -150px;
}

The corresponding HTML snippet in the footer looks like the following:

			<div class="cols">
				<div class="w20p">
					<a id="f-fb" href="#">Facebook</a>
				</div>
				<div class="w20p">
					<a id="f-tw" href="#">Twitter</a>
				</div>
				<div class="w20p">
					<a id="f-ln" href="#">LinkedIn</a>
				</div>
				<div class="w20p">
					<a id="f-gp" href="#">Google+</a>
				</div>
				<div class="w20p">
					<a id="f-rss" href="#">RSS</a>
				</div>
			</div>

You might have noticed that I secretly declared the .w20p class. This works in the same way as the previously introduced similar classes.

Check the source code of the actual step on GitHub.

Cleaning up

You did it! You have reached the end of this tutorial post. You have built a complex static HTML from scratch. Congrats!

Even though the HTML we created is fully functional, you probably remember that sometimes I was not very satisfied with how we organized the code. For example, the .header-button class contained color codes, although all of the color related classes should be in the colors.css file. What a mess!

My solution for this problem is that I introduced a new class called .bg-red-hover. It's in the colors.css file and its only responsibility is that it adds hover behaviour to the element. I wanted to remove all of the colors from the .header-button declaration, so I also set the default color of links.

a {
	color: #58585A;
}

...

.bg-red-hover:hover {
	background-color: #C92C1E;
	color: #FFFFFF;
}

This way, you can remove all of the color related declarations from the classes similar to the button class. And it's even better that you can add different hover colors to them!

Besides the incredibly serious color related issue described above, there were only small things I changed.

The first is that I moved all of the padding related classes from layout.css to a new file called spacings.css. Also, I removed the unused classes. In the layout.css file, only the column and container related classes remained. The spacings.css file looks like this:

.sm-padding {
	padding: 10px;
}

.sm-padding-tb {
	padding-top: 10px;
	padding-bottom: 10px;
}

.m-padding-tb {
	padding-top: 30px;
	padding-bottom: 30px;
}

.l-padding-tb {
	padding-top: 100px;
	padding-bottom: 100px;
}

The final thing I refactored is that I renamed the button.css file to components.css. The .button and .header-button classes were already there and I moved the .new-decorator and the .socials here.

Besides the mentioned refactoring, I added a call to action button to the hero unit.

Check the source code of the actual step on GitHub.

Summary

This post of the Modern HTML Email tutorial formulates a small HTML + CSS framework, which is built on the patterns and components learnt in the previous lesson.

We have added several new features, for example the zig-zag multi-column, the re-appearing top menu, the "new decorator" and the icons with CSS image sprites.

By reaching the end of the post, you might had a feeling of good structuring of the code. The final CSS files are responsible for different functionalities, so it's very easy to combine them with each other.

  • defaults.css: CSS resets (margin, padding -> 0); font-size, line-height & font-family declarations
  • layout.css: container and multi-column related classes
  • spacings.css: padding & margin related classes
  • colors.css: background and font color related classes; hover related classes
  • all of the color related declarations should be in this file.
  • components.css: In the end I put all of the components created throughout the tutorial to this file
  • for example: button or socials
  • images.css: image related declarations
  • main.css: header, content and footer related declarations

These separate files can be concatenated and then minified, so you can save bandwidth and your page will load faster. There are several ways to do that, but that is the topic of another post.

I hope you enjoyed this chapter of the Modern HTML Email tutorial series. If you want to read similar in-depth posts like this is, please subscribe to our newsletter.

In the next chapter we will investigate the core differences between classic HTML and email HTML. Stay tuned and Merry Christmas.