I am trying to show the proper amount (and color) of dots based on the class that is indicated for each various element. There will be several different required colors (probably 7 or 8), and some will be mixed. Chaining is not really an option, unfortunately, due to the large quantity of possible combinations.
<a class="reddot bluedot greendot purpledot"> Blah Blah Blah</a>
<a class="purpledot"> Blah Blah Blah</a>
<a class="greendot blackdot"> Blah Blah Blah</a>
I've tried the following css:
.reddot{
background-image: url('/images/reddot.png');
background-position: right bottom;
background-repeat: no-repeat;
}
.bluedot{
background-image: url('/images/bluedot.png');
background-position: right bottom;
background-repeat: no-repeat;
}
.reddot.bluedot{
background-image: url('/images/reddot.png'),url('/images/bluedot.png');
background-position: right bottom;
background-repeat: no-repeat;
}
etc.
Yes, I know the images overlap here ... that's not really the end of the world. I think I know how to position them better.
The above css code gets me what I want, but there are so many combinations of the various elements that change.
I know I'm working with background-image here, and I know that the classes cannot be accumulated (therefore, chaining seems like the only way). However, is there another way using CSS that I can find a way to add dots .. or other background or foreground images or icons .. simply by adding classes to the html?
I can't add or any other hierarchy of classes.
Let's assume that you always want dots and that the colors are always in the same order...
Gradients
You can do this with CSS background-gradients and variables but its a bit complex.
Here's an example (and on Codepen if you want to play with it) I made the default gray but you could change it to transparent if you don't want to visually show the slots.
.dots {
border: 1px #dadada solid;
min-height: 2rem;
width: 10rem;
margin: 1rem 2rem;
background:
radial-gradient(1rem 1rem at 1rem 50%, var(--c1, #dadada) 45%, transparent 51%),
radial-gradient(1rem 1rem at 2.5rem 50%, var(--c2, #dadada) 45%, transparent 51%),
radial-gradient(1rem 1rem at 4rem 50%, var(--c3, #dadada) 45%, transparent 51%),
radial-gradient(1rem 1rem at 5.5rem 50%, var(--c4, #dadada) 45%, transparent 51%);
}
.red {
--c1:#D50000;
}
.gold {
--c2:#FDD835;
}
.blue {
--c3:#1976D2;
}
.green {
--c4:#00E676;
}
<div class="dots"></div>
<div class="dots red blue"></div>
<div class="dots green"></div>
<div class="dots gold blue"></div>
<div class="dots red gold green blue"></div>
Edit: Using a background image instead
If you don't like the look of a radial gradient, you could chain and position background-image the same way. In this case, you would use a variable for the file path you want to display in the background.
.stackedBG {
border: 1px #dadada solid;
height: 40px;
width: 160px; /* 40 *4 */
margin: 1rem 2rem;
background-color: transparent;
background-image: var(--b1, none), var(--b2, none), var(--b3, none), var(--b4, none);
/* all images are 40x40px */
background-position: 0 0px, 40px 0, 80px 0, 120px 0;
background-repeat: no-repeat;
}
.bg1 {
--b1:url(https://i.imgur.com/ivPLv2g.png);
}
.bg2 {
--b2:url(https://i.imgur.com/v8GNPuX.png);
}
.bg3 {
--b3:url(https://i.imgur.com/ywuzlHn.png);
}
.bg4 {
--b4:url(https://i.imgur.com/peTsfUi.png);
}
<div class="stackedBG bg3"></div>
<div class="stackedBG bg1"></div>
<div class="stackedBG bg2 bg4"></div>
<div class="stackedBG bg1 bg2 bg3 bg4"></div>
Edit 2: Positioning background
I think the easiest way to position either of these options (if relative to the upper left isn't desired) is to use a pseudo-element. Contain the backgrounds in a :after or :before and then absolutely position the pseudo-element.
.dots {
border: 1px #dadada solid;
min-height: 5rem;
margin: 1rem 2rem;
padding: 0.5rem;
font-family: Sans-Serif;
/* the important part */
position: relative;
}
.dots:after {
content:'';
position: absolute;
/* size is based on the background layout */
width:6.5rem;
height: 1rem;
/* typically I would do positioning here
But it's easier to show an example if its separate */
background:
radial-gradient(1rem 1rem at 1rem 50%, var(--c1, #dadada) 45%, transparent 51%),
radial-gradient(1rem 1rem at 2.5rem 50%, var(--c2, #dadada) 45%, transparent 51%),
radial-gradient(1rem 1rem at 4rem 50%, var(--c3, #dadada) 45%, transparent 51%),
radial-gradient(1rem 1rem at 5.5rem 50%, var(--c4, #dadada) 45%, transparent 51%);
background-repeat: no-repeat;
}
/* positioning */
.tr:after {
top: 0.5rem;
right: 0.5rem;
}
.br:after {
bottom: 0.5rem;
right: 0.5rem;
}
.tl:after {
top: 0.5rem;
left: 0.5rem;
}
.bl:after {
bottom: 0.5rem;
left: 0.5rem;
}
/* variables still work the same with the pseudo class */
.red {
--c1:#D50000;
}
.gold {
--c2:#FDD835;
}
.blue {
--c3:#1976D2;
}
.green {
--c4:#00E676;
}
<div class="dots">Parent Element</div>
<div class="dots red blue tr">Parent Element</div>
<div class="dots green tl">Parent Element</div>
<div class="dots gold blue br">Parent Element</div>
<div class="dots red gold green blue bl">Parent Element</div>
Unfortunatley I don't believe you can accomplish this with pure css.
My suggestion would be to append whatever dots you need to your <a></a> element. Like <span class=""reddot></span>. Then you can then style then independently, and let them position themselves naturally.
I've made an example here: example fiddle
Related
I have a div that gets resized programmatically and sits inside a wrapper div. I would like the background color of the (inner) div to be a gradient, but with the gradient based on the height of the wrapper div.
For example, the gradient could be something like background: linear-gradient(0deg, green 0%, green 50%, yellow 80%, orange 90%, red 100%)
When the inner div is less than 50% of the height of the wrapper div, I want it to be completely green, but if it gets to 70%, it would start to turn yellow at the top, at 80% it starts going orange at the top and if it hit 100% it would have the full gradient. See the codepen below for an example of what I mean in terms of the colors.
The inner div will be resized every 10th of a second or so and will look similar to an audio peak meter.
Is this possible to achieve with pure CSS, or do I need to use javascript? If I use javascript, would it be more performant to have a bunch of css classes and switch them depending on percentage, or color things directly?
I could achieve this with multiple blocks, something like https://codepen.io/octod/pen/vPQLVo (not mine), but ideally I want it to be one continuous block of color with a smooth gradient.
I could also achieve it by keeping the inner div full height and resizing an overlay div, but unfortunately I have a transparent background, so this is not ideal.
EDIT: As requested, this is what I currently have that does not work (it shows the full gradient when the inner div is not the full height). I have simplified it and put css inline for this post.
real snippet: (Edited by Mister Jojos - this is not representative of my code, but the accepted answer is based on this version, so I have left it like this)
.outer {
display: inline-block;
height: 400px;
width: 40px;
background-color: dimgrey;
padding: 5px;
margin: 1em;
}
.outer > div {
width: 100%;
}
#inner50 {
height: 50%;
background: linear-gradient(0deg, green 0%, green 50%, yellow 80%, orange 90%, red 100%);
}
#inner70 { /* please set the gradient values */
height: 70%;
background: linear-gradient(0deg, green 0%, green 50%, yellow 80%, orange 90%, red 100%);
}
#inner100 { /* please set the gradient values */
height: 100%;
background: linear-gradient(0deg, green 0%, green 50%, yellow 80%, orange 90%, red 100%);
}
<!-- result in case 50% -->
<div class="outer"> <div id="inner50"></div> </div>
<!-- result in case 70% -->
<div class="outer"> <div id="inner70"></div> </div>
<!-- result in case 100% -->
<div class="outer"> <div id="inner100"></div> </div>
Javascript snippet:
// this function is called every 1/10th of a second
function updateMeter(newHeight) {
getElementById("inner").style.height = newHeight+'px';
}
Simply fix the size of the gradient to the size of the outer div:
.outer {
display: inline-block;
height: 400px;
width: 40px;
background-color: dimgrey;
padding: 5px;
margin: 1em;
}
.outer>div {
width: 100%;
background:
linear-gradient(0deg, green 0%, green 50%, yellow 80%, orange 90%, red 100%)
top/ /* place it on the top */
100% 400px; /* width=100% height=400px */
}
#inner50 {
height: 50%;
}
#inner70 {
height: 70%;
}
#inner100 {
height: 100%;
}
<!-- result in case 50% -->
<div class="outer">
<div id="inner50"></div>
</div>
<!-- result in case 70% -->
<div class="outer">
<div id="inner70"></div>
</div>
<!-- result in case 100% -->
<div class="outer">
<div id="inner100"></div>
</div>
Also like below:
.outer {
display: inline-flex;
height: 400px;
width: 40px;
background-color: dimgrey;
padding: 5px;
margin: 1em;
}
.outer>div {
width: 100%;
margin-top:auto;
background:
linear-gradient(0deg, green 0%, green 50%, yellow 80%, orange 90%, red 100%)
bottom/ /* place it on the top */
100% 400px; /* width=100% height=400px */
}
#inner50 {
height: 50%;
}
#inner70 {
height: 70%;
}
#inner100 {
height: 100%;
}
<!-- result in case 50% -->
<div class="outer">
<div id="inner50"></div>
</div>
<!-- result in case 70% -->
<div class="outer">
<div id="inner70"></div>
</div>
<!-- result in case 100% -->
<div class="outer">
<div id="inner100"></div>
</div>
div {
height: 50px;
width: 100%;
background-image: linear-gradient(to right, white 50%, red 46px);
}
body {
padding: 20px;
}
<div></div>
I'm trying to use linear gradients as a two tone solid color background in a div.
The div can be any width, and I would like one of the colors to have a specified width in px - and the other color to fill up whatever is left of the total width. Is that possible as all?
Like:
div {
background-image: linear-gradient(to right, white auto, red 46px);
}
You Can simply go with:
Use the fixed background colour first then just put 0 in the second colour it will fill the rest of the div.
background: linear-gradient(to right, lightgreen 19px, darkgreen 0);
This will work fine for you.
div {
display: inline-block;
background: linear-gradient(to right, lightgreen 19px, darkgreen 0);
width: 50%;
height: 100px;
color: white;
text-align: center;
}
<div>
Test
</div>
Hope this was helpfull.
You can try this :
Use the value needed for the first color (here 46px) and simply use a small value for the second color (between 0 and 45px). Then change the direction of the gradient depending on your needs.
div.first {
height:100px;
background-image: linear-gradient(to right, red 46px, blue 40px);
}
div.second {
margin-top:10px;
height:100px;
background-image: linear-gradient(to left, red 46px, blue 0px);
}
<div class="first">
</div>
<div class="second">
</div>
I think this is a nice time to use css variables, we can set a variable as a breakpoint and only have to update that one variable when moving the gradient.
div {
--gradient-break: calc(100% - 46px);
height: 50px;
background-image: linear-gradient(to right, darkgreen var(--gradient-break), tomato var(--gradient-break));
}
<div></div>
You can use this method to make a Javascript controlled progress bar.
let progressCounter = 0;
setInterval(function() {
if (progressCounter >= 100) {
progressCounter = 0;
} else {
progressCounter++;
}
document.querySelector('.progress').style.setProperty('--gradient-break', progressCounter + "%")
}, 50)
div.progress {
--gradient-break: 0%;
height: 50px;
background-image: linear-gradient(to right, darkgreen var(--gradient-break), tomato var(--gradient-break));
}
<div class="progress"></div>
I'm setting the progress percentage with document.querySelector('.progress').style.setProperty('--gradient-break',progressCounter+"%") and the css is taking care of the rest.
Hope this is helpful.
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
Are there any methods that can provide greater control of the dashed borders appearance?
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!
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:
This is what it looks like to scale:
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:
correctly scaled =
Step 2 - Create the CSS — this example requires 4 basic steps
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;
Complete example
Note the border: dashed 4px #000 fallback. Non-supporting browsers will receive this border.
.bordered {
display: inline-block;
padding: 20px;
/* Fallback dashed border
- the 4px width here is overwritten with the border-image-width (if set)
- the border-image-width can be omitted below if it is the same as the 4px here
*/
border: dashed 4px #000;
/* Individual border image properties */
border-image-source: url("http://i.stack.imgur.com/wLdVc.png");
border-image-slice: 2;
border-image-repeat: round;
/* or use the shorthand border-image */
border-image: url("http://i.stack.imgur.com/wLdVc.png") 2 round;
}
/*The border image of this one creates wider gaps*/
.largeGaps {
border-image-source: url("http://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>
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:
SVGs by nature are scalable graphics and can adapt to any container dimensions.
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.
Browser support for SVG is pretty good and fallback can be provided using VML for IE8-.
Cons:
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:
Scalable and can adapt even if the container's dimensions are dynamic.
Does not make use of any extra pseudo-elements which means they can be kept aside for any other potential usage.
Cons:
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-.
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:
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.
A very unique effect can be produced by adding a different color for each box shadow.
Cons:
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.
IE8 and lower do not support box shadow. However, this can be overcome by using libraries like CSS3 PIE.
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>
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;
}
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
Short one: No, it's not. You will have to work with images instead.
Update
Thanks to kovart for this great tool try it
https://kovart.github.io/dashed-border-generator/
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;
}
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/
.outline {
outline: 48px dashed #d5fb62;
outline-offset: -4px;
overflow:hidden;
}
if overflow hidden not problem else outline 4 instead 48.
<div class="outline"></div>
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.
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.
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;
}
I found some information about border-color and it turns out, that you can specify each of the borders with different colors. My question here is following: Is it possible to specify the left border with two or more colors?
The deal is, that I have a navigation bar, with li elements, which are divided with padding and a border properties. For example:
li {
float: left;
padding-left&right: 10px;
border-left: 2px solid white;
}
and the border is as tall as the text itself in the li element. What I need is to get the border shorter than text. So I thought I could give it 3 colors: transparent - white - transparent.
Maybe there is a realistic way to do this? This was just at the top of my head and I found information, that it is not possible to shorten the border under the height of the li element.
The most appropriate way to implement this would be to make use of the border-image property along with a linear gradient like mentioned in Stephen Brickner's answer. But the downside to it is the browser support which is very low at present.
There are a couple of other approaches with better browser support than can be made use of and they are as follows:
Method 1: Pseudo Elements with Border
You could make use of a pseudo-element (:before or :after) with height shorter than the parent li element, add a border to it and position it appropriately to achieve the required effect. Thickness of the separator line is determined by the width of the pseudo-element's border.
.right-to-left {
position: relative;
float: left;
width: 150px;
padding: 0px 10px;
}
.right-to-left:after {
position: absolute;
content: '';
right: 0px;
height: 50%;
top: 25%;
border-right: 2px solid;
}
/* just for demo */
body {
background: black;
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
color: white;
}
<div class="right-to-left">Some text <br/> and more</div>
<div class="right-to-left">Some text <br/> and more</div>
<div class="right-to-left">Some text <br/> and more</div>
This method has the highest browser support among the possible options. However, it cannot be used if more than one color is required for the separator (or) a gradient effect is required.
Method 2: Background Gradients
You could add a linear-gradient as background image to the element and position it appropriately to produce a line shorter than the text. In this approach, thickness of the separator line is determined by the width of the background image.
.right-to-left {
width: 150px;
float: left;
padding: 0px 10px;
background-image: linear-gradient(to bottom, transparent 25%, white 25%, white 75%, transparent 75%);
background-size: 2px 100%;
background-repeat: no-repeat;
background-position: right top;
}
.right-to-left.multi {
background-image: linear-gradient(to bottom, transparent 25%, red 25%, white 75%, transparent 75%);
}
/* just for demo */
body {
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
color: white;
}
hr{ clear: both; }
div{ margin: 10px 0px; }
<!-- prefix free library to support old browsers and avoid prefixes -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="right-to-left">Some text <br/> and more</div>
<div class="right-to-left">Some text <br/> and more</div>
<div class="right-to-left">Some text <br/> and more</div>
<hr>
<div class="right-to-left multi">Some text <br/> and more</div>
<div class="right-to-left multi">Some text <br/> and more</div>
<div class="right-to-left multi">Some text <br/> and more</div>
The browser support for this is better than border-image approach but worse when compared with the pseudo-element approach. The advantage is that the separator can have multiple colors or even a gradient pattern like in the above snippet.
You have to use a transform on it. Example:
.right-to-left {
border-width: 3px 3px 3px 0;
border-style: solid;
-webkit-border-image:
-webkit-gradient(linear, 0 0, 100% 0, from(black), to(rgba(0, 0, 0, 0))) 1 100%;
-webkit-border-image:
-webkit-linear-gradient(left, black, rgba(0, 0, 0, 0)) 1 100%;
-moz-border-image:
-moz-linear-gradient(left, black, rgba(0, 0, 0, 0)) 1 100%;
-o-border-image:
-o-linear-gradient(left, black, rgba(0, 0, 0, 0)) 1 100%;
border-image:
linear-gradient(to left, black, rgba(0, 0, 0, 0)) 1 100%;
}
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
Are there any methods that can provide greater control of the dashed borders appearance?
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!
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:
This is what it looks like to scale:
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:
correctly scaled =
Step 2 - Create the CSS — this example requires 4 basic steps
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;
Complete example
Note the border: dashed 4px #000 fallback. Non-supporting browsers will receive this border.
.bordered {
display: inline-block;
padding: 20px;
/* Fallback dashed border
- the 4px width here is overwritten with the border-image-width (if set)
- the border-image-width can be omitted below if it is the same as the 4px here
*/
border: dashed 4px #000;
/* Individual border image properties */
border-image-source: url("http://i.stack.imgur.com/wLdVc.png");
border-image-slice: 2;
border-image-repeat: round;
/* or use the shorthand border-image */
border-image: url("http://i.stack.imgur.com/wLdVc.png") 2 round;
}
/*The border image of this one creates wider gaps*/
.largeGaps {
border-image-source: url("http://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>
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:
SVGs by nature are scalable graphics and can adapt to any container dimensions.
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.
Browser support for SVG is pretty good and fallback can be provided using VML for IE8-.
Cons:
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:
Scalable and can adapt even if the container's dimensions are dynamic.
Does not make use of any extra pseudo-elements which means they can be kept aside for any other potential usage.
Cons:
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-.
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:
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.
A very unique effect can be produced by adding a different color for each box shadow.
Cons:
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.
IE8 and lower do not support box shadow. However, this can be overcome by using libraries like CSS3 PIE.
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>
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;
}
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
Short one: No, it's not. You will have to work with images instead.
Update
Thanks to kovart for this great tool try it
https://kovart.github.io/dashed-border-generator/
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;
}
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/
.outline {
outline: 48px dashed #d5fb62;
outline-offset: -4px;
overflow:hidden;
}
if overflow hidden not problem else outline 4 instead 48.
<div class="outline"></div>
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.
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.
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;
}