├── README.md ├── assets ├── css │ └── styles.css ├── img │ └── indicator.svg ├── js │ └── main.js └── scss │ ├── base │ └── _base.scss │ ├── components │ ├── _breakpoints.scss │ └── _navbar.scss │ ├── config │ └── _variables.scss │ └── styles.scss ├── index.html └── preview.png /README.md: -------------------------------------------------------------------------------- 1 | # 💧Liquid Navigation Menu Indicator 2 | ## [Watch it on youtube](https://youtu.be/argynmjupK8) 3 | ### 💧Liquid Navigation Menu Indicator 4 | 5 | - Liquid Navigation Menu Indicator Using HTML CSS & JavaScript 6 | - Smooth scrolling in each section. 7 | - Developed first with the Mobile First methodology, then for desktop. 8 | - Compatible with all mobile devices and with a beautiful and pleasant user interface. 9 | 10 | 💙 Join the channel to see more videos like this. [Bedimcode](https://www.youtube.com/c/Bedimcode) 11 | 12 |  13 | -------------------------------------------------------------------------------- /assets/css/styles.css: -------------------------------------------------------------------------------- 1 | /*=============== GOOGLE FONTS ===============*/ 2 | @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap"); 3 | 4 | /*=============== VARIABLES CSS ===============*/ 5 | :root { 6 | /*========== Colors ==========*/ 7 | --first-color: hsl(231, 48%, 56%); 8 | --title-color: hsl(231, 24%, 20%); 9 | --text-color: hsl(231, 4%, 45%); 10 | --body-color: hsl(231, 100%, 99%); 11 | --container-color: #fff; 12 | 13 | /*========== Font and typography ==========*/ 14 | --body-font: 'Poppins', sans-serif; 15 | --tiny-font-size: .625rem; 16 | } 17 | 18 | @media screen and (min-width: 968px) { 19 | :root { 20 | --tiny-font-size: .688rem; 21 | } 22 | } 23 | 24 | /*=============== BASE ===============*/ 25 | * { 26 | box-sizing: border-box; 27 | padding: 0; 28 | margin: 0; 29 | } 30 | 31 | html { 32 | scroll-behavior: smooth; 33 | } 34 | 35 | body { 36 | font-family: var(--body-font); 37 | background-color: var(--body-color); 38 | color: var(--text-color); 39 | } 40 | 41 | ul { 42 | list-style: none; 43 | } 44 | 45 | a { 46 | text-decoration: none; 47 | } 48 | 49 | /*=============== NAVBAR ===============*/ 50 | .container { 51 | max-width: 968px; 52 | margin-left: 1.5rem; 53 | margin-right: 1.5rem; 54 | } 55 | 56 | /*Remove the property of 100vh, when inserting its content*/ 57 | .container section { 58 | height: 100vh; 59 | padding: 2rem 0; 60 | } 61 | 62 | .container h2 { 63 | text-align: center; 64 | color: var(--title-color); 65 | } 66 | 67 | .nav { 68 | position: fixed; 69 | bottom: 2rem; 70 | left: 0; 71 | right: 0; 72 | width: 328px; 73 | height: 72px; 74 | background-color: var(--container-color); 75 | box-shadow: 0 8px 32px hsla(231, 44%, 45%, .2); 76 | margin: 0 auto; 77 | padding: 1.5rem .5rem; 78 | border-radius: .65rem; 79 | overflow: hidden; 80 | } 81 | 82 | .nav__list { 83 | display: flex; 84 | justify-content: center; 85 | column-gap: 2rem; 86 | } 87 | 88 | .nav__link { 89 | display: flex; 90 | flex-direction: column; 91 | align-items: center; 92 | } 93 | 94 | .nav__link i { 95 | font-size: 1.5rem; 96 | color: var(--title-color); 97 | z-index: 20; 98 | transition: .3s; 99 | } 100 | 101 | .nav__name { 102 | font-size: var(--tiny-font-size); 103 | position: absolute; 104 | font-weight: 500; 105 | transition: .4s; 106 | transform: translateY(50px); 107 | z-index: 20; 108 | color: var(--body-color); 109 | opacity: 0; 110 | } 111 | 112 | /* Indicator link */ 113 | .indicator { 114 | position: absolute; 115 | left: 5px; 116 | bottom: 0; 117 | fill: var(--first-color); 118 | transition: .3s; 119 | } 120 | 121 | /* Active link */ 122 | .active-link i { 123 | color: var(--body-color); 124 | } 125 | 126 | .active-link .nav__name { 127 | opacity: 1; 128 | transform: translateY(28px); 129 | } 130 | 131 | /* Move indicator */ 132 | .nav__link:nth-child(1).active-link ~ .indicator { 133 | transform: translateX(calc(56px * 0)); 134 | } 135 | 136 | .nav__link:nth-child(2).active-link ~ .indicator { 137 | transform: translateX(calc(56px * 1)); 138 | } 139 | 140 | .nav__link:nth-child(3).active-link ~ .indicator { 141 | transform: translateX(calc(56px * 2)); 142 | } 143 | 144 | .nav__link:nth-child(4).active-link ~ .indicator { 145 | transform: translateX(calc(56px * 3)); 146 | } 147 | 148 | .nav__link:nth-child(5).active-link ~ .indicator { 149 | transform: translateX(calc(56px * 4)); 150 | } 151 | 152 | /*=============== BREAKPOINTS ===============*/ 153 | /* For small devices */ 154 | @media screen and (max-width: 320px) { 155 | .nav { 156 | zoom: .8; 157 | } 158 | } 159 | 160 | /* For large devices */ 161 | @media screen and (min-width: 968px) { 162 | .container { 163 | margin-left: auto; 164 | margin-right: auto; 165 | } 166 | .nav { 167 | zoom: 1.1; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /assets/img/indicator.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/js/main.js: -------------------------------------------------------------------------------- 1 | /*=============== SCROLL SECTIONS ACTIVE LINK ===============*/ 2 | const sections = document.querySelectorAll('section[id]') 3 | 4 | function scrollActive(){ 5 | const scrollY = window.pageYOffset 6 | 7 | sections.forEach(current =>{ 8 | const sectionHeight = current.offsetHeight, 9 | sectionTop = current.offsetTop - 58, 10 | sectionId = current.getAttribute('id') 11 | 12 | if(scrollY > sectionTop && scrollY <= sectionTop + sectionHeight){ 13 | document.querySelector('.nav__list a[href*=' + sectionId + ']').classList.add('active-link') 14 | }else{ 15 | document.querySelector('.nav__list a[href*=' + sectionId + ']').classList.remove('active-link') 16 | } 17 | }) 18 | } 19 | window.addEventListener('scroll', scrollActive) 20 | 21 | /* If you do not require the indicator activated by scrolling sections. 22 | Delete the main tag code in HTML and the scroll sections code in 23 | JavaScript. 24 | 25 | And uncomment the active link code in JavaScript 👇. 26 | */ 27 | 28 | /*=============== ACTIVE LINK ===============*/ 29 | // const navlink = document.querySelectorAll('.nav__link') 30 | 31 | // function activeLink(){ 32 | // navlink.forEach((item) => item.classList.remove('active-link')) 33 | // this.classList.add('active-link') 34 | // } 35 | 36 | // navlink.forEach((item) => item.addEventListener('click', activeLink)) -------------------------------------------------------------------------------- /assets/scss/base/_base.scss: -------------------------------------------------------------------------------- 1 | /*=============== BASE ===============*/ 2 | *{ 3 | box-sizing: border-box; 4 | padding: 0; 5 | margin: 0; 6 | } 7 | 8 | html{ 9 | scroll-behavior: smooth; 10 | } 11 | 12 | body{ 13 | font-family: var(--body-font); 14 | background-color: var(--body-color); 15 | color: var(--text-color); 16 | } 17 | 18 | ul{ 19 | list-style: none; 20 | } 21 | 22 | a{ 23 | text-decoration: none; 24 | } -------------------------------------------------------------------------------- /assets/scss/components/_breakpoints.scss: -------------------------------------------------------------------------------- 1 | /*=============== BREAKPOINTS ===============*/ 2 | /* For small devices */ 3 | @media screen and (max-width: 320px){ 4 | .nav{ 5 | zoom: .8; 6 | } 7 | } 8 | 9 | /* For large devices */ 10 | @media screen and (min-width: 968px){ 11 | .container{ 12 | margin-left: auto; 13 | margin-right: auto; 14 | } 15 | 16 | .nav{ 17 | zoom: 1.1; 18 | } 19 | } -------------------------------------------------------------------------------- /assets/scss/components/_navbar.scss: -------------------------------------------------------------------------------- 1 | /*=============== NAVBAR ===============*/ 2 | .container{ 3 | max-width: 968px; 4 | margin-left: 1.5rem; 5 | margin-right: 1.5rem; 6 | 7 | //Remove the property of 100vh, when inserting its content 8 | & section{ 9 | height: 100vh; 10 | padding: 2rem 0; 11 | } 12 | & h2{ 13 | text-align: center; 14 | color: var(--title-color); 15 | } 16 | } 17 | 18 | .nav{ 19 | position: fixed; 20 | bottom: 2rem; 21 | left: 0; 22 | right: 0; 23 | width: 328px; 24 | height: 72px; 25 | background-color: var(--container-color); 26 | box-shadow: 0 8px 32px hsla(231, 44%, 45%, .2); 27 | margin: 0 auto; 28 | padding: 1.5rem .5rem; 29 | border-radius: .65rem; 30 | overflow: hidden; 31 | 32 | &__list{ 33 | display: flex; 34 | justify-content: center; 35 | column-gap: 2rem; 36 | } 37 | &__link{ 38 | display: flex; 39 | flex-direction: column; 40 | align-items: center; 41 | 42 | & i{ 43 | font-size: 1.5rem; 44 | color: var(--title-color); 45 | z-index: 20; 46 | transition: .3s; 47 | } 48 | } 49 | &__name{ 50 | font-size: var(--tiny-font-size); 51 | position: absolute; 52 | font-weight: 500; 53 | transition: .4s; 54 | transform: translateY(50px); 55 | z-index: 20; 56 | color: var(--body-color); 57 | opacity: 0; 58 | } 59 | } 60 | 61 | /* Indicator link */ 62 | .indicator{ 63 | position: absolute; 64 | left: 5px; 65 | bottom: 0; 66 | fill: var(--first-color); 67 | transition: .3s; 68 | } 69 | 70 | /* Active link */ 71 | .active-link i{ 72 | color: var(--body-color); 73 | } 74 | 75 | .active-link .nav__name{ 76 | opacity: 1; 77 | transform: translateY(28px); 78 | } 79 | 80 | /* Move indicator */ 81 | .nav__link:nth-child(1).active-link ~ .indicator{ 82 | transform: translateX(calc(56px * 0)); 83 | } 84 | .nav__link:nth-child(2).active-link ~ .indicator{ 85 | transform: translateX(calc(56px * 1)); 86 | } 87 | .nav__link:nth-child(3).active-link ~ .indicator{ 88 | transform: translateX(calc(56px * 2)); 89 | } 90 | .nav__link:nth-child(4).active-link ~ .indicator{ 91 | transform: translateX(calc(56px * 3)); 92 | } 93 | .nav__link:nth-child(5).active-link ~ .indicator{ 94 | transform: translateX(calc(56px * 4)); 95 | } -------------------------------------------------------------------------------- /assets/scss/config/_variables.scss: -------------------------------------------------------------------------------- 1 | /*=============== GOOGLE FONTS ===============*/ 2 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap'); 3 | 4 | /*=============== VARIABLES CSS ===============*/ 5 | :root{ 6 | /*========== Colors ==========*/ 7 | --first-color: hsl(231, 48%, 56%); 8 | --title-color: hsl(231, 24%, 20%); 9 | --text-color: hsl(231, 4%, 45%); 10 | --body-color: hsl(231, 100%, 99%); 11 | --container-color: #fff; 12 | 13 | /*========== Font and typography ==========*/ 14 | --body-font: 'Poppins', sans-serif; 15 | --tiny-font-size: .625rem; 16 | 17 | // Responsive typography 18 | @media screen and (min-width: 968px){ 19 | --tiny-font-size: .688rem; 20 | } 21 | } -------------------------------------------------------------------------------- /assets/scss/styles.scss: -------------------------------------------------------------------------------- 1 | @import 'config/variables'; 2 | @import 'base/base'; 3 | @import 'components/navbar'; 4 | @import 'components/breakpoints'; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |