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);
}