Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concave and convex shape navigation using CSS3

Tags:

css

css-shapes

Is there any way to create navigation bar with transparent background color like below image?

enter image description here

I tried using CSS3 pseudo selectors but the curves are not as per the design:

div::before{
  width: 200px;
  height: 90px;
  background: rgba(255, 255, 255, 0.2);
  background: radial-gradient(circle 0 at -20% 50%,transparent,transparent 100px,rgba(255, 255, 255, 0.2) 100px),
   radial-gradient(circle 20px at 180px 50%,transparent,transparent 100px,rgba(255, 255, 255, 0.2) 100px);
  background-size:100px 90px, 100px 90px;
  background-position:0 0,100% 0;
  background-repeat:no-repeat
}
like image 411
Rakesh Vadnal Avatar asked Dec 18 '22 17:12

Rakesh Vadnal


1 Answers

You can do this in multiple ways with CSS and I've shown few of them in the below answer. I've used ul and li tags because I feel they are more suited for a navigation bar but you can easily convert it to work with div tags also.

One drawback that both CSS approaches have is that the parent element is still basically a rectangle and so mouse interactions would happen outside the curve (but inside the element's boundaries). The only solution I have for this problem is to use clip-path.

Using Radial Gradient:

This is just like what you had started to do. I have just set the gradient at the correct position and have used it to produce the right hand side black border also. The curve on element's left side is done using the border-radius property.

The radial gradient is transparent for 20px (half the height of the element) and is black color for 1px (to produce the border), has the required background color for the rest of it.

Drawback of using gradients is that they would not work in IE9 and lower because they do not support gradients.

li {
  position: relative;
  float: left;
  width: 33%;
  height: 40px;
  line-height: 36px; /* height - 2 * border width */
  text-indent: 10px;
  border: 2px solid rgba(0, 0, 0, .5);
  border-right: none;
  border-radius: 20px 0px 0px 20px;
  background: radial-gradient(20px 20px at calc(100% + 4px) 50%, transparent 18px, rgba(0, 0, 0, .5) 19px, rgba(0, 0, 0, .5) 20px, rgba(255, 255, 255, .25) 21px); /* the first color after transparent is border color, the last color is background color */
  background-clip: content-box;
  box-shadow: -1px 2px 1px rgba(0, 0, 0, .25);
  overflow: hidden;
}
ul {
  list-style-type: none;
}
* {
  box-sizing: border-box;
}
body {
  background: radial-gradient(circle, chocolate 0%, sandybrown 100%);
  min-height: 100vh;
}
<ul>
  <li>One</li>
  <li>Two</li>
  <li>Three</li>
</ul>

Using Box Shadow:

This has better browser support because box-shadow works even in IE9. For this approach, we need a pseudo-element which is placed just inside the right border of the parent element. Both the elements (that is, the pseudo and the parent) have a border-radius assigned to create the curve. Background color is achieved using a wide box-shadow on the pseudo-element because assigning a background color to the parent or the pseudo-element will bleed outside the shape also.

li {
  position: relative;
  float: left;
  width: 33%;
  height: 40px;
  line-height: 36px; /* height - 2 * border width */
  text-indent: 10px;
  border: 2px solid rgba(0, 0, 0, .5);
  border-right: none;
  border-radius: 20px 0px 0px 20px;
  box-shadow: -1px 2px 1px rgba(0, 0, 0, .25);
  overflow: hidden;
}
ul {
  list-style-type: none;
}
li:after {
  position: absolute;
  content: '';
  height: 100%;
  width: 100%;
  left: calc(100% - 18px); /* 100% - (half of height  - border width) */
  top: -2px; /* inverse of border width */
  border-radius: 20px;
  border: 2px solid rgba(0, 0, 0, .5);
  box-shadow: 0px 0px 0px 999px rgba(255, 255, 255, .25); /* the color here is the background color */
  z-index: -1;
}
*{
  box-sizing: border-box;
}
body {
  background: radial-gradient(circle, chocolate 0%, sandybrown 100%);
  min-height: 100vh;
}
<ul>
  <li>One</li>
  <li>Two</li>
  <li>Three</li>
</ul>

Using SVG:

You can do this using SVG also by creating the required shape with a path element and positioning it absolutely with respect to the parent.

li {
  position: relative;
  float: left;
  width: 33%;
  height: 40px;
  line-height: 40px;
  text-indent: 10px;
}
ul {
  list-style-type: none;
}
svg {
  position: absolute;
  top: 0px;
  left: 0px;
  width: 100%;
  height: 100%;
}
path {
  stroke: rgba(0, 0, 0, .5); /* border color */
  stroke-width: 2; /* border width */
  fill: rgba(255, 255, 255, .25); /* background color */
}
path:hover{
  stroke: red;
}
body {
  background: radial-gradient(circle, chocolate 0%, sandybrown 100%);
  min-height: 100vh;
}
<ul>
  <li>
    <svg viewBox='0 0 200 40' preserveAspectRatio='none'>
      <path d='M20,1 A19,19 0 1,0 20,39 L200,39 A19,19 0 0,1 200,1z' />
    </svg>One</li>
  <li>
    <svg viewBox='0 0 200 40' preserveAspectRatio='none'>
      <path d='M20,1 A19,19 0 1,0 20,39 L200,39 A19,19 0 0,1 200,1z' />
    </svg>Two</li>
  <li>
    <svg viewBox='0 0 200 40' preserveAspectRatio='none'>
      <path d='M20,1 A19,19 0 1,0 20,39 L200,39 A19,19 0 0,1 200,1z' />
    </svg>Three</li>
</ul>
like image 68
Harry Avatar answered Jan 13 '23 10:01

Harry