To create a web app, with frameworks (like Angular 2 or React) or soon natively (with the Web Components standard), you'll develop components : you'll write JavaScript for the behavior, but without a view, your component is worthless. And here come HTML and CSS.

Yeah, I know : you work with complex frameworks like Symfony or "serious" languages like Java, so you're smart enough to understand what is a tag and how to put a text in red. Well, that's not enough. Quick-and-dirty HTML leads to poor search engine optimization, bad ergonomy and no accessibility, and something is clearly not easy : CSS positionning. There is 3 major pitfalls you won't guess by magic.

So please do yourself and others a favor : put aside your pride for a few minutes to learn solid and clean basics in HTML5 CSS3.

You'll find other guides and a general explanation here.

HTML5 essentials

Doctype

Always start your HTML page with this document type, and only this one. There are consequences for JavaScript too. No exception.

<!doctype html>

Encoding

Always work in UTF-8. Some modern tools, including JSON (JavaScript Object Notation, which replaces XML in most web services), only work in UTF-8.

<meta charset="utf-8">

Structure

You need to build a solid structure, to be able to position elements in CSS and to manipulate them in JavaScript. Regroup in blocks what belong together as much as you can, especially blocks aligned horizontally (it will be important for CSS). Think of it as scopes / encapsulation. Name your blocks with an id if it's unique, or add it to class (group) if there is some repitition. Forget tables.

<!-- Bad structure -->
<div>Logo on left</div>
<div>Menu on right</div>
<div>Content 1</div>
<div>Content 2</div>
<div>Sidebar</div>
<div>Footer</div>

<!-- Good structure -->
<div id="wrapper-global">
  <div id="header">
    <div id="header-logo">Logo on left</div>
    <div id="header-nav">Menu on right</div>
  </div>
  <div id="wrapper-main">
    <div id="content">
      <div class="story">Content 1</div>
      <div class="story">Content 2</div>
    </div>
    <div id="sidebar">Sidebar</div>
  </div>
  <div id="footer">Footer</div>
</div>

HTML5 added new blocks with semantic, for search engine optimization and accessibility.

<div id="wrapper-global">
  <header id="header">
    <div id="header-logo">Logo on left</div>
    <nav id="header-nav">Menu on right</nav>
  </header>
  <div id="wrapper-main">
    <main id="content">
      <article class="story">Content 1</article>
      <article class="story">Content 2</article>
    </main>
    <aside id="sidebar">Sidebar</aside>
  </div>
  <footer id="footer">Footer</footer>
</div>

Medias

Do not forget an alternative text for images (for accessibility) and dimensions are the only exception of graphic informations in HTML (for performance). Prefer SVG when possible, or PNG, and JPEG only for high quality pictures, but with compression.

<img src="image.png" alt="Description" width="500" height="300">

Control bar in videos is not automatic, you must ask for it. Choose appropriate codecs for encoding (MPEG H.264 video / MP3 audio). Tag must be closed.

<video controls src="video.mp4" width="500" height="300"></video>

Links

<a href="https://developer.mozilla.org" target="_blank">Explicit text</a>

Semantics

Every content (text, images, links...) must be prioritized with one of the following semantic blocks. It will be important for CSS positionning.

<h1>Page title</h1>
<h2>Subtitles</h2>
<h3>Subtitles</h3>
<p>Normal text content</p>
<figure>Illustrative content (like an image)</figure>
<ul>
  <li>List</li>
  <li>List</li>
</ul>

Then, and only then, you can give importance to some words for search engine optimization.

<p>Hello world ! This page is about <strong>keyword</strong>.</p>
<p><em>Emphasised introduction...</em></p>

Some common errors.

<!-- Bad semantics -->
<a href="https://developer.mozilla.org">Explicit text</a>
<img src="image.png" alt="Description" width="500" height="300">
<div>Normal text content</div>
<span>Normal text content</span>

<!-- Good semantics -->
<p><a href="https://developer.mozilla.org">Explicit text</a></p>
<figure><img src="image.png" alt="Description" width="500" height="300"></figure>
<div><p>Normal text content</p></div>
<p>Normal text content</p>
        

Be aware of 3 special characters : <, >, &.

&lt;
&gt;
&amp;

Forms

Forms are where you ask users to interact. So it's where ergonomy and accessibility must be perfect. For example, each input needs a linked label. Also use the new input types.

Input names will be used by the server, do not confuse with id.

<form method="post" action="signup.php">

  <label for="signup-email">E-mail (required) :</label>
  <input type="email" name="email" id="signup-email" required>

  <label for="signup-password">Password (required) :</label>
  <input type="password" name="password" id="signup-password" required>

  <label for="signup-nickname">Nickname :</label>
  <input type="text" name="nickname" id="signup-nickname" maxlength="250">

  <label for="signup-phone">Phone :</label>
  <input type="tel" name="phone" id="signup-phone" pattern="[0-9 \+\-\.]+">

  <label for="signup-website">Website :</label>
  <input type="url" name="website" id="signup-website">

  <label for="signup-birthdate">Birthdate :</label>
  <input type="date" name="birthdate" id="signup-birthdate">

  <fieldset>
    <legend>Gender :</legend>
    <input type="radio" name="gender" id="signup-gender-n" value="n" checked>
    <label for="signup-gender-n">Not specified</label>
    <input type="radio" name="gender" id="signup-gender-w" value="w">
    <label for="signup-gender-w">Woman</label>
    <input type="radio" name="gender" id="signup-gender-m" value="m">
    <label for="signup-gender-m">Man</label>
  </fieldset>

  <label for="signup-country">Country :</label>
  <select name="country" id="signup-country">
    <option value="ca">Canada</option>
    <option value="fr" selected>France</option>
  </select>

  <label for="signup-description">Description :</label>
  <textarea name="description" id="signup-description"></textarea>

  <input type="checkbox" name="conditions" id="signup-conditions" required>
  <label for="signup-conditions">I accept general conditions.</label>.

  <button type="submit">Sign up</button>

</form>

<form method="get" action="search.php">

  <label for="search-email">Search :</label>
  <input type="search" name="search" id="search-input" placeholder="some keyword...">

  <button type="submit">Search</button>

</form>

Respect HTTP methods or it will lead to security issues. Choose get for read operations (search...) and post for modification operations (signup, signin, back-office...).

Do not rely on any HTML or JavaScript validation : we're on the client side, which cannot be secure. New HTML5 attributes are just here for ergonomy, you must check again on the server side.

HTML validation

You would not push your Java or PHP code in production without any testing, right ? Well, please keep a good methodology for HTML too. Displaying your page in a browser is not enough : you'll just see visual problems (i.e. mostly CSS problems) but not HTML problems (like a broken tree because of a missing closing tag). You'll manipulate this structure in JavaScript, so do not expect it goes well if the structure is weak or broken.

So use the W3C HTML validator before continuing. Some frameworks like Angular 2 will check this for you.

CSS3 essentials

Selectors

Any element can be named by one id and/or several classes.

<h1 id="page-title" class="title color-main">Page title</h1>

You can group blocks with <div> like already done in the HTML structure step, and you can also group part of a content. But as seen before, <span> alone has no semantic meaning.

<p>Some <span class="color-main">content</span>...</p>

Now we can select anything in the page to style them in CSS, but you'll also use the same selectors in JavaScript to manipulate elements.

/* By type */
h1 {}
/* By class */
.title {}
/* By id */
#page-title {}

Factoring.

h1,
h2 {}

Tree-based selectors. As you can see, a space has a meaning in CSS selectors, so do not put unnecessary spaces, it will lead to wrong selectors.

/* All descendants (elements of the list and any sublists) */
#header-nav-list li {}
/* Children only (elements of this list only) */
#header-nav-list>li {}

Attribute selector.

input[type="text"] {}

Pseudo-classes : understand them as conditions / filters.

a:hover {}
#header-nav-list>li:first-child {}

Selectors priority (CSS pitfall n°1)

For different selectors, the priority is not about order (either in HTML or in CSS) but specificity. So : #id > .class > tag. If the priority is the same, the last selector wins (cascading).

If you do your CSS in a clever way and order, you should not have too much troubles. If any, use the Inspector development tool in your browser.

/* 1. General graphics */
body {
  font-family: 'Arial', sans-serif;
}

.color-main {
  color: rgb(255, 0, 0);
}

/* 2. Positionning */
#header {
  display: flex;
}

Do not use !important. Except in very uncommon (and justified) cases, it is a very bad practice as it breaks the cascading system.

Never use inline styles in HTML. They are impossible to override, and they can be forbidden by a new security option in HTML5 called Content Security Policy.

Graphics

You should know font, text-align, list-style, color, background, units (em or rem are recommanded).

CSS3 allows to do advanced graphics with no heavy images to load : custom fonts, gradients, text and box shadows, border radius...

Animations

CSS3 introduced transformations (rotation, translation...), transitions and standalone animations. It's only for small and visual animations, interaction is still the role of JavaScript. But especially transitions can help you in JavaScript to simplify animations (before, we had to do complex recursive timers).

A transition does nothing by itself : in this example, it only tells : if there is any modification on margin-left, do it in 5 seconds instead of instantly.

#some-element {
  transition: margin-left 5s;        
}

In JavaScript, you'll have the transitionend event to know when the transion is finished.

Normalizing and box-sizing (CSS pitfall n°2)

Be aware that by default, width and height are the content dimensions, not the block dimensions. It's the major pitfall in CSS as it's really against-intuitive. Hopefully that can be changed in CSS3 with box-sizing.

It's done by sanitize.css library, also with a normalization of default styles accross browsers (especially for new HTML5 tags). Use it, you'll thank me.

Positionning (CSS pitfall n°3)

You should know : width, height, max-width (often better for responsive), margin, padding, border, overflow.

Be aware you can only give dimensions to block elements : <div>, <h1>, <h2>, <h3>, <p>, <figure>, <ul>, <li>, <header>, <nav>, <main>, <article>, <aside>, <footer>... It's why it was important to prioritize every content in HTML, or you won't have a block to work on it.

By default, block elements are displayed vertically and content elements horizontally (inline). It is automatically managed by the display property. Do not touch it and never use the special inline-block option to align blocks horizontally : it's not the purpose of this value and will lead to troubles.

To align blocks horizontally, only use the new positionning system in CSS3 :

#header {
  display: flex;
  /* And some optional alignment if needed */
  justify-content: space-between;
  align-items: center;        
}

In JavaScript, you'll need to show and hide elements : only use display.

#popup {
  display: none; /* Good */
  visibility: hidden; /* Bad */   
}

Responsive design

As there is more traffic on mobile than desktop today, being responsive is required. First, always include this line in HTML head to request a normally scaled display on mobile :

<meta name="viewport" content="width=device-width, initial-scale=1">

Then you just have to adapt your CSS (dimensions, axis...) with media queries. Here are the common cases :

/* Default styles for classic screens */
@media all {
  #wrapper-global {
    max-width: 960px; /* Max width recommended on desktop */
    margin: 0 auto; /* If you need to center you app */
  }
}
        
/* Tablets in portrait */
@media all and (min-width: 760px) and (max-width: 959px) {}

/* Mini-tablets in portrait & very good mobiles in landscape */
@media all and (min-width: 560px) and (max-width: 759px) {}

/* Mobiles in landscape */
@media all and (min-width: 460px) and (max-width: 559px) {}

/* Mobiles in portrait (common and smallest width is 320px) */
@media all and (max-width: 459px) {}

Any interactive item (links...) must be 48x48px minimum with 8px margin minimum.

You may want to optimize image sources (for performance and quality) with the new srcset HTML attribute, and some parts of the page can be adapted in JavaScript with the same media queries (for example a wide menu converted to a select box).