21

Is it possible to use CSS to define a line (or shape edge) with two alternating colors that are dashed? That is, if 1 and 2 are different colored pixels, then

1212121212121212 or 112211221122

I basically want some way to use stroke-dasharray with two colors. The line itself is completely colored.

If this is not possible, what is a good way to approximate it? For example, I could create a repeated linear gradient with two colors alternating, but this would be hard to set the two colors from javascript.

Andrew Mao
  • 35,740
  • 23
  • 143
  • 224
  • One way: http://www.webdevout.net/test?01v&raw (that is, layer one element with one color behind another with another color [in the form of a dashed stroke]) – reisio Sep 25 '12 at 01:29
  • What reisio said seems to be the best and safest answer so far. Duopixel's solution seems to have more potential for screwups if the browser does something wrong. Mind converting your comment to an answer? – Andrew Mao Sep 25 '12 at 07:36

6 Answers6

34

This is not possible in SVG with just one element, but you can use two different rects and then apply a stroke-dashoffset: x...

rect.stroke-red {
  stroke: red;
  fill: none;
  stroke-width: 5;
}

rect.stroke-green {
  stroke: green;
  fill: none;
  stroke-dasharray: 5,5; 
  stroke-width: 5;
}
<svg xmlns="http://www.w3.org/2000/svg">
    <rect class="stroke-red" x="10" y="10" width="101" height="101" />
    <rect class="stroke-green" x="10" y="10" width="101" height="101" />
</svg>
methodofaction
  • 70,885
  • 21
  • 151
  • 164
  • 2
    Your answer is good, but I'll point out that I prefer the implementation in the above comment - solid line rectangle behind a dashed line rectangle - for being less error-prone. It seems like the `stroke-dashoffset` could result in funny looking rectangles if the CSS was slightly off or the browser started the dashes in different places. – Andrew Mao Oct 01 '12 at 06:37
  • 1
    I think if the browser is starting the dashes in different places that's a browser bug, and if the CSS is slightly off, you're going to have the same issues with the solution from @reisio. However, that answer will work for browsers that don't support SVG. – Colin Young Mar 22 '13 at 19:32
  • 1
    The first version was actually better. @AndrewMao, overlaying the stripes on top of a solid stroke messes up the anti-aliasing. http://jsfiddle.net/rkzpC/ – Wray Bowling Feb 03 '14 at 00:48
20

Building on the answer from @duopixel, you can use the stroke-dasharray property to build up a fairly complex pattern with multiple colors:

.L4 {
    stroke: #000;
    stroke-dasharray: 20,10,5,5,5,10;
}
.L5 {
    stroke: #AAA;
    stroke-dasharray: 0,20,10,15,10,0
}
.L6 {
    stroke: #DDD;
    stroke-dasharray: 0,35,5,15
}

See http://jsfiddle.net/colin_young/Y38u9/ demonstrating lines and a circle with the composite dash pattern.

Updated with SO snippet:

svg {
    width: 100%;
    height: 160px;
}
path, circle {
    stroke-width: 4;
}
text {
    alignment-baseline: central;
    font-family: sans-serif;
    font-size: 10px;
    stroke-width: 0;
    fill: #000;
    text-anchor: middle;
}
.dim {
    stroke: #AAA;
    stroke-width: 1;
    stroke-dasharray: 1, 1;
}
circle.dim {
    fill: #FFF;
}
.L4 {
    stroke: #000;
    stroke-dasharray: 20, 10, 5, 5, 5, 10;
}
.L5 {
    stroke: #AAA;
    stroke-dasharray: 0, 20, 10, 15, 10, 0
}
.L6 {
    stroke: #DDD;
    stroke-dasharray: 0, 35, 5, 15
}
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
    <g fill="none" stroke="black">
        <path class="dim" d="M5 20 l0 80" />
        <path class="dim" d="M25 20 l0 80 l-10 20" />
        <path class="dim" d="M35 20 l0 80 l-10 30" />
        <path class="dim" d="M40 20 l0 120" />
        <path class="dim" d="M45 20 l0 80 l10 30" />
        <path class="dim" d="M50 20 l0 80 l10 20" />
        <path class="dim" d="M60 20 l0 80 l15 10" />

        <text x="5" y="110">0</text>
        <text x="5" y="125">20</text>
        <text x="25" y="135">30</text>
        <text x="40" y="150">35</text>
        <text x="55" y="140">40</text>
        <text x="65" y="125">45</text>
        <text x="82" y="115">55</text>

        <path class="L4" d="M5 20 l215 0" />
        <path class="L5" d="M5 20 l215 0" />
        <path class="L6" d="M5 20 l215 0" />

        <!-- separated to show composition -->
        <text x="5" y="70" style="text-anchor:start">Separated to show composition:</text>
        <path class="L4" d="M5 80 l215 0" />
        <path class="L5" d="M5 90 l215 0" />
        <path class="L6" d="M5 100 l215 0" />

        <circle class="L4" cx="400" cy="80" r="60" />
        <circle class="L5" cx="400" cy="80" r="60" />
        <circle class="L6" cx="400" cy="80" r="60" />
    </g>
</svg>
Colin Young
  • 3,018
  • 1
  • 22
  • 46
3

One way:

<!doctype html>
<html>
	<head>
		<title></title>
		<style>
div {
	width: 100px;
	height: 100px;
}
.dashbox {
	border: 4px dashed blue;
	background: orange;
}
.dashbox > div {
	background: white;
}
		</style>
	</head>
	<body>
		<div class="dashbox">
			<div></div>
		</div>
	</body>
</html>

That is, layer one element with one color behind another with another color [in the form of a dashed stroke].

reisio
  • 3,242
  • 1
  • 23
  • 17
1

Here is a CSS only solution.

<div style="
    margin:1rem;
    width:4rem;
    height:4rem;
    border:5px solid red;
    outline:5px dashed green;
    outline-offset: -5px;"
></div>
Terry Riegel
  • 159
  • 10
0

One way that might work for you is using a repeating linear gradient on the stroke. It's a workaround that works well for lines, since you can rotate the gradient to match the line.

For other shapes - it may work, but not as good as a dash array. On the up side, it's css-only, and does not require extra shapes.

Codepen example:

https://codepen.io/michbarsinai/pen/YzwXYwg

Michael Bar-Sinai
  • 2,729
  • 20
  • 27
-3

For a border that has 50 dashes along the bottom, create 50 divs with increasing margin-left, and an overall container with overflow:hidden.

Sebass van Boxel
  • 2,514
  • 1
  • 22
  • 37