Search code examples
cssbordercss-shapes

Border within border CSS


With the help of CSS Triangle tutorial, I learnt to create triangle shapes.

.arrow-down {
    width: 0; 
    height: 0; 
    border-left: 20px solid transparent;
    border-right: 20px solid transparent;   
        border-top: 20px solid #ccc;
}

I'm trying to add a border to the triangle but I was unable to do it.

what I achieved: enter image description here

Expected:(trying something similar border with gray) enter image description here

Check this JSFiddle

Stuck up no where to start this. I tried outline, but none worked(I know it won't work).

Thanks for taking time to read my question.

Any help is appreciated.

Note: I'm trying this in CSS instead of using images.


Solution

  • When the main triangle or arrow is itself created using the CSS borders, it is impossible to add another border to it without using extra elements. The below are a few options.

    Option 1: Using a bigger size pseudo-element and positioning it behind the parent to produce a border-effect.

    .arrow-down {
      position: relative;
      width: 0;
      height: 0;
      border-left: 20px solid transparent;
      border-right: 20px solid transparent;
      border-top: 20px solid #ccc;
    }
    .arrow-down:before {
      position: absolute;
      content: "";
      left: -22px;
      top: -20px;
      height: 0px;
      width: 0px;
      border-left: 21px solid transparent;
      border-right: 21px solid transparent;
      border-bottom: 21px solid transparent;
      border-top: 21px solid black;
      z-index: -1;
    }
    <div class="arrow-down"></div>

    .arrow-down:before {
      position: absolute;
      content: "";
      left: -22px;
      top: -20px;
      height: 0px;
      width: 0px;
      border-left: 21px solid transparent;
      border-right: 21px solid transparent;
      border-bottom: 21px solid transparent;
      border-top: 21px solid black;
      z-index: -1;
    }
    

    Option 2: Rotating the element (which has the border hack to produce the triangle) and then adding a box-shadow to it.

    .arrow-down {
      width: 0;
      height: 0;
      margin: 10px;
      border-left: 0px solid transparent;
      border-right: 30px solid transparent;
      border-top: 30px solid #ccc;
      -ms-transform: rotate(225deg);  /* IE 9 */
      -webkit-transform: rotate(225deg);  /* Chrome, Safari, Opera */
      -moz-transform: rotate(225deg);
      transform: rotate(225deg);
      box-shadow: 0px -3px 0px -1px #444;
    }
    <div class="arrow-down"></div>

    .arrow-down {
      width: 0;
      height: 0;
      margin: 10px;
      border-left: 0px solid transparent;
      border-right: 30px solid transparent;
      border-top: 30px solid #ccc;
      transform: rotate(225deg); /* browser prefixes added in snippet */
      box-shadow: 0px -3px 0px -1px #444;
    }
    

    Tested in Chrome v24 and Safari v5.1.7. Should work in other CSS3 compatible browsers also.


    The following options do not directly answer the question as it doesn't do a border within border but are others way of producing an arrow/triangle with a border.

    Option 3: Using linear-gradients on an element, rotating it to produce the triangle and then adding a border to it using the normal border property.

    .arrow-down {
      width: 30px;
      height: 30px;
      margin: 10px;
      border-left: 2px solid #444;
      background: -webkit-linear-gradient(45deg, #ccc 50%, transparent 50%);
      background: -moz-linear-gradient(45deg, #ccc 50%, transparent 50%);
      background: -o-linear-gradient(45deg, #ccc 50%, transparent 50%);
      background: linear-gradient(45deg, #ccc 50%, transparent 50%);
      -webkit-transform: rotate(-45deg);
      -moz-transform: rotate(-45deg);
      transform: rotate(-45deg);
      -webkit-backface-visibility:hidden; /** <-- to prevent diagonal line aliasing in chrome **/
    }
    <div class="arrow-down"></div>

    .arrow-down {
      width: 30px;
      height: 30px;
      margin: 10px;
      border-left: 2px solid #444;
      background: linear-gradient(45deg, #ccc 50%, transparent 50%);
      transform: rotate(-45deg);
      backface-visibility:hidden;
    }
    

    Option 4: Using a rotated pseudo-element (with background as the color of the triangle) to produce the triangle and then adding a normal border to it. The parent element's overflow is set to hidden and the pseudo-element is positioned appropriately so as to display only half of it (creating the illusion of a triangle).

    .arrow-down {
      position: relative;
      height: 50px;
      width: 50px;
      overflow: hidden;
    }
    .arrow-down:before {
      position: absolute;
      content: '';
      top: -webkit-calc(100% * -1.414 / 2);
      top: calc(100% * -1.414 / 2);
      left: 0px;
      height: 100%;
      width: 100%;
      background: #CCC;
      border-left: 2px solid #444;
      -webkit-transform: rotate(-45deg);
      -moz-transform: rotate(-45deg);
      transform: rotate(-45deg);
    }
    <div class="arrow-down"></div>

    .arrow-down:before {
      position: absolute;
      content: '';
      top: calc(100% * -1.414 / 2);
      left: 0px;
      height: 100%;
      width: 100%;
      background: #CCC;
      border-left: 2px solid #444;
      transform: rotate(-45deg);
    }