Control the dashed border stroke length and distance between strokes
Asked Answered
E

11

218

Is it possible to control the length and distance between dashed border strokes in CSS?

This example below displays differently between browsers:

div {
  border: dashed 4px #000;
  padding: 20px;
  display: inline-block;
}
<div>I have a dashed border!</div>

Big differences: IE 11 / Firefox / Chrome

IE 11 borderFirefox BorderChrome border

Are there any methods that can provide greater control of the dashed borders appearance?

Elana answered 5/5, 2010 at 7:1 Comment(0)
V
27

Css render is browser specific and I don't know any fine tuning on it, you should work with images as recommended by Ham. Reference: http://www.w3.org/TR/CSS2/box.html#border-style-properties

Vanillin answered 5/5, 2010 at 7:20 Comment(0)
E
218

The native dashed border property value does not offer control over the dashes themselves... so bring on the border-image property!

Brew your own border with 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.

Let's create these

These borders will display exactly the same cross-browser!

Goal example Goal example with wider gaps

Step 1 - Create a suitable image

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:

Example Border Image Background Blown Up

This is what it looks like to scale:

Example Border Image Background Actual Size

Controlling gap and stroke length

To create wider / shorter gaps or strokes, widen / shorten the gaps or strokes in the image.

Here is an image with wider 10px gaps:

Larger gaps correctly scaled = Larger gaps to scale

Step 2 - Create the CSS — this example requires 4 basic steps

  1. Define the border-image-source:

     border-image-source:url("https://i.stack.imgur.com/wLdVc.png");  
    
  2. 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.

  3. 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:

Slices example

  1. 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("https://i.stack.imgur.com/wLdVc.png") 2 round;

Complete example

Note: border-style must be set to a value such as solid or dashed as the initial border style is none. Alternatively, you can add a fallback border, such as border: dashed 4px #000 in this example, non-supporting browsers will receive this border.

.bordered {
  display: inline-block;
  padding: 20px;
  /* Optional: 
     A normal dashed border can be set as a fallback, particularly if older browsers need to be supported. Notes:
     - the 4px width here is overwritten with any border-image-width value
     - a border-image-width can be omitted if it is the same value as the dashed border width
  */
  border: dashed 4px #000;/*optional*/

  /* the initial value of border-style is "none", so it must be set to a different value for the border-image to show*/
  border-style: dashed;

  /* Individual border image properties */
  border-image-source: url("https://i.stack.imgur.com/wLdVc.png");
  border-image-slice: 2;
  border-image-repeat: round;

  /* or use the shorthand border-image */
  border-image: url("https://i.stack.imgur.com/wLdVc.png") 2 round;
}


/*The border image of this one creates wider gaps*/

.largeGaps {
  border-image-source: url("https://i.stack.imgur.com/LKclP.png");
  margin: 0 20px;
}
<div class="bordered">This is bordered!</div>

<div class="bordered largeGaps">This is bordered and has larger gaps!</div>
Ewall answered 11/11, 2014 at 5:29 Comment(7)
Note that you need to specify border-style: solid (or something similar) if you omit the fallback.Menial
This solution does not work with 'border-color' attributePackston
@MichaelRovinsky Of course. If you want other colors you'll need to make another image, with the color you want. border-color will never change the color of the border image.Acting
It doesn't work with border-radius. Do you know of a fix for that?Radicand
@KlevisMiho would depend on what type of border you want. Maybe a background image and :before like: css-tricks.com/almanac/properties/b/border-image-source/… or an SVG like the answer below.Ewall
@Ewall this did the trick kovart.github.io/dashed-border-generatorRadicand
This is a bit blurry right?Britishism
M
152

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:

Method 1: Using SVG

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:

  1. SVGs by nature are scalable graphics and can adapt to any container dimensions.
  2. Can work very well even if there is a border-radius involved. We would just have replace the path with a circle like in this answer (or) convert the path into a circle.
  3. Browser support for SVG is pretty good and fallback can be provided using VML for IE8-.

Cons:

  1. When the dimensions of the container do not change proportionately, the paths tend to scale resulting in a change in size of the dash and the space between them (try hovering on the first box in the snippet). This can be controlled by adding vector-effect='non-scaling-stroke' (as in the second box) but the browser support for this property is nil in IE.

.dashed-vector {
  position: relative;
  height: 100px;
  width: 300px;
}
svg {
  position: absolute;
  top: 0px;
  left: 0px;
  height: 100%;
  width: 100%;
}
path{
  fill: none;
  stroke: blue;
  stroke-width: 5;
  stroke-dasharray: 10, 10;
}
span {
  position: absolute;
  top: 0px;
  left: 0px;
  padding: 10px;
}


/* just for demo */

div{
  margin-bottom: 10px;
  transition: all 1s;
}
div:hover{
  height: 100px;
  width: 400px;
}
<div class='dashed-vector'>
  <svg viewBox='0 0 300 100' preserveAspectRatio='none'>
    <path d='M0,0 300,0 300,100 0,100z' />
  </svg>
  <span>Some content</span>
</div>

<div class='dashed-vector'>
  <svg viewBox='0 0 300 100' preserveAspectRatio='none'>
    <path d='M0,0 300,0 300,100 0,100z' vector-effect='non-scaling-stroke'/>
  </svg>
  <span>Some content</span>
</div>

Method 2: Using Gradients

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{
  height: 100px;
  width: 200px;
  padding: 10px;
  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%);
  background-position: left top, left bottom, left top, right top;
  background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
  background-size: 20px 3px, 20px 3px, 3px 20px, 3px 20px;
}

.dashed-repeating-gradient {
  height: 100px;
  width: 200px;
  padding: 10px;
  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%);
  background-position: left top, left bottom, left top, right top;
  background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
  background-size: 20px 3px, 20px 3px, 3px 20px, 3px 20px;
}

/* just for demo */

div {
  margin: 10px;
  transition: all 1s;
}
div:hover {
  height: 150px;
  width: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='dashed-gradient'>Some content</div>
<div class='dashed-repeating-gradient'>Some content</div>

Pros:

  1. Scalable and can adapt even if the container's dimensions are dynamic.
  2. Does not make use of any extra pseudo-elements which means they can be kept aside for any other potential usage.

Cons:

  1. Browser support for linear gradients is comparatively lower and this is a no-go if you want to support IE 9-. Even libraries like CSS3 PIE do not support creation of gradient patterns in IE8-.
  2. Cannot be used when border-radius is involved because backgrounds don't curve based on border-radius. They get clipped instead.

Method 3: Box Shadows

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:

  1. The dimensions of the dash is controllable by changing the dimensions of the pseudo-element. The spacing is controllable by modifying the space between each shadow.
  2. A very unique effect can be produced by adding a different color for each box shadow.

Cons:

  1. Since we have to manually set the dimensions of the dash and the spacing, this approach is no good when the dimensions of the parent box is dynamic.
  2. IE8 and lower do not support box shadow. However, this can be overcome by using libraries like CSS3 PIE.
  3. Can be used with border-radius but positioning them would be very tricky with having to find points on a circle (and possibly even transform).

.dashed-box-shadow{
  position: relative;
  height: 120px;
  width: 120px;
  padding: 10px;
}
.dashed-box-shadow:before{ /* for border top and bottom */
  position: absolute;
  content: '';
  top: 0px;
  left: 0px;
  height: 3px; /* height of the border top and bottom */
  width: 10px; /* width of the border top and bottom */
  background: blue; /* border color */
  box-shadow: 20px 0px 0px blue, 40px 0px 0px blue, 60px 0px 0px blue, 80px 0px 0px blue, 100px 0px 0px blue, /* top border */
    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 */
}
.dashed-box-shadow:after{ /* for border left and right */
  position: absolute;
  content: '';
  top: 0px;
  left: 0px;
  height: 10px; /* height of the border left and right */
  width: 3px; /* width of the border left and right */
  background: blue; /* border color */
  box-shadow: 0px 20px 0px blue, 0px 40px 0px blue, 0px 60px 0px blue, 0px 80px 0px blue, 0px 100px 0px blue, /* left border */
    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 */
}
<div class='dashed-box-shadow'>Some content</div>
Mofette answered 9/7, 2015 at 11:19 Comment(2)
If you're going to use the svg solution I advise adding pointer-events:none to svg inorder to be able to interact with the content.Koestler
While fairly impractical for many border situations, I had not thought to use box shadows like this previously. This opens the possibility of a lot of really cool effects. +1 just for the inspiration.Separation
A
54

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;
}
Antitype answered 23/5, 2020 at 16:31 Comment(3)
This is a simple, easy and quick solutionMaryannemarybella
Wonderful resource, thanks for sharing!Duffie
thanks for sharing @kovart's site, solid solutionOteliaotero
G
37

Update Thanks to kovart for this great tool try it https://kovart.github.io/dashed-border-generator/

 a tool to generate dashed custom borders

my answer was:

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;
}
Gaspard answered 9/1, 2021 at 9:29 Comment(2)
Wow that border generator was a amazing one! Thanks for sharingYuyuan
@CalebTaylor lol he just edited his to add a screenshot of the site I shared a year prior in my answer, but ok :)Antitype
E
28

Short one: No, it's not. You will have to work with images instead.

Eastman answered 5/5, 2010 at 7:3 Comment(6)
this answer is outdated as of 2018Salade
@WilliamHampshire I would go with this technique youtu.be/vs34f9FiHps?t=779 but check accepted answer, you might like other solutions betterSalade
@Salade Thanks!! But's that's using SVG so still not using just css...Swanner
@WilliamHampshire there is box-shadow solution in the thread I meant answer by HarrySalade
@Salade Have you tried the solution? The solution drawn the dashed line segment by segment. It's just a POC and useless in practice!Marnamarne
@YuJianrong yeah, I agree, personally I would use SVG solution (SVG embedded in CSS background-image property)Salade
V
27

Css render is browser specific and I don't know any fine tuning on it, you should work with images as recommended by Ham. Reference: http://www.w3.org/TR/CSS2/box.html#border-style-properties

Vanillin answered 5/5, 2010 at 7:20 Comment(0)
M
12

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

https://jsfiddle.net/ksf9zoLh/

Mauriac answered 12/12, 2019 at 14:3 Comment(2)
But this way you will unable to click contents of original element because "after" pseudoelement will cover it. So the best way is use SVG.Mauriac
You can add pointer-events: none to prevent the overlay issue.Stoup
D
5
.outline {
    outline: 48px dashed #d5fb62;
    outline-offset: -4px;
    overflow:hidden;
}

if overflow hidden not problem else outline 4 instead 48.

<div class="outline"></div>
Darbydarce answered 15/10, 2021 at 10:4 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Necessaries
P
3

I think I've just found the definitive solution to this problem with the use of clip-path property. Basically all there is to add a dashed border then mask the excess.

The clip-path property also supports rounded corners so you can match it up with the border-radius and have custom dashed borders and rounded corners!

.demo {
  display: inline-flex;
  width: 200px;
  height: 100px;
  position: relative;
  clip-path: inset(0 round 30px 0 30px 0);
}

.demo::before {
  content: '';
  position: absolute;
  left: -7px;
  top: -7px;
  right: -7px;
  bottom: -7px;
  border: 8px dashed rgba(0, 0, 255, 0.3);
  border-radius: 37px 0 37px 0;
  box-sizing: border-box;
}
<div class="demo"></div>

You could do this directly on the div itself of course without using the ::after pseudo element. But this would mean you have to clip into the div and it would end up smaller than it's initial size.

Pipit answered 30/3, 2022 at 17:42 Comment(0)
T
0

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.

Though answered 7/2, 2020 at 8:17 Comment(0)
H
-1

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;
}
Holloway answered 13/11, 2019 at 21:28 Comment(1)
By "provide greater control of the dashed borders appearance", the OP (Original Poster) means that he wants to control the length of each dash, as stated at the beginning of the question. Sorry for any confusion.Untuck

© 2022 - 2024 — McMap. All rights reserved.