Skip to content

tinchangg/Natours_CSS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🏔️ Natours

A landing page for a fictional travel agency, showcasing CSS skills with custom forms, navigation, and smooth animations.

🔗Live Demo

🛠️Tools & Coding Patterns

This project adopts established methodologies for clean, scalable, and maintainable code, using:

  • SASS/SCSS for modular and maintainable styling

  • BEM (Block, Element, Modifier) for consistent naming conventions and readability

  • 7-1 Architecture for organized, scalable SCSS file structure

🚀Demo

Below are highlights of interactive animations and custom UI elements — all built with pure CSS!

🎞️Keyframe-Based Animation

Smooth entrance effects using @keyframes and the animation property to animate key elements like headings and buttons.

@keyframes moveInLeft {
  0% {
    opacity: 0;
    transform: translateX(-10rem);
  }

  80% {
    transform: translateX(1rem);
  }

  100% {
    opacity: 1;
    transform: translate(0);
  }
}

🃏3D Card Flip Animation

Cards flip on hover to reveal additional details using transform, perspective, and backface-visibility to create a 3D flipping effect.

.card {
  perspective: 150rem; // For the flipping effects
  position: relative;
  height: 52rem;

  // Card div -> both sides of the card
  &__side {
    // ...other styling omitted...

    // Stack two cards together -> create two sides
    position: absolute;
    top: 0;
    left: 0;
    backface-visibility: hidden; // To hide the back part of the element

    transition: all 0.6s ease;

    // Front side
    &--front {
      // ...other styling omitted...
    }

    // Back side
    &--back {
      // Make back side already rotated at the begining
      transform: rotateY(180deg);

      // ...other styling omitted...
    }
  }

  // When hover on the card container -> rotate both sides
  &:hover &__side--front {
    transform: rotateY(180deg);
  }

  &:hover &__side--back {
    transform: rotateY(360deg);
  }
}

📩CSS-Only Popup Modal

A lightweight popup modal triggered by the :target pseudo-class — no JavaScript required.

.popup {
  // Black background
  // ...

  // Functionality -> hide and show the entire popup
  opacity: 0;
  visibility: hidden;
  transition: all 0.2s;

  &:target {
    opacity: 1;
    visibility: visible;
  }

  // Popup window -> the container
  &__content {
    // ...other styling omitted...

    transform: scale(0.1);
    opacity: 0;
    transition: all 0.3s 0.15s; // Set a delay
  }

  &:target &__content {
    transform: scale(1);
    opacity: 1;
  }
}

📝Interative Custom Form

Live validation and floating labels using pseudo-classes like :focus, :invalid, and :placeholder-shown. Custom radio buttons are styled with hidden inputs and the :checked selector.

.form {
  // Overall styling
  // ...

  // Input styling
  &__input {
    // ...other styling omitted...

    // Focus -> improve accessibility
    &:focus {
      outline: none;
      border-bottom: 3px solid $color-primary;
      box-shadow: 0 1rem 2rem rgba($color-black, 0.1);

      // Invalid -> provide live feedback
      &:invalid {
        border-bottom: 3px solid $color-secondary-dark;
      }
    }

    &::placeholder {
      // ...other styling omitted...
    }
  }

  // Label styling
  &__label {
    // ...other styling omitted...

    transition: all 0.2s;
  }

  // Floating label effects
  &__input:placeholder-shown + &__label {
    // Hide the label -> placeholder not shown, label floats in
    visibility: hidden;
    opacity: 0;
    transform: translateY(-4rem);
  }

  // Custom radio button
  &__radio-group {
    // ...other styling omitted...
  }

  // Hide the default input -> leverage the :checked selector
  &__radio-input {
    display: none;
  }

  &__radio-label {
    // ...other styling omitted...
  }

  // Build customized radio botton
  &__radio-button {
    display: inline-block;
    // Build the outline of the circle
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    border: 3.5px solid $color-primary;
    position: absolute;
    top: -0.3rem;
    left: 0;

    // Build the inner circle
    &::after {
      content: "";
      display: block;

      width: 1rem;
      height: 1rem;
      border-radius: 50%;
      background-color: $color-primary;
      opacity: 0; // Hide the circle -> only shown when checked
      transition: opacity 0.15s;

      // Center the circle
      @include absolute-center;
    }
  }

  // Checked effects -> using :checked and adjancent selector
  &__radio-input:checked + &__radio-label &__radio-button::after {
    opacity: 1;
  }
}

Navigation

A floating button toggles a full-screen menu using a hidden checkbox and the :checked selector. Icon transitions are handled via ::before and ::after pseudo-elements.

.navigation {
  // Hidden checkbox input -> leverage :checked selector
  &__checkbox {
    display: none;
  }

  // Button -> checkbox label
  &__button {
    // ...other styling omitted...
  }

  // Background image -> hidden behind the label
  &__background {
    // ...other styling omitted...

    // Menu extended effects -> using hidden checkbox
    transition: transform 0.7s cubic-bezier(0.83, 0, 0.17, 1);
  }

  // Menu container
  &__nav {
    // ...other styling omitted...

    // Hide the menu until checkbox were checked
    width: 0;
    opacity: 0;
    transition: all 0.7s cubic-bezier(0.68, -0.6, 0.32, 1.6);
  }

  // Menu -> unorder list
  &__list {
    // ...other styling omitted...
  }

  // Menu item -> list item
  &__item {
    // ...other styling omitted...
  }

  // Menu text -> anchor tag in the list item
  &__link {
    // Numerical marks -> simply used attribute selector to avoid complexity
    span {
      display: inline-block;
      margin-right: 1.5rem;
    }

    // Text
    &:link,
    &:visited {
      // ...other styling omitted...

      // For hover effects
      background-image: linear-gradient(
        120deg,
        transparent 0%,
        transparent 50%,
        $color-white 50%
      );
      background-size: 240%;
      transition: all 0.3s;
    }

    &:hover,
    &:active {
      background-position: 100%;
      color: $color-primary;
      transform: translateX(1rem);
    }
  }

  // Navigation functionality -> achieve by hidden checkbox
  &__checkbox:checked ~ &__background {
    transform: scale(80);
  }

  &__checkbox:checked ~ &__nav {
    width: 100%;
    opacity: 1;
  }

  // Menu icon -> span in the checkbox label
  &__icon {
    position: relative;
    margin-top: 3.4rem;

    &,
    &::before,
    &::after {
      width: 3rem;
      height: 2px;
      border-radius: 10px;
      background-color: $color-grey-dark-3;
      display: inline-block;
      transition: all 0.3s;
    }

    &::before,
    &::after {
      content: "";
      position: absolute;
      left: 0;
    }

    &::before {
      top: -0.8rem;
    }

    &::after {
      top: 0.8rem;
    }
  }

  // Menu icon hover effects
  &__button:hover &__icon {
    transform: translateY(-0.1rem);

    &::before {
      top: -1rem;
    }

    &::after {
      top: 1rem;
    }
  }

  // Menu icon clicked effects -> using the hidden checkbox
  &__checkbox:checked + &__button &__icon {
    background-color: transparent;

    &::before {
      top: 0;
      transform: rotate(
        135deg
      ); // 180deg - 45deg -> to make the animation more dramatic
    }

    &::after {
      top: 0;
      transform: rotate(
        -135deg
      ); // -180deg -(-45deg) -> to make the animation more dramatic
    }
  }
}

©️ Copyright & Credits

This project is built under the guidance of Jonas Schmedtmann's Advanced CSS course.
All design credits go to Jonas Schmedtmann.