Skip to content

Instantly share code, notes, and snippets.

@bgoonz
Created August 15, 2022 18:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bgoonz/2aea9e758c74e32d70202748095cdf72 to your computer and use it in GitHub Desktop.
Save bgoonz/2aea9e758c74e32d70202748095cdf72 to your computer and use it in GitHub Desktop.
Dashed Border Generator
<div class="content">
<h2>Dashed border using <span>background-image</span> property</h2>
<p>
Creating dashed borders with background-image is not a new concept. Many people use it because it allows full flexibility, and with a little creativity (and a few lines of code) it is possible to do cool things without it being too complicated.
</p>
<div class="boxes">
<div class="box box-a">Simple</div>
<div class="box box-b">Slanted</div>
<div class="box box-c">Dotted</div>
<div class="box box-d">Long</div>
<div class="box box-e">Cornered</div>
<div class="box box-f">Centered</div>
<div class="box box-g">Faded</div>
<div class="box box-h">Animated</div>
</div>
<hr>
<h2>Create your own <span>background-image</span> border</h2>
<div class="generator">
<form>
<Label>
Border width
<input name="borderWidth" type="range" class="input" min="1" max="10" value="3">
</Label>
<Label>
Border color<br>
<input name="borderColor" type="color" class="input" value="#333333">
</Label>
<Label>
Dash length
<input name="dashLength" type="range" class="input" min="1" max="30" value="10">
</Label>
<Label>
Spacing
<input name="spacing" type="range" class="input" min="1" max="30" value="10">
</Label>
<Label>
Slanting angle
<input name="slanting" type="range" class="input" min="-60" max="60" value="0">
</Label>
<Label>
Fade
<input name="borderFade" type="range" class="input" min="0" max="100" value="0">
</Label>
<Label>
<input name="diraction" type="checkbox">
Flip diraction
</Label>
<Label>
Animation
<input name="animation" type="range" class="input" min="0" max="1" step="0.1" value="0">
</Label>
</form>
<div class="result"></div>
</div>
</div>
<a href="https://twitter.com/bgooonz" class="twitterLink" target="_blank">
<img src="https://assets.codepen.io/1948355/twitterLogo2.png" />
</a>
function _(e, all=false) {
let divs = document.querySelectorAll(e);
if (all || (divs.length > 1)) { return divs; }
return divs[0];
}
_('input', true).forEach(element => {
element.addEventListener('input', drawBordr);
});
const resultDiv = _('.result');
drawBordr();
function drawBordr() {
let borderWidth = Number(_('[name="borderWidth"]').value);
let color1 = _('[name="borderColor"]').value;
let dashLength = Number(_('[name="dashLength"]').value);
let spacing = Number(_('[name="spacing"]').value);
let slanting = Number(_('[name="slanting"]').value);
let borderFade = 100 - Number(_('[name="borderFade"]').value);
let diraction = _('[name="diraction"]').checked;
let animation = Number(_('[name="animation"]').value);
let color2 = 'transparent';
const backgroundImage = `
repeating-linear-gradient(${slanting + (diraction ? 180 : 0) }deg, ${color1}, ${color1} ${Math.round(dashLength * borderFade) / 100}px, ${color2} ${dashLength}px, ${color2} ${dashLength + (Math.round(spacing * borderFade) / 100)}px, ${color1} ${dashLength + spacing}px),
repeating-linear-gradient(${slanting + (diraction ? 270 : 90)}deg, ${color1}, ${color1} ${Math.round(dashLength * borderFade) / 100}px, ${color2} ${dashLength}px, ${color2} ${dashLength + (Math.round(spacing * borderFade) / 100)}px, ${color1} ${dashLength + spacing}px),
repeating-linear-gradient(${slanting + (diraction ? 0 : 180) }deg, ${color1}, ${color1} ${Math.round(dashLength * borderFade) / 100}px, ${color2} ${dashLength}px, ${color2} ${dashLength + (Math.round(spacing * borderFade) / 100)}px, ${color1} ${dashLength + spacing}px),
repeating-linear-gradient(${slanting + (diraction ? 90 : 270)}deg, ${color1}, ${color1} ${Math.round(dashLength * borderFade) / 100}px, ${color2} ${dashLength}px, ${color2} ${dashLength + (Math.round(spacing * borderFade) / 100)}px, ${color1} ${dashLength + spacing}px)`;
const borderLengthPx = Math.round((dashLength + spacing) / Math.sin((90 - Math.abs(slanting)) * Math.PI / 180) * 100) / 100;
const borderLength = (animation > 0) ? `calc(100% + ${borderLengthPx}px)` : '100%';
const backgroundSize = `${borderWidth}px ${borderLength}, ${borderLength} ${borderWidth}px, ${borderWidth}px ${borderLength} , ${borderLength} ${borderWidth}px`;
const backgroundPosition = `0 0, 0 0, 100% 0, 0 100%`;
resultDiv.style.backgroundImage = backgroundImage;
resultDiv.style.backgroundSize = backgroundSize;
resultDiv.style.backgroundPosition = backgroundPosition;
const animationPropery = (animation > 0) ? `borderAnimation ${Math.round((1.1 - animation) * 10) / 10}s infinite linear${diraction ? ' reverse' : ''}` : 'unset';
resultDiv.style.animation = animationPropery;
let animationTxt = '';
if (animation > 0) {
document.documentElement.style.setProperty('--AnimationLength', `-${borderLengthPx}px`);
animationTxt = `
<span><b>animation:</b> ${animationPropery};</span>
}<br>
<br>
@keyframes <b>borderAnimation</b> {
<span>from { background-position: 0 0, -${borderLengthPx}px 0, 100% -${borderLengthPx}px, 0 100%; }</span>
<span>to { background-position: 0 -${borderLengthPx}px, 0 0, 100% 0, -${borderLengthPx}px 100%; }</span>
`;
}
resultDiv.style.padding = `calc(1em + ${borderWidth}px)`;
resultDiv.innerHTML = `
<code>
.box {
<span><b>background-image:</b> ${backgroundImage};</span>
<span><b>background-size:</b> ${backgroundSize};</span>
<span><b>background-position:</b> ${backgroundPosition};</span>
<span><b>background-repeat:</b> no-repeat; </span>
${animationTxt}
}
</code>
`;
}
@import url('https://fonts.googleapis.com/css2?family=Open+Sans+Condensed:wght@300;700&display=swap');
*, *::before, *::after {
padding: 0;
margin: 0 auto;
box-sizing: border-box;
}
body {
font-family: 'Open Sans Condensed', sans-serif;
min-height: 100vh;
background-color: #eee;
background-size: 10px 10px;
background-image:
radial-gradient(circle at 50% 50%, #ddd, #ddd 1px, transparent 1px),
radial-gradient(circle at 0 0, #ddd, #ddd 1px, transparent 1px),
radial-gradient(circle at 0 100%, #ddd, #ddd 1px, transparent 1px),
radial-gradient(circle at 100% 0, #ddd, #ddd 1px, transparent 1px),
radial-gradient(circle at 100% 100%, #ddd, #ddd 1px, transparent 1px);
color: #333;
}
:root {
--clr-border: #333;
--AnimationLength: 0px;
}
.content {
width: 100%; max-width: 960px;
padding: 2em 2em 10em;
}
h2 {
margin: 1em auto;
text-decoration: underline;
text-decoration-color: #aaa;
& span {
color: #777;
}
}
p {
margin: 2em auto;
font-weight: bold;
}
hr {
height: 3px;
border: none;
margin: 4em auto;
background-color: #aaa;
}
.boxes {
width: 100%;
display: grid;
grid-gap: 2em;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
}
.box {
display: flex;
justify-content: center;
align-items: center;
width: 100%; height: 123px;
font-size: 2em;
padding: 0.5em;
line-height: 1;
background-position: 0 0, 0 0, 100% 0, 0 100%;
background-size: 3px 100%, 100% 3px, 3px 100% , 100% 3px;
background-repeat: no-repeat;
}
.box-a { // Simple
background-image:
repeating-linear-gradient(0deg, var(--clr-border), var(--clr-border) 10px, transparent 10px, transparent 20px), // left
repeating-linear-gradient(90deg, var(--clr-border), var(--clr-border) 10px, transparent 10px, transparent 20px), // top
repeating-linear-gradient(180deg, var(--clr-border), var(--clr-border) 10px, transparent 10px, transparent 20px), // right
repeating-linear-gradient(270deg, var(--clr-border), var(--clr-border) 10px, transparent 10px, transparent 20px) // bottom
;
border-image: repeating-linear-gradient(0deg, var(--clr-border), var(--clr-border) 10px, transparent 10px, transparent 20px);
}
.box-b { // Slanted
background-image:
repeating-linear-gradient(45deg, var(--clr-border), var(--clr-border) 10px, transparent 10px, transparent 20px), // left
repeating-linear-gradient(135deg, var(--clr-border), var(--clr-border) 10px, transparent 10px, transparent 20px), // top
repeating-linear-gradient(225deg, var(--clr-border), var(--clr-border) 10px, transparent 10px, transparent 20px), // right
repeating-linear-gradient(315deg, var(--clr-border), var(--clr-border) 10px, transparent 10px, transparent 20px) // bottom
;
}
.box-c { // Dotted
background-image:
repeating-linear-gradient(0deg, var(--clr-border), var(--clr-border) 3px, transparent 3px, transparent 6px), // left
repeating-linear-gradient(90deg, var(--clr-border), var(--clr-border) 3px, transparent 3px, transparent 6px), // top
repeating-linear-gradient(180deg, var(--clr-border), var(--clr-border) 3px, transparent 3px, transparent 6px), // right
repeating-linear-gradient(270deg, var(--clr-border), var(--clr-border) 3px, transparent 3px, transparent 6px) // bottom
;
}
.box-d { // Long
background-image:
repeating-linear-gradient(0deg, var(--clr-border), var(--clr-border) 30px, transparent 30px, transparent 36px), // left
repeating-linear-gradient(90deg, var(--clr-border), var(--clr-border) 30px, transparent 30px, transparent 36px), // top
repeating-linear-gradient(180deg, var(--clr-border), var(--clr-border) 30px, transparent 30px, transparent 36px), // right
repeating-linear-gradient(270deg, var(--clr-border), var(--clr-border) 30px, transparent 30px, transparent 36px) // bottom
;
}
.box-e { // Cornered
background-image:
linear-gradient(0deg, var(--clr-border), var(--clr-border) 25%, transparent 25%, transparent 75%, var(--clr-border) 75%), // left
linear-gradient(90deg, var(--clr-border), var(--clr-border) 25%, transparent 25%, transparent 75%, var(--clr-border) 75%), // top
linear-gradient(180deg, var(--clr-border), var(--clr-border) 25%, transparent 25%, transparent 75%, var(--clr-border) 75%), // right
linear-gradient(270deg, var(--clr-border), var(--clr-border) 25%, transparent 25%, transparent 75%, var(--clr-border) 75%) // bottom
;
}
.box-f { // Centered
background-image:
linear-gradient(0deg, transparent 15%, var(--clr-border) 15%, var(--clr-border) 85%, transparent 85%), // left
linear-gradient(90deg, transparent 15%, var(--clr-border) 15%, var(--clr-border) 85%, transparent 85%), // top
linear-gradient(180deg, transparent 15%, var(--clr-border) 15%, var(--clr-border) 85%, transparent 85%), // right
linear-gradient(270deg, transparent 15%, var(--clr-border) 15%, var(--clr-border) 85%, transparent 85%) // bottom
;
}
.box-g { // Faded
background-image:
repeating-linear-gradient(0deg, var(--clr-border), var(--clr-border) 10px, transparent 20px, transparent 30px, var(--clr-border) 40px), // left
repeating-linear-gradient(90deg, var(--clr-border), var(--clr-border) 10px, transparent 20px, transparent 30px, var(--clr-border) 40px), // top
repeating-linear-gradient(180deg, var(--clr-border), var(--clr-border) 10px, transparent 20px, transparent 30px, var(--clr-border) 40px), // right
repeating-linear-gradient(270deg, var(--clr-border), var(--clr-border) 10px, transparent 20px, transparent 30px, var(--clr-border) 40px) // bottom
;
}
.box-h { // Animated
background-image:
repeating-linear-gradient(0deg, var(--clr-border), var(--clr-border) 10px, transparent 10px, transparent 20px), // left
repeating-linear-gradient(90deg, var(--clr-border), var(--clr-border) 10px, transparent 10px, transparent 20px), // top
repeating-linear-gradient(180deg, var(--clr-border), var(--clr-border) 10px, transparent 10px, transparent 20px), // right
repeating-linear-gradient(270deg, var(--clr-border), var(--clr-border) 10px, transparent 10px, transparent 20px) // bottom
;
background-size: 3px calc(100% + 20px), calc(100% + 20px) 3px, 3px calc(100% + 20px) , calc(100% + 20px) 3px;
animation: boxBorderAnimation 1s infinite linear;
@keyframes boxBorderAnimation {
from { background-position: 0 0, -20px 0, 100% -20px, 0 100%; }
to { background-position: 0 -20px, 0 0, 100% 0, -20px 100%; }
}
}
// Generator:
.generator {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 3em;
@media (max-width: 768px) {
grid-template-columns: 1fr;
}
}
form {
width: 100%;
label {
display: block;
font-weight: bold;
width: 100%;
& + label {
margin-top: 1.5em;
}
}
.input {
display: block;
width: 100%;
}
}
.result {
width: 100%;
height: 100%;
padding: 1em;
line-height: 1.2;
background-repeat: no-repeat;
span {
display: block;
padding-left: 4em;
text-indent: -2em;
margin: 0.5em auto;
}
@keyframes borderAnimation {
from { background-position: 0 0, var(--AnimationLength) 0, 100% var(--AnimationLength), 0 100%; }
to { background-position: 0 var(--AnimationLength), 0 0, 100% 0, var(--AnimationLength) 100%; }
}
}
.twitterLink {
position: fixed;
bottom: 0.5em; right: 0.5em;
& img {
width: 2em;
filter: grayscale(100%);
transition: filter 0.25s;
&:hover {
filter: grayscale(0%);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment