How I made a responsive fitness website (with JS)
Tags: tutorial, html, css, webdev
Published: 2023-01-18 23:55:23

#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](https://Fitness-Website.lensco825.repl.co). 
{% codepen https://codepen.io/lensco825/pen/PoBJBZa %}
##Table of contents
* [Responsive nav bar](#nav)
* [Intro section](#Intro)
* [Course Grid](#grid)
* [Custom Graph](#graph)
* [Blog Section](#blog)
* [Review Section](#review)
* [Footer Nav](#footer)
* [Slide In Transition](#transition)
* [Conclusion](#conclusion)
<hr>

## Responsive Nav <a name="nav"></a>
First, we make an icon (which I got from ion-icons) and a nav element where in the nav are paragraphs.

```html
<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>
```

- 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.

```CSS
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;
}

```
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. 

```CSS
@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;
  }
}
```
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.
```css
.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;
}

```
<br>
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. 

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

menu.addEventListener('click', function () {
  nav.classList.toggle('mobil_navbar');
})
```
###Results
![Nav](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5m9u0fb7tw0f8nilmmyz.gif)
<hr>
#Intro section <a name="Intro"></a>
In the intro section there's a header, pragraph element, and button element inside a div.
```html
<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>
```
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. 

```css
.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;
}
```
<hr>
#Course grid <a name="grid"></a>
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.

```html
<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>
```
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. 

```css
.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*/
```
###Results
![giff](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oinhk6ljdx7jagzod40b.gif)
<hr>
#Custom graph <a name="graph"></a>
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);`.

```css
.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;
}
```
###Results
![Graph](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1keyoksuarz0jir37jrk.png)
<hr>
#Blog section <a name="blog"></a>
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`

```css

.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;
}
```
###Results
![blogs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/56z2cwiw079iqf2js0r4.gif)

<hr>
#Review section <a name="review"></a>
- 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.

```css
.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;
  }
}
```
###Results
![review](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/juvger9yzas1irko843v.png)

<hr>
#Footer Nav <a name="footer"></a>
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
```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>
```
###CSS

```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;
}
```
###Results

![nav](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ntvbncuk4kz6ebqovnsh.png)


<hr>
# Slide in transition <a name="transition"></a>
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. 

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

.show {
  opacity: 1;
  transform: translateX(0);
}
```
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.

``` js
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));
```
###Results
![Hidden](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tjhg9inx3d29atsl48x4.gif)
<hr>
#Conclusion <a name="conclusion"></a>
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!