DEV Community

Cover image for How I made a responsive fitness website (with JS)
Lens
Lens

Posted on

How I made a responsive fitness website (with JS)

Introduction

During the three-day weekend, I made a fitness website that's responsive to most devices, it took me a while but, in the end, I'm happy with the outcome. So, in this blog, I'll show you how I made it by explaining each part of the website. If you have any questions, you can comment below. Below this introduction is a codepen for a preview of what the website looks like, but to see it fullscreen go here: fullcreen link.

Table of contents

Responsive Nav

First, we make an icon (which I got from ion-icons) and a nav element where in the nav are paragraphs.

<ion-icon name="menu-outline" class="menu"></ion-icon>
<nav>
<p><ion-icon name="barbell-outline"></ion-icon>Fitco</p>
<p>Home</p>
<p>Prices</p>
<p>About</p>
<p>Courses</p>
<p>Blog</p>
</nav>
Enter fullscreen mode Exit fullscreen mode
  • With CSS we use flex to make the nav bar horizontal then we give it a width of 100% and a height of 5% so it doesn't cover the whole website but stretches across it.
  • We center everything with align-items and justify-content set to center, then give the nav a background-color of red.

  • For the elements in the nav we give their after pseudo-element a transition where the width goes from 0 to 100% when it's hovered making a smooth underline animation (to make it more noticeable I gave it a border when it's hovered).

  • Finally, we give the nav a position of fixed and a high z-index so it always stays on top of the screen. For now, we'll set the menu icon's display to none since we don't need it right now.

nav {
  display: flex;
  width: 100%;
  gap: 10%;
  align-items: center;
  justify-content: center;
  z-index: 4;
  height: 5%;
  border: solid;
  position: fixed;
  background-color: red;
  font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;
}

nav > p {
cursor: pointer;
}


nav > p::after {
  content: "";
  width: 0px;
  transition: 0.3s;
  display: block;
  background-color: black;
}

nav > p:hover::after {
  width: 100%;
  border: solid 1px black;
}

Enter fullscreen mode Exit fullscreen mode

Now we need to make it responsive, we'll make a media query where the nav's display is set to none and the menu is visible when the width of the website is under 580 pixels.

@media (max-width: 580px) {
  .menu {
    display: block;
/*just stylizing the icon ^_^*/
    position: fixed;
    color: white;
    font-size: 50px;
    background-color: red;
    border-radius: 5px;
    left: 10px;
    cursor: pointer;
    z-index: 3;
  }
  nav {
    display: none;
  }
}
Enter fullscreen mode Exit fullscreen mode

Next, we make a custom class for the mobile version of the nav. In it we use the inset property to make it cover up the right side of the page, we'll also set the flex-direction to column so all of the content is vertical. Finally, we set the align-items property to flex-start so we can see the nav content and a position of fixed with a width of 100% so it can always stretch vertically across the website.

.mobil_navbar {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  inset: 0 0 0 60%;
  position: fixed;
  height: 100%;
  gap: 10%;
}
/*To center the text*/
.navbar > p {
  margin-left: 70px;
}

Enter fullscreen mode Exit fullscreen mode



Now we just need JavaScript so whenever we click the menu, the mobile navbar will pop up. All we need to do is give the menu an event listener where when it's clicked the nav element will toggle the mobile navbar class to itself.

var menu = document.querySelector('.menu');
var nav = document.querySelector('nav');

menu.addEventListener('click', function () {
  nav.classList.toggle('mobil_navbar');
})
Enter fullscreen mode Exit fullscreen mode

Results

Nav


Intro section

In the intro section there's a header, pragraph element, and button element inside a div.

<section class="Intro">
<div>
<h1>Keep your body fit any time, all the time</h1>
<p>With fitco, you can always exrcise and track your journey to reach your body goals</p>
<button>Learn More</button>
</div>
</section>
Enter fullscreen mode Exit fullscreen mode

We gave the section a display of flex to align the items onto the center horizontally. We'll make the div small to squeeze all of the content in and make sure it doesn't spread out. Finally, we give the section a background image which I got from Unsplash. For the button, we give it a transition where the colors switch when it's hovered on.

.Intro {
  background-image: url("https://images.unsplash.com/photo-1517836357463-d25dfeac3438?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80");
  color: white;
/* background-size's cover value is important to make the
background-image actually cover the section*/
  background-size: cover;
  font-family: "Poppins";
  display: flex;
  align-items: center;
  font-size: 30px;
  height: 40rem;
}

.Intro > div {
  width: 30rem;
}

/*Stylizing the button*/
.Intro > div > button {
  height: 40px;
  cursor: pointer;
  background-color: transparent;
  color: white;
  border: solid white;
  border-radius: 5px;
  transition: 0.3s;
}

.Intro > div > button:hover {
  color: black;
  background-color: white;
}
Enter fullscreen mode Exit fullscreen mode

Course grid

Inside the lesson section, we make a div with a class called courses that contains the lesson_container. The lesson_container has six div's inside that'll be our grid.

<div class="courses">
<h2 class="hidden">Popular courses</h2>
<div class="lesson_container hidden">
<div class="lesson_card"></div> 
<div class="lesson_card"></div>
<div class="lesson_card"></div>
<div class="lesson_card"></div>
<div class="lesson_card"></div>
<div class="lesson_card"></div>
</div>
</div>
Enter fullscreen mode Exit fullscreen mode

With CSS make the lesson_container a 3-column grid. For the divs in the lesson_container, which we call the lesson_cards, they'll be a 200px square. We give the lesson_card's a height transition and make a psuedo-class for it where when it hovered the height grows. To give each lesson_card a title I position all of their before psuedo-elements below and give them each a specific title. Finally, I give each lesson_card a different background image to match its title.

.lesson_container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  column-gap: 30px;
  row-gap: 60px;
}

.lesson_card {
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: height 0.5s, brightness 0.3s;
    background-size: cover;
    border: solid;
    width: 200px;
    height: 200px;
    cursor: pointer;
}

.lesson_card:hover {
    height: 350px;
}


/* I won't show the background image for each image to
reduce the amount of code in this, but just know there's
5 more selectors like the one below*/
.lesson_card:nth-child(1) {
  background-image: url("https://images.unsplash.com/photo-1603503364272-6e28e046b37a?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=388&q=80");
}


.lesson_card:before {
    content: '';
    position: relative;
    top: 135px;
}

.lesson_card:after {
    display: none;
}

.lesson_card:hover:after {
 display: block;
 margin-right: 80px;
}


.lesson_card:nth-child(1):before {
content: 'Upper body warmup';
}
/*Once again I'm not going to show all of the selectors
to make this shorter, so look for the 5 other titles from the Codepen or the full screen website*/
Enter fullscreen mode Exit fullscreen mode

Results

giff


Custom graph

To make the custom graph in the tracking section we first make a div with a class name called graph and seven div's inside it. Now with CSS, we give the graph a background image that makes it looks like a graph and a display of grid to make the div's inside it vertical. We now separate the div's by setting the graph's gap to 10px. Finally, we give the div's different widths, and there! we now have our graph. The last problem we have is that it's sideways, but all we have to do is rotate the graph 90 degrees using transform: rotate(90deg);.

.graph {
    display: grid;
    border: solid;
    width: 400px;
    height: 400px;
    gap: 10px;
    transform: rotate(-90deg);
background-image: url()/*Im not going to put 
the actual URL here, since it's WAY too big*/;
}

.graph > div {
    background-color: red;
}
Enter fullscreen mode Exit fullscreen mode

Results

Graph


Blog section

I made my three examples in my blog section by putting them in a div called blog_container. It uses flex to put them in a row, but using a media query I made it so that when the width of the website is small one of them is taken away. I also gave them a hover effect where the background changes. I use grid inside each blog to make the content vertical and center the text with text-align: center while centering everything in the blog with place-items: center


.blog_container {
    display: flex;
    gap: 40px;
}
.blogs {
    border-radius: 10px;
    display: grid;
    place-items: center;
    text-align: center;
    width: 220px;
    padding: 30px;
}

.blogs:hover {
    background-color: #4a4e69;
}
Enter fullscreen mode Exit fullscreen mode

Results

blogs


Review section

  • A two-column grid with one being an image and the other containing a div that changes the font size every time the width gets smaller.
.reviews {
    display: grid;
    grid-template-columns: 40% auto;
    place-items: center;
    font-family: 'Poppins';
    height: 30rem;
}

.reviews > div {
    height: 15rem;
    background-color: #1d3557;
    border-radius: 10px;
}

.reviews > div > p {
  font-size: 15px;
}

@media (max-width: 651px) {
  .reviews > .quote > p {
    font-size: 13px;
  }
}

@media (max-width: 465px) {
  .reviews > .quote > p {
    font-size: 12px;
  }
}
Enter fullscreen mode Exit fullscreen mode

Results

review


Footer Nav

The footer nav uses flex to space out the logo and two lists evenly. Each list item in the unordered lists have a hover effect where they turn blue.

HTML

<footer class="about">
<h2 style="text-decoration: none;">
<ion-icon name="barbell-outline"></ion-icon>Fitco
</h2>
<ul class="contacts">
<li>About us</li>
<li>Twitter</li>
<li>Facebook</li>
<li>Jobs</li>
<li>Offers</li>
</ul>
<ul class="contacts">
<li>Lensco</li>
<li>Blog</li>
<li>Github rep</li>
<li>Twitter</li>
</ul>
</footer>
Enter fullscreen mode Exit fullscreen mode

CSS

.about {
    display: flex;
    justify-content: space-around;
    font-family: 'Poppins';
    align-items: center;
}

.contacts {
    list-style-type: none;
    display: grid;
    column-gap: 20px;
}

li {
    cursor: pointer;
}

li:hover {
    color: blue;
}
Enter fullscreen mode Exit fullscreen mode

Results

nav


Slide in transition

With CSS we make a hidden and show class. The hidden class will have an opacity of 0 and is translated on the X-axis by -100%. The show class is the opposite, with an opacity of 1 and no translation.

.hidden {
  opacity: 0;
  transform: translateX(-100%);
  transition: 1s;
}

.show {
  opacity: 1;
  transform: translateX(0);
}
Enter fullscreen mode Exit fullscreen mode

Next, we give the elements we want to have the transition to the hidden class. With JavaScript, we collect all those elements and put them in a variable. We then use the Intersection Observer API function so when something intersects the viewport it'll have the show class added, but if it isn't it'll be removed. We assign the function to all the hidden class elements, and there you have it! You can give it a transition to make it look better.

var hidden = document.querySelectorAll('.hidden');

const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      entry.target.classList.add("show");
    } else {
      entry.target.classList.remove("show");
    }
  });
});

hidden.forEach((el) => observer.observe(el));
Enter fullscreen mode Exit fullscreen mode

Results

Hidden


Conclusion

Even though this may have been the best-looking project I've made, I still need better practice when it comes to making websites responsive. Notice that for the nav part, I did it in bulletins to make it a bit shorter, if you liked it, should I continue using bulletins for my blogs? Anyways I hope this blog helped you or inspired you, and next week I'll be making an E-commerce website, so follow me for more! Have a great Day!

Latest comments (1)

Collapse
 
ilyamarkin profile image
Ilya Markin

Hi, interesting post, thanks for sharing your experience!
I also recommend reading the article on the Gapsy studio blog, which provides practical advice on creating a design for a fitness website and explains why design is important for a website in this industry.