Elegant rounded bordered sidebar design to highlight selected navigation items using HTML and CSS

I am looking to replicate the sidebar design displayed in the image below by using HTML and CSS. While I have successfully rounded the borders on the left side of a selected link, I am stuck when it comes to rounding the borders on the right side.

Answer №1

Utilize the :before and :after selectors strategically. Implement :after for border radius at the end. Additionally, experiment with the :has selector to apply CSS styles to the previous element (compatibility may vary among browsers).

Note: If needed, you can use JavaScript for click events to select elements.

Check out the code snippet below:

const items = document.querySelectorAll(".item");

items.forEach(item=>{
  item.addEventListener("click", (event)=>{
    items.forEach(item=>{ 
      item.classList.remove("active");
    });

    event.currentTarget.classList.add("active");
  });
});
.menu {
  padding: 1rem;
  width: 100px;
}

.title {
  background-color: black;
  color: white;
  padding: 1rem;
  text-align: center;
  font-size: 1.5rem;
}

ul {
  padding: 0;
  margin: 0;
}

.item {
  cursor: pointer;
  list-style: none;
  height: 3rem;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
}

.item.noclick {
  height: 2rem;
  pointer-events: none;
}

.item.noclick:before, .item.noclick:after {
  height: 2rem;
  pointer-events: none;

}
.item i{
  background-color: black;
  color: white;
  width: 4rem;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-left: -1.375rem;
}

.item.active i {
  color: black;
  background-color: white;
  border-top-left-radius: 999px;
  border-bottom-left-radius: 999px;
}

.item:before, .item:after{
  content: "";
  display: inline-block;
  width: 3rem;
  height: 3rem;
  background-color: black;
}

.item:before{
  width: 4rem;
}

.item.active:after{
  background-color: white;
}

.item:has(+.active):after{
  border-bottom-right-radius: 999px;
}

.item.active + .item:after {
  border-top-right-radius: 999px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" rel="stylesheet"/>

<div class="menu">
  <div class="title">Test</div>
  <ul>
    <li class="item noclick"><div></div></li>
    <li class="item"><i class="fa-solid fa-chart-column"></i></i></li>
    <li class="item"><i class="fa-solid fa-chart-column"></i></li>
    <li class="item active"><i class="fa-solid fa-chart-column"></i></li>
    <li class="item"><i class="fa-solid fa-chart-column"></i></li>
    <li class="item"><i class="fa-solid fa-chart-column"></i></li>
    <li class="item noclick"><div></div></li>
  </ul>
</div>

Answer №2

You have the ability to achieve this by utilizing the ::after pseudo element of your li element. By positioning it absolutely, you can generate a block that overlays the parent div. Utilize clip path to define the shape you desire and adjust the sizing until it aligns perfectly. The example provided below may require some further tweaking, which I will leave in your capable hands.

I rely on a couple of handy resources for this task. Firstly, there's the SVG Path Builder at mavo.io for customizing SVGs. Additionally, there is a helpful Clip Path Converter on GitHub. This tool converts your SVG code and provides the necessary HTML and CSS to apply clipping to your elements.

.sidebar {
  font-size: 1.5rem;
  color: white;
  width: fit-content;
  background-color: black;
  padding: 1rem;
}

.menulist {
  padding-left: 0;
  list-style-type: none;
  width: 100%;
}

.menulist > li {
  position: relative;
  width: 100%;
  margin-block: 1rem;
  text-align: center;
}

.menulist > li:hover {
  background-color: white;
  color: black;
  border-top-left-radius: 100vh;
  border-bottom-left-radius: 100vh;
}

.menulist > li:hover::after {
  content: "";
  position: absolute;
  top: -1rem;
  left: 100%;
  bottom: -1rem;
  width: 1rem;
  background-color: white;
  background-size: cover;
  clip-path: url(#my-clip-path);
}

.svg {
  /*hide the SVG */
  position: absolute;
  width: 0;
  height: 0;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w==" crossorigin="anonymous" referrerpolicy="no-referrer" />

<svg class="svg">
  <clipPath id="my-clip-path" clipPathUnits="objectBoundingBox"><path d="m0,0.25 a1,0.25,0,0,0,1,-0.25 l0,1 a1,0.25,0,0,0,-1,-0.25 l0,-0.5"></path></clipPath>
</svg>

<div class='sidebar'>
  <div class='title'>Test</div>
  <ul class='menulist'>
    <li><i class="fa-solid fa-chart-line"></i></li>
    <li><i class="fa-solid fa-chart-line"></i></li>
    <li><i class="fa-solid fa-chart-line"></i></li>
    <li><i class="fa-solid fa-chart-line"></i></li>
    <li><i class="fa-solid fa-chart-line"></i></li>
  </ul>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having trouble retrieving the default selected value using the index in Angular Material's mat-button-toggle functionality

I'm encountering an issue with setting the default value for a toggle button group. The code is simple and the toggle buttons are correctly fetching values from the index, but I can't seem to get one of them to be default selected. I tried settin ...

Chrome does not support top.frames functionality

I have three HTML pages: main.html, page1.html, and page2.html. I am displaying page1.html and page2.html within main.html using the code below. <!DOCTYPE html> <html> <frameset frameborder="1" rows="50%, *"> <frame name="f ...

Align the content of the list items to the center and position the list in the center of

I am struggling to get the List centered beneath "Contact Me" and the hr tag. Both of those elements are perfectly centered in the column, but the list and icons are aligned to the left. Ideally, I would like them to be in the center like everything else. ...

Updating user credits through the Model::factory() method is a common practice in my workflow

I need to update the UserCredits after a purchase. For example, if a user currently has 10 credits and purchases 10 more, I want to add the purchased credits to their existing total. The goal is to increment the current credit score with the new credits ...

Extracting Data from JSON Using Vue.js

I am facing an issue with extracting data from a JSON file using Vue.js. Below is the HTML and JSON data along with the script. Any help would be appreciated. <!DOCTYPE html> <html> <head> <title>Vu ...

Utilize Ajax, jQuery, and HTML select elements to showcase customized information

Hey everyone, I could really use some assistance with this. What I'm trying to accomplish is selecting data from a database using the onchange() function in Ajax and then returning the result to the client. I have successfully used Ajax to send inform ...

Turn off drag and drop functionality and activate selection in HTML

Recently, I encountered a strange issue where selected text became draggable and droppable onto other text, causing it to concatenate. To resolve this problem, I added the following code: ondragstart="return false" onmousedown="return false" However, thi ...

Incorporate SVG or HTML5 elements into a Box2D World

My SVG logo is primarily composed of elements. I am interested in animating it by placing it in a "gravity world". Although I am new to Box2D and Canvas, I have managed to convert my SVG into HTML5 canvas using canvg. Currently, I am going through the begi ...

Is it possible to minify HTML in PHP without parsing JavaScript and CSS code?

After finding a solution in this discussion, I successfully managed to 'minify' HTML content. function process_content($buffer) { $search = array( '/\>[^\S ]+/s', // eliminate spaces after tags, except for ...

Using PHP's include/require method with a dynamic path

Looking for assistance with my issue! Ajax is returning the correct information and displaying it in an 'alert(html)' on 'success'. The PHP code echoes $idName and $path correctly on the carrier page where the code resides. There are no ...

Fine-tuning the design of the Box Model layout

I can't seem to get the table in my code to center properly and not be stuck against the left border. Despite trying various solutions, the table in column 2 is floating off to the left and touching the border. I need it to be more centered within the ...

Are third-party scripts and HTML widgets able to replicate your website's data, including cookies, HTML, and other elements?

Currently, I am in the process of constructing a website that incorporates a third-party weather HTML widget. The widget is sourced from a trusted and reliable source on the web. It consists of a link and small JavaScript tags that are executed once loaded ...

Display the percentage text behind a filling Bootstrap progress bar

I'm working on a bootstrap progress bar that displays a percentage along with the numerical value. Currently, the text fits next to the progress bar up until around 85%, after which it blocks the bar from growing further. You can see the issue in the ...

Responsive CSS Dropdown Menu - Divided into Two Columns

After searching for solutions in the support resources and experimenting with various techniques, I am struggling to divide this CSS Dropdown menu into two columns. The nav list is long enough that it extends below the fold. Although the menu adapts respo ...

showcasing pictures on a .handlebars/html interface

Having some trouble linking images to my .handlebars/html files in the views directory. I've already set up a public folder as per the requirements, but the linked images still aren't showing up when I view my webpage. Below is the node.js code ...

Envelop the phrases onto a fresh line

I'm having trouble getting the text inside a div to display correctly. When the text is too long, it just keeps stretching instead of breaking into new lines. How can I make sure that the content displays as a block within the div? Thank you. .box ...

Retrieve the erased document using Google's cache feature

After accidentally overwriting my .php web document file with an old version, I attempted to access the cached copy on Google. The only thing I could find was the HTML scripts, as the PHP coding was not visible. Now I am seeking a method to recover the e ...

What are the methods to ascertain whether an HTML element possesses a pseudo element?

Is there a method to identify whether an HTML element has a pseudo element (::before / ::after) applied to it without invoking the function: window.getComputedStyle(element, ":before/:after"); MODIFIED: the response is NEGATIVE The issue with getCompute ...

Complex UL structure with nested LI items and both column and inline styling

I'm facing a challenge that seems insurmountable - I can't even begin to tackle it, so I don't have a polished solution to present. All I have is the source code and my goal. My task is to create a three-level UL structure. The top level sh ...

Instructions for removing a class using the onclick event in JavaScript

Is there a way to make it so that pressing a button will display a specific class, and if another button is pressed, the previous class is removed and a new one is shown? Thank you for your assistance. function myFunction() { document.getElementById ...