Is it possible to control the length and distance between dashed border strokes in CSS?
This example below displays differently between browsers:
div {_x000D_
border: dashed 4px #000;_x000D_
padding: 20px;_x000D_
display: inline-block;_x000D_
}
_x000D_
<div>I have a dashed border!</div>
_x000D_
Big differences: IE 11 / Firefox / Chrome
Are there any methods that can provide greater control of the dashed borders appearance?
This question is related to
css
border
css-shapes
In addition to the border-image
property, there are a few other ways to create a dashed border with control over the length of the stroke and the distance between them. They are described below:
We can create the dashed border by using a path
or a polygon
element and setting the stroke-dasharray
property. The property takes two parameters where one defines the size of the dash and the other determines the space between them.
Pros:
border-radius
involved. We would just have replace the path
with a circle
like in this answer (or) convert the path
into a circle.Cons:
vector-effect='non-scaling-stroke'
(as in the second box) but the browser support for this property is nil in IE..dashed-vector {_x000D_
position: relative;_x000D_
height: 100px;_x000D_
width: 300px;_x000D_
}_x000D_
svg {_x000D_
position: absolute;_x000D_
top: 0px;_x000D_
left: 0px;_x000D_
height: 100%;_x000D_
width: 100%;_x000D_
}_x000D_
path{_x000D_
fill: none;_x000D_
stroke: blue;_x000D_
stroke-width: 5;_x000D_
stroke-dasharray: 10, 10;_x000D_
}_x000D_
span {_x000D_
position: absolute;_x000D_
top: 0px;_x000D_
left: 0px;_x000D_
padding: 10px;_x000D_
}_x000D_
_x000D_
_x000D_
/* just for demo */_x000D_
_x000D_
div{_x000D_
margin-bottom: 10px;_x000D_
transition: all 1s;_x000D_
}_x000D_
div:hover{_x000D_
height: 100px;_x000D_
width: 400px;_x000D_
}
_x000D_
<div class='dashed-vector'>_x000D_
<svg viewBox='0 0 300 100' preserveAspectRatio='none'>_x000D_
<path d='M0,0 300,0 300,100 0,100z' />_x000D_
</svg>_x000D_
<span>Some content</span>_x000D_
</div>_x000D_
_x000D_
<div class='dashed-vector'>_x000D_
<svg viewBox='0 0 300 100' preserveAspectRatio='none'>_x000D_
<path d='M0,0 300,0 300,100 0,100z' vector-effect='non-scaling-stroke'/>_x000D_
</svg>_x000D_
<span>Some content</span>_x000D_
</div>
_x000D_
We can use multiple linear-gradient
background images and position them appropriately to create a dashed border effect. This can also be done with a repeating-linear-gradient
but there is not much improvement because of using a repeating gradient as we need each gradient to repeat in only one direction.
.dashed-gradient{_x000D_
height: 100px;_x000D_
width: 200px;_x000D_
padding: 10px;_x000D_
background-image: linear-gradient(to right, blue 50%, transparent 50%), linear-gradient(to right, blue 50%, transparent 50%), linear-gradient(to bottom, blue 50%, transparent 50%), linear-gradient(to bottom, blue 50%, transparent 50%);_x000D_
background-position: left top, left bottom, left top, right top;_x000D_
background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;_x000D_
background-size: 20px 3px, 20px 3px, 3px 20px, 3px 20px;_x000D_
}_x000D_
_x000D_
.dashed-repeating-gradient {_x000D_
height: 100px;_x000D_
width: 200px;_x000D_
padding: 10px;_x000D_
background-image: repeating-linear-gradient(to right, blue 0%, blue 50%, transparent 50%, transparent 100%), repeating-linear-gradient(to right, blue 0%, blue 50%, transparent 50%, transparent 100%), repeating-linear-gradient(to bottom, blue 0%, blue 50%, transparent 50%, transparent 100%), repeating-linear-gradient(to bottom, blue 0%, blue 50%, transparent 50%, transparent 100%);_x000D_
background-position: left top, left bottom, left top, right top;_x000D_
background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;_x000D_
background-size: 20px 3px, 20px 3px, 3px 20px, 3px 20px;_x000D_
}_x000D_
_x000D_
/* just for demo */_x000D_
_x000D_
div {_x000D_
margin: 10px;_x000D_
transition: all 1s;_x000D_
}_x000D_
div:hover {_x000D_
height: 150px;_x000D_
width: 300px;_x000D_
}
_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>_x000D_
<div class='dashed-gradient'>Some content</div>_x000D_
<div class='dashed-repeating-gradient'>Some content</div>
_x000D_
Pros:
Cons:
border-radius
is involved because backgrounds don't curve based on border-radius
. They get clipped instead.We can create a small bar (in the shape of the dash) using pseudo-elements and then create multiple box-shadow
versions of it to create a border like in the below snippet.
If the dash is a square shape then a single pseudo-element would be enough but if it is a rectangle, we would need one pseudo-element for the top + bottom borders and another for left + right borders. This is because the height and width for the dash on the top border will be different from that on the left.
Pros:
Cons:
border-radius
but positioning them would be very tricky with having to find points on a circle (and possibly even transform
)..dashed-box-shadow{_x000D_
position: relative;_x000D_
height: 120px;_x000D_
width: 120px;_x000D_
padding: 10px;_x000D_
}_x000D_
.dashed-box-shadow:before{ /* for border top and bottom */_x000D_
position: absolute;_x000D_
content: '';_x000D_
top: 0px;_x000D_
left: 0px;_x000D_
height: 3px; /* height of the border top and bottom */_x000D_
width: 10px; /* width of the border top and bottom */_x000D_
background: blue; /* border color */_x000D_
box-shadow: 20px 0px 0px blue, 40px 0px 0px blue, 60px 0px 0px blue, 80px 0px 0px blue, 100px 0px 0px blue, /* top border */_x000D_
0px 110px 0px blue, 20px 110px 0px blue, 40px 110px 0px blue, 60px 110px 0px blue, 80px 110px 0px blue, 100px 110px 0px blue; /* bottom border */_x000D_
}_x000D_
.dashed-box-shadow:after{ /* for border left and right */_x000D_
position: absolute;_x000D_
content: '';_x000D_
top: 0px;_x000D_
left: 0px;_x000D_
height: 10px; /* height of the border left and right */_x000D_
width: 3px; /* width of the border left and right */_x000D_
background: blue; /* border color */_x000D_
box-shadow: 0px 20px 0px blue, 0px 40px 0px blue, 0px 60px 0px blue, 0px 80px 0px blue, 0px 100px 0px blue, /* left border */_x000D_
110px 0px 0px blue, 110px 20px 0px blue, 110px 40px 0px blue, 110px 60px 0px blue, 110px 80px 0px blue, 110px 100px 0px blue; /* right border */_x000D_
}
_x000D_
<div class='dashed-box-shadow'>Some content</div>
_x000D_
This will make an orange and gray border using the class="myclass" on the div.
.myclass {
outline:dashed darkorange 12px;
border:solid slategray 14px;
outline-offset:-14px;
}
Stroke length depends on stroke width. You can increase length by increasing width and hide part of border by inner element.
EDIT: added pointer-events: none;
thanks to benJ.
.thin {
background: #F4FFF3;
border: 2px dashed #3FA535;
position: relative;
}
.thin:after {
content: '';
position: absolute;
left: -1px;
top: -1px;
right: -1px;
bottom: -1px;
border: 1px solid #F4FFF3;
pointer-events: none;
}
There's a cool tool made by @kovart called the dashed border generator.
It uses an svg as a background image to allow setting the stroke dash array you desire, and is pretty convenient.
You would then simply use it as the background property on your element in place of the border:
div {
background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' stroke='black' stroke-width='4' stroke-dasharray='6%2c 14' stroke-dashoffset='0' stroke-linecap='square'/%3e%3c/svg%3e");
padding: 20px;
display: inline-block;
}
I just recently had the same problem. I have made this work around, hope it will help someone.
HTML + tailwind
<div class="dashed-border h-14 w-full relative rounded-lg">
<div class="w-full h-full rounded-lg bg-page z-10 relative">
Content goes here...
<div>
</div>
CSS
.dashed-border::before {
content: '';
position: absolute;
top: 50%;
left: 0;
width: 100%;
height: calc(100% + 4px);
transform: translateY(-50%);
background-image: linear-gradient(to right, #333 50%, transparent 50%);
background-size: 16px;
z-index: 0;
border-radius: 0.5rem;
}
.dashed-border::after {
content: '';
position: absolute;
left: 50%;
top: 0;
height: 100%;
width: calc(100% + 4px);
transform: translateX(-50%);
background-image: linear-gradient(to bottom, #333 50%, transparent 50%);
background-size: 4px 16px;
z-index: 1;
border-radius: 0.5rem;
}
Short one: No, it's not. You will have to work with images instead.
I just recently had the same problem.
I managed to solve it with two absolutely positioned divs carrying the border (one for horizontal and one for vertical), and then transforming them. The outer box just needs to be relatively positioned.
<div class="relative">
<div class="absolute absolute--fill overflow-hidden">
<div class="absolute absolute--fill b--dashed b--red"
style="
border-width: 4px 0px 4px 0px;
transform: scaleX(2);
"></div>
<div class="absolute absolute--fill b--dashed b--red"
style="
border-width: 0px 4px 0px 4px;
transform: scaleY(2);
"></div>
</div>
<div> {{Box content goes here}} </div>
</div>
Note: i used tachyons in this example, but i guess the classes are kind of self-explanatory.
The native dashed border property value does not offer control over the dashes themselves... so bring on the border-image
property!
border-image
Compatibility: It offers great browser support (IE 11 and all modern browsers). A normal border can be set as a fallback for older browsers.
These borders will display exactly the same cross-browser!
This example is 15 pixels wide by 15 pixels high and the gaps are currently 5px wide. It is a .png with transparency.
This is what it looks like in photoshop when zoomed in:
This is what it looks like to scale:
To create wider / shorter gaps or strokes, widen / shorten the gaps or strokes in the image.
Here is an image with wider 10px gaps:
correctly scaled =
Define the border-image-source:
border-image-source:url("http://i.stack.imgur.com/wLdVc.png");
Optional - Define the border-image-width:
border-image-width: 1;
The default value is 1. It can also be set with a pixel value, percentage value, or as another multiple (1x, 2x, 3x etc). This overrides any border-width
set.
Define the border-image-slice:
In this example, the thickness of the images top, right, bottom and left borders is 2px, and there is no gap outside of them, so our slice value is 2:
border-image-slice: 2;
The slices look like this, 2 pixels from the top, right, bottom and left:
Define the border-image-repeat:
In this example, we want the pattern to repeat itself evenly around our div. So we choose:
border-image-repeat: round;
Writing shorthand
The properties above can be set individually, or in shorthand using border-image:
border-image: url("http://i.stack.imgur.com/wLdVc.png") 2 round;
Note the border: dashed 4px #000
fallback. Non-supporting browsers will receive this border.
.bordered {_x000D_
display: inline-block;_x000D_
padding: 20px;_x000D_
/* Fallback dashed border_x000D_
- the 4px width here is overwritten with the border-image-width (if set)_x000D_
- the border-image-width can be omitted below if it is the same as the 4px here_x000D_
*/_x000D_
border: dashed 4px #000;_x000D_
_x000D_
/* Individual border image properties */_x000D_
border-image-source: url("http://i.stack.imgur.com/wLdVc.png");_x000D_
border-image-slice: 2;_x000D_
border-image-repeat: round; _x000D_
_x000D_
/* or use the shorthand border-image */_x000D_
border-image: url("http://i.stack.imgur.com/wLdVc.png") 2 round;_x000D_
}_x000D_
_x000D_
_x000D_
/*The border image of this one creates wider gaps*/_x000D_
.largeGaps {_x000D_
border-image-source: url("http://i.stack.imgur.com/LKclP.png");_x000D_
margin: 0 20px;_x000D_
}
_x000D_
<div class="bordered">This is bordered!</div>_x000D_
_x000D_
<div class="bordered largeGaps">This is bordered and has larger gaps!</div>
_x000D_
Source: Stackoverflow.com