Understand CSS Variables and Animations by Building A pimped up And Responsive Navbar
CSS variables are widely used by the web masters to perform tricks that amaze everybody. Let's learn what it is and how to use it.
Variables
Variables are essential part of programming languages and most recently cascading style sheets (CSS). These variables are used to store information to be referenced and manipulated in a computer program. They also provide a way of labeling data with a descriptive name, so our programs can be understood more clearly by the reader and ourselves.
What are CSS Variables
CSS variables also known as custom properties are entities defined by CSS authors that contain specific values to be reused throughout a document. They are set using custom property notation (e.g., --bg-color-light: ash;
) and are accessed using the var()
function (e.g., background-color: var( --bg-color-light);
).
CSS variables are very essential for use in a large websites that require the usage of the same property value through out the site. For instance, a particular duration might be used to handle animations through out a site and if the duration needs to be changed, the change will only be performed at the variable set in the global state.
CSS variables can be set globally inside the :root
selector so that it can be accessed by every element of the HTML document. It can also be scoped locally inside a particular element using a class, id or other CSS selectors. Also, they are case sensitive meaning that site-color
is different from site-Color
. For this example, I set different background color for each button by using variables such as style="--bgColorItem: #f54888"
. This variables would be used in the style.css
to set the background-color
for each button( or .menu__items)
.
Here is an example of a basic usage of CSS variables:
Note: CSS variables values can be changed in an HTML or JavaScript file.
Building Out The Navbar skeleton
To build the navbar, our codebase will consist of an HTML, CSS and script file.
In the HTML file, we will create an element with class of .wrapper
that wraps the whole app. It will contain two elements: nav
and a div
.
The nav
will contain five buttons
. The button
will contain a svg
element.The div
element will contain it's own svg
tag too.
In the CSS file, it will contain a basic styling to show the svg and its container in it's most crooked way.
Here is the skeleton codes:
Styling the Navbar
.wrapper style
We will begin with the wrapper class by adding a transition to handle the background-color
change. You can style the wrapper the way you want.
.wrapper {
background-color: #ffb457;
-webkit-tap-highlight-color: transparent;
/* Styling */
transition: background-color var(--duration);
display: flex;
justify-content: center;
padding: 6em 0;
}
.icon style
The next step is to set the style of the icon. The styles would give the icons the shapes they will take for the rest of the project.
.icon {
/* Helps view the icon */
width: 2.6em;
height: 2.6em;
stroke: white;
/* End of help */
/* Beautification styling */
stroke-width: 0.1em;
stroke-dasharray: 400;
stroke-miterlimit: 10;
stroke-linecap: round;
stroke-linejoin: round;
/* End of Beautification styling */
}
.menu style
The .menu
class is used to grab the nav
tag which is essentially all the button
container. We will also set the media query
for smaller screens.
We will make use of the --bgColorMenu
variable in the :root
selector to style the background color.
.menu {
width: 32.05em;
font-size: 1.5em;
background-color: var(--bgColorMenu);
display: flex;
justify-content: center;
padding: 0 2.85em;
position: relative;
}
@media screen and (max-width: 50em) {
.menu {
font-size: 0.8em;
}
}
.menu__item style
The .menu__item
selects the button
. Here, we first of all unset every possible css property using the all: unset
property. We also use the timeOut variable just to toggle the value of the transform from undefined to the duration specified. It somewhat acts like a memory cleanup for the navbar.
We also style the pseudo element before it so we can toggle the transition property with Javascript. This essentially sets the round underlay on the button.
We also style the active element by moving it up a bit using the transform: translateY()
property and value. The active class background color is set to a scoped color set on the each button
. Check the HTML file to see the colors set in its style.
The smooth animation of the icons is handled using the stroker
keyframes by using the stroke-dashoffset
property.
.menu__item {
/* "all" resets every property of an element and requires you to set each property yourself */
all: unset;
flex-grow: 1;
z-index: 1;
position: relative;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
padding: 0.55em 0 0.85em;
border-radius: 50%;
/* The var inside a var is used as a kind of if statement. If the first isn't available, it uses the second one and vice versa */
transition: transform var(--timeOut, var(--duration));
will-change: transform;
}
.menu__item::before {
content: "";
position: absolute;
z-index: -1;
width: 4.4em;
height: 4.4em;
border-radius: 50%;
transform: scale(0);
/* You can combine two or more properties in transition */
transition: background-color var(--duration), transform var(--duration);
}
.menu__item.active {
/* This and the transition above handles the movement of the active button */
transform: translateY(-0.8em);
}
.menu__item.active::before {
transform: scale(1);
/* This handles the changing color of active button */
background-color: var(--bgColorItem);
}
/* This handles movement of the icons from left to right */
.menu__item.active .icon {
/* The reverse direction offers a smother experience */
animation: stroker 1.5s reverse;
}
@keyframes stroker {
100% {
stroke-dashoffset: 400;
}
}
menu__border style
The menu__border
essentially appears over the icon on press or click. We will toggle it's current position using JavaScript but for the moment, let's give it a default position.
We begin by grabbing the svg
using the #menu
id set in the HTML. Next, we set it's position to absolute and the .svg-container
to a height and width of zero.
.menu__border {
/* Access the svg using id from the html */
clip-path: url(#menu);
position: absolute;
left: 0;
bottom: 99%;
/* Handle size of svg in with id menu */
width: 10.9em;
height: 2.7em;
background-color: var(--bgColorMenu);
transition: transform var(--timeOut, var(--duration));
will-change: transform;
}
.svg-container {
width: 0;
height: 0;
}
The full styling should look like this:
Add The Toggle Functionality
We are done with the essential styling but the buttons do not respond on click. To make them work, we use Javascript.
Grab The DOM Elements
The first step is to grab all the elements we want using querySelector or querySelectorAll
and specify the background colors to be used in an array:
const wrapper = document.querySelector(".wrapper");
const menu = document.querySelector(".menu");
const menuItems = document.querySelectorAll(".menu__item");
const menuBorder = document.querySelector(".menu__border");
let activeItem = document.querySelector(".active");
const backgroundColors = [
"#ffb457",
"#ff96bd",
"#9999fb",
"#ffe797",
"#cffff1",
];
Create the handleClick function
The handleClick
functions takes in an item
and index
parameters. It is the entry point to the whole Navbar toggling.
function handleClick(item, index) {
if (item === activeItem) return;
if (activeItem) {
activeItem.classList.remove("active");
}
item.classList.add("active");
wrapper.style.backgroundColor = backgroundColors[index];
activeItem = item;
}
`
Add Click Event Listener to the Menu Items
This is achieved by iterating through the nodelist provided by the querySelectorAll when grabbing the .menu__item
elements.
menuItems.forEach((item, index) => {
item.addEventListener("click", () => handleClick(item, index));
});
Handle Position of the Menu Border
We can achieve this by creating a function that takes the activeItem
and menuBorder
. Then we use the activeItem
width, left distance, the menuBorder
offsetWidth and the menu
offsetLeft to transform the menuBorder
by translateX()
.
Handle Animations on window resize
To achieve this we listen to the resize event on the window like this:
window.addEventListener("resize", () => {
handleBorderPosition(activeItem, menuBorder);
});
Enable Synced behavior between menuBorder and activeItem backgroundColor
To do this, set the property of --timeOut
to none
like this:
menu.style.setProperty("--timeOut", "none");
, in the resize eventListener.
Also, remove the property timeOut
at the topmost part of the handleClick
function like this:
menu.style.removeProperty("--timeOut");
The final product should look similar to this:
Conclusion
To conclude, the CSS variable is a very powerful aspect of CSS that can be used to create very powerful animations and beautiful interfaces based on user preferences such as themes. We need opportuinity to use it the more to get very exciting and amazing results.
Shout Outs and Appreciations:
Designed by: Mauricio Bucardo
Original image: dribbble.com/shots/5619509-Animated-Tab-Bar