Frontend Mentor QR code

In this post, we will review 2 Frontend Mentor QR code challenge solutions we built.

Frontend Mentor is a platform that hosts challenges for front-end developers to improve their coding skills by building real projects. If you’re just interested in the solutions, you can find them using the following URLs

The QR code component challenge is a beginner-friendly challenge that involves building a card with an image of a QR code, a heading, and a paragraph. You can find this specific challenge and more on the Frontend Mentor site.

Solution 1 | HTML, CSS & BEM methodology

Our first solution tackles the challenge using pure HTML and CSS with the BEM methodology and the mobile-first workflow.

Setting up the HTML

At first, I began by putting the browser into responsive mobile mode with a width of 375px. Next, I mapped out the basic HTML structure by adding the QR code image, Heading text, and paragraph. At this point, my HTML looked like the following

<body>
  <img src="./images/image-qr-code.png" alt="QR code image">
  <h1>
    Improve your front-end skills by building projects
  </h1>
  <p>
    Scan the QR code to visit Frontend Mentor and take your coding skills to the next level
  </p>
</body>

One important thing to note is that I used a <h1> element. For accessibility reasons, web pages require one h1 element. This is usually something like a page title. Since we don’t really have anything besides our card component, I use it for the card title. Another benefit of using the correct heading elements is search engine optimization (SEO). Good SEO-designed web pages will drastically increase your Google ranking and overall website visibility. This is because search engines tend to understand h1 tags as the main content of a page and are therefore treated as relevant and matching to a person’s search query.

With my basic HTML structure set up, I started grouping elements to what made the most sense to me. Since we are creating something that looks like a card, I decided to group it how I would group a card element. In this step, I also added my primary class name to the upper wrapper of my card. I ended up with the following HTML

<body>
  <main class="card">
    <div>
      <img src="./images/image-qr-code.png" alt="QR code image">
    </div>
    <div>
      <h1>
        Improve your front-end skills by building projects
      </h1>
      <p>
        Scan the QR code to visit Frontend Mentor and take your coding skills to the next level
      </p>
    </div>
  </div>
</body>

Since I wanted to use the BEM methodology for this challenge, this was the point where I started naming my elements accordingly. Implementing the BEM methodology resulted in the following HTML. Also note the usage of the main HTML element. This is one of the many available semantic elements. When building your HTML structure it´s good practice to design by semantics first as these increase the accessibility of your webpages.

<body>
  <main class="card">
    <div class="card__header">
      <img class="card__image" src="./images/image-qr-code.png" alt="QR code image">
    </div>
    <div class="card__content">
      <h1 class="card__heading">
        Improve your front-end skills by building projects
      </h1>
      <p class="card__subtext">
        Scan the QR code to visit Frontend Mentor and take your coding skills to the next level
      </p>
    </div>
  </div>
</body>

At this point, my HTML was ready to go. Next up, the styling!

Setting up the CSS

Let’s go through the CSS I wrote together. I started by defining the given colors as variables within my :root selector so that they are globally available and within one spot.
For people a bit newer to CSS, the :root selector is effectively the same as the html selector but ranks higher in specificity. Specificity is the hierarchy in which CSS styling, which targets the same element, fights over priority.

After setting up my colors, I defined some general styling inside my html selector. The reason for picking the html selector here instead of the :root selector is that the new styling elements can override styling within the html element. In the :root selector, I only put the styling rules that I deem unchangeable.

At this point, my CSS file was looking like this

:root {
    --clr-white: hsl(0, 0%, 100%);
    --clr-grey-light: hsl(212, 45%, 89%);
    --clr-blue-grey: hsl(219, 15%, 55%);
    --clr-blue-dark: hsl(218, 44%, 22%);
    font-family: 'Outfit', sans-serif;
}

body {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 100vh;
    height: 100%;
    align-items: center;
    margin: 1.75rem;
    background-color: var(--clr-grey-light);
}

Next up was styling the card. My way of working here was that I envisioned the card as an object with layers. The background layer is the white background color, and the higher layers are the image and content. I started with the background layer, my card class.

.card {
    border-radius: 1rem;
    background-color: var(--clr-white);
    display: flex;
    flex-direction: column;
    padding: 1rem;
    padding-bottom: 1.5rem;
    max-width: 320px;

    -webkit-box-shadow: 0px 0px 10px -8px var(--clr-blue-dark);
    -moz-box-shadow: 0px 0px 10px -8px var(--clr-blue-dark);
    box-shadow: 0px 0px 10px -8px var(--clr-blue-dark);
}

Memorable lines here are that I chose a flex approach to get the items below each other and centered nicely. You can find the 3rd party where I created the box-shadow here.

Now that my card background looked good, I moved on to the content part. I came up with the following styling

.card__image {
    border-radius: 1rem;
    width: 100%;
}

.card__content {
    text-align: center;
}

.card__heading {
    font-size: 22px;
    font-weight: bold;
    color: var(--clr-blue-dark);
    padding-left: 0.25rem;
    padding-right: 0.25rem;
}

.card__subtext {
    color: var(--clr-blue-grey);
    font-size: 15px;
    font-weight: normal;
    padding-left: 1.25rem;
    padding-right: 1.25rem;
}

Using the styling works fine on a mobile viewport. Scaling up to a desktop viewport did bring some issues with it. For that, I had to resolve Media Queries. Media Queries are how we attach different stylings when a screen reaches another viewport resolution. An ideal solution to the issue we are having now.

I came up with the following two Media Queries

@media only screen and (min-width: 756px) {
    .card__content {
        padding-left: 1.75rem;
        padding-right: 1.75rem;
    }

    .card__heading, .card__subtext {
        padding: 0;
    }
}

Combining all styling + HTML resulted in the following mobile and desktop results, which look like the designs provided.

Mobile result QR Code Frontend Mentor
Desktop result QR code Frontend Mentor

Solution 2 | HTML & CSS

The second solution focuses on a simpler approach. We do the job with only the smallest changes necessary to complete the design.

Setting up the HTML

At first, I started with editing the index.html file.

The initial code did not contain many HTML elements with classes or ids. That is why I first added a main container with a card containing the centered QR code. Finally, I added a footer element containing the attribution to Frontend Mentor. I was wrapping up editing the index.html file by adding an image containing the QR code, a H1 element for the card’s header, and a paragraph containing the additional text. You can view the content of the final index.html version below:

<body>
<div class="container">
    <main class="card">
        <img src="./images/image-qr-code.png" alt="QR Code">
        <h1>Improve your front-end skills by building projects</h1>
        <p>Scan the QR code to visit Frontend Mentor and take your coding skills to the next level</p>
    </main>

    <footer class="attribution">
        Challenge by <a href="https://www.frontendmentor.io?ref=challenge" target="_blank" rel="noopener">Frontend Mentor</a>.<br>
        Coded by <a href="https://onlineblogzone.com/">Online Blog Zone</a>.
    </footer>
</div>
</body>

Setting up the CSS

Now that we completed the template for our QR code, we move on to adding the styling of the page. For this, I added a styles.css file containing all CSS rules for the page. The initial rules are pretty straightforward:

* {
    box-sizing: border-box;
    }

    html {
    font-family: 'Outfit', sans-serif;
    }

The first rule on the * classifier includes the padding and border of all elements to their width and height. Setting the border-box of the * classifier is a personal preference. Next, the font-family of all elements is set to Outfit since the font-family is used for all elements within the HTML block.

body {
    background-color: hsl(212, 45%, 89%);
    display: flex;
    flex-direction: row;
    align-content: center;
    justify-content: center;
    align-items: center;
    height: 100vh;
}

After adding the basic CSS rules, I started styling the content itself. For this, I ensured the whole page had a 100vh (100% device height). Using display: flex, I provided all elements were centered and aligned in vertical and horizontal positions. Last, I set the page’s background color to background-color: hsl(212, 45%, 89%);.

p {
    font-weight: 400;
    font-size: 15px;
}

.container {
    width: 300px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-content: center;
}

The styling of all paragraphs is the same, so I added them to the p classifier. The .container classifier contains all styling rules for the content container. The width is 300px as per the design. The container also has a flex display. Since the elements must be positioned underneath each other, the flex-direction is column.

.card {
    padding: 15px;
    position: relative;
    display: block;
    background-color: hsl(0, 0%, 100%);
    border-radius: 20px;
    text-align: center;
}

.card h1 {
    font-size: 23px;
    font-weight: 700;
    color: hsl(218, 44%, 22%);
}

.card img {
    border-radius: 10px;
    width: 100%;
}

.card p {
    color: hsl(220, 15%, 55%);
}

Finally, we changed the card element and its HTML element children. First, we set some basic rules for the card itself. The image must be full width within the card, and the heading and paragraph must contain the styling as per the design.

Below you can see the results:

Frontend Mentor QR Code 2

Below you can also see the final version of the styles.css file.

* {
    box-sizing: border-box;
}

html {
    font-family: 'Outfit', sans-serif;
}

body {
    background-color: hsl(212, 45%, 89%);
    display: flex;
    flex-direction: row;
    align-content: center;
    justify-content: center;
    align-items: center;
    height: 100vh;
}

p {
    font-weight: 400;
    font-size: 15px;
}

.container {
    width: 300px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-content: center;
}

.card {
    padding: 15px;
    position: relative;
    display: block;
    background-color: hsl(0, 0%, 100%);
    border-radius: 20px;
    text-align: center;
}

.card h1 {
    font-size: 23px;
    font-weight: 700;
    color: hsl(218, 44%, 22%);
}

.card img {
    border-radius: 10px;
    width: 100%;
}

.card p {
    color: hsl(220, 15%, 55%);
}

Conclusion

In conclusion, the QR code component challenge on Frontend Mentor is an excellent opportunity for beginners to improve their coding skills. This solution by both Matthias and Richard provides  a perfect example on how to implement the BEM methodology, the mobile-first workflow, and general HTML & CSS. Using variables for colors and REM makes the code more efficient and easier to scale. As mentioned at the start of this post, you can find both projects here:

If you want to improve your own front-end skills, check out Frontend Mentor here</a

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *