By the time you have finished this tutorial post you will have learnt the most important concepts in HTML and CSS. If you follow all of the steps, you will have a solid knowledge which will help you learn more advanced topics. We start our tutorial series with classic HTML and CSS, and later we go on with email HTML to point out the core differences between the two.

At our company there are many engineers who think about site building - especially CSS - as some kind of dark magic. Engineers just don't find it logical, because it seems as if there are totally random things which have an effect on seemingly unrelated other things.

Now here is my confession: I'm one of those engineers. But as an engineer I just can't accept that it's impossible to create order in the world of stylesheets.

As the CTO of a company which deals with HTML emails, I have had to swallow all of my hatred towards CSS. I have improved myself in this field in the last few years and I have learnt the fundamentals and some advanced topics in HTML and CSS. I have also learnt how to think in HTML + CSS patterns and components which help me to be very, very efficient.

Throughout this tutorial I will do my best to help you get a good understanding of (email) HTML & CSS. Since I'm not a professional site builder, I might do things in a slightly weird way. That is why I asked one of my co-founders Gergely Mécs, who is officially the Grand Dark Mage of HTML Emails at our EDMdesigner to thoroughly review my blog posts.


In the next chapter, you will learn about the most important concepts in HTML & CSS. You might skip this section if you are already familiar with it.

In the section afterwards we will go through the steps to create a simple static HTML you can see below.

Through these steps we will formulate some very useful patterns and components which will be the first building blocks in our arsenal. We will build upon these patterns in the next post of the tutorial to introduce more advanced techniques.

The Most Important CSS Properties in This Lesson

In this section you will read about the CSS properties which you will use to create the layout shown above. Of course there are other very important properties, but with these you will be able to create relatively complex layouts. Deep understanding of these CSS props will help you a lot with site building.

If you are familiar with this CSS properties, just skip to the next section.

The Display CSS Property

There are many possible values of the display property, but the three most critical ones are inline, block, and inline-block.

display: inline;

Inline elements behave like the characters in the text. They flow next to each other in one line and when the line is full, a new line starts. These elements don't have width and height property, but they can have padding-left and padding-right. Since they behave like text, the might have font-size and line-height properties.

display: block;

The most important thing about block elements is that they can have width and height properties. By default, they use the available width which is defined by their parents but their height is calculated based on their width and the size of the content they have.

display: inline-block;

An inline-block element is the combination of the previous two. They flow inline and they can have width and height.


Each element type has its default display value. For example <span> elements' default display value is inline, whereas <div>s are block elements by default. The typical example for inline-block elements is <img/>, although images have alt text, which makes them a little bit more complicated.

There is one more essential display value, which is most useful when used together with media queries to hide some elements on mobile devices. I am talking about display: none;.

MDN - display reference.

The Width CSS Property

The width property is essential to create layouts. Just think about it. It would be very hard to create a multi-column layout without setting the width of columns.

The two most cross compatible units of the width property's value are pixel (eg.: width: 100px;) and percentage (eg.: width: 50%;). If you don't set its value or you set it to auto (width: auto;) then the default value of the DOM element will be applied. (For block elements, it's 100%, for others it can be their natural width.)

Similarly to the width, you can set the height of the elements. It is not as important as the width of the element, because it does not have any effect on creating columns.

MDN - width reference.

The Float and Clear CSS Properties

Floating the elements is also essential to create layouts. You can set the value of the float property to right or left (eg.: float: left;). It means that the elements will be arranged next to each other until they fill up the space in their parent container. When the parent container's first "row" is filled up, then the elements which can't fit to the top, will be arranged under those elements.

MDN - float reference

If you need to explicitly add a new row, then you have to add an element with clear: both; property after the floated elements in the row. This explicitly tells the browser to disable floating on the successor elements so they will be in a different row. You must set this property if the height of your elements in the row is not the same and you want to create a new row.

Many people don't use extra element in their markup to add clear: both;. They usually apply it with the :after selector, so they put it on a pseudo element. This way, your markup will stay cleaner.

In our examples we don't use the :after selector, but we use distinct <div> elements. We believe that the examples will be more understandable this way.

MDN - clear reference

Creating Multi-Column Layouts

<Attention! This is the most important part in this lesson!>

To create complex layouts, we can combine the CSS properties described in the previous three section.

If you want to create multiple columns, you just have to set the width of block elements and you can float them next to each other. If you want to start a new row, then you have to add an element after them with clear: both;.

Simple, is it not? :)

</Attention! This is the most important part in this lesson!>

Building a Simple Example

As you have seen previously, we will create a fully responsive simple layout with asymmetric multi-columns. You can check out the end result in the preview below.

We will start from scratch and with each step we will get closer to our goal.

Check the source on Github


I started to build this example from a very simple HTML which was generated by my text editor when I created a new HTML file.

<!DOCTYPE html>  
<html>  
<head>  
    <title>Simple page layout</title>
</head>  
<body>

</body>  
</html>  

I use this extremely simple HTML file as a basis. At every step I will highlight the differences compared to the previous step. At the end of each section you will find a link to the full source code to the actual step.

Check the source on Github

CSS Resets & Defaults

The first step is to add some CSS resets to make sure that different browsers will render everything in the same way.

I included the following CSS code snippets to the defaults.css file.

CSS Resets

html, body, div, p, ul, ol, li, h1, h2, h3, h4, h5, h6 {  
    margin: 0;
    padding: 0;
}

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

The first thing you can see above is that I set the padding and margin of some element types. This is the way that we make sure that there won't be weird rendering issues on certain devices.

Also, I set the font size and line height on the body element.

These explicit declarations are the best way to avoid rendering differences.

Default Typography

h1, h2, h3, h4, h5, h6 {  
    font-family: "Roboto", sans-serif;
}


h1 {  
    font-size: 28px;
    line-height: 32px;

    margin-bottom: 24px;
}

h2 {  
    font-size: 24px;
    line-height: 28px;

    margin-bottom: 20px;
}

h3 {  
    font-size: 20px;
    line-height: 24px;

    margin-bottom: 16px;
}

p {  
    font-size: 16px;
    line-height: 20px;
}

I set the font size and line height of heading and paragraphs as well. Both of these values are decreasing from h1 to h3 and they are even smaller on paragraphs (p tags).

People who are good in design (it's not me) say that titles should have different typography, so I applied Roboto font on headings. :)

Container Sized Block Images

img {  
    width: 100%;
    height: auto;

    display: block;

    margin: 0;
}

Probably this is the most interesting part so far. By setting display: block; on images, you can avoid tons of weird things which are related to the fact that images are inline-blockish elements. (Sometimes there can be unexplainable margin-like spacings next to images even though there are no margins on the image.)

Because of width: 100%; these images will have the same width as their parent container. The parent containers will have size anyways, so if you have big enough images, then everything is fine. If your image is smaller than the parent container, then your image will be enlarged and distorted. I will show you a solution which tackles this issue later.


You also have to modify the head part in your html, to link the font and the defaults.css file. I might not always indicate to add a new CSS file to the head. If you feel lost, then checking out the actual step on Github will make everything crystal clear.

<head>  
    <title>Simple page layout</title>

    <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" />

    <link href="defaults.css" />
</head>  

Check the source on Github

Colors

The next step is very easy. I picked the colors from the result image I had to achieve and created a colors.css file with class names describing those colors. (Don't forget to add the colors.css to your HTML's head.)

body {  
    background-color: #F4F4F4;
}

.bg-white {
    background-color: #FFFFFF;
    color: #58585A;
}

.bg-brown {
    background-color: #F8F7F0;
    color: #58585A;
}

.bg-gray {
    background-color: #58585A;
    color: #FFFFFF;
}

As you can see above, I set the background color and the font color as well. This way I can make sure that if I apply a certain background color to an element than the text within will be readable and will look good.

To check the color combinations, add the following code to your HTML's body.

    <div id="pre-header">
        <p>
            Pre-header
        </p>
    </div>
    <div id="header" class="bg-white">
        <p>
            Header
        </p>
    </div>
    <div id="content" class="bg-brown">
        <p>
            Content
        </p>
    </div>
    <div id="footer" class="bg-gray">
        <p>
            Footer
        </p>
    </div>

The ids don't have any effect so far, because there are no CSS queries which use them. At the moment their role is rather semantic, they indicate different parts of the document so you might have an idea what kind of content will be there.

Check the source on Github

Basic Layout - Main Container

In this step we add a container element which creates a "page" down the middle of your screen. We will also add some markup which will be the basis of our multi-columns. As an extra, I put a nice image to the header.

The first thing to do is to wrap everything in your body to a container div.

<div class="container600">  
    <div id="pre-header">
        <p>
            Pre-header
        </p>
    </div>
    <div id="header" class="bg-white">
        <p>
            Header
        </p>
    </div>
    <div id="content" class="bg-brown">
        <p>
            Content
        </p>
    </div>
    <div id="footer" class="bg-gray">
        <p>
            Footer
        </p>
    </div>
</div>  

Now, create a file named layout.css and write the following code to it.

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

This sets the width of your container. By setting the left and right margin to auto, your container will be centered.

As you can see I use many CSS files. It's because these files are responsible for very different things which I don't like to mix.

Some people might say that this way the code is much longer and the browser will have to send more HTTP requests. These things are true, but just think about it. You can easily concatenate and minify your code and it's much better organized this way. So I don't find it a good reasoning. On top of that, it's much easier to understand CSS this way and it helps the readers to structure their code better.

As I mentioned I also added some extra markup which will be the basis of multi-columns and I added an image. There is not much to explain about the image and I will talk about the multi-columns a little bit later.

            <div class="cols">
                <div>
                    left part 1
                </div>
                <div>
                    right part 1
                </div>
            </div>

Check the source on Github

Basic Layout - Columns

In the previous step, we created the basic markup of the columns but they did not float next to each other. In this step we make them float next to each other, and will add an image to the left columns.

            <div class="cols">
                <div class="w200">
                    <img src="img/logo3.png" />
                </div>
                <div class="w400">
                    <h2>SubTitle</h2>

                    <p>
                        sub-content 1
                    </p>
                </div>
                <div class="clr"></div>
            </div>

In the markup above you can see that there are two children of the cols div, w200 and w400. It suggests that the width of them will be 200 and 400 pixels.

You can also see the "clear div", which was described previously.

Check the source on Github

Basic Layout - Columns + Spacing Problems

In our original example there was a nice 30 pixel wide padding on our content block. As you can see below if we apply them it will ruin our multi-columns.

This is because our main container (.container600) is 600 pixel wide and when we apply any padding on an element within that leaves less space we can use. In our example it's 30 pixel on both sides, which leaves 540 pixel in our container.

Since our columns were 200 and 400 pixels wide, it's obvious that they won't fit into one row.

It's also time to add some lorem ipsum to the text parts, so we can see the spacings much better.

Check the source on Github

Basic Layout - Fluid Columns

If you use percentage based fluid columns, then the previous problem will disappear. This way you can put your multi-columns into any container. The width of the parent container does not matter if you use fluid (percentage based) columns.

            <div class="cols marginTop100">
                <div class="w33p">
                    <img src="img/logo3.png" />
                </div>
                <div class="w66p">
                    <h2>SubTitle1</h2>

                    <p>
                        Lorem ipsum dolor sit amet, ...
                    </p>
                </div>
                <div class="clr"></div>
            </div>

The main difference in the HTML is that I use different classes within the cols div. Their names are w33p and w66p which suggests that their width are 33 and 66 percent.

In the layout CSS you can see that their widths are percentage based indeed.

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

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

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

.clr {
    clear: both;
}

Check the source on Github

Buttons

Buttons are one of the most important parts of HTML pages. They are responsible for some kind of user action. Eventually buttons will take your users to another page - just like links - or they help your users to interact with the website.

Either way it's very important that buttons are easy to click on mobile devices. This is one of the reasons why we rather not use simple links anymore: they are much harder to click (tap) on.

In our example, buttons are simple <a> tags, so functionally they are not different from simple links. The main difference is that we give some nice formatting to them through the class name called button. From the example below, you can figure out, that I added some extra classes to the colors.css file.

<a class="button bg-red" href="http://edmdesigner.com" target="_blank">Read more</a>

Just to be consequent, we put it to the css file called button.css. Below, you can see the css code of the button.

.button {
    display: inline-block;

    padding: 10px;
    margin-top: 15px;

    border-radius: 20px;

    font-size: 16px;
    line-height: 16px;

    text-decoration: none;

    transition: all .5s;
}

.button:hover {
    box-shadow: 2px 2px 5px #888888;

    transition: all .5s;
}

Our button element is an inline-block element, so it can have dimensions, paddings and margins without any restrictions. I did not set any color, so it's possible to combine it with our color related classes. The only thing I could not resist is that I added some box-shadow on hover.

Check the source on Github

Finalizing the Desktop View

To finalize the desktop view, we have to do two things. The first thing is to add some spacing between the image and the text next to each other in the columns. Besides that, we can set the length of the texts, so the whole impression is much better. (Yes, copywriters will have to be very careful, not to destroy your beautiful design.)

Okay, now our template looks nice on desktop, but if you switch to the mobile view, you will see that we still need to work to make it responsive.

Check the source on Github

Responsive Layout

There are two main things we have to achieve to make our HTML responsive.

The first is when the screen is smaller than 600 pixels, then our main container (.container600) should have the same width as the screen has. You can achieve this with media queries:

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

The code above means that the width property will be overwritten with the value 100% if the screen width is less or equal to 599 pixels.

Actually, you can achieve the same thing without media queries.

.container600 {
    width: 100%;
    max-width: 600px;
    margin: 0 auto;
}

The second thing you need to do is to stack the columns on each other. I added the reorder class to my markup.

            <div class="cols reorder marginTop100">
                <div class="w33p">
                    <img src="img/logo3.png" />
                </div>
                <div class="w66p">
                    <div class="paddingLeft10">
                        <h2>SubTitle2</h2>

                        <p>
                            Lorem ipsum dolor sit amet, ...
                        </p>

                        <a class="button bg-blue" href="http://edmdesigner.com" target="_blank">Read more</a>
                    </div>
                </div>
                <div class="clr"></div>
            </div>

This way I have control over the behavior of the template, I only add the reorder class when I want the columns to be stacked on small screens. The final thing is that you need to add the followings to the media queries part of your CSS file.

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

    .reorder .w33p {
        width: 100%;
    }

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

It means that if the reorder class is applied on a div containing the columns, then the columns width will be overwritten with 100%. This is the basic way to do stacking on mobile.

On the mobile preview, you can see that I did not apply the reorder class on the third multi-column to demonstrate that columns can stay as they are on mobile.

Check the source on Github

Responsive Images and Buttons

As you can see from the examples, our image works pretty well, except one thing. When its original width is less than 600 pixels, then it will be stretched and distorted on mobile devices.

We have to add a class which sets the width of the image, which should be lesser than or equal to the original width. Also, we need to align it to the center on mobile with margin-left: auto; and margin-right: auto; on mobile. I also added some margin to the bottom, so there will be some space between the image and the other stacked column.

img {  
    width: 100%;
    height: auto;

    display: block;

    margin: 0;
}

.w200 {
    max-width: 200px;
}

@media all and (max-width: 599px) {
    .w200 {
        margin-bottom: 20px;
        margin-left: auto;
        margin-right: auto;
    }
}

The other thing is that it would be nice that we had bigger buttons on small screens, so they are easier to tap on.

@media all and (max-width: 599px) {
    .button {
        display: block;
        margin: 30px 50px;
        padding: 20px;

        text-align: center;
    }
}

Setting the display property to block helps us to have a big full-width button. I also added big paddings to make it easier to tap.

This is the end result, you have made it to the end! Congratulations!

Check the source on Github

Summary

By finishing this post of the tutorial series, you have learnt the very basics of HTML and CSS aka site building.

We went through the basic CSS properties and some other basic concepts we needed to accomplish this session.

Hopefully you have started your path on the way of thinking in patterns and components. If you build up your arsenal of these patterns, then you will work extremely effective.

The patterns you have learnt throughout this session will be the basis of the next post in this tutorial series which is going to be a step by step tutorial, just like this is. Also, they are useful generally, so you can start using them in practice right now.

If you would like to read similar posts in every second week, please subscribe to our newsletter.

Author
Gyula Németh

Gyula Németh

Co-founder & CTO @ EDMdesigner.com

  • Git Branching Workflows in SaaS Development and the Review ASAP Policy Git Branching Workflows in SaaS Development and the Review ASAP Policy

    This article shows you a git branching workflow which helps developers to review changes frequently, leading to better code quality.

    Read more
  • Tabular Data Representation in Modern HTML Emails Tabular Data Representation in Modern HTML Emails

    Responsive tables are the most common ways to represent tabular data in HTML emails. Learn about the best practices and the card layout design approach.

    Read more
  • Lessons Learned in SaaS Development Lessons Learned in SaaS Development

    In this article series we are going to share with you all the software development lessons we learned while building a robust SaaS product with 99,8% uptime

    Read more