In this post, we’ll see how to add a sidebar like the one displayed below when pressing the button.
It’s responsive to the user’s viewport size. It slides horizontally from the right, but if the viewport width is less than 768 px, it will slide up from the bottom.
The lateral sidebar is commonly used as a navigation menu. The variation that slides up from the bottom is useful to display navigation options or extra content. For example, setting the parameters to filter products on an e-commerce website, or displaying additional information after clicking on an element.
Sidebar markup
Let’s start by setting up the markup.
<div class="sidebar"> <button class="close_button">×</button> <!-- Sidebar content comes here --> <p>Hello World!</p> </div>
The sidebar is just a div
container inside which we place the contents of the sidebar. We also add a button to close it.
Mobile CSS styles
We will design the sidebar mobile-first, meaning the default CSS rules will be aimed towards mobile devices.
Without styling, the sidebar div will be rendered like a regular paragraph with a button. We use the following CSS rules to stick it to the left-bottom corner of the page.
* { margin: 0; padding: 0; box-sizing: border-box; } .sidebar { position: fixed; bottom: 0; left: 0; height: 60%; border-top: solid 1px #969696; border-radius: 15px 15px 0 0; width: 100%; box-shadow: 4px 3px 8px 1px #969696; animation: slide-up ease-out 400ms forwards; background: #fff; z-index: 1000; } .sidebar p { padding: 1rem; } .close_button { position: absolute; top: 1rem; right: 20px; background: #000; border: none; width: 30px; height: 30px; color: #fff; font-size: 130%; border-radius: 15px; display: flex; justify-content: center; align-items: center; padding: 0; cursor: pointer; } @keyframes slide-up { 0% { height: 0; } 100% { height: 60%; } }
The most important CSS rules are position: fixed
, bottom: 0
and height: 60%
. They position the sidebar fixed to the bottom of the viewport, and up to 60% of the viewport’s height.
The slide-up
animation will generate a slide-up effect by gradually varying the sidebar height.
With these rules, our sidebar will be rendered as follows.
Desktop styles
We would like the sidebar to show on the right side of the screen when the viewport is large enough. To do so, we’ll modify the CSS rules based on the viewport size using media queries. The main idea is to fix the sidebar at the top-right corner of the viewport, set its height to 100% and the width to 40%.
@media (min-width: 768px) { .sidebar { top: 0; height: 100%; left: unset; right: 0; width: 40%; border-top: unset; border-left: solid 1px #969696; border-radius: 15px 0 0 15px; animation-name: slide-left; } } @keyframes slide-left { 0% { width: 0; } 100% { width: 40%; } }
The block above needs to be added after the first .sidebar
block that contains the mobile rules.
Additionally, we need to slightly modify the close button rules.
@media (min-width: 768px) { .close_button { left: 90%; } }
Initially, the close button was absolutely positioned relative to the right end of the sidebar. While this styling could work for the desktop layout as well, I found that the close button did not respond to the close animation. Possibly because closing the sidebar does not change the right
property of the sidebar. Positioning the close button relative to the left
end of the container solved this issue.
The sidebar will be displayed as follows on devices with a widht of more than 768 px
.
Close sidebar animation
Closing the sidebar will be executed by setting the height
property to 0
(for mobile) and setting the width
property to 0
(for desktop). We will add a close_sidebar
class that handles this transition with an animation.
.close_sidebar { animation-name: slide-down; } @media (min-width: 768px) { .close_sidebar { animation-name: slide-right; } }
The corresponding animations are:
@keyframes slide-down { 0% { height: 60%; } 100% { height: 0; } } @keyframes slide-right { 0% { width: 40%; } 100% { width: 0; } }
Close sidebar handler
At this stage, the sidebar can’t be closed by clicking the close button. Let’s define the following close handler:
const closeHandler = () => document.querySelector(".sidebar").classList.add("close_sidebar");
Then we add it as an event listener to the close button.
document.querySelector(".close_button").addEventListener("click", closeHandler);
By doing so, we’ll be able to close the sidebar by pressing the close button.
While this approach is functional, what we’re doing is only hiding the sidebar by setting its height or width to zero. To be more effective, we’ll also remove it from the layout with the following CSS class.
.hidden { display: none; }
We’ll add this new hidden
class to the sidebar after closing it. Let’s modify the close handler as follows:
const closeHandler = () => { document.querySelector(".sidebar").classList.add("close_sidebar"); setTimeout(() => { document.querySelector(".sidebar").classList.add("hidden"); document.querySelector(".sidebar").classList.remove("close_sidebar"); }, 400); };
Note that we trigger the hidden class only after a delay of 400 ms (the time it takes the close animation to play). If we directly added the hidden
class to the sidebar, it would disappear immediately without the smooth animation. Additionally, we also remove the close_sidebar
class so that they don’t conflict with the default opening sidebar rules.
Open sidebar handler
Opening the sidebar can be done by simply removing the hidden
class.
const openHandler = () => document.querySelector(".sidebar").classList.remove("hidden");
We can add this handler to any button or HTML element we want to trigger the sidebar.
document.getElementById("open_sidebar_button").addEventListener("click", openHandler);
Putting it all together
We can create a simple working example as follows.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Sidebar example</title> <link rel="stylesheet" href="styles.css" /> </head> <body> <div class="sidebar hidden"> <button class="close_button">×</button> <p>Hello World!</p> </div> <button id="open_sidebar_button">Open</button> <script src="scripts.js"></script> </body> </html>
Note that the sidebar element is initially part of the hidden
class.
/* styles.css */ * { margin: 0; padding: 0; box-sizing: border-box; } .sidebar { position: fixed; bottom: 0; left: 0; height: 60%; border-top: solid 1px #969696; border-radius: 15px 15px 0 0; width: 100%; box-shadow: 4px 3px 8px 1px #969696; animation: slide-up ease-out 400ms forwards; background: #fff; z-index: 1000; } .sidebar p { padding: 1rem; } @media (min-width: 768px) { .sidebar { top: 0; height: 100%; left: unset; right: 0; width: 40%; border-top: unset; border-left: solid 1px #969696; border-radius: 15px 0 0 15px; animation-name: slide-left; } } .close_button { position: absolute; top: 1rem; right: 20px; background: #000; border: none; width: 30px; height: 30px; color: #fff; font-size: 130%; border-radius: 15px; display: flex; justify-content: center; align-items: center; padding: 0; cursor: pointer; } @media (min-width: 768px) { .close_button { left: 90%; } } .close_sidebar { animation-name: slide-down; } .hidden { display: none; } @media (min-width: 768px) { .close_sidebar { animation-name: slide-right; } } @keyframes slide-up { 0% { height: 0; } 100% { height: 60%; } } @keyframes slide-down { 0% { height: 60%; } 100% { height: 0; } } @keyframes slide-left { 0% { width: 0; } 100% { width: 40%; } } @keyframes slide-right { 0% { width: 40%; } 100% { width: 0; } }
// scripts.js const openHandler = () => document.querySelector(".sidebar").classList.remove("hidden"); const closeHandler = () => { document.querySelector(".sidebar").classList.add("close_sidebar"); setTimeout(() => { document.querySelector(".sidebar").classList.add("hidden"); document.querySelector(".sidebar").classList.remove("close_sidebar"); }, 400); }; document .getElementById("open_sidebar_button") .addEventListener("click", openHandler); document.querySelector(".close_button").addEventListener("click", closeHandler);
This markup along with the CSS styles and the JS scripts will be rendered as the sidebar that we saw at the beginning of this post.
It is possible to do a gradient on borders but it takes a little bit of trickery. For example: https://codeprozone.com/code/css/38095/css-gradient-border.html