DEV Community

Cover image for Creating an Accessible, Responsive Pixel Perfect Website
Jose Felix
Jose Felix

Posted on • Edited on • Originally published at jfelix.info

Creating an Accessible, Responsive Pixel Perfect Website

Last post addressed the definition, benefits, and application of semantic HTML. In this post, I will walk through the process of coding an accessible, responsive website using what we've learned in the series.

Starting this series, we had the following design:

Website design with navbar and hero section

And we created a layout model using a technique learnt on the first post of the series:

Layout model of website design

Having this we can begin translating this model to HTML and CSS!

Responsive Design

One more thing before starting, we have to think about how we will make the site responsive. There are two ways we can achieve this:

  1. Set a max-width to all our sections and focus on the most used breakpoints.
  2. Make it fluid on all screens.

Note: Every design should aim to be responsive in all screen sizes. However, it can be really time-consuming, therefore we use one of the two methods above to avoid creating media queries for all screens available.

Selecting one of both methods greatly depends on the situation and preference.

Setting a max-width is what I normally go for. The design stays consistent on big screens and is easier to style since there are fewer breakpoints to worry about.

Making it fluid is better for some designs. If implemented well (using grid e.g. 12 column grid) it can be done really quickly and will be responsive in all breakpoints. However, its cost of implementation can be quite high.

For the sake of this tutorial, we will go with the first method. For the breakpoints, we'll be using the most common:

  • Mobile (640px)
  • Tablet (768px)
  • Tablet Landscape (1024px)
  • Laptop (1440px)
  • Really big screens (>= 2000px)

CSS Normalization

Whenever creating a website, writing CSS that is consistent in all browsers is a must. To guarantee this, we use something called CSS Normalization. Normalize.css is great for this, however, it is an overkill for this kind of project. Therefore, we will be using a very basic CSS Normalization, but I highly recommend Normalize.css.

In our basic normalizer, we will just remove browsers added margin and padding. Also, add box-sizing to guarantee a consistent width and height property.

Apart from removing browser's defaults, using rem units instead of px will streamline the process of making the site responsive since each element will grow or decrease based on the user's browser zoom or breakpoints. To achieve this, we will change font-size value to a percent. In this case, 62.5%, so that 1 rem would be equal to 10 pixels. On the other hand, whenever we need for the design to stay consistent we can use px units.

/*
  Breakpoints: 
    Mobile (640px = 40em)
    Tablet (768px = 48em)
    Tablet Landscape (1024px = 64em)
    Laptop (1440px = 90em)
    Really large screens ( >= 2000 = 125 em)
*/

@import url("https://fonts.googleapis.com/css?family=Fira+Sans:400,500&display=swap");

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

html {
  font-size: 62.5%; /*1rem = 10px*/
  box-sizing: border-box;
}

@media only screen and (max-width: 64em) {
  html {
    font-size: 50%;
  }
}

/* For really big screens */
@media only screen and (min-width: 125em) {
  html {
    font-size: 75%;
  }
}

body {
  font-size: 1.4rem;
  font-family: "Fira Sans", sans-serif;
}
Enter fullscreen mode Exit fullscreen mode

Navigation Bar

Let's start with the navbar. The navbar section element is header since it serves as our website's heading containing the site's main links and general brand.

Note: I will be using BEM notation for elements CSS classes since it increases legibility.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Pixel Perfect Layout</title>
  </head>
  <body>
    <header class="navigation">
      <svg       
        class="navigation__logo" 
        width="75"
        height="24"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
      >
        <path
          d="M9 0C3.648 0 0 3.648 0 9c0 5.256 3.72 8.856 9 8.856 2.376 0 4.752-.48 7.008-1.68V7.488H9.504v2.736h3.48v4.008c-1.2.672-2.688.888-3.96.888-3.648 0-5.856-2.808-5.856-6.312C3.168 5.424 5.52 2.736 9 2.736c1.584 0 3.288.552 4.44 1.656l2.232-2.256C13.872.504 11.352 0 9 0zM24.664 5.616c-1.512 0-2.784.792-3.408 2.112h-.048V5.904h-2.88v11.52h2.88v-6c0-1.536.912-3.072 3.096-3.072.432 0 .84.072 1.392.216V5.784c-.384-.096-.6-.168-1.032-.168zM31.528 5.616c-2.256 0-3.864.792-4.896 1.848l1.512 1.512a4.577 4.577 0 013.072-1.2c1.584 0 2.64.792 2.64 2.136v.336h-.888c-4.944 0-7.08 1.344-7.08 4.008 0 2.112 1.824 3.456 4.2 3.456 1.536 0 2.88-.576 3.696-1.872h.072v1.584h2.592v-6.888c0-2.712-.984-4.92-4.92-4.92zm-2.76 8.424c0-1.224 1.536-1.776 4.08-1.776h.84v.72c0 1.464-.912 2.568-2.88 2.568-1.08 0-2.04-.528-2.04-1.512zM36.986 5.904l4.704 11.52h3.072l4.536-11.52h-2.952l-3.096 8.064h-.048L40.13 5.904h-3.144zM51.456.264c-1.032 0-1.824.792-1.824 1.728 0 .936.792 1.728 1.824 1.728s1.872-.696 1.872-1.728c0-.984-.816-1.728-1.872-1.728zm-1.416 5.64v11.52h2.88V5.904h-2.88zM56.258 2.568v3.336h-2.376v2.448h2.376v5.4c0 2.904 1.056 3.96 3.768 3.96.648 0 1.728-.12 2.28-.384v-2.424c-.24.192-.84.36-1.56.36-1.128 0-1.608-.576-1.608-1.8V8.352h3.168V5.904h-3.168V2.568h-2.88z"
          fill="#222"
        />
        <path
          d="M61.994 5.904l4.92 11.616-.504 1.248c-.528 1.272-.816 1.824-2.328 1.824-.504 0-1.008-.12-1.464-.288l-.36 2.592c.72.192 1.464.288 2.208.288 2.88 0 3.648-1.416 4.584-3.792l5.256-13.488h-3l-2.88 7.992h-.048l-3.216-7.992h-3.168z"
          fill="#222"
        />
      </svg>

      <span class="navigation__icon">
        <svg
          width="20"
          height="20"
          fill="none"
          xmlns="http://www.w3.org/2000/svg"
        >
          <path
            fill-rule="evenodd"
            clip-rule="evenodd"
            d="M0 8.5a8.5 8.5 0 1115.453 4.89l3.44 3.437a1 1 0 010 1.415l-.649.647a1 1 0 01-1.413 0l-3.44-3.437A8.5 8.5 0 010 8.5zm8.5 6.071A6.078 6.078 0 012.429 8.5 6.078 6.078 0 018.5 2.429 6.078 6.078 0 0114.571 8.5 6.078 6.078 0 018.5 14.571z"
            fill="#222"
          />
        </svg>
      </span>
      <button class="navigation__button">
        <svg
          width="34"
          height="14"
          fill="none"
          xmlns="http://www.w3.org/2000/svg"
        >
          <path fill="#222" d="M0 0h34v3H0zM16 11h18v3H16z" />
        </svg>
      </button>
     <nav class="navigation__links">
        <ul>
          <li><a href="/">Home</a>></li>
          <li><a href="/about">About</a></li>
          <li><a href="/contact">Contact</a></li>
        </ul>
      </nav>
    </header>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Writing the styles for the navigation bar is pretty straightforward once you have the CSS purpose of each block. We can refer to our model:

Layout model of navigation bar

By taking a look, the block uses flex to organize its elements.

Also, it has some padding (more on its right and left than top and bottom). Let's translate this to CSS:

/* ... */ 

/* SECTION */
.navigation {
  display: flex;
  align-items: center;
  justify-content: space-between;

  padding: 5rem 9rem;

  max-width: 1440px;
  margin: 0 auto;
}

@media only screen and (max-width: 40em) {
  /* Reduce the padding on smaller screens */
  .navigation {
    padding: 5rem 3rem;
  }
}

/* ELEMENT */
.navigation__search {
  cursor: pointer;
}

/* ELEMENT */
.navigation__button {
  border: none;
  background: transparent;
  cursor: pointer;
  outline: none;
}

/* BLOCK */
.navigation__links {
  display: none;
}
Enter fullscreen mode Exit fullscreen mode

Desktop navigation bar

Mobile navigation bar

That's all for our navigation bar!

Hero Section

Next, let write our hero. This time we'll use a section tag as the container since we are defining a group of related content.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Pixel Perfect Layout</title>
  </head>
  <body>
   <header><!-- ... --></header>
   <section class="hero">
      <img class="hero__video" src="assets/video.png" />
      <header class="hero__heading">
        <div class="hero__text-box">
          <h1 class="heading-primary">Work around you and your team</h1>
          <p class="hero__text text">
            From ads that dance or sing to MTV-like commercials, online
            advertisers are now using a new type of technology “rich media” to
            attract consumers.
          </p>
          <button class="hero__button btn btn--purple">get started</button>
        </div>
        <div class="hero__loader">
          <p>01</p>
          <progress value="40" max="100"></progress>
          <p>03</p>
        </div>
      </header>
      <img class="hero__image" src="assets/groove.png" />
    </section>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

You may see we are using header inside a section. It is perfectly normal to do this since it indicates that it is the introductory element of that section. Looking back at our navigation bar, it is the introductory element for our document or website.

We'll have something like this. Although semantic and accessible, it lacks beauty and responsiveness.

Hero section with no CSS applied

Styling our hero has a higher complexity than our navigation since it has more elements and blocks. Regardless, using our model we can achieve the pixel-perfect look we want.

It is important to take things one step at a time looking at each CSS purpose of our model. Likewise, some of the code will be trial and error; it is perfectly fine to do this as long as it gets to look as our intended design.

Layout model of hero section

/* ... */ 

/* SECTION */
.hero {
  display: flex;

  max-width: 1440px;
  margin: 0 auto;

  /*
    Since we have an unnatural block on this section
    we have to make our section relative for it to act
    as an anchor.
  */
  position: relative;
}

@media only screen and (max-width: 48em) {
  .hero {
    flex-direction: column;
  }
}

/* UNNATURAL */
.hero__video {
  position: absolute;

  top: 50%;
  left: 60%;
  transform: translate(-60%, 0);

  object-fit: contain;

  box-shadow: -20px 60px 120px rgba(0, 0, 0, 0.3);
}

@media only screen and (max-width: 90em) {
  .hero__video {
    width: 30vw;
  }
}

@media only screen and (max-width: 48em) {
  .hero__video {
    top: initial;

    bottom: -2%;
    left: 50%;

    transform: translate(-50%, 0);
  }
}

@media only screen and (max-width: 40em) {
  .hero__video {
    width: 30rem;
  }
}

/* BLOCK */
.hero__heading {
  flex: 1;

  display: flex;
  flex-direction: column;
  justify-content: space-around;

  padding: 3rem 9rem;
}

@media only screen and (max-width: 40em) {
  .hero__heading {
    padding: 3rem 4rem;
  }
}

/* BLOCK */
.hero__text-box {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
}

.hero__text {
  max-width: 450px;
}

.hero__text-box > *:not(:last-child) {
  margin-bottom: 5rem;
}

.hero__button {
  align-self: start;
  margin-top: 2rem;
}

/* ELEMENT */
.hero__image {
  width: 50%;
  object-fit: contain;
}

@media only screen and (max-width: 48em) {
  .hero__image {
    width: 100%;
    height: 50rem;
    object-fit: fill;
    padding: 2rem 9rem;
  }
}

@media only screen and (max-width: 40em) {
  .hero__image {
    padding: 2rem 4rem;
  }
}

/* BLOCK */
.hero__loader {
  display: flex;
  align-items: center;
  width: 100%;
  margin-top: 4rem;
}

.hero__loader > *:not(:last-child) {
  margin-right: 2rem;
}

/* ELEMENT */
.hero__loader p {
  font-size: 1.6rem;
}

/* ELEMENT */
.hero__loader progress {
  width: 20rem;
  height: 0.3rem;
}

.hero__loader progress[value] {
  /* Reset the default appearance */
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;

  /* Get rid of default border in Firefox. */
  border: none;
}

.hero__loader progress[value]::-webkit-progress-bar {
  background-color: #d7d4d4;
}

.hero__loader progress[value]::-webkit-progress-value {
  background: #c6b393;
}

/* Firefox */
.hero__loader progress[value]::-moz-progress-bar {
  background: #c6b393;
}

/* COMPONENTS */

.heading-primary {
  font-size: 6rem;

  color: #151515;
}

.text {
  font-size: 1.8rem;
  line-height: 28px;

  color: #222222;

  opacity: 0.7;
}

.btn {
  padding: 1.5rem 3rem;

  font-family: inherit;
  text-transform: uppercase;

  letter-spacing: 2px;
  font-weight: 500;

  border: none;
  cursor: pointer;
}

.btn--purple {
  background-color: #4737ff;
  color: white;
}
Enter fullscreen mode Exit fullscreen mode

Now we have this!!

Final website looking exactly like mockup

And on mobile:

Note: The mockup didn't have a mobile version, regardless, this is a little extra.

Mobile version of final design

Here is the sandbox if you want to play around with the website.

Conlusion

Creating pixel-perfect layouts is very important for web developers since most websites have a mockup behind them. With layout models and semantic HTML, we can create almost any website with high fidelity while taking care of accessibility and responsiveness.

Thanks for reading this series on how to create Pixel Perfect Layouts 🥳! Feel free to check out the other parts. Follow me on Twitter, and Dev.to! See you soon 🔥💻


Did you know I have a newsletter? 📬

If you want to get notified when I publish new blog posts and receive an awesome weekly resource to stay ahead in web development, head over to https://jfelix.info/newsletter.

Top comments (4)

Collapse
 
bassimsmile profile image
Bassim RAJI

Thank you it's very illuminating .

Collapse
 
igcp profile image
Igor Conde

Thank you very much for the article, I learned a lot of new things

Collapse
 
adrianamota profile image
Adriana Mota

Thank you, I really appreciate your posts, I learn a lot from most!!

Collapse
 
thisdotmedia_staff profile image
This Dot Media

Super helpful 🙌 Thanks Jose