Search code examples
csscss-shapesclip-path

clip-path and dropdowns cause different shapes


I'm using the CSS style clip-path in my navigation to alter the shape of the background at the corner. This works as i expect until i add a dropdown to the content area.

When the dropdown is hidden the shape is displayed correctly, when the dropdown is visible the shape changes. Based on my research then this is due to clip-path using the elements width and height to determine the clipping of the element, and when the dropdown is visible the elements height changes.

Is there any way to alter this behavior? My goal is to keep the same clipping regardless if the dropdown is visible or not.

CSS

.dropdown {
  background-color: #000;
  -webkit-clip-path: polygon(100% 0,100% 0,100% 100%,10% 100%,0 0);
  clip-path: polygon(100% 0,100% 0,100% 100%,10% 100%,0 0);
  padding-left: 50px;
}


.nav .open>a:focus,
.nav>li>a:focus,
.nav>li>a:hover,
.dropdown:focus,
.dropdown:hover,
.nav .open>a {
  background-color: #000;

}

.dropdown-menu {
  float: right;
  right: 0px;
  left: auto;
}`

HTML

<div id="navbar">
  <ul class="nav navbar-nav">
    <li class="active"><a href="#">Home</a></li>
    <li><a href="#about">About</a></li>
    <li><a href="#contact">Contact</a></li>
    <li class="dropdown">
      <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown menu goes here <span class="caret"></span></a>
      <ul class="dropdown-menu">
        <li><a href="#">Action</a></li>
      </ul>
    </li>
  </ul>
</div>

JSFiddle

https://jsfiddle.net/7hg1efdj/1/


Solution

  • Reason:

    As you've already indicated in question, the problem seems to be because of the percentage values used in the clip-path. When the drop-down is in collapsed state, the content's height is small (only around 50px) but when it is in expanded state, the content's height is large (including that of the drop-down list). So, 100% on Y-axis means a different value far lower down and hence the slope seems to be steeper.

    In the below snippet, we can see how the presence of an extra element (second p) affects height of second div and thus impacts the slope of the clip-path.

    div {
      position: relative;
      width: 200px;
      height: 50px;
      margin: 10px;
      -webkit-clip-path: polygon(100% 0, 100% 0, 100% 100%, 10% 100%, 0 0);
      clip-path: polygon(100% 0, 100% 0, 100% 100%, 10% 100%, 0 0);
    }
    span{
      display: block;
      height: 100%;
    }  
    span:nth-of-type(1) {
      background: red;
    }
    span:nth-of-type(2) {
      position: absolute;
      width: 100%;
      top: 100%;
      background: green;
    }
    <div>
      <span>
        Red Background
      </span>
    </div>
    <div>
      <span>
        Red Background
      </span>
      <span>
        Green Background
      </span>
    </div>


    Solution:

    Solution would be to put the clip-path on a.dropdown-toggle element because neither the height nor the width of this element are affected by the state of the drop-down.

    .navbar-nav > li > a.dropdown-toggle {
      background-color: #000;
      -webkit-clip-path: polygon(100% 0, 100% 0, 100% 100%, 10% 100%, 0 0);
      clip-path: polygon(100% 0, 100% 0, 100% 100%, 10% 100%, 0 0);
      padding-left: 50px;
    }
    .nav .open>a:focus, .nav>li>a:focus, .nav>li>a:hover, .nav .open>a {
      background-color: #000;
    }
    .dropdown-menu {
      float: right;
      right: 0px;
      left: auto;
    }
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
    <div id="navbar">
      <ul class="nav navbar-nav">
        <li class="active"><a href="#">Home</a>
        </li>
        <li><a href="#about">About</a>
        </li>
        <li><a href="#contact">Contact</a>
        </li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown menu goes here <span class="caret"></span></a>
          <ul class="dropdown-menu">
            <li><a href="#">Action</a>
            </li>
            <li><a href="#">Another action</a>
            </li>
            <li><a href="#">Something else here</a>
            </li>
            <li role="separator" class="divider"></li>
            <li class="dropdown-header">Nav header</li>
            <li><a href="#">Separated link</a>
            </li>
            <li><a href="#">One more separated link</a>
            </li>
          </ul>
        </li>
      </ul>
    </div>

    Note: Stack Snippet output is not the same as Fiddle (with respect to colors) probably because of the order of linked files and CSS. Here is the JSFiddle Demo.