Let's build a layout from scratch

Let's build a layout from scratch

·

10 min read

Today let's build the layout for an entire website from scratch using HTML, CSS, flexbox, grid layout and so much more...

Read the full article or watch me code this on Youtube:

Result

screenshot-main.png

Blank HTML5 Document

Let's start with a blank HTML5 Document. This is our starting point which we're going to extend bit by bit throughout the following chapters.

Did you know that typing an exclamation mark (!) and hitting tab in VS CODE generates a blank HTML5 Document?

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>BEAMCLOUD</title>
  </head>
  <body>
    <!-- content will go here -->
  </body>
</html>

Using Styles and External Fonts

There are three (more or less) external resources we have to include in the documents <head>:

  1. Our own stylesheet in styles.css.
  2. We'll be using the font Nunito as the page's default font. Therefore it is loaded via Google Fonts. The font weights 200, 400 and 700 will be used. Especially 200 looks quite elegant with larger text (as in headings).
  3. Font Awesome via cdnjs.com. Watch out for the integrity attribute as it is a nice security feature. If the SHA checksum of the file downloaded by the user agent differs from the SHA checksum given in the integrity attribute, the browser knows that the downloaded content was tampered with and is therefore rejected. See this MDN Article for more about subresource integrity.
<head>
  ....

  <!-- or own styles -->
  <link rel="stylesheet" 
    href="styles.css"
    type="text/css" />

  <!-- "Nunito" font via google fonts -->
  <link rel="preconnect" 
    href="https://fonts.gstatic.com" />
  <link rel="stylesheet"
    href="https://fonts.googleapis.com/css2?family=Nunito:wght@200;400;700&display=swap" >

  <!-- Font Awesome via CDNJS  -->
  <link rel="stylesheet" 
    href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" 
    integrity="sha512-HK5fgLBL+xu6dm/Ii3z4xhlSUyZgTT9tuc/hSrtw6uzJOvgRr2a9jyxxT1ely+B+xFAmJKVSTbpM/CuL7qxO8w==" 
    crossorigin="anonymous" />
  </head>

Variables and Basic Styles

Now, in our styles.css file, let's start with a few basic things. For instance, variables. It's extremely useful for customization to have the colors we'll be using in variables and common, repetitive things like the transition setup also.

:root {
  --bg-start: #2c35a2;
  --bg-end: #0f133b;

  --highlight-fg: #161c49;
  --highlight-primary: #73fff5;
  --highlight-secondary: #cf0389;

  --fg-color: rgba(255, 255, 255, 0.9);

  --transition: 250ms ease-out;
}

This block resets padding, margin and box-sizing for each element, so it brings us a great deal of consistency across browsers and elements.

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

On the root <html> element we're defining the basic text color as well as the basic font, including the font size. This is quite important, as we're going to use a lot of rem values and they are always relative to the font size being set on the root <html> element.

html {
  color: var(--fg-color);

  font-family: "Nunito", sans-serif;
  font-weight: 400;
  font-size: 18px;
}

The <body> is simply going to be a flex container that centers content horizontally and puts content to the very top. min-height: 100vh ensures that the body always takes at least the full viewport height, which spans the gradient across the entire page.

body {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;

  padding: 2rem;
  min-height: 100vh;


  background: linear-gradient(
    45deg,
    var(--bg-start), 
    var(--bg-end)
  );
}

The first actual content element is the logo. It's embedded in a header tag and is simply a div with an img tag referencing an SVG image and a logo text.

<body>
  <header>
    <div class="logo">
      <img src="logo.svg">
      beamcloud
    </div>
  </header>
</body>

Styling on this one is quite simple, as it is also a flex container that puts the image and the logo text next to each other and centers them vertically. Additionally the height of the image is set to match the font size.

.logo {
  display: flex;
  align-items: center;

  text-transform: uppercase;
  font-size: 2rem;
}

.logo > img {
  height: 2rem;
  margin-right: 1rem;
}

The navigation bar is the second element inside the header and uses an unordered list ul for the navigation items embedded in a nav providing semantics already on the markup level.

<body>
  <header>
    ...
    <nav>
      <ul>
        <li class="active">
          <a href="#">About Us</a>
        </li>
        <li>
          <a href="#">Reviews</a>
        </li>
        <li>
          <a href="#">Pricing</a>
        </li>
        <li class="highlight">
          <a href="#">Sign In</a>
        </li>
      </ul>
    </nav>
  </header>
</body>

In order to arrange logo and navigation items next to each other, the header element is also set to be a flex-container and pushing both items to the very left/right by using justify-content: space-between.

header {
  display: flex;

  justify-content: space-between;
}

Since (almost?) every browser renders links in a highlighted color and underlined, let's undo that kind of styling by setting the color to the respective variable and unsetting all kinds of text decoration.

a {
  color: var(--fg-color);

  text-decoration: none;
}

Finally, for the navigation items themselves we're using a grid layout being configured for automatically flowing all items each into their own column. By using grid-auto-columns: max-content each cell is wrapped nicely around a navigation item without making the contained text wrap.

nav > ul {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: max-content;
  gap: 0.5rem;

  list-style-type: none;
}

nav > ul a {
  padding: 0.25rem 1.25rem;

  text-transform: uppercase;

  transition: color var(--transition),
    background-color var(--transition);
}

Main Content

For the main content of the page we're also using the main semantic HTML tag. Inside it is a section tag containing a heading and a paragraph and a nice little artwork which we're going to put next to it.

<body>
  ...
  <main>
    <section>
      <div class="content">
        <h1>Scale well, sleep well.</h1>
        <p>
          Get the most out of your apps and websites with our highly available and scalable cloud infrastructure. All you need, directly at your fingertips.
        </p>
        <a href="#" class="button">
          Learn More
        </a>
      </div>
      <div class="artwork">
        <img src="artwork.svg" >
      </div>
    </section>
  </main>
</body>

The section itself is also going to be a grid layout, but this time it is explicitly configured to have exactly two columns, whereas the left column is given one fraction (1fr) of the available space and the right column two fractions (2fr).

main {
  max-width: 50rem;
  padding: 2rem;
}

section {
  display: grid;
  grid-template-columns: 1fr 2fr;
  grid-template-rows: 1fr;
  grid-template-areas: "content artwork";
  place-content: center;
}

section > .content {
  grid-area: content;
  place-self: center stretch;
}

section > .artwork {
  grid-area: artwork;
  place-self: stretch;
}

h1 {
  margin-bottom: 1rem;

  color: var(--highlight-primary);

  font-size: 2.5rem;
  font-weight: 200;
}

p {
  margin-bottom: 1rem;

  font-size: 1.25rem;
  font-weight: 200;
}

At last, we have reached the bottom of the page being a footer. We'll be using it to put a bunch of social media icons which is why we have included font awesome at the very beginning.

<body>
  ...
  <footer>
    <a href="#"><i class="fab fa-twitter"></i></a>
    <a href="#"><i class="fab fa-facebook-f"></i></a>
    <a href="#"><i class="fab fa-instagram"></i></a>
    <a href="#"><i class="fab fa-youtube"></i></a>
    <a href="#"><i class="fab fa-github"></i></a>
    <a href="#"><i class="fab fa-linkedin-in"></i></a>
  </footer>
</body>

The footer is again a grid layout configured to automatically flow each element into its own column with a gap of 1rem between each of them.

footer {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: min-content;
  gap: 1rem;
  justify-content: center;

  margin-top: 4rem;
  padding-top: 1rem;
  width: 80%;
}

To spice the header slightly up we're not going to use a "normal" border, but a gradient. Therefore the footer::before pseudo-class allows us to put an element at the top of the footer having a gradient as background. And that's already it!

footer {
  position: relative;
  ...
}

footer::before {
  content: '';

  position: absolute;
  top: 0%;
  left: 0%;
  right: 0%;
  height: 2px;

  background: linear-gradient(
    90deg,
    transparent,
    var(--highlight-secondary),
    transparent
  );
}