Steps to Construct a Civilization with CSS

I'm struggling to recreate this navigation bar design but I'm not sure what it's called. I've made progress using tailwind and custom CSS, but I've hit a roadblock.

Can anyone help me identify the style of this nav bar (for updating the title) and provide guidance on how to build it? https://i.sstatic.net/I8uium.png

Here is my attempt:

.active::before {
  content: "";
  position: absolute;
  background-color: transparent;
  border-color: white;
  border-width: 0 0.5rem 0.5rem 0;
  width: 2rem;
  height: 2rem;
  right: -0.5rem;
  border-radius: 0 0 100% 0;
  top: -1.5rem;
}

.active::after {
  content: "";
  position: absolute;
  background-color: transparent;
  border-color: white;
  border-width: 0.5rem 0.5rem 0 0;
  width: 2rem;
  height: 2rem;
  right: -0.5rem;
  border-radius: 0 100% 0 0;
  bottom: -1.5rem;
}

.active-link {
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: white;
  border-top-left-radius: 10rem;
  border-bottom-left-radius: 10rem;
  width: 5rem;
  height: 2rem;
}
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />

<nav class="w-32 h-64 bg-indigo-900 rounded-xl">
  <div class="flex flex-col items-center justify-between h-full py-12">
    <div>
      Title
    </div>
    <div class="w-full">
      <ul class="flex flex-col items-center space-y-12 w-full">
        <li class="w-full flex justify-center relative active">
          <nuxt-link :to="menuItem.target" class="active-link">
            <i class="text-black">Icon</i>
          </nuxt-link>
        </li>
      </ul>
    </div>
    <div>
      <i>Icon</i>
    </div>
  </div>
</nav>

Answer №1

If you only need to assign a classname to the selected element, rather than altering the DOM structure whenever a new item in the navbar is clicked, there is a simpler way to achieve this:

The following code snippet accomplishes the task:

let nav = document.getElementsByClassName('navbar')[0];
for (let item of document.getElementsByClassName('item')) {
  item.addEventListener('click', () => {
    let selected = nav.querySelector('.item.selected');
    if (selected) selected.classList.remove('selected');
    item.classList.add('selected');
  });
}
body { font-family: monospace; }
.navbar {
  position: absolute;
  left: 0; top: 0;
  width: 60px; height: 100%;
  padding-left: 10px;
  background-color: rgba(70, 0, 170);
  overflow: hidden;
}
.item {
  position: relative;
  height: 60px; line-height: 60px;
  color: #fff;
  text-align: center;
  z-index: 1;
  cursor: pointer;
}
.item.selected {
  background-color: #fff;
  border-radius: 100%;
  color: #000;
}
.item.selected::before,
.item.selected::after {
  content: ' '; display: block;
  position: absolute;
  left: 0; width: 100%; height: 100%;
  pointer-events: none;
  border-radius: 100%;
  border: 50px solid rgba(0, 0, 0, 0);
  border-right: 50px solid #fff;
  margin-left: -50px;
  z-index: -1;
}

.item.selected::before { bottom: 100%; margin-bottom: -50px; transform: rotate(45deg); }
.item.selected::after { top: 100%; margin-top: -50px; transform: rotate(-45deg);  }
<div class="navbar">
  <div class="item">(1)</div>
  <div class="item">(2)</div>
  <div class="item selected">(3)</div>
  <div class="item">(4)</div>
</div>

This code snippet is interactive, so feel free to click on the menu items!

Note that the design closely resembles the image provided, as we are utilizing true circle radii.

The key here is to add ::before and ::after pseudo-elements to the selected item, apply borders to them, eliminate all but one side of the border, and then rotate these elements to achieve the desired effect. The following code demonstrates this technique:

@keyframes styleBefore {
  0% {
    border: 0 solid #000;
    margin-left: 0;
    margin-bottom: 0;
  }
  20% {
    border: 50px solid #000;
    border-right: 50px solid #000;
    margin-left: -50px;
    margin-bottom: -50px;
  }
  40% {
    border: 50px solid #000;
    border-right: 50px solid #fff;
  }
  60% {
    border: 50px solid transparent;
    border-right: 50px solid #fff;
    transform: rotate(0deg);
  }
  95% {
    border: 50px solid transparent;
    border-right: 50px solid #fff;
    transform: rotate(45deg);
  }
  100% {
    border: 50px solid transparent;
    border-right: 50px solid transparent;
    margin-left: -50px;
    margin-bottom: -50px;
    transform: rotate(45deg);
  }
}
@keyframes styleAfter {
  0% {
    border: 0 solid #000;
    margin-left: 0;
    margin-top: 0;
  }
  20% {
    border: 50px solid #000;
    border-right: 50px solid #000;
    margin-left: -50px;
    margin-top: -50px;
  }
  40% {
    border: 50px solid #000;
    border-right: 50px solid #fff;
  }
  60% {
    border: 50px solid transparent;
    border-right: 50px solid #fff;
    transform: rotate(0deg);
  }
  95% {
    border: 50px solid transparent;
    border-right: 50px solid #fff;
    transform: rotate(-45deg);
  }
  100% {
    border: 50px solid transparent;
    border-right: 50px solid transparent;
    margin-left: -50px;
    margin-top: -50px;
    transform: rotate(-45deg);
  }
}

body { font-family: monospace; }
.navbar {
  position: absolute;
  left: 0; top: 0;
  width: 90px; height: 100%;
  padding-left: 10px;
  background-color: rgba(70, 0, 170);
  overflow: hidden;
}
.item {
  position: relative; top: -85px;
  height: 90px; line-height: 90px;
  color: #fff;
  text-align: center;
  z-index: 1;
  cursor: pointer;
  font-size: 200%;
}
.item.selected {
  background-color: #fff;
  border-radius: 100%;
  color: #000;
}
.item.selected::before,
.item.selected::after {
  content: ' '; display: block;
  position: absolute;
  left: 0; width: 100%; height: 100%;
  pointer-events: none;
  border-radius: 100%;
  z-index: -1;
}
.item.selected::before { bottom: 100%; animation: 10s infinite linear styleBefore; }
.item.selected::after { top: 100%; animation: 10s infinite linear styleAfter;  }
<div class="navbar">
  <div class="item">(1)</div>
  <div class="item">(2)</div>
  <div class="item selected">(3)</div>
  <div class="item">(4)</div>
</div>

Answer №2

When it comes down to it, tweaking the border-radius and top & bottom properties pixel by pixel is key. I toyed around with it.

.active::before {
    content: "";
    position: absolute;
    background-color: transparent;
    border-color: white;
    border-width: 0 0.5rem 0.7rem 0;
    width: 2rem;
    height: 2rem;
    right: -0.5rem;
    border-radius: 0 0 100% 0;
    top: -1.34rem;
    outline: white;
}

.active::after {
    content: "";
    position: absolute;
    background-color: #f8f8f800;
    border-color: white;
    border-width: 0.7rem 0.7rem 0px 0px;
    width: 2rem;
    height: 2rem;
    right: -0.7rem;
    border-radius: 0 100% 0 0;
    bottom: -1.30rem;
}

.active-link {
    display: flex;
    float: right;
    justify-content: center;
    align-items: center;
    background-color: white;
    border-top-left-radius: 10rem;
    border-bottom-left-radius: 10rem;
    width: 8rem;
    height: 5rem;
    margin-left: 10px;
}

.active-link .text-black {
    margin-left: -10px;
}
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />

<nav class="w-24 h-64 bg-indigo-900 rounded-xl">
  <div class="flex flex-col items-center justify-between h-full py-12">
    <div>
      Title
    </div>
    <div class="w-full">
      <ul class="flex flex-col items-center space-y-12 w-full">
        <li class="w-full flex justify-center relative active">
          <nuxt-link :to="menuItem.target" class="active-link">
            <i class="text-black">Icon</i>
          </nuxt-link>
        </li>
      </ul>
    </div>
    <div>
      <i>Icon</i>
    </div>
  </div>
</nav>

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

Styling the scroll bar within a fixed parent container's inner div with CSS

Check out the JSBIN link here: JSBIN The modules container has a fixed height of 100%. I am attempting to make the list items scroll while keeping the search div fixed within the wrapper container, ensuring that the search bar remains visible at all times ...

Discovering the color of a locator (Button/Label) through a CSS locator in Selenium: What's the method?

I have a set of automation scripts in place that handle the downloading and saving of files from a server. These scripts also involve moving the downloaded files from the downloads folder to a user-specific location. When this process is complete, the co ...

The elusive Holy Grail layout for Flex content cannot be achieved on IE11

UPDATE I attempted to insert height:100vh into the .app-container, but unfortunately, it did not have the desired effect. I am utilizing bootstrap 4 for creating my web application. My goal is to implement the Holy grail layout. Everything appears to be ...

Child elements should adjust their height based on the root parent container by utilizing flex properties, even if there is a potential top offset present

I am attempting to nest multiple "blocks" within each other, utilizing flex for this specific case. The structure I am aiming for is as follows: Parent (highlighted in blue in JSFIDDLE) Container: margin-top: 32px, (highlighted in red) Row 1: colored ...

Content that is dynamically generated by a database

I have been working on creating a unique wall feature for my website, inspired by Facebook. My aim is to allow users to submit form data and have it validated before storing it in a database. Additionally, I want this stored data to be displayed in a desig ...

Flexbox properties are being ignored by input fields

Hey there, I'm currently working on a product calculator and need to create 9 input fields organized in 3 rows of three columns. However, when I try to use display: flex and flex-direction: row on the parent div, it doesn't seem to be working as ...

Attempting to conceal image previews while incorporating pagination in Jquery

I'm working on implementing pagination at the bottom of a gallery page, allowing users to navigate between groups of thumbnail images. On this page, users can click on thumbnails on the left to view corresponding slideshows on the right. HTML <di ...

What is the best way to align text within both the grid row and column while still maintaining the border?

When I apply justify-self and align-self rules, it successfully centers items vertically and horizontally. However, the issue arises when the borders wrap around the text instead of expanding all the way to the edges. My goal is to have a 1px border aroun ...

The namespace 'pages' has not been registered

Attempting to load an index in this environment: ├── admin_material │   ├── admin.py │   ├── apps.py │   ├── forms.py │   ├── __init__.py │   ├── models.py │   ├── __pycache__ │   │  ...

I am attempting to utilize Ajax in order to transfer information to a different webpage

It's a bit complex and I can't figure out why it's not working. My goal is to create a page with textboxes, dropdown lists, and a datagrid using easyui. The issue arises when I select something from the dropdown list - I want two actions to ...

Changing a specific instance of an anchor tag's href in Javascript

I have implemented a chat widget called Purechat for customer and operator communication. However, I've encountered an issue where the href values of anchors within this widget are getting appended with "", rendering them unclickable for our users. Wh ...

When I add text to div boxes, they begin to drift downward

After creating four div boxes with content, I encountered an issue. Initially, when inserting filler text, everything seemed fine. However, as soon as I started adding actual content into the first box, the other three boxes shifted downwards by the same a ...

How can I change the font size in PHP from each font size="" to font-size:?

Is there a way to use PHP to replace every instance of font size="somenumber" (with a different number each time) with font-size="somenumber"? I need to convert text that looks like this: Hello <font size="4">today</font> is my <font size= ...

Can I leverage Bootstrap's 5 grid system exclusively?

Previous iterations of Bootstrap allowed for the creation of custom setups, specifically focusing on the grid system. Is it possible to craft a tailored Bootstrap 5 configuration that exclusively includes support for the grid system? ...

What is the best way to animate an element to slide down when it is hidden with

I'm working on an html tag called "loginBox" (<loginBox> ... </loginBox>) that is initially hidden with display:none. When a user selects an option, I want it to smoothly slide down instead of just appearing and disappearing. How can I ach ...

Guide on positioning a div to float from bottom left to top right using CSS as the window screen size is reduced

I am wondering if it is possible to float the div using CSS in the following manner. My goal is to have CSS DIV 2 move under CSS DIV 1 to the right when the window size is reduced. Please refer to the screenshot below: On larger window sizes, three DIVs a ...

What is the best way to showcase nested array information from a JSON file on an HTML webpage?

students.json { "students": [ { "studentname": "Rohit Kumar", "grade": "A", "student": [ { "SNo": "1", "Subject": "Maths", "Concept": "Numbers" }, { "SNo": "2", ...

Listening for events to wait for all XMLHttpRequest requests within an iframe

I have a basic HTML page that includes an iframe element <html> <head> $('#page-wrapper').ajaxStop(function() { console.log("Page Fully Loaded." ); }); </head> <body> <h3>Demo Page<h3> <iframe id= ...

I'm struggling to determine the correct path to use in the background-image: url(); CSS property to display a specific image within a Vue.js project

Currently, I am working on a Vue.js project and this is the structure of my file tree (showing only relevant folders and files): root src assets image.jpg components header.vue index.html Within the header.v ...

An image tag acts in a similar way to a div element

I'm a bit confused about how the picture tag works in relation to an img tag when its parent has 'display: flex' applied. When I set width: 50% on the img tag, it doesn't make the image 50% of the div but rather 50% of the picture eleme ...