SVG images formatting issues in CSS - javascript

I'm trying to achieve a similar effect to Lando Norris' website where his achievements scroll horizontally. I tried recreating that by creating svg images and then formatting them with the help of css. It doesn't seem to work on most web browsers though. Should I change my approach at recreating this horizontal banner or is there a way to make the images display properly?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>PawelosFPV achievements</title>
<link href="https://fonts.googleapis.com/css?family=Baloo+Tamma|PT+Sans" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
<style>
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
position: relative;
}
:root {
font-family: "PT Sans", sans-serif;
font-size: 20px;
}
body {
background-color: #EFF1ED;
min-height: 100vh;
}
h1 {
color: #161032;
font-family: "Baloo Tamma", sans-serif;
font-size: 1.5rem;
}
h1::after {
background-color: #00A8E8;
bottom: 0;
content: "";
display: block;
height: 0.25rem;
position: absolute;
width: 1rem;
}
p {
color: rgba(0, 0, 0, 0.8);
}
.container {
margin: 0 auto 2rem;
max-width: 900px;
padding: 0 1.5rem;
}
.sample-item {
width: auto;
height: 125px;
vertical-align: middle;
padding-right: 20px;
}
.horizontal-scrolling-banner {
overflow: hidden;
}
.horizontal-scrolling-banner__helper-wrapper {
align-items: center;
display: flex;
left: 0;
transform: translateZ(0);
transition-property: left;
transition-timing-function: linear;
}
</style>
</head>
<body>
<!-- partial:index.partial.html -->
<div class="container">
</div>
<div class="horizontal-scrolling-banner">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/FAI-World-Drone-Cup-Riga-2018.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/FAI-World-Drone-Cup-Modena-2018.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/Sumo-Challange-2018.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/Polish-Junior-Championship-2019.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/Polish-Championship-2019-V2.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/Drone-Champions-League-2019.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/DCL-Salina-Turda-2019.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/DCL-VADUZ-2019.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/DCL-TURIN-2019.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/VICE-FAI-World-Cup-Ranking-2019.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/DRL-Tryouts-2019.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/DCL-Laax-2019.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/IDSC-Korea-Yeongwol.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/EPFL-FAI-2019.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/XFLY-Tianjin-2019.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/FAI-World-Drone-Cup-Partouche-2019.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/DRL-Tryouts-2020.svg" class="sample-item">
<img src="http://pawelosfpv.com/wp-content/uploads/2022/05/Drone-Champions-League-2020.svg" class="sample-item">
</div>
</div>
<!-- partial -->
<script>
(function horizontalScrollingBanner() {
var banners = document.getElementsByClassName('horizontal-scrolling-banner');
if (!banners || banners.length === 0) {
return;
}
var pxPerSecond = 25;
setUpElements();
scrollTheBanners();
window.addEventListener('resize', setUpElements);
function setUpElements() {
for (var i = 0; i < banners.length; i++) {
var currentBanner = banners[i];
var helperWrapperClass = 'horizontal-scrolling-banner__helper-wrapper';
var currentHelperWrapper = currentBanner.querySelector('.' + helperWrapperClass);
if (currentHelperWrapper) {
var clones = currentHelperWrapper.querySelectorAll('[data-clone]');
Array.prototype.forEach.call(clones, function(clone) {
clone.remove();
});
var childrenCount = currentHelperWrapper.children.length;
for (var i = 0; i < childrenCount; i++) {
currentBanner.appendChild(currentHelperWrapper.children[0]);
}
currentHelperWrapper.remove();
}
var children = currentBanner.children;
var bannerWidth = currentBanner.getBoundingClientRect().width;
var minWidthToCoverBanner = (bannerWidth * 2) + children[0].getBoundingClientRect().width;
var childrenWidth = Array.prototype.reduce.call(children, function(r, child) {
return r + child.getBoundingClientRect().width;
}, 0);
var currentWidth = childrenWidth;
do {
Array.prototype.forEach.call(children, function(child) {
var clone = child.cloneNode();
clone.setAttribute('aria-hidden', true);
clone.dataset.clone = true;
currentBanner.appendChild(clone);
});
currentWidth += childrenWidth;
} while (currentWidth < minWidthToCoverBanner);
var transitionHelperWrapper = document.createElement('div');
transitionHelperWrapper.classList.add('horizontal-scrolling-banner__helper-wrapper');
var childrenCount = children.length;
for (var i = 0; i < childrenCount; i++) {
transitionHelperWrapper.appendChild(children[0]);
}
currentBanner.appendChild(transitionHelperWrapper);
transitionHelperWrapper.dataset.childrenWidth = childrenWidth;
}
}
function scrollTheBanners() {
for (var i = 0; i < banners.length; i++) {
var helperWrapper = banners[i].firstElementChild;
var childrenWidth = helperWrapper.dataset.childrenWidth;
var offsetLeft = helperWrapper.offsetLeft;
if (offsetLeft <= (childrenWidth * -1)) {
helperWrapper.style.transitionDuration = '0s';
helperWrapper.style.left = '0px';
helperWrapper.style.removeProperty('transition-duration');
} else if (helperWrapper.style.left === '' || helperWrapper.style.left === '0px') {
setTimeout(function() {
helperWrapper.style.transitionDuration = (childrenWidth / pxPerSecond).toFixed() + 's';
helperWrapper.style.left = (childrenWidth * -1) + 'px';
}, 0);
}
}
requestAnimationFrame(scrollTheBanners);
}
})();
</script>
</body>
</html>

Fonts are are not automatically embedded
Locally installed fonts used in svg are not available for users of your website/app unless they happen to have this particular font installed.
Besides firefox usually rejects local font file usage due to security policies (could be changed in settings as described here: "Custom (System installed) fonts in Firefox?")
Some options:
Open your svg in Illustrator and convert text to (path) outlines before saving as svg via convert text to outlines selcting all elements by CTRLa and CTRLshiftO should do the trick
embed the font via #font-face using a data URL. A tool like transfonter can help
You should also concider using an open source alternative to your font like the SIL OFL v1.1 licensed "D-Din" available on font squirrel
Still weird letter spacing?
Illustrator often splits text elements into seperate <text>or <tspan> elements. This is usually caused by customized spacing/kerning values.
<text class="cls-1" transform="translate(133.05 117.67)">2018</text>
<text class="cls-2" transform="translate(143.07 61.95)">1<tspan class="cls-3" x="19.99" y="0">S</tspan>
<tspan x="39.83" y="0">T</tspan>
</text><text class="cls-4" transform="translate(57.23 179.3)">SUMO CHAL<tspan class="cls-5" x="147.92" y="0">L</tspan>
<tspan x="162.25" y="0">ANGE</tspan>
</text>
Unfortunately markup will only work for this particular font. So you might need to simplify your structure like so:
<text x="50%" y="30%" text-anchor="middle" dominant-baseline="central">2022<tspan x="50%" data-dx="50%" dy="15%">1ST</tspan></text>
<text x="50%" y="90%" text-anchor="middle" dominant-baseline="central">
AWARD
</text>
Example: embedded vs not embedded font
img,
svg{
height:200px
}
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght#700" rel="stylesheet">
<p>Font embedded</p>
<img src="https://svgshare.com/i/iW8.svg" class="sample-item">
<p>Font not embedded (fallback font is used)</p>
<img src="https://svgshare.com/i/iY4.svg" class="sample-item">
<p>Inline SVG - using Webfont (Roboto)</p>
<svg id="Achievement" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 185">
<defs>
<style>
text {
font-family: 'Roboto Condensed', sans-serif;
font-size: 32px;
font-weight: bold;
}
</style>
</defs>
<path id="wreath" d="M2.4 88.7c0-0.3 8.9 0.8 20.8 12.8a58.6 58.6 0 0 1-4.3-8.9c-13.4-3.7-15.9-9.4-19-19.5c1.3 2.6 10.3 4.8 12.7 9c1.8 3.3 3.8 6.4 5.5 8a51.4 51.4 0 0 1-1.9-8.3c-0.1-0.5-0.1-0.9-0.2-1.3c-4.4-2.2-14.6-9.4-15.3-23.2c2 2.9 9.3 2.6 14.9 18.5a82.9 82.9 0 0 1 0.2-9.3c-4.3-3.5-12.5-13.9-11-35c1.7 3.3 10.4 14.3 10.8 21.9a60.7 60.7 0 0 0 0.8 7.3c0.1-0.6 0.1-1.1 0.2-1.7a67.3 67.3 0 0 1 1.6-8.2a26.1 26.1 0 0 0-4.7-10.9a9.8 9.8 0 0 1-1.1-11c1.2-2.6 0.6-8.5 0.6-8.5s8.2 8.2 6.1 27.4a61.7 61.7 0 0 1 2.7-6.9a15.3 15.3 0 0 0-1.3-8.7c-2.2-4.7-4.8-12 1.3-22.9c0.1 4.3 3.8 11.4 3.4 16.9a76.8 76.8 0 0 1-1.8 11.5a57.8 57.8 0 0 1 3.7-6c0.3-2.9-1.1-7-0.9-14.2c0.2-8.7 4-10.5 4.9-15.2c3.4 9 1.5 19.4-1.2 25.6l0.8-1c0.9-1.2 1.8-2.3 2.6-3.4a35.1 35.1 0 0 1 3.7-15.4c1.7-3 6.8-5.5 6.9-8c1.3 9.3-3.2 15.6-7.3 20.2l0 0.1a14.6 14.6 0 0 1 16-2.8s-5.3 4.9-9.7 5.3c-4.2 0.3-6.3 0-8.6 1.4c-0.7 1-1.6 2.1-2.5 3.2c5.7-3.1 14.2-0.1 17.5 2c-4.8 3.8-9.6 2.9-12.3 1.1c-2.4-1.6-5.2-0.1-6.9-0.9a70.2 70.2 0 0 0-4.4 6.3a61.2 61.2 0 0 0-3.7 7.8c3.1-4.4 8.5-9.7 15.3-9.9c-0.2 2.8-3.3 8.2-7.7 10.7c-3.6 2-7.3 2.9-9.4 4.7a65.1 65.1 0 0 0-2 10v0.1c4-10.1 15.2-14.7 18.2-14.9c0 0-5 3.6-5.3 8.3s-4.8 7.2-8.8 8.5a8.8 8.8 0 0 0-4.7 4.1a77.5 77.5 0 0 0 0 12.9c1.3-19.3 14.5-19.3 14.5-19.3a7.8 7.8 0 0 0-2.4 5c-0.4 3.4-1.2 6.1-5.3 10.6a21 21 0 0 0-5.5 11.3a54 54 0 0 0 5.8 13.9c-2.4-6-3.9-14.4-0.8-21.7c0.5 4.2 6.8 10.4 6.8 15.6c0 4.5-1.8 10.4-0.3 14.2c0.8 0.9 1.6 1.9 2.5 2.8c-0.4-2.7-0.1-6.7-0.7-9.5c1.5 2.2 2.4 8.2 3.4 12.3a71 71 0 0 0 6 5.1c-5.1-6-7.7-15.7-6.6-24.8c3.7 3.6 8.7 11.1 8.9 16.9a28.1 28.1 0 0 0 3.7 11.9l1.1 0.6c1.1 0.6 2.3 1.2 3.4 1.7c-5.6-5-7-14.1-7-18.1c6.3 4.4 13 14.6 13.8 20.6c1.2 0.3 2.4 0.6 3.6 0.9c4.8 0.9 10.2 1 14.5-1.3l0.3 0.5h0l0.3 0.5l0.5 1c-5.1 2.6-10.9 2.5-16 1.5a47.4 47.4 0 0 1-5.5-1.5c-2.3 3.8-8.5 7.2-12.4 6.8s-8.2-2.4-10.9-1.5c3.6-6 9.8-7.7 13.9-6.3c3.6 1.2 6.1 1.6 8 0.5a56.2 56.2 0 0 1-7.5-3.4l-1-0.5c-4.9 3-11.2 2.5-15.3 1.1c-4.6-1.5-6.3-6.1-10.1-8.1c9.6-2.5 14.8 0.9 17 3a9.8 9.8 0 0 0 6.5 2.9a66.4 66.4 0 0 1-10.3-7.9c-2.7-0.1-8.3 1.7-12.4-1.7c4-1.3 7.1-1.7 9.8-0.9c-0.9-0.9-1.7-1.8-2.5-2.8c-3.1 0.1-8.7 2-13-0.4a70.7 70.7 0 0 1-10.9-8.1s7.3-0.3 11.2 0.7c-3.6-2-14.3-13.4-14.3-13.7z" />
<use href="#wreath" style="transform: translate(100%,0) scale(-1, 1);" />
</use>
<text x="50%" y="30%" text-anchor="middle" dominant-baseline="central">2022<tspan x="50%" data-dx="50%" dy="15%">1ST</tspan></text>
<text x="50%" y="90%" text-anchor="middle" dominant-baseline="central">
AWARD
</text>
</svg>
Inline svg (appended to your html body) could use webfonts loaded via #font-face. Unfortunately your carousel script apparenty only support single elements (without nested child nodes).

Related

How can I make a circle progress bar fluid?

I’m trying to fluidify a circle progress bar in a timer. The progress bar represents the progression in the duration of the timer. I made an svg <circle> circle element for the progress bar. Every 10th of second, I change the css attribute stroke-dashoffset of the circle. This works fine but if we choose less than 5 minutes for the time, the movements of the progress bar are not fluid. What can I do to make that fluid ?
class Timer {
constructor(circle, text) {
this.circle = circle
this.text = text
this.text.innerHTML
}
async start(hours, minutes, seconds) {
this.circle.style["stroke-dasharray"] = parseInt(Math.PI * this.circle.getBoundingClientRect().width)
this.circle.style["stroke-dashoffset"] = parseInt(Math.PI * this.circle.getBoundingClientRect().width)
await this.countdown()
this.circle.classList = "progress"
var remaining, interval, duration, end;
duration = parseInt(hours) * 3600000 + parseInt(minutes) * 60000 + (parseInt(seconds) + 1) * 1000
end = Date.now() + duration
interval = setInterval(async () => {
remaining = end - Date.now()
this.circle.style["stroke-dashoffset"] = remaining * parseInt(Math.PI * this.circle.getBoundingClientRect().width) / duration;
if (remaining < 0) {
this.circle.style["stroke-dashoffset"] = 0
clearInterval(interval)
window.location.href = "./"
return true
} else {
this.text.innerHTML = `${("0" + parseInt(remaining / 3600000)).slice(-2)}:${("0" + parseInt(remaining % 3600000 / 60000)).slice(-2)}:${("0" + parseInt(remaining % 3600000 % 60000 / 1000)).slice(-2)}`
}
}, 100)
}
countdown() {
var duration;
duration = 2
this.text.innerHTML = 3
return new Promise(resolve => {
setInterval(async () => {
if (duration <= 0) {
resolve(true)
} else {
this.text.innerHTML = duration
duration -= 1
}
}, 1000)
})
}
}
const timer = new Timer(document.getElementById("progress"), document.getElementById("text"))
const params = new URLSearchParams(window.location.search)
timer.start(0, 0, 10)
:root {
--pi: 3.141592653589793
}
circle.progress {
display: block;
position: absolute;
fill: none;
stroke: url(#circle.progress.color);
stroke-width: 4.5vmin;
stroke-linecap: round;
transform-origin: center;
transform: rotate(-90deg);
}
circle.progress.animation {
animation: circle 3s linear forwards;
}
.progress-container {
left: 50vw;
top: 50vh;
width: 90vmin;
height: 90vmin;
margin-top: -45vmin;
margin-left: -45vmin;
position: absolute;
padding: none;
}
.outer {
margin: none;
width: 100%;
height: 100%;
border-radius: 50%;
box-shadow: 6px 6px 10px -1px rgba(0, 0, 0, 0.15), -6px -6px 10px -1px rgba(255, 255, 255, 0.7);
padding: 2.5%;
}
.inner {
margin: 2.5%;
width: 95%;
height: 95%;
border-radius: 50%;
box-shadow: inset 4px 4px 6px -1px rgba(0, 0, 0, 0.15), inset -4px -4px 6px -1px rgba(255, 255, 255, 0.7);
}
svg {
display: block;
position: absolute;
left: 50vw;
top: 50vh;
width: 90.5vmin;
height: 90.5vmin;
margin-top: -45.25vmin;
margin-left: -45.25vmin;
}
svg text {
font-size: 10vmin;
font-family: 'Roboto', sans-serif;
}
#keyframes circle {
0% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: calc(45.5vmin * var(--pi) * 2);
}
}
<link href="https://cdn.jsdelivr.net/npm/#materializecss/materialize#1.2.1/dist/css/materialize.min.css" rel="stylesheet"/>
<div class="progress-container">
<div class="outer center-align">
<div class="inner"></div>
</div>
</div>
<svg xmlns="http://www.w3.org/2000/svg" class="center" version="1.1">
<defs>
<linearGradient id="circle.progress.color">
<stop offset="0%" stop-color="BlueViolet" />
<stop offset="100%" stop-color="MediumVioletRed" />
</linearGradient>
</defs>
<circle id="progress" class="progress animation" cy="45.25vmin" cx="45.25vmin" r="42.75vmin" />
<text id="text" text-anchor="middle" x="50%" y="50%">Temps restant</text>
</svg>
<script src="https://cdn.jsdelivr.net/npm/#materializecss/materialize#1.2.1/dist/js/materialize.min.js"></script>
The code here runs the timer for 10 seconds. Normally, you would have to choose the time in another page. To have the time input, go to that page (the page is in french).
I'm not able to explain the issue, so here I have an alternative solution. The function setInterval has issues with the timing (maybe that is actually you issue...). You cannot expect it to be precise. Instead of controlling the progress using setInterval you can use a keyframe animation with the Web Animations API. This is a better alternative to the JavaScript animation where you update an attribute/style, and easier to work with then SVG SMIL animations.
So, I rely on the animation doing its job and then update the time displayed by asking for the currenttime on the animation object.
const progress = document.getElementById('progress');
const text = document.getElementById('text');
document.forms.form01.addEventListener('click', e => {
if(e.target.value){
var progressKeyframes = new KeyframeEffect(
progress,
[
{ strokeDasharray: '0 100' },
{ strokeDasharray: '100 100' }
],
{ duration: parseInt(e.target.value), fill: 'forwards' }
);
var a1 = new Animation(progressKeyframes, document.timeline);
a1.play();
let timer = setInterval(function(){
if(a1.playState == 'running'){
text.textContent = Math.floor(a1.currentTime/1000);
}else if(a1.playState == 'finished'){
text.textContent = Math.round(e.target.value/1000);
clearInterval(timer);
}
}, 100);
}
});
<form name="form01">
<input type="button" value="2000" />
<input type="button" value="5000" />
<input type="button" value="10000" />
</form>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="300">
<defs>
<linearGradient id="circle.progress.color">
<stop offset="0%" stop-color="BlueViolet" />
<stop offset="100%" stop-color="MediumVioletRed" />
</linearGradient>
<filter id="shadow">
<feDropShadow dx=".4" dy=".4" stdDeviation="1" flood-color="gray"/>
</filter>
</defs>
<circle r="40" stroke="white" stroke-width="8" fill="none" transform="translate(50 50)" filter="url(#shadow)"/>
<circle id="progress" r="40" stroke="url(#circle.progress.color)" stroke-width="8" fill="none" pathLength="100" stroke-dasharray="0 100" transform="translate(50 50) rotate(-90)" stroke-linecap="round"/>
<text id="text" dominant-baseline="middle" text-anchor="middle" x="50" y="50">0</text>
</svg>

Dynamically added svg viewbox values not working? [duplicate]

This question already has an answer here:
Cannot scale svg if created with js
(1 answer)
Closed 10 months ago.
I'm trying to add an svg dynamically to a menu, but I'm having a problem setting the viewbox.
When I inline the svgs (svg and svg-2), the viewbox has to be correct for the respective icon (0 0 512 512 and 0 0 24 24), as expected. Changing the viewbox removes the icon from view.
But for my dynamically added icons (dynamic-svg and dynamic-svg-2), changing the viewbox values (0 0 24 24 and 0 0 512 512) does nothing. In fact I can't get dynamic-svg-2 to show at all. dynamic-svg continues to display even if I change the viewbox to random values.
I must be doing something wrong, or have a bug somewhere, but I really can't see it. Would appreciate if someone could take a look. Thanks
codepen
const container = document.querySelector('.container');
const svgWrapper = document.createElement('div');
svgWrapper.className = 'dynamic-svg-wrapper'
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg")
const path1 = document.createElementNS("http://www.w3.org/2000/svg", 'path')
svg.setAttribute("aria-hidden","true");
svg.setAttribute('viewbox', '0 0 24 24');
svg.setAttribute('class', 'dynamic-svg');
path1.setAttribute('d', `M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z`);
path1.setAttribute('fill', '#000000');
svg.append(path1);
svgWrapper.append(svg);
container.append(svgWrapper);
const svgWrapper2 = document.createElement('div');
svgWrapper2.className = 'dynamic-svg-wrapper-2'
const svg2 = document.createElementNS("http://www.w3.org/2000/svg", "svg")
const path2 = document.createElementNS("http://www.w3.org/2000/svg", 'path')
svg2.setAttribute("aria-hidden","true");
svg2.setAttribute('viewbox', '0 0 512 512');
svg2.setAttribute('class', 'dynamic-svg-2');
path2.setAttribute('d', `M461.6,109.6l-54.9-43.3c-1.7-1.4-3.8-2.4-6.2-2.4c-2.4,0-4.6,1-6.3,2.5L194.5,323c0,0-78.5-75.5-80.7-77.7
c-2.2-2.2-5.1-5.9-9.5-5.9c-4.4,0-6.4,3.1-8.7,5.4c-1.7,1.8-29.7,31.2-43.5,45.8c-0.8,0.9-1.3,1.4-2,2.1c-1.2,1.7-2,3.6-2,5.7
c0,2.2,0.8,4,2,5.7l2.8,2.6c0,0,139.3,133.8,141.6,136.1c2.3,2.3,5.1,5.2,9.2,5.2c4,0,7.3-4.3,9.2-6.2L462,121.8
c1.2-1.7,2-3.6,2-5.8C464,113.5,463,111.4,461.6,109.6z`);
path2.setAttribute('fill', '#000000');
svg2.append(path2);
svgWrapper2.append(svg2);
container.append(svgWrapper2);
* {
margin: 0;
}
.container {
display: flex;
justify-content: center;
width: 100%;
height: 100vh;
background-color: lightgrey;
}
.svg-wrapper {
display: flex;
width: 24px;
height: 24px;
border: 1px solid black;
margin: 10px;
}
.svg {
display: flex;
width: 24px;
height: 24px;
}
.svg-wrapper-2 {
display: flex;
width: 24px;
height: 24px;
border: 1px solid black;
margin: 10px;
}
.dynamic-svg-wrapper {
display: flex;
width: 24px;
height: 24px;
border: 1px solid black;
margin: 10px;
}
.dynamic-svg {
display: flex;
width: 24px;
height: 24px;
}
.dynamic-svg-wrapper-2 {
display: flex;
width: 24px;
height: 24px;
border: 1px solid black;
margin: 10px;
}
.dynamic-svg-2 {
display: flex;
width: 24px;
height: 24px;
}
<div class="container">
<div class="svg-wrapper">
<svg class="svg" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 512 512">
<path d="M461.6,109.6l-54.9-43.3c-1.7-1.4-3.8-2.4-6.2-2.4c-2.4,0-4.6,1-6.3,2.5L194.5,323c0,0-78.5-75.5-80.7-77.7
c-2.2-2.2-5.1-5.9-9.5-5.9c-4.4,0-6.4,3.1-8.7,5.4c-1.7,1.8-29.7,31.2-43.5,45.8c-0.8,0.9-1.3,1.4-2,2.1c-1.2,1.7-2,3.6-2,5.7
c0,2.2,0.8,4,2,5.7l2.8,2.6c0,0,139.3,133.8,141.6,136.1c2.3,2.3,5.1,5.2,9.2,5.2c4,0,7.3-4.3,9.2-6.2L462,121.8
c1.2-1.7,2-3.6,2-5.8C464,113.5,463,111.4,461.6,109.6z"/>
</svg>
</div>
<div class="svg-wrapper-2">
<svg class='svg-2' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"/></svg>
</div>
</div>
]1
You can save yourself a lot of headaches using modern technologies,
A <svg-icon> Web Component, supported in all modern browsers.
I processed some of your <path> with https://yqnn.github.io/svg-path-editor/, to make them smaller.
You don't need 0.nnn precision when you stuff a 512x512 viewBox in 40x40 pixels
It does not matter where or when you execute customElements.define;
all existing or new <svg-icon> will automagically upgrade.
<style>
div {
display: flex; justify-content: center;
width:100%; background:pink;
}
</style>
<div>
<svg-icon>
<path fill="green" d="m461.6 109.6-54.9-43.3c-1.7-1.4-3.8-2.4-6.2-2.4-2.4 0-4.6 1-6.3 2.5l-199.7 256.6c0 0-78.5-75.5-80.7-77.7-2.2-2.2-5.1-5.9-9.5-5.9-4.4 0-6.4 3.1-8.7 5.4-1.7 1.8-29.7 31.2-43.5 45.8-.8.9-1.3 1.4-2 2.1-1.2 1.7-2 3.6-2 5.7 0 2.2.8 4 2 5.7l2.8 2.6c0 0 139.3 133.8 141.6 136.1 2.3 2.3 5.1 5.2 9.2 5.2 4 0 7.3-4.3 9.2-6.2l249.1-320c1.2-1.7 2-3.6 2-5.8 0-2.5-1-4.6-2.4-6.4z" />
</svg-icon>
<svg-icon vb="5120">
<path fill="red" d="m4616 1096-549-433c-17-14-38-24-62-24-24 0-46 10-63 25l-1997 2566c0 0-785-755-807-777-22-22-51-59-95-59-44 0-64 31-87 54-17 18-297 312-435 458-8 9-13 14-20 21-12 17-20 36-20 57 0 22 8 40 20 57l28 26c0 0 1393 1338 1416 1361 23 23 51 52 92 52 40 0 73-43 92-62l2491-3200c12-17 20-36 20-58 0-25-10-46-24-64z" />
</svg-icon>
<svg-icon vb="24">
<path fill="blue" d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z" />
</svg-icon>
<svg-icon vb="24">
<path fill="rebeccapurple" d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z" />
</svg-icon>
</div>
<script>
customElements.define("svg-icon", class extends HTMLElement {
connectedCallback() {
let vb = this.getAttribute("vb") || 512;
setTimeout(() => { // wait till path innerHTML is parsed
let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("viewBox",`0 0 ${vb} ${vb}`);
svg.innerHTML = this.innerHTML;
this.replaceWith(svg); // Web Component did its job, no need to keep it
});
}
});
</script>
Take this idea some steps further and you get https://iconmeister.github.io

Brushstroke effect using CSS/Javascript

I want to add a brush stroke effect animation on my webpage. I tried using transform but it didn't work. I want to the brush stoke to have wipe animation from left to right so that it reveal itself.
Can anyone suggest the way to do it?
You can use SVG clipPath and animation to reach this effect, take a look at Code snippet:
Take a look at comments in code for more details.
Regarding clipPathUnits="objectBoundingBox" take a look at this DOC page.
Regarding SVG animation take a look at this page.
/* create wrapper */
.brush-wrap {
position: relative;
display: inline-block;
padding: 3rem;
}
/* applying example animation (indefinite variant) */
.brush-wrap.brush-wrap--indefinite:before {
clip-path: url(#clip-indefinite);
}
/* clipping/animating object (pseudo element) */
.brush-wrap:before {
content: '';
position: absolute;
height: 100%;
width: 100%;
top: 0;
left: 0;
background: black;
z-index: -1;
clip-path: url(#clip); /* applying clip animation */
}
.brush-wrap p {
font-size: 2rem;
text-transform: uppercase;
margin: 0;
color: white;
font-style: italic;
filter: drop-shadow(0px 0px 2px black);
}
<div class="brush-wrap">
<p>Vivamus in erat</p>
</div>
<div class="brush-wrap brush-wrap--indefinite">
<p>Vivamus (indefinite)</p>
</div>
<!-- create svg inline with clipPath and animation -->
<!-- do not hide SVG with display: none; it will disable anim/clipping -->
<svg height="0" width="0" xmlns="http://www.w3.org/2000/svg">
<defs>
<!--
square that can be animated
animating view area
user for clipping shape
-->
<!-- runs only once -->
<clipPath id="rect-cp">
<rect id="rect" x="0" y="0" width="0" height="1">
<animate
id="anim"
attributeName="width"
dur="1s"
fill="freeze"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.5,0,0.5,1"
values="0;1"
/>
</rect>
</clipPath>
<!-- indefinite example -->
<clipPath id="rect-cp-indefinite">
<rect id="rect" x="0" y="0" width="0" height="1">
<animate
id="anim-indefinite"
attributeName="width"
dur="1s"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.5,0,0.5,1"
values="0;1"
begin="0s;anim-indefinite.end+1s"
/>
</rect>
</clipPath>
<!--
clip path for shape;
clip path should use clipPathUnits="objectBoundingBox" to stretch to full size
in this case path should contain points from 0 to 1 (1px size)
-->
<clipPath id="clip" clipPathUnits="objectBoundingBox">
<use href="#brush-shape" clip-path="url(#rect-cp)" />
</clipPath>
<clipPath id="clip-indefinite" clipPathUnits="objectBoundingBox">
<use href="#brush-shape" clip-path="url(#rect-cp-indefinite)" />
</clipPath>
<!-- brush shape -->
<path id="brush-shape" d="M.261.995A.07.07 0 0 0 .257.978V.975C.258.97.255.972.257.967.259.963.255.96.257.959V.95C.256.943.259.948.257.943.256.934.255.956.255.944.255.937.254.943.253.94.252.939.253.938.254.937.257.934.257.931.26.926.267.907.277.916.284.899.293.885.287.897.29.879.295.874.308.872.312.862.288.866.246.848.22.864.207.871.2.872.188.891.175.892.176.901.161.91.156.928.143.92.138.928c0-.005-.025-.012-.022.01-.007.013.01-.01.011-.003-.001.004.006 0 .004.003L.13.942C.13.947.113.951.111.945.103.948.059.92.089.918.069.889.048.9.029.904.028.901.002.922.008.898.012.884.032.892.029.873.026.872.031.869.029.867c0-.004.002-.012.005-.014A.055.055 0 0 0 .017.85C.021.826.042.831.045.818.044.818.038.815.041.811.042.804.053.795.046.793.041.79.032.788.029.791.026.792.019.799.024.783V.782C.024.784.022.778.022.781.021.786.019.782.022.778.024.774.023.773.02.77.011.75.041.756.045.75.037.732.04.727.048.717.051.714.045.713.046.704.04.698.026.726.019.716L.02.713C.02.711.049.696.036.696.031.688.013.697.011.7.009.699.012.689.015.686c.004-.01-.008 0-.009 0A.083.083 0 0 0 .01.671C-.015.656.013.64.022.638.065.619.022.624.05.602.076.574.047.581.061.565.065.559.049.563.054.556.056.549.035.568.036.554.034.55.047.529.046.527.045.52.061.504.058.495c0-.008.021-.016.024-.022C.09.469.095.459.101.455.102.454.101.453.1.453.093.454.093.447.09.446.087.446.094.439.095.443c.003.002.008 0 .012.005.004.008.001-.003 0-.006C.1.427.133.438.124.42c0-.006.005-.003.002-.009C.12.412.106.413.104.406.104.395.105.393.098.392.088.392.105.381.108.38.117.373.133.38.141.371.143.369.143.369.143.362V.348C.142.342.143.341.151.342.164.342.166.334.179.329.161.323.132.331.118.344v.002c-.001 0 0 .006-.002.001C.113.338.115.354.112.347.107.338.107.36.1.34.098.344.1.32.101.324L.102.32C.106.32.109.307.111.316H.11L.108.32v.002c0 .006.004.01.002.005C.109.324.115.328.115.325.116.32.117.33.118.324.118.317.119.319.12.315.121.311.125.309.125.304c0-.011.001.007.002-.001.002-.008 0 .008.002.001S.122.289.131.283C.133.283.135.281.135.277.136.271.143.276.144.27.14.26.126.277.123.262.121.254.124.257.122.252S.124.252.124.25C.121.245.128.243.128.247c0 .002 0 .002 0 0A.017.017 0 0 0 .135.244C.137.244.138.239.136.239.129.233.144.217.147.217.155.202.113.217.11.212.107.209.11.217.108.216.104.212.101.22.106.206c0 0-.004.003-.002 0C.106.198.112.215.113.205.112.202.121.202.12.205.122.199.131.198.134.195.139.19.14.192.144.188.151.183.13.188.131.187.123.185.055.231.084.194.128.159.184.15.23.132.26.119.281.094.313.079.321.079.338.05.341.074c0 .004.001.001.002.002C.345.074.342.09.344.084.339.11.33.106.375.088.4.081.424.072.449.069.461.086.479.065.497.067c.07-.01.145.008.213.021a.525.525 0 0 1 .129.034C.844.128.854.123.855.13c0 .003.001.004.001.001 0-.004.002.001.003 0C.861.13.861.145.859.136.832.14.793.123.76.123c.021.019.057.01.076.03C.833.158.826.15.821.149.814.149.802.15.793.142.789.15.775.143.77.146.772.151.768.154.762.151.727.147.687.119.652.139c.037.02.079.016.115.035.043.029.096.022.135.042C.887.223.852.214.835.215.826.213.824.214.829.217c.004.001.004.005 0 .008-.005.007.02.007.025.009.009.001.01.002.01.005-.003.007.027.007.029.012C.905.263.867.262.889.269c.024.003.053.029.075.04 0 .004-.005.002-.006.004 0 .003.006.005.003.01-.002.003.001.007.006.01S.975.34.973.34c-.001.002.01.009.013.013C.996.36.983.358.981.365.977.371.964.355.965.375c.002.002.021.013.01.014-.006 0-.004.003-.01.003-.014.004.012.011.014.015C.986.411.954.416.975.425c.006.006.009.001.013.007C.989.437.984.446.985.44.987.435.984.437.984.44S.983.443.977.442C.97.441.968.442.97.448c.002.018.019.014.022.027C.988.486.961.462.958.476.962.503 1 .488.997.509.997.516.99.514.992.527.994.536.99.539.995.541.998.56.982.538.982.547c-.004.017.002.022 0 .024v.002c.003.004-.011 0-.01.009C.972.584.971.585.97.585.96.586.978.604.98.608c.008-.002.015.013.005.02C.985.637.937.619.957.635.98.649.955.642.973.668.974.674.974.68.972.679.97.696.966.692.96.693.952.691.953.703.945.698.942.699.935.701.94.71c.002.006.022.018.015.026C.955.743.952.751.951.75.95.755.936.753.94.764c.003.01.007.005.005.022.001.009-.001 0-.002.002L.939.796C.948.8.939.808.935.813.931.818.934.825.926.816.922.812.921.812.919.819S.903.814.904.82c0 .003.013.008.01.011C.91.837.926.846.93.849.929.859.927.861.93.87.926.877.906.852.903.859c-.004.009.01.012.012.023C.916.887.906.881.906.884.91.894.899.882.898.881S.888.87.887.877c-.004.014.02.018.027.028C.93.914.907.914.905.915c0 .001.008.008.004.011C.908.931.9.921.901.926.914.945.868.935.866.939.807.926.75.894.69.896.674.894.679.901.673.897.668.896.661.885.657.89.656.892.653.89.653.887.62.879.637.881.59.88.563.878.561.88.536.882.532.882.527.891.529.895.526.915.52.903.513.904.485.903.45.918.424.927.418.921.398.928.392.932c.001.009.005.002.005.011 0 .004-.001.004-.002 0C.394.937.394.945.393.943.373.954.352.952.329.962.303.968.298.993.278.992.273.994.265.996.261 1V.995zm0-.019c-.002-.009-.003.019 0 0zM.354.945C.356.942.356.942.352.943L.337.948c0 .003.014 0 .017-.003zM.097.92C.097.919.095.919.095.921.096.924.097.921.097.92zm.04-.007c0-.003-.003-.002-.003 0 0 .004.003.002.003 0zM.111.903C.111.901.11.901.109.902.106.907.111.907.111.903zM.423.902C.429.893.404.901.396.903.394.904.42.908.423.902zm.02-.006c0-.002-.012 0-.006.003C.439.9.441.898.443.896zM.09.897c.003 0-.004-.007-.003 0 .001.004.002-.001.003 0zM.451.894c-.006-.006-.007.008 0 0zM.883.87C.884.867.876.868.88.87c.002.002.002.002.003 0zM.032.84C.031.839.03.841.032.841V.84zM.038.837C.041.834.037.836.036.837c-.001.002 0 .002.002 0zm.007.001C.05.822.038.834.042.835c.002 0 .001.007.003.003zM.943.802C.943.8.94.799.942.802c.001.002.001.002.001 0zM.059.718C.058.717.057.719.059.719V.718zM.055.712c0-.008-.009.005-.002.004L.055.712zm.01.001C.064.71.062.709.062.712c0 .004.003.004.003.001zM.061.711C.063.708.057.709.058.711c-.001.003.002.003.003 0zM.981.47C.981.467.98.467.98.47c0 .002.001.002.001 0zM.985.431H.984c-.001.002.002.002.001 0zM.977.406H.975c-.002.002.004.002.002 0zM.952.39C.951.388.941.38.94.382c.001.002.012.01.012.008zM.146.371C.148.368.144.369.144.371c-.001.002.001.002.002 0zM.948.359C.948.357.931.349.935.355c0 .001.013.007.013.004zM.115.334c0-.003-.001-.002-.001 0s.001.002.001 0zM.189.33C.188.329.187.331.189.331V.33zM.103.327.102.325C.1.324.104.332.103.327zM.105.324v.002-.002zM.137.31C.141.307.165.296.154.283.154.278.179.276.163.27.16.27.147.281.153.284.154.287.147.287.145.294c0 .002 0 .002-.001 0 0-.002-.001-.002 0 0C.144.299.138.3.137.298c0-.001-.001-.002-.001 0C.136.303.13.305.129.31c.001.005.007 0 .008 0zM.16.235C.159.233.157.239.159.237L.16.235zM.827.227c0-.002-.003-.003-.003 0 0 .002.003.002.003 0zM.161.214h.001C.159.205.155.219.161.214zm.661 0C.822.212.82.212.82.214c.001.002.002.002.002 0zm.003.001C.824.214.823.216.825.216V.215zM.171.21C.17.209.169.211.171.211V.21zM.109.208c0-.003-.001-.003-.001 0 0 .002.001.002.001 0zM.123.202.122.205.123.202zm.006.001c0-.008-.001.002-.001.003L.129.203zM.852.132C.851.131.85.133.852.133V.132zM.343.09C.343.087.342.085.342.089c0 .003.001.004.001.001zM.081.976c0-.007-.003-.01.002-.011C.087.964.081.97.083.973.085.973.086.97.086.967.085.965.091.977.092.969c.001-.006.003.013.002.01C.093.978.094.971.093.976.092.98.081.979.081.976zM.073.971V.965c.002.001.002.01 0 .006zM.085.955C.084.948.087.951.088.95.092.949.086.966.085.955zM.42.939.421.937C.422.936.42.943.42.939zM.426.938C.427.935.428.937.426.939V.938zM.13.932c.003-.018.003.009 0 0zM.753.913c0-.003.002-.002.002 0 .001.003-.002.003-.002 0zM.744.911c0-.002.001-.003.002 0 0 .002-.002.002-.002 0zM.196.908C.195.899.2.907.2.909.197.911.196.91.196.908zM.674.903c0-.005.002.002.001.002L.674.903zM.666.901c-.001-.005.001-.006 0 0 0 .002 0 .002 0 0zm.002.001V.899C.67.9.67.905.668.902zM.933.891V.886v.005zM.247.879c0-.002.002-.003.002 0-.001.002-.001.002-.002 0zM.252.875c0-.004.007-.006.006-.003v.002C.261.876.251.88.252.875zM.027.87.028.867C.029.87.027.875.027.87zM.032.816.033.813c0-.001-.001.01-.001.003zM.036.815V.813v.002zM.998.546C.997.541 1.001.547 1 .548L.998.546zM.091.393c0-.002.002-.002.002 0 0 .003-.002.002-.002 0zm.023-.03L.113.359C.117.355.136.351.124.36.121.362.117.369.114.363zm-.007 0h.001c.001.002-.001.002-.001 0zM.097.335V.332v.003zM.112.317C.112.309.108.31.113.302.119.292.119.3.117.305v.002C.123.31.117.312.115.311v.004C.114.315.113.323.112.317zM.119.301C.118.297.122.292.12.3c0 .001 0 .002-.001.001zM.1.214c0-.003.001-.002.002 0C.102.217.1.216.1.214zM.112.205C.113.201.113.201.113.204.113.205.11.21.112.205zm.78-.034C.893.169.896.167.897.168c0 .006-.006.003-.005.003zM.889.169c0-.007.005.006 0 0zM.875.166A.211.211 0 0 0 .837.157L.841.15l.001.004C.844.156.845.145.844.152c0 .002 0 .002 0 0C.849.147.855.155.86.155c.005 0 .014.001.019.006 0 .006-.002.008-.004.005zM.852.156C.852.153.85.154.85.156c-.001.002.002.002.002 0zM.882.15C.88.149.881.141.882.148V.15zM.87.142C.869.136.86.144.861.134.863.127.867.141.869.135.87.133.872.133.873.135.874.144.871.15.87.142zm.006.001c.003-.01.002.009 0 0zM.23.128h.001C.232.129.229.13.23.128zM.341.069c0-.005.002.002.001.002L.341.069zM.354.07C.352.062.357.067.356.056.357.049.364.052.363.042.364.035.365.046.366.043.367.035.37.044.37.041V.039C.372.038.372.047.374.047V.04C.379.034.474-.004.45.035c-.009.004.01.003.007.01 0 .001-.008.003-.008.001C.439.043.424.048.415.042a.039.039 0 0 1-.016.007C.398.045.396.049.395.05.395.047.39.048.389.052.388.058.378.062.378.055.377.057.378.064.376.059.375.057.375.057.375.059.375.063.37.06.37.063.369.07.366.059.366.058c0 .003-.001.009-.002.005C.362.062.355.074.354.07zM.346.06c0-.007.002 0 .001.002L.346.06zM.348.057.349.056C.351.057.347.06.348.057zM.539.051c-.004-.002 0-.006.001 0 0 .004 0 .001-.001 0zM.527.047c.002-.002.002-.002.001 0 0 .001-.003.003-.001 0zm.003 0c0-.003.003.003.001.002L.53.047zM.459.042C.457.035.479.039.478.04c.003-.001.003.002 0 .003C.475.045.477.036.475.044.472.051.471.042.469.045.468.047.467.046.468.042.467.04.46.049.459.042zm.045.003c0-.005.002.002.001.002L.504.045zM.482.041c-.002-.004 0-.003 0 0 .001.002.001.002 0 0zM.697.04C.694.034.683.044.68.033L.683.027c.001-.001 0 .01.002.004.002-.007.003.008.003.001 0-.01.003.002.003.001.002-.007.002.003.006 0C.7.034.703.034.703.039.704.042.697.043.697.04zm.009 0c0-.005.008-.003.003.001C.708.043.706.042.706.04zM.667.033C.666.028.662.034.662.033.659.03.651.032.644.028.64.022.632.036.629.028.601.037.582.02.551.023.539.021.485.026.498.008.535-.012.61.011.65.019.655.021.667.017.665.03.666.029.669.028.669.024v.001c0 .005.007-.001.008.002 0 .002.005.002.003.003C.678.03.678.031.679.032.682.035.668.037.667.033zM.506.015C.505.009.504.018.506.018V.015zM.474.022V.019c-.002.003 0-.006 0-.008.001.012.004.011.002 0C.475.005.482.012.482.008c0-.003.004-.004.004 0 0 .002 0 .002.001 0 .002-.004 0 .005 0 .006.001.009.002-.017.004-.008l.001.012C.494.019.492.022.49.022.483.026.483.005.481.014c0 .003.001-.002.001.003C.482.021.48.016.48.02.481.023.472.028.474.022zM.489.014V.012c-.002 0 0 .006 0 .002zM.466.022C.467.016.468.021.468.011.47.012.467.029.466.022zM.47.016c0-.007.002.002 0 .003V.016zM.472.011C.473.007.477.007.476.013.474.008.47.018.472.011zM.465.01h.001C.467.012.464.012.465.01zm.029 0C.492.007.495.008.495.01s0 .002-.001 0zM.491.006C.49 0 .494.011.492.01L.491.006z"/>
</defs>
</svg>

Center navigation bar (Bootstrap) items horizontally

I have a navigation bar with 2 icons evenly distributed.
I am wanting to scale them horizontally so they are centered horizontally in relation to the navigation bar.
I think the viewbox of the svg's are cause it to not look visually centred.
I've tried playing with the size without much luck.
I did try justifying content which didn't work.
Then I tried adding padding to the icons to allow for them to move.
Code:
.bar {
display: flex;
justify-content: center;
}
/* Style the navigation menu */
.navbar {
width: 90%;
background: #3CE18F;
/* Forces the icons to not go outside the scrollbar. If we left it to invisble it would display
them outside. */
overflow: auto;
/* Curves the corners of the Nav Bar. */
border-radius: 10px 10px 30px 30px;
position: fixed;
bottom: 3%;
display: block;
margin:auto;
}
/* Navigation links */
.navbar a {
float: left;
padding: 12px;
color: white;
text-decoration: none;
font-size: 17px;
width: 48.6%; /* Four equal-width links. If you have two links, use 50%, and 33.33% for three links, etc.. */
text-align: center; /* If you want the text to be centered */
}
/* Add a background color on mouse-over */
.navbar a:hover {
background-color: #000;
}
/* Style the current/active link */
.navbar a.active {
background-color: #4CAF50;
}
.microphoneIcon {
/* position: absolute;
left: 65.36%;
right: 26.29%;
top: 54.22%;
bottom: 0.46%;*/
fill: #FFFFFF;
stroke: #FFFFFF;
-webkit-filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7));
filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7));
/* Similar syntax to box-shadow */
/*background: #FFFFFF;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);*/
}
.cameraIcon {
fill: #FFFFFF;
stroke: #FFFFFF;
-webkit-filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7));
filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7));
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="theme-color" content="#009578">
<title>PWA</title>
<link rel="stylesheet" href="src/navigationBar.css">
<!-- Javascript Docs -->
<script type="text/javascript" src="src/index.js"></script>
<link rel="manifest" href="/manifest.json">
<link rel="apple-touch-icon" href="images/logo192.png">
</head>
<body>
<!-- Class for the Bottom Navigation Bar -->
<div class="bar">
<nav class="navbar fixed-bottom navbar-light bg-light nav-fill">
<a href="#">
<svg class='microphoneIcon' id='microphoneIcon' width="42" height="46" viewBox="0 0 42 46" stroke="grey">
<path d='M21 23.7571C25.0314 23.7571 28.2857 21.1043 28.2857 17.8179V5.93928C28.2857 2.65288 25.0314 0 21 0C16.9686 0 13.7143 2.65288 13.7143 5.93928V17.8179C13.7143 21.1043 16.9686 23.7571 21 23.7571ZM18.5714 5.93929C18.5714 4.85043 19.6643 3.95953 21 3.95953C22.3357 3.95953 23.4286 4.85043 23.4286 5.93929V17.8179C23.4286 18.9067 22.3357 19.7976 21 19.7976C19.6643 19.7976 18.5714 18.9067 18.5714 17.8179V5.93929ZM21 27.7167C27.7029 27.7167 33.1429 23.282 33.1429 17.8179H38C38 24.8064 31.6614 30.5477 23.4286 31.5178V37.6155H18.5714V31.5178C10.3386 30.5477 4 24.8064 4 17.8179H8.85714C8.85714 23.282 14.2971 27.7167 21 27.7167Z'/>
</svg>
</a>
<a href="#">
<svg class ='cameraIcon' id='cameraIcon' xmlns="http://www.w3.org/2000/svg" width="50" height="46" viewBox="0 0 50 46">
<path d="M 45 36 a 3 3 90 0 1 -3 3 H 6 a 3 3 90 0 1 -3 -3 V 18 a 3 3 90 0 1 3 -3 h 3.516 a 9 9 90 0 0 6.36 -2.637 l 2.49 -2.484 A 3 3 90 0 1 20.481 9 h 7.032 a 3 3 90 0 1 2.121 0.879 l 2.484 2.484 A 9 9 90 0 0 38.484 15 H 42 a 3 3 90 0 1 3 3 v 18 z M 6 12 a 6 6 90 0 0 -6 6 v 18 a 6 6 90 0 0 6 6 h 36 a 6 6 90 0 0 6 -6 V 18 a 6 6 90 0 0 -6 -6 h -3.516 a 6 6 90 0 1 -4.242 -1.758 l -2.484 -2.484 A 6 6 90 0 0 27.516 6 H 20.484 a 6 6 90 0 0 -4.242 1.758 l -2.484 2.484 A 6 6 90 0 1 9.516 12 H 6 z M 24 33 a 7.5 7.5 90 1 1 0 -15 a 7.5 7.5 90 0 1 0 15 z m 0 3 a 10.5 10.5 90 1 0 0 -21 a 10.5 10.5 90 0 0 0 21 z M 9 19.5 a 1.5 1.5 90 1 1 -3 0 a 1.5 1.5 90 0 1 3 0 z"/>
</svg>
</a>
</nav>
</div>
</body>
</html>
Here is a simple way to scale them horizontally. The display of the navbar must be inline-flex. I have added it.
As you have requested to scale them vertically. I have changed the CSS of a tag width.
Please take a look at the CSS. #Nitrogen
.bar {
display: flex;
justify-content: center;
}
/* Style the navigation menu */
.navbar {
width: 90%;
background: #3CE18F;
/* Forces the icons to not go outside the scrollbar. If we left it to invisble it would display
them outside. */
overflow: auto;
/* Curves the corners of the Nav Bar. */
border-radius: 10px 10px 30px 30px;
position: fixed;
bottom: 3%;
display: block;
margin:auto;
}
/* Navigation links */
.navbar a {
width: 100% !important;
float: left;
padding: 12px;
color: white;
text-decoration: none;
font-size: 17px;
width: 48.6%; /* Four equal-width links. If you have two links, use 50%, and 33.33% for three links, etc.. */
text-align: center; /* If you want the text to be centered */
}
/* Add a background color on mouse-over */
.navbar a:hover {
background-color: #000;
}
/* Style the current/active link */
.navbar a.active {
background-color: #4CAF50;
}
.microphoneIcon {
/* position: absolute;
left: 65.36%;
right: 26.29%;
top: 54.22%;
bottom: 0.46%;*/
fill: #FFFFFF;
stroke: #FFFFFF;
-webkit-filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7));
filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7));
/* Similar syntax to box-shadow */
/*background: #FFFFFF;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);*/
}
.cameraIcon {
fill: #FFFFFF;
stroke: #FFFFFF;
-webkit-filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7));
filter: drop-shadow( 3px 3px 2px rgba(0, 0, 0, .7));
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="theme-color" content="#009578">
<title>PWA</title>
<link rel="stylesheet" href="src/navigationBar.css">
<!-- Javascript Docs -->
<script type="text/javascript" src="src/index.js"></script>
<link rel="manifest" href="/manifest.json">
<link rel="apple-touch-icon" href="images/logo192.png">
</head>
<body>
<!-- Class for the Bottom Navigation Bar -->
<div class="bar">
<nav class="navbar fixed-bottom navbar-light bg-light nav-fill">
<a href="#">
<svg class='microphoneIcon' id='microphoneIcon' width="42" height="46" viewBox="0 0 42 46" stroke="grey">
<path d='M21 23.7571C25.0314 23.7571 28.2857 21.1043 28.2857 17.8179V5.93928C28.2857 2.65288 25.0314 0 21 0C16.9686 0 13.7143 2.65288 13.7143 5.93928V17.8179C13.7143 21.1043 16.9686 23.7571 21 23.7571ZM18.5714 5.93929C18.5714 4.85043 19.6643 3.95953 21 3.95953C22.3357 3.95953 23.4286 4.85043 23.4286 5.93929V17.8179C23.4286 18.9067 22.3357 19.7976 21 19.7976C19.6643 19.7976 18.5714 18.9067 18.5714 17.8179V5.93929ZM21 27.7167C27.7029 27.7167 33.1429 23.282 33.1429 17.8179H38C38 24.8064 31.6614 30.5477 23.4286 31.5178V37.6155H18.5714V31.5178C10.3386 30.5477 4 24.8064 4 17.8179H8.85714C8.85714 23.282 14.2971 27.7167 21 27.7167Z'/>
</svg>
</a>
<a href="#">
<svg class ='cameraIcon' id='cameraIcon' xmlns="http://www.w3.org/2000/svg" width="50" height="46" viewBox="0 0 50 46">
<path d="M 45 36 a 3 3 90 0 1 -3 3 H 6 a 3 3 90 0 1 -3 -3 V 18 a 3 3 90 0 1 3 -3 h 3.516 a 9 9 90 0 0 6.36 -2.637 l 2.49 -2.484 A 3 3 90 0 1 20.481 9 h 7.032 a 3 3 90 0 1 2.121 0.879 l 2.484 2.484 A 9 9 90 0 0 38.484 15 H 42 a 3 3 90 0 1 3 3 v 18 z M 6 12 a 6 6 90 0 0 -6 6 v 18 a 6 6 90 0 0 6 6 h 36 a 6 6 90 0 0 6 -6 V 18 a 6 6 90 0 0 -6 -6 h -3.516 a 6 6 90 0 1 -4.242 -1.758 l -2.484 -2.484 A 6 6 90 0 0 27.516 6 H 20.484 a 6 6 90 0 0 -4.242 1.758 l -2.484 2.484 A 6 6 90 0 1 9.516 12 H 6 z M 24 33 a 7.5 7.5 90 1 1 0 -15 a 7.5 7.5 90 0 1 0 15 z m 0 3 a 10.5 10.5 90 1 0 0 -21 a 10.5 10.5 90 0 0 0 21 z M 9 19.5 a 1.5 1.5 90 1 1 -3 0 a 1.5 1.5 90 0 1 3 0 z"/>
</svg>
</a>
</nav>
</div>
</body>
</html>
put display:flex in to navbar div
.navbar {
display:flex;
}
button in separate lines
.navbar {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

Not cloning as expected

I have a JavaScript code that clones the last li node, if a user clicks on the button Add Choice or if an input clicked is the last input. The cross button on the right removes the li node it is located in. It won't remove if there's only one input element left.
Everything works fine except:
If you start removing the lis from bottom to top until there's only one input element and click on the input element, it will clone and add a new li. Now if you click on the second(cloned) input element, it doesn't clone. I get the following error in the console.
TypeError: el.parentNode.nextSibling.nextSibling.classList is undefined
Also, how would I go about attaching a focus event listener to the input element and trigger the cloning process without conflicting with the click event. I tried doing this the cloning is being done twice. If the user navigates through the inputs using the Tab key, and if the last input is focused. I'd like to trigger the cloning process.
var wheelBuilder = {
getNodes: function(c) {
return document.querySelectorAll(c);
},
getLast: function(e) {
return [].slice.call(e).pop();
},
insertAfter: function(n, r) {
r.parentNode.insertBefore(n, r.nextSibling);
},
clone: function() {
var inputs = wheelBuilder.getNodes('.choiceInput'),
lastInput = wheelBuilder.getLast(inputs),
cl = lastInput.parentNode.cloneNode(true);
wheelBuilder.insertAfter(cl, lastInput.parentNode);
var cross = wheelBuilder.getNodes('.cross'),
choiceInput = wheelBuilder.getNodes('.choiceInput'),
lastCross = wheelBuilder.getLast(cross),
lastChoiceInput = wheelBuilder.getLast(choiceInput);
lastCross.addEventListener('click', wheelBuilder.removeChoice);
lastChoiceInput.addEventListener('click', wheelBuilder.addIfLastInput);
},
addIfLastInput: function(e) {
var el = e.target,
inputs = wheelBuilder.getNodes('.choiceInput');
isLast = (inputs.length > 1) ? el.parentNode.nextSibling.nextSibling.classList.contains('input') : false;
if (!isLast) {
wheelBuilder.clone();
el.focus();
}
},
removeChoice: function(e) {
var choice = e.target.parentNode.parentNode.parentNode.parentNode,
node = choice.parentNode;
if (wheelBuilder.getNodes('.choiceInput').length > 1) {
node.removeChild(choice);
}
}
}
wheelBuilder.getNodes('.cross').forEach(function(el, _) {
el.addEventListener('click', wheelBuilder.removeChoice);
});
wheelBuilder.getNodes('.choiceInput').forEach(function(el, _) {
el.addEventListener('click', wheelBuilder.addIfLastInput);
});
var addChoice = document.getElementById('addChoice');
addChoice.addEventListener('click', wheelBuilder.clone);
.wheelBuilder {
position: absolute;
width: 100%;
font-size: 1.3em;
font-family: Sans;
}
.wheelBuilder .wrapper {
max-width: 60%;
margin: 0 auto;
margin-bottom: 50px;
padding: 0 10px 10px 10px;
}
.title #gears svg {
transform: translate(5px, 5px);
fill: #565656;
}
.wheelBuilder .title {
text-align: center;
font-family: Arial, Helvetica, sans-serif;
font-size: 1.5em;
font-weight: 500;
padding: 15px 20px;
margin: 0 0 20px 0px;
line-height: 40px;
outline: 0;
width: 100%;
background: #ffffff;
color: #565656;
box-shadow: 0px 0px 4px 4px #dfdfdf;
}
.wrapper ol {
position: relative;
padding: 0;
margin: 0.25em 0.125em;
width: 100%;
background: #ffffff;
padding: 20px;
box-shadow: 0px 0px 4px 4px #dfdfdf;
}
.choices {
position: relative;
list-style-type: none;
width: 100%;
}
.choices:first-child {
text-align: left;
color: #565656;
}
.choices:not(:last-child) {
margin-bottom: 10px;
}
.add {
text-align: left;
}
#plus svg {
z-index: 3;
transform: translate(20px, 7px);
fill: #565656;
cursor: pointer;
}
#addChoice, #applyChanges {
position: relative;
height: 40px;
padding: 0 .8em;
background: #ffffff;
border: 0;
font-size: 1.2em;
color: #565656;
cursor: pointer;
margin-top: 10px;
box-sizing: border-box;
border: 1px solid #ffffff;
box-shadow: 0px 0px 5px 3px #dfdfdf;
transition: 0.2s all ease-in;
}
#addChoice {
margin-left: -32px;
padding: 0 .8em 0 2.2em;
}
#applyChanges {
width: 100%;
}
#plus:hover + #addChoice, #addChoice:hover, #applyChanges:hover {
border: 1px solid #a8ab0a;
box-shadow: 0px 0px 5px 4px #d1d1d1;
}
.choiceInput {
width: 100%;
height: 40px;
background: #ffffff;
padding: 0 .4em;
color: #565656;
font-size: 1.2em;
border: 1px solid #cfcfcf;
transition: border .2s ease-in, box-shadow .2s ease-in;
}
.choiceInput:hover {
border: 1px solid #c6c85f;
box-shadow: inset 0 0 5px 1px #cfcfcf;
}
.choiceInput:focus {
border: 1px solid #a8ab0a;
box-shadow: inset 0 0 5px 1px #cfcfcf;
}
.cross {
position: absolute;
height: 40px;
right: 0;
top: 0;
}
.cross svg {
transform: translate(50%, 0);
}
.cross path {
cursor: pointer;
}
svg g .outline {
stroke:#c2c2c2;
fill:#ffffff;
}
svg g .x {
fill:none;
stroke:#c4c4c4;
stroke-width:2;
stroke-linecap:round;
}
.cross g:hover path {
stroke: #e75141;
}
#media only screen and (max-width: 480px) {
.toast p, .toast span, .spinBtn {
font-size: 18px;
line-height: 18px;
}
.wheelBuilder {
top: 120vmin;
}
.wheelBuilder .wrapper {
max-width: 90%;
}
.wrapper ol li {
padding: 0;
}
}
<div class="wheelBuilder">
<div class="wrapper">
<h2 class="title">
<span id="gears">
<svg xmlns="http://www.w3.org/2000/svg" width="30" viewBox="0 0 24 24">
<path d="M 16.064453 2 C 15.935453 2 15.8275 2.0966094 15.8125 2.2246094 L 15.695312 3.2363281 C 15.211311 3.4043017 14.773896 3.6598036 14.394531 3.9882812 L 13.457031 3.5839844 C 13.339031 3.5329844 13.202672 3.5774531 13.138672 3.6894531 L 12.201172 5.3105469 C 12.136172 5.4215469 12.166531 5.563625 12.269531 5.640625 L 13.078125 6.2402344 C 13.030702 6.4865104 13 6.7398913 13 7 C 13 7.2601087 13.030702 7.5134896 13.078125 7.7597656 L 12.269531 8.359375 C 12.166531 8.435375 12.137172 8.5774531 12.201172 8.6894531 L 13.138672 10.310547 C 13.202672 10.422547 13.339031 10.468969 13.457031 10.417969 L 14.394531 10.011719 C 14.773896 10.340196 15.211311 10.595698 15.695312 10.763672 L 15.8125 11.775391 C 15.8275 11.903391 15.935453 12 16.064453 12 L 17.935547 12 C 18.064547 12 18.1725 11.903391 18.1875 11.775391 L 18.304688 10.763672 C 18.789173 10.59553 19.227802 10.340666 19.607422 10.011719 L 20.542969 10.414062 C 20.660969 10.465063 20.797328 10.420594 20.861328 10.308594 L 21.798828 8.6875 C 21.863828 8.5765 21.833469 8.4344219 21.730469 8.3574219 L 20.923828 7.7578125 C 20.970992 7.5121818 21 7.2593796 21 7 C 21 6.7398913 20.969298 6.4865104 20.921875 6.2402344 L 21.730469 5.640625 C 21.833469 5.564625 21.862828 5.4225469 21.798828 5.3105469 L 20.861328 3.6894531 C 20.797328 3.5774531 20.660969 3.5310312 20.542969 3.5820312 L 19.605469 3.9882812 C 19.226104 3.6598036 18.788689 3.4043017 18.304688 3.2363281 L 18.1875 2.2246094 C 18.1725 2.0966094 18.064547 2 17.935547 2 L 16.064453 2 z M 17 5.25 C 17.966 5.25 18.75 6.034 18.75 7 C 18.75 7.967 17.966 8.75 17 8.75 C 16.034 8.75 15.25 7.967 15.25 7 C 15.25 6.034 16.034 5.25 17 5.25 z M 7.0644531 9 C 6.9354531 9 6.8275 9.0966094 6.8125 9.2246094 L 6.6386719 10.710938 C 5.8314079 10.940599 5.1026855 11.35237 4.5175781 11.921875 L 3.1582031 11.335938 C 3.0402031 11.284937 2.9038438 11.329406 2.8398438 11.441406 L 1.9023438 13.0625 C 1.8373437 13.1735 1.8677031 13.315578 1.9707031 13.392578 L 3.1679688 14.279297 C 3.0687954 14.672064 3 15.076469 3 15.5 C 3 15.923531 3.0687954 16.327936 3.1679688 16.720703 L 1.9707031 17.609375 C 1.8677031 17.685375 1.8383437 17.827453 1.9023438 17.939453 L 2.8398438 19.560547 C 2.9038438 19.672547 3.0402031 19.717016 3.1582031 19.666016 L 4.5175781 19.078125 C 5.1026855 19.64763 5.8314079 20.059401 6.6386719 20.289062 L 6.8125 21.775391 C 6.8275 21.903391 6.9354531 22 7.0644531 22 L 8.9355469 22 C 9.0645469 22 9.1725 21.903391 9.1875 21.775391 L 9.3613281 20.289062 C 10.168592 20.059401 10.897314 19.64763 11.482422 19.078125 L 12.841797 19.664062 C 12.959797 19.715062 13.096156 19.670594 13.160156 19.558594 L 14.097656 17.9375 C 14.162656 17.8265 14.132297 17.684422 14.029297 17.607422 L 12.832031 16.720703 C 12.931205 16.327936 13 15.923531 13 15.5 C 13 15.076469 12.931205 14.672064 12.832031 14.279297 L 14.029297 13.390625 C 14.132297 13.314625 14.161656 13.172547 14.097656 13.060547 L 13.160156 11.439453 C 13.096156 11.327453 12.959797 11.282984 12.841797 11.333984 L 11.482422 11.921875 C 10.897314 11.35237 10.168592 10.940599 9.3613281 10.710938 L 9.1875 9.2246094 C 9.1725 9.0966094 9.0645469 9 8.9355469 9 L 7.0644531 9 z M 8 13.5 C 9.105 13.5 10 14.395 10 15.5 C 10 16.605 9.105 17.5 8 17.5 C 6.895 17.5 6 16.605 6 15.5 C 6 14.395 6.895 13.5 8 13.5 z"></path>
</svg>
</span> Wheel Builder
</h2>
<ol>
<li class="choices">Choices (enter up to 50 choices):</li>
<li class="choices input">
<input class="choiceInput" type="text" autocomplete="off" value="" />
<span class="cross">
<svg xmlns="http://www.w3.org/2000/svg" height="40" viewBox="0 0 60 40" version="1.1">
<g>
<path class="outline" d="M10,20 l12,-20 h38 v40 h-38z" />
<path class="x" d="M40,20 m-7,-7 l14,14 m0,-14 l-14,14" />
</g>
</svg>
</span>
</li>
<li class="choices input">
<input class="choiceInput" type="text" autocomplete="off" value="" />
<span class="cross">
<svg xmlns="http://www.w3.org/2000/svg" height="40" viewBox="0 0 60 40" version="1.1">
<g>
<path class="outline" d="M10,20 l12,-20 h38 v40 h-38z" />
<path class="x" d="M40,20 m-7,-7 l14,14 m0,-14 l-14,14" />
</g>
</svg>
</span>
</li>
<li class="choices input">
<input class="choiceInput" type="text" autocomplete="off" value="" />
<span class="cross">
<svg xmlns="http://www.w3.org/2000/svg" height="40" viewBox="0 0 60 40" version="1.1">
<g>
<path class="outline" d="M10,20 l12,-20 h38 v40 h-38z" />
<path class="x" d="M40,20 m-7,-7 l14,14 m0,-14 l-14,14" />
</g>
</svg>
</span>
</li>
<li class="choices input">
<input class="choiceInput" type="text" autocomplete="off" value="" />
<span class="cross">
<svg xmlns="http://www.w3.org/2000/svg" height="40" viewBox="0 0 60 40" version="1.1">
<g>
<path class="outline" d="M10,20 l12,-20 h38 v40 h-38z" />
<path class="x" d="M40,20 m-7,-7 l14,14 m0,-14 l-14,14" />
</g>
</svg>
</span>
</li>
<li class="choices input">
<input class="choiceInput" type="text" autocomplete="off" value="" />
<span class="cross">
<svg xmlns="http://www.w3.org/2000/svg" height="40" viewBox="0 0 60 40" version="1.1">
<g>
<path class="outline" d="M10,20 l12,-20 h38 v40 h-38z" />
<path class="x" d="M40,20 m-7,-7 l14,14 m0,-14 l-14,14" />
</g>
</svg>
</span>
</li>
<li class="choices add">
<span id="plus">
<svg xmlns="http://www.w3.org/2000/svg" height="28" viewBox="0 0 32 32" version="1.1">
<path d="M 16 3 C 8.832031 3 3 8.832031 3 16 C 3 23.167969 8.832031 29 16 29 C 23.167969 29 29 23.167969 29 16 C 29 8.832031 23.167969 3 16 3 Z M 16 5 C 22.085938 5 27 9.914063 27 16 C 27 22.085938 22.085938 27 16 27 C 9.914063 27 5 22.085938 5 16 C 5 9.914063 9.914063 5 16 5 Z M 15 10 L 15 15 L 10 15 L 10 17 L 15 17 L 15 22 L 17 22 L 17 17 L 22 17 L 22 15 L 17 15 L 17 10 Z "></path>
</svg>
</span>
<input id="addChoice" type="button" name="addChoice" value="Add Choice..." />
</li>
<li class="choices">
<input id="applyChanges" type="button" name="applyChanges" value="Apply Wheel Changes" />
</li>
</ol>
</div>
</div>
I'd appreciate any help.
Now if you click on the second(cloned) input element, it doesn't clone. I get the following error in the console.
The issue is in your addIfLastInput method. el.parentNode.nextSibling.nextSibling.classList.contains('input') is a fragile code. Small changes in tree structure (as you can see) can crash your application. It seems you want to check if the parent element of the clicked element is the last li that has .choices.input class names. For that, you can simply code:
addIfLastInput: function(e) {
var el = e.target,
inputs = wheelBuilder.getNodes('.choices.input'),
isLast = el.parentNode === wheelBuilder.getLast(inputs);
if (isLast) {
/// ...
}
},
Also, how would I go about attaching a focus event listener to the input element and trigger the cloning process without conflicting with the click event.
I'd just listen to focus event instead of click.
wheelBuilder.getNodes('.choiceInput').forEach(function(el, _) {
el.addEventListener('focus', wheelBuilder.addIfLastInput);
});
And:
clone: function() {
// ...
lastChoiceInput.addEventListener('focus', wheelBuilder.addIfLastInput);
},
Here is a demo on jsfiddle.

Categories