I've designed a 3-bar icon using pure SVG code in HTML. I'm using CSS3 transforms to rotate the top & bottom bars into an X shape. The problem is that they rotate around their own center, but I need them rotating around the icon's center. To get around this I've adjusted their X/Y coordinates.
This causes a LOT of buggy issues with Internet Explorer, Firefox, & Safari. Chrome seems to be alright but obviously I'd like to code this the "right" way so it'll work in all browsers.
Here's my live CodePen
HTML
<svg id="burgericon" xmlns="http://www.w3.org/2000/svg" width="90" height="80">
<g class="icon">
<rect class="frstbar" x="10" y="10" width="70" height="12" rx="7" ry="7" fill="#414141"/>
<rect class="scndbar" x="10" y="35" width="70" height="12" rx="7" ry="7" fill="#414141"/>
<rect class="thrdbar" x="10" y="60" width="70" height="12" rx="7" ry="7" fill="#414141"/>
</g>
</svg>
CSS
.hamburger { display:block; text-align:center; }
svg { cursor:pointer; }
.frstbar, .scndbar, .thrdbar {
-webkit-transition: all 0.35s linear;
-moz-transition: all 0.35s linear;
-o-transition: all 0.35s linear;
transition: all 0.35s linear;
}
#burgericon.open .frstbar {
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
#burgericon.open .thrdbar {
-webkit-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
transform: rotate(-45deg);
}
#burgericon.open .scndbar { width: 0; opacity: 0; }
JS
$('#burgericon').on('click', function(e) {
if($(this).attr('class') != "open") {
$(this).attr('class','open');
$('.frstbar').attr('x','25').attr('y','-5');
$('.thrdbar').attr('x','-35').attr('y','55');
}
else {
$(this).attr('class','default');
$('.frstbar').attr('x','10').attr('y','10');
$('.thrdbar').attr('x','10').attr('y','60');
}
});
I also think changing the X/Y coords is causing a blurry effect. I've added a screenshot below. First you'll see the completed X icon and then you'll see how it looks when animated back to default.
The bars aren't perfectly straight but instead they look crooked for some reason.
Screenshot here
I'm still new to SVG manipulation so I'm not sure how to properly rotate <rect> elements with CSS3/JS. Any help or tips in the right direction would be more than appreciated.
You can remove the JS positioning by using the CSS transform-origin property. You can set it on the left of the first and second bars with transform-origin: 0 50%;.
This way they will cross each other when they are rotated :
document.getElementById('burgericon').addEventListener('click', function (e) {
this.classList.toggle('open');
});
.hamburger {
display: block;
text-align: center;
}
svg {
cursor: pointer;
}
.frstbar,.scndbar,.thrdbar {
transition: all 0.35s linear;
transform: rotate(0deg);
transform-origin: 0% 50%;
}
#burgericon.open .frstbar {
transform: rotate(45deg);
}
#burgericon.open .thrdbar {
transform: rotate(-45deg);
}
#burgericon.open .scndbar {
width: 0;
opacity: 0;
}
<nav class="hamburger">
<svg id="burgericon" xmlns="http://www.w3.org/2000/svg" width="90" height="80">
<g class="icon">
<rect class="frstbar" x="10" y="10" width="70" height="12" rx="7" ry="7" fill="#414141" />
<rect class="scndbar" x="10" y="35" width="70" height="12" rx="7" ry="7" fill="#414141" />
<rect class="thrdbar" x="10" y="60" width="70" height="12" rx="7" ry="7" fill="#414141" />
</g>
</svg>
</nav>
<div>
</div>
Credits to David Thomas for the JS
Note that the transform-origin property needs the same vendor prefixes as the transform property. I have omited them for both in the above snippet
CSS
Using css transform: rotate() I rotated the elements so they form the X
Using css opacity and transitions; made the object gradually go transparent.
.icon {
stroke: none;
fill: #777;
}
.icon .frstbar {
transform-origin: 10% 50%;
transition: transform 1s;
}
.icon:hover .frstbar {
transform: rotate(45deg);
}
.icon .thrdbar {
transform-origin: 10% 50%;
transition: transform 1s;
}
.icon:hover .thrdbar {
transform: rotate(-45deg);
}
.scndbar {
opacity: 1;
transition: opacity 1s;
}
.icon:hover .scndbar {
opacity: 0;
}
<svg id="burgericon" xmlns="http://www.w3.org/2000/svg" width="90" height="90" viewBox="0 0 100 100">
<g class="icon">
<rect class="frstbar" x="10" y="10" width="90" height="12" rx="7" ry="7" />
<rect class="scndbar" x="10" y="35" width="90" height="12" rx="7" ry="7" />
<rect class="thrdbar" x="10" y="60" width="90" height="12" rx="7" ry="7" />
</g>
</svg>
Related
I am trying to animate the width of a svg rect with the following code.
window.onload = function() {
var viewBoxWidth = document.querySelector('svg').viewBox.baseVal.width;
var rect1 = document.getElementById('r1');
var rect1Width = rect1.getBBox().width;
var pct = (rect1Width / viewBoxWidth) * 100;
rect1.style.setProperty('--w1', pct + '%');
}
.r1 {
animation-name: moveWidth;
animation-delay: 2s;
animation-duration: 2s;
animation-iteration-count: 1;
animation-timing-function: linear;
animation-direction: normal;
animation-fill-mode: forwards;
}
#keyframes moveWidth {
0% {
width: 0%;
}
100% {
width: var(--w1);
}
}
<!DOCTYPE html>
<html>
<body>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect class="r1" id="r1" x="10" y="10" width="200" height="20" stroke="none" fill="orange"></rect>
<rect class="r2" id="r2" x="10" y="30" width="200" height="20" stroke="none" fill="green"></rect>
</svg>
</body>
</html>
The animation is taking place but how can I hide the width of r1 till the animation kicks in at the 2s, (till the delay).
window.onload = function() {
var viewBoxWidth = document.querySelector('svg').viewBox.baseVal.width;
var rect1 = document.getElementById('r1');
var rect1Width = rect1.getBBox().width;
var pct = (rect1Width / viewBoxWidth) * 100;
rect1.style.setProperty('--w1', pct + '%');
}
.r1 {
visibility:hidden;/*hide default*/
animation-name: moveWidth;
animation-delay: 2s;
animation-duration: 2s;
animation-iteration-count: 1;
animation-timing-function: linear;
animation-direction: normal;
animation-fill-mode: forwards;
}
#keyframes moveWidth {
0% {
visibility:visible;/*show again*/
width: 0%;
}
100% {
visibility:visible;/*Edit-2 maintains visibility after animation overs*/
width: var(--w1);
}
}
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect class="r1" id="r1" x="10" y="10" width="200" height="20" stroke="none" fill="orange"></rect>
<rect class="r2" id="r2" x="10" y="30" width="200" height="20" stroke="none" fill="green"></rect>
</svg>
use css visibility
Edit-2: maintains visibility after animation overs)
Simple and easy solution change animation-fill-mode: forwards; to animation-fill-mode: both; and width into px or %
.r1 {
animation-name: moveWidth;
animation-delay: 2s;
animation-duration: 2s;
animation-iteration-count: 1;
animation-timing-function: linear;
animation-direction: normal;
animation-fill-mode: both;
}
#keyframes moveWidth {
0% {
width: 0%;
}
100% {
width: 200px;
}
}
<!DOCTYPE html>
<html>
<body>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect class="r1" id="r1" x="10" y="10" width="200" height="20" stroke="none" fill="orange"></rect>
<rect class="r2" id="r2" x="10" y="30" width="200" height="20" stroke="none" fill="green"></rect>
</svg>
</body>
</html>
I'm trying to set an opacity of 1 to the lines that I have in a gauge component, here's a link to the code: https://codepen.io/SergiuT/pen/RwgmOqw
Here's the code:
<svg width="244" height="126" viewBox="0 0 244 126" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="4" y="0" width="236" height="122">
<rect x="4.97656" width="234.175" height="122" fill="url(#paint0_linear)" />
</mask>
<g mask="url(#mask0)">
<circle cx="122" cy="125.5" r="115" fill="url(#paint1_radial)" />
</g>
<path id="line1" opacity="0.5" d="M22.5763 57.2082C10.2411 75.2339 2.76131 96.7911 2 120.032" stroke="#75FCC6" stroke-width="4"
stroke-linecap="round" />
<path id="line2" opacity="0.5" d="M81.134 11.9933C59.6579 19.7007 41.0318 33.3096 27.248 50.8443" stroke="#75FCC6"
stroke-width="4" stroke-linecap="round" />
<path id="line3" opacity="0.5" d="M88.6836 9.56243C99.262 6.53918 110.44 4.91934 122 4.91934C133.56 4.91934 144.738 6.53919 155.317 9.56245"
stroke="#979797" stroke-width="4" stroke-linecap="round" />
<path id="line4" opacity="0.5" d="M162.867 11.9933C184.343 19.7007 202.969 33.3096 216.753 50.8443" stroke="#FBE850"
stroke-width="4" stroke-linecap="round" />
<path id="line5" opacity="0.5" d="M221.424 57.2082C233.759 75.2339 241.239 96.791 242 120.032" stroke="#FBE850" stroke-width="4"
stroke-linecap="round" />
<defs>
<linearGradient id="paint0_linear" x1="122.064" y1="58.5794" x2="122.064" y2="122"
gradientUnits="userSpaceOnUse">
<stop />
<stop offset="1" stop-opacity="0" />
</linearGradient>
<radialGradient id="paint1_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"
gradientTransform="translate(122 125.5) rotate(90) scale(115)">
<stop offset="0.765625" stop-color="#75FCC6" stop-opacity="0" />
<stop offset="1" stop-color="#75FCC6" stop-opacity="0.33" />
</radialGradient>
</defs>
</svg>
<div class="indicator">
<div class="wrapper">
<div class="line"></div>
</div>
</div>
.indicator {
width: 100%;
height: 100%;
display: flex;
align-items: center;
position: absolute;
top: 45%;
margin: 0 10px;
#keyframes go {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(150deg);
}
}
.wrapper {
width: 100px;
position: absolute;
left: 1%;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards !important ;
transform-origin: bottom right;
animation: go 2s ease-in;
.line {
display: inline-block;
width: 85px;
border-radius: 2px;
border: 1px solid white;
height: 0;
}
}
}
Edit: The lines shine based on the value of the rotate() from .wrapper
Example: I can pass in 150deg to rotate, or 30deg, or 80deg. So I'm not going to pass all the lines everytime
Put an id="svg" to your svg. Then find the animations shine 1 to 5.
body {
background: black
}
.indicator {
width: 100%;
height: 100%;
display: flex;
align-items: center;
position: absolute;
top: 45%;
margin: 0 10px;
}
#keyframes go {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(150deg);
}
}
.wrapper {
width: 100px;
position: absolute;
left: 1%;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards !important ;
transform-origin: bottom right;
animation: go 2s ease-in;
}
.wrapper .line {
display: inline-block;
width: 85px;
border-radius: 2px;
border: 1px solid white;
height: 0;
}
#svg #line1{
animation: shine1 2s ease-in;
}
#keyframes shine1 {
0% {
opacity: 1
}
20% {
opacity: 1
}
40% {
opacity: 0.5
}
60% {
opacity: 0.5
}
80% {
opacity: 0.5
}
100% {
opacity: 0.5
}
}
#svg #line2{
animation: shine2 2s ease-in;
}
#keyframes shine2 {
0% {
opacity: 0.5
}
20% {
opacity: 0.5
}
40% {
opacity: 1
}
60% {
opacity: 1
}
80% {
opacity: 0.5
}
100% {
opacity: 0.5
}
}
#svg #line3{
animation: shine3 2s ease-in;
}
#keyframes shine3 {
0% {
opacity: 0.5
}
20% {
opacity: 0.5
}
40% {
opacity: 0.5
}
60% {
opacity: 1
}
80% {
opacity: 1
}
100% {
opacity: 0.5
}
}
#svg #line4{
animation: shine4 2s ease-in;
}
#keyframes shine4 {
0% {
opacity: 0.5
}
20% {
opacity: 0.5
}
40% {
opacity: 0.5
}
60% {
opacity: 0.5
}
80% {
opacity: 1
}
100% {
opacity: 1
}
}
#svg #line5{
animation: shine5 2s ease-in;
}
#keyframes shine5 {
0% {
opacity: 0.5
}
20% {
opacity: 0.5
}
40% {
opacity: 0.5
}
60% {
opacity: 0.5
}
80% {
opacity: 0.5
}
100% {
opacity: 1
}
}
<svg id="svg" width="244" height="126" viewBox="0 0 244 126" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="4" y="0" width="236" height="122">
<rect x="4.97656" width="234.175" height="122" fill="url(#paint0_linear)" />
</mask>
<g mask="url(#mask0)">
<circle cx="122" cy="125.5" r="115" fill="url(#paint1_radial)" />
</g>
<path id="line1" opacity="0.5" d="M22.5763 57.2082C10.2411 75.2339 2.76131 96.7911 2 120.032" stroke="#75FCC6" stroke-width="4"
stroke-linecap="round" />
<path id="line2" opacity="0.5" d="M81.134 11.9933C59.6579 19.7007 41.0318 33.3096 27.248 50.8443" stroke="#75FCC6"
stroke-width="4" stroke-linecap="round" />
<path id="line3" opacity="0.5" d="M88.6836 9.56243C99.262 6.53918 110.44 4.91934 122 4.91934C133.56 4.91934 144.738 6.53919 155.317 9.56245"
stroke="#979797" stroke-width="4" stroke-linecap="round" />
<path id="line4" opacity="0.5" d="M162.867 11.9933C184.343 19.7007 202.969 33.3096 216.753 50.8443" stroke="#FBE850"
stroke-width="4" stroke-linecap="round" />
<path id="line5" opacity="0.5" d="M221.424 57.2082C233.759 75.2339 241.239 96.791 242 120.032" stroke="#FBE850" stroke-width="4"
stroke-linecap="round" />
<defs>
<linearGradient id="paint0_linear" x1="122.064" y1="58.5794" x2="122.064" y2="122"
gradientUnits="userSpaceOnUse">
<stop />
<stop offset="1" stop-opacity="0" />
</linearGradient>
<radialGradient id="paint1_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"
gradientTransform="translate(122 125.5) rotate(90) scale(115)">
<stop offset="0.765625" stop-color="#75FCC6" stop-opacity="0" />
<stop offset="1" stop-color="#75FCC6" stop-opacity="0.33" />
</radialGradient>
</defs>
</svg>
<div class="indicator">
<div class="wrapper">
<div class="line"></div>
</div>
</div>
I'm using the latest version of these:
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-
DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.1/dist/umd/popper.min.js"
integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/js/bootstrap.min.js"
integrity="sha384-+YQ4JLhjyBLPDQt//I+STsc9iw4uQqACwlvpslubQzn4u2UU2UFM80nGisd026JF"
crossorigin="anonymous"></script>
This is the CSS I am using to achieve the desired CSS animation effects across literally all browsers except Safari.
.tt-divider {
border-style: outset;
border-color: LawnGreen;
border-radius: 3px;
margin-bottom: 2.5vh;
margin-top: 2.5vh;
background: gold;
border-width: 2px;
animation: grow-divider 2s forwards linear;
margin: auto;
}
#-webkit-keyframes grow-divider{
from {width:0%; }
to {width:100%; }
}
#keyframes grow-divider{
from {width:0%; }
to {width:100%; }
}
#landing-logo {
display: inline-block;
max-width: 350px;
min-width: 150px;
width: 50vw;
margin-top: 5vh;
margin-bottom: 1vh;
}
#navigation{
padding-left: 7.5vh;
padding-right: 7.5vh;
text-align:center;
}
#btm-right-nav{
max-width: 55px;
position: fixed;
right: 25px;
bottom: 10px;
}
.btm-right-ico {
display: block;
color: lawngreen;
margin:auto;
margin-bottom: 5vh;
font-size: 16px;
text-rendering: optimizeLegibility;
}
.fontawesome-i2svg-active .btm-right-ico {
animation-name: grow-buttons;
animation-duration: 2s;
animation-timing-function: linear;
animation-play-state: running;
animation-fill-mode: forwards;
animation-iteration-count: 1;
animation-direction: normal;
}
#-webkit-keyframes grow-buttons{
from {font-size:16px; }
to {font-size: 45px; }
}
#keyframes grow-buttons{
from {font-size:16px}
to {font-size:45px;}
}
The grow-divider animation works perfectly, and another irrelevant one works perfectly as well on a different page. The only one I cannot get to work only on Safari is the grow-buttons animation. Yes Safari in general I've back-tested every version made in the past 5 years it does exactly the same thing..
Initially I thought it was a CSS naming problem... no I've tried multiple implementations of CSS for compatibility to no avail. I then thought it was just Safari, it could be, but why are my other CSS animations working then? I even put my CSS on the newly generated element via JS and it doesn't work. I even used async programming in JQuery to make sure the CSS wasn't applied before the <i> was changed to <svg>
It's worth mentioning that the CSS classes on the original <i> element are injected into the new <svg> from font-awesome... so the CSS animation is inherited.. this logic works on all browsers except Safari...
I have absolutely no idea what is causing it, anyway here's the html for the entire page:
<!--Display none is changed to block when the page is done loading-->
<div id="landing" style="display:none">
<div id="navigation">
<img id="landing-logo" src="example.gif" alt="example">
<div class="tt-divider"></div>
<div id="page">
</div>
<div id="btm-right-nav">
<i class="fas fa-bars btm-right-ico" data-fa-mask="fas fa-circle" data-fa-
transform="shrink-7"></i>
<i class="fas fa-phone btm-right-ico" data-fa-mask="fas fa-circle" data-fa-
transform="shrink-7"></i>
</div>
</div>
</div>
I think I could get it to work if I just yanked my own svg and put it neatly in an <img> and didn't do some masking magic on my buttons.. I don't want to do that because that'll cut off a ton of features of fontawesome and take more time... so in the meantime I have the animation turned off for Safari users and it's sad because I want this animation it's incredibly satisfying and I really don't want to have to bake my own masked SVGs and put them in a <img> just so I can run CSS animations over SVGs... I mean.. is that what I have to do?
Can I inject inline SVG into a src?
Here's the baked SVG data from fontawesome after the page loads (I took out the data:)
<div id="btm-right-nav">
<svg class="svg-inline--fa fa-bars fa-w-16 btm-right-ico" data-
fa-mask="fas fa-circle" data-fa-transform="shrink-7" aria-
hidden="true" focusable="false" data-prefix="fas" data-icon="bars"
role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"
data-fa-i2svg=""><defs><clipPath id="clip-hzzHNtGIZRrn"><path
fill="currentColor" d=""></path></clipPath><mask x="0" y="0"
width="100%" height="100%" id="mask-jyjnVEKbKq5c"
maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse"><rect
x="0"
y="0" width="100%" height="100%" fill="white"></rect><g
transform="translate(256 256)"><g transform="translate(0, 0)
scale(0.5625, 0.5625) rotate(0 0 0)"><path fill="black" d=""
transform="translate(-224 -256)"></path></g></g></mask></defs><rect
fill="currentColor" clip-path="url(#clip-hzzHNtGIZRrn)"
mask="url(#mask-
jyjnVEKbKq5c)" x="0" y="0" width="100%" height="100%"></rect></svg>
<!--<i class="fas fa-bars btm-right-ico" data-fa-mask="fas fa-
circle"
data-
fa-transform="shrink-7"></i> Font Awesome fontawesome.com -->
<svg class="svg-inline--fa fa-phone fa-w-16 btm-right-ico" data-
fa-mask="fas fa-circle" data-fa-transform="shrink-7" aria-hidden="true"
focusable="false" data-prefix="fas" data-icon="phone" role="img"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" data-fa-
i2svg=""><defs><clipPath id="clip-YDDPIJZX3DpE"><path
fill="currentColor" d=""></path></clipPath><mask x="0" y="0"
width="100%" height="100%" id="mask-eJs29EAdXlZv"
maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse"><rect
x="0" y="0" width="100%" height="100%" fill="white"></rect><g
transform="translate(256 256)"><g transform="translate(0, 0)
scale(0.5625, 0.5625) rotate(0 0 0)"><path fill="black" d=""
transform="translate(-256 -256)"></path></g></g></mask></defs><rect
fill="currentColor" clip-path="url(#clip-YDDPIJZX3DpE)"
mask="url(#mask-
eJs29EAdXlZv)" x="0" y="0" width="100%" height="100%">
</rect></svg>
<!--<i class="fas fa-phone btm-right-ico" data-fa-
mask="fas
fa-circle" data-fa-transform="shrink-7"></i> Font Awesome
fontawesome.com-->
</div>
Wow..... really hope this helps someone...
To fix the problem you use regular old css to transform scale it in the animation.
Font-size can be used to scale up inline SVGs on all browsers except Safari
#-webkit-keyframes grow-buttons{
from { -webkit-transform: scale(1); transform: scale(1);}
to { -webkit-transform: scale(3); transform: scale(3);}
}
#keyframes grow-buttons{
from { -webkit-transform: scale(1); transform: scale(1);}
to { -webkit-transform: scale(3); transform: scale(3);}
}
Bottom line:
Use transform: scale() instead of font-size: ()px on SVG CSS animations to maximize compatibility.
I'm working to create an SVG circle progress indicator in react... Here is my output:
CODEPEN
The problem is I need the red stroke to start at the top, not at the current 90% angle... Is there some CSS I can add to reposition the red stroke to start at the top?
FYI, I'm using the following component in react to render this HTML: https://github.com/wmartins/react-circular-progress/blob/gh-pages/src/js/components/CircularProgress.jsx.js
codepen source below
html
<svg class="CircularProgress" width="50" height="50" viewBox="0 0 50 50">
<circle class="CircularProgress-Bg" cx="25" cy="25" r="24" stroke-width="2px"></circle>
<circle class="CircularProgress-Fg" cx="25" cy="25" r="24" stroke-width="2px" style="stroke-dasharray: 150.796; stroke-dashoffset: 125.161;"></circle>
<text class="CircularProgress-Text" x="25" y="25" dy=".4em" text-anchor="middle">17%</text>
</svg>
css
.CircularProgress-Bg,
.CircularProgress-Fg {
fill: none;
}
.CircularProgress-Bg {
stroke: #CCC;
}
.CircularProgress-Fg {
transition: stroke-dashoffset .5s ease-in-out;
stroke: red;
}
.CircularProgress-Text {
font-size: 15px;
font-weight: 600;
fill: rgba(255,255,255,0.9);
transform: translate(0 50%);
}
You could use transform, add transform="rotate(-90 25 25)" and it will start at the top
.CircularProgress-Bg,
.CircularProgress-Fg {
fill: none;
}
.CircularProgress-Bg {
stroke: #CCC;
}
.CircularProgress-Fg {
transition: stroke-dashoffset .5s ease-in-out;
stroke: red;
}
.CircularProgress-Text {
font-size: 15px;
font-weight: 600;
fill: rgba(255,255,255,0.9);
transform: translate(0 50%);
}
<svg class="CircularProgress" width="50" height="50" viewBox="0 0 50 50">
<circle class="CircularProgress-Bg" cx="25" cy="25" r="24" stroke-width="2px"></circle>
<circle transform="rotate(-90 25 25)" class="CircularProgress-Fg" cx="25" cy="25" r="24" stroke-width="2px" style="stroke-startOffest: 50%;stroke-dasharray: 150.796; stroke-dashoffset: 125.161;"></circle>
<text class="CircularProgress-Text" x="25" y="25" dy=".4em" text-anchor="middle">17%</text>
</svg>
If to use CSS, you can rotate the svg element instead of the circle (which might or might not be possible based on its shape)
.CircularProgress {
transform: rotate(-90deg);
}
.CircularProgress-Bg,
.CircularProgress-Fg {
fill: none;
}
.CircularProgress-Bg {
stroke: #CCC;
}
.CircularProgress-Fg {
transition: stroke-dashoffset .5s ease-in-out;
stroke: red;
}
.CircularProgress-Text {
font-size: 15px;
font-weight: 600;
fill: rgba(255,255,255,0.9);
transform: translate(0, 50%);
}
<svg class="CircularProgress" width="50" height="50" viewBox="0 0 50 50">
<circle class="CircularProgress-Bg" cx="25" cy="25" r="24" stroke-width="2px"></circle>
<circle class="CircularProgress-Fg" cx="25" cy="25" r="24" stroke-width="2px" style="stroke-dasharray: 150.796; stroke-dashoffset: 125.161;"></circle>
<text class="CircularProgress-Text" x="25" y="25" dy=".4em" text-anchor="middle">17%</text>
</svg>
I doesn’t know how to do the following with jQuery.
I have created a page hero with two sections (red/black):
What I want is, when hovering over the black one for example, it will expand over the red section, so you get a full black box. The same result I want of course for the red section:
How should I make this work?
var redSection = $('#red');
var blackSection = $('#black');
redSection.on('mouseover', function() {
// Do something - overlay the other section
});
The HTML markup is as follow:
<section id="hero">
<figure id="urbandesign">
<a href=“#" target="_blank">
<img src="images/urbandesign.jpg" alt="Urban Design">
</a>
</figure><!-- End figure -->
<figure id="photography">
<a href=“#" target="_blank">
<img src="images/photography.jpg" alt="Photography">
</a>
</figure><!-- End figure -->
</section><!-- End section#hero -->
And the CSS:
#hero {
height: 480px; /* Default 500px */
padding: 0;
position: relative;
overflow: hidden;
z-index: 1;
background: url(../images/hero.jpg) no-repeat center; /* remove */
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
#hero figure {
position: absolute;
top: 0;
background: #FFF;
}
#hero img {
width: 100%;
max-width: none;
position: relative;
opacity: 0.4;
}
The final result I want to replace the red and black section with images.
Look out to your response! Thank you.
A mix of CSS3 and jQuery with Graceful Degradation should sort this.
CSS
.page {
position:fixed;
width:100%;
height:100%;
overflow:hidden;
}
.black {
background:#000;
width:50%;
height:100%;
position:absolute;
width:100%;
left:-50%;
transform:skew(30deg,0);
transition:0.5s ease-in-out;
z-index:1;
}
.red {
background:#ff0000;
width:50%;
height:100%;
position:absolute;
width:100%;
right:-50%;
transform:skew(30deg,0);
transition:0.5s ease-in-out;
}
.red:hover {
transform:skew(0);
transform:translate(-50%,0);
}
.black:hover {
transform:skew(0);
transform:translate(50%,0);
}
.inactive {
z-index:-1
}
HTML
<div class="page">
<div class="black"></div>
<div class="red"></div>
</div>
jQuery
The jQuery is necessary to fix a z-index problem with the last element in the DOM tree that ruins the fluid animation.
$(document).ready(function(){
$('.black').hover(function(){
$('.red').addClass('inactive');
},function(){
$('.red').removeClass('inactive');
});
$('.red').hover(function(){
$('.black').addClass('inactive');
},function(){
$('.black').removeClass('inactive');
});
});
Be aware that adding any content to the two divs you will have to add an inner div and reset the skew with 'transform:skew(-30deg,0);'. The prefixed versions of transition and transform will also need adding.
JSFiddle Reference
You could do this using svg's path for the shape, pattern for the image and a little bit of JavaScript for handling the mouseover and mouseleave events.
var hero = document.getElementById('hero');
var animLeft = document.getElementById('anim-left');
var animRight = document.getElementById('anim-right');
hero.addEventListener('mouseover', function(e) {
(e.target.id == 'left') ? animRight.beginElement() : animLeft.beginElement();
})
hero.addEventListener('mouseleave', function(e) {
(e.target.id == 'left') ? animRight.endElement() : animLeft.endElement();
})
<svg id="hero" width="600" height="200" viewBox="0 0 600 200">
<defs>
<pattern id="image-left" patternUnits="userSpaceOnUse" width="600" height="200" viewBox="0 0 600 200">
<image xlink:href="http://dummyimage.com/600x200/40000c/000" width="600" height="200" />
</pattern>
<pattern id="image-right" patternUnits="userSpaceOnUse" width="600" height="200" viewBox="0 0 600 200">
<image xlink:href="http://dummyimage.com/600x200/002a33/fff" width="600" height="200" />
</pattern>
</defs>
<a xlink:href="#">
<path id="right" d="M0,0 h600 v200 h-600z" fill="url(#image-right)" />
</a>
<a xlink:href="#">
<path id="left" d="M0,0 h350 l-100,200 h-250z" fill="url(#image-left)" />
<animate id="anim-left" xlink:href="#left" attributeType="XML" attributeName="d" from="M0,0 h350 l-100,200 h-250z" to="M0,0 h0 l-100,200 h0z" dur="1" begin="indefinite" repeatCount="1" fill="freeze" />
<animate id="anim-right" xlink:href="#left" attributeType="XML" attributeName="d" from="M0,0 h350 l-100,200 h-250z" to="M0,0 h700 l-100,200 h-600z" dur="1" begin="indefinite" repeatCount="1" fill="freeze" />
</a>
</svg>
A simple CSS only solution with no additional re-paints, etc.:
.parent {
overflow: hidden;
position: absolute;
width: 90%;
height: 90%;
}
.item {
position: absolute;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
transition: transform 1s, z-index 1s;
z-index: 1;
overflow: hidden;
}
.item .image {
transition: transform 1s;
}
.item:hover {
transform: translate3d(0px, 0px, 0px);
z-index: 100;
}
.item:hover .image {
transform: skewX(0deg);
}
.red {
background: #f00;
transform: translate3d(-50%, 0px, 0px) skewX(-10deg);
}
.red .image {
transform: skewX(10deg);
}
.black {
background: #000;
transform: translate3d(50%, 0px, 0px) skewX(-10deg);
}
.black img {
transform: skewX(10deg);
}
<section class="parent">
<div class="red item">
<img class="image" src="http://placehold.it/450/ff0000/000000" />
</div>
<div class="black item">
<img class="image" src="http://placehold.it/450/000000/ffffff" />
</div>
</section>