I'm trying to work out if it's possible to toggle the rotation of a div on a click function, e.g. Clicking on a menu button rotates the arrow from pointing downwards to upwards and clicking again will reverse this (upwards to downwards).
I have a jsfiddle demo setup which will make more sense of it: http://jsfiddle.net/bf7Ke/1/
jQuery —
$(document).ready(function(){
$('.menu-category-title').click(function(){
$('#menu-'+$(this).attr('hook')).fadeToggle('slow');
$(this).children('.menu-title-arrow').rotate({animateTo:180});
return false;
});
});
Thus far clicking on .menu-category-title fades in the relevant content below and rotates the corresponding arrow by 180 degrees. Clicking .menu-category-title again fades out the relevant content but the arrow stays at 180 degrees. Is there anyway to toggle this function also?I can't figure it out, any suggestions would be greatly appreciated!
Think you should check if element is visible or not before arrow rotation
$(document).ready(function(){
$('.menu-category-title').click(function(){
var elem = $('#menu-'+$(this).attr('hook')),
arrow = $(this).children('.menu-title-arrow')
if (!elem.is(':visible')) {
arrow.rotate({animateTo:180});
} else {
arrow.rotate({animateTo:360});
}
elem.fadeToggle('slow', function() {
});
return false;
});
});
http://jsfiddle.net/bf7Ke/2/
How about this to fit your need: http://jsfiddle.net/HMKXq/
OR bit of the animated demo here: http://jsfiddle.net/HMKXq/2/
Good source: Rotate image on toggle with jQuery
Hope it helps :)
code
$(document).ready(function () {
$('.menu-category-title').click(function () {
$('#menu-' + $(this).attr('hook')).fadeToggle('slow');
$(this).children('.menu-title-arrow').toggleClass("rotate1 rotate2");
});
});
css
.menu-category-title {
position: relative;
height: 70px;
line-height: 70px;
text-transform: uppercase;
letter-spacing: 1px;
font-size: 20px;
border-bottom: 1px solid black;
cursor: pointer;
}
.menu-food-wrap {
position: relative;
margin-top: 25px;
padding-bottom: 45px;
text-transform: uppercase;
font-size: 12px;
line-height: 15px;
border-bottom: 1px solid black;
display: none;
}
.rotate1 {
-webkit-transform: rotate(0deg) translate3d(0, 0, 0);
-moz-transform: rotate(0deg);
-o-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
-o-transition:.5s;
-ms-transition:.5s;
-moz-transition:.5s;
-webkit-transition:.5s;
transition:.5s;
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0);
}
.rotate2 {
-webkit-transform: rotate(-180deg) translate3d(0, 0, 0);
-moz-transform: rotate(-180deg);
-o-transform: rotate(-180deg);
-ms-transform: rotate(-180deg);
transform: rotate(-180deg);
-o-transition:.5s;
-ms-transition:.5s;
-moz-transition:.5s;
-webkit-transition:.5s;
transition:.5s;
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
}
return false is not needed in your case, additionally hook attribute is not a HTML attribute, therefore it's invalid.
Use data-hook attribute instead.
FIDDLE DEMO
<div class="menu-category-title" data-hook="01">
Than do like:
$(document).ready(function () {
$('.menu-category-title').click(function () {
var dat = $(this).data('rotate');
$(this).data('rotate', !dat? 0 : 180);
$('#menu-' + $(this).data('hook')).fadeToggle('slow');
$(this).children('.menu-title-arrow').rotate({animateTo: dat});
});
});
what this does is setting an additional data (rotate) on click, than using a ternary operator ( ? : ) set respectively to 0 : 180 depending on the boolean/value returned by var dat.
You need to restore the div's angle to 0 when closing the div. Try this:
$(document).ready(function(){
$('.menu-category-title').click(function(){
var targetAngle = $('#menu-'+$(this).attr('hook')).is(":visible") ? 0 : 180;
$('#menu-'+$(this).attr('hook')).fadeToggle('slow');
$(this).children('.menu-title-arrow').rotate({animateTo:targetAngle});
return false;
});
});
Here's an updated jsFiddle:
http://jsfiddle.net/rFxJM/
Related
I found a button on a website that has the animation of a google Button.
How do you make such a button that it makes an animation wherever you click?
Here is my code what I have done so far:
button {
text-transform: uppercase;
padding: 0.8em;
width: 100px;
background: #0053d9;
color: #fff;
border: none;
border-radius: 5px;
transition: all 0.2s;
font-size: 15px;
font-weight: 500;
}
button:hover {
filter: brightness(80%);
cursor: pointer;
}
button:active {
transform: scale(0.92)
}
<button>Login</button>
This effect is known as the Material ripple effect (or at least that's along the lines of what most people call it).
There are two ways to accomplish this effect - one using JS and CSS, for the full-fledged effect, which means the ripple comes out of where the mouse is, and one using pure CSS, and no JS - which results in the ripple coming out of the button no matter where the mouse is inside the button.
Some people prefer the CSS-only one as it is cleaner, but most prefer the full-fledged version as it takes into account the mouse position and hence delivers a slightly better experience...
Anyway, I've created both these effects, chose whichever you prefer :).
PS: here are the rules for any full-fledged versions you see:
The ripple must be created when the mouse is down on the button - not when the mouse is clicked because that takes an extra hundred miliseconds on mobile devices (because mobile browsers delay delivering the click event to be able to check if it is a single click or a double click). So with this kind of dalay before showing the ripple, user experience goes down drastically as your site will seem slow and laggy even though it probably isn't.
The ripple must stay on the button and cover its background until the mouse is up, or the button has lost focus - whichever comes first.
Without further ado, here is the code...
window.addEventListener("mousedown", e => {
const target = e.target;
if(target.nodeName == "BUTTON" && !target.classList.contains("css-only-ripple")) {
show_ripple(target);
}
});
function show_ripple(button) {
const style = getComputedStyle(button);
let ripple_elmnt = document.createElement("span");
let diameter = Math.max(parseInt(style.height), parseInt(style.width)) * 1.5;
let radius = diameter / 2;
ripple_elmnt.className = "ripple";
ripple_elmnt.style.height = ripple_elmnt.style.width = diameter + "px";
ripple_elmnt.style.position = "absolute";
ripple_elmnt.style.borderRadius = "1000px";
ripple_elmnt.style.pointerEvents = "none";
ripple_elmnt.style.left = event.clientX - button.offsetLeft - radius + "px";
ripple_elmnt.style.top = event.clientY - button.offsetTop - radius + "px";
ripple_elmnt.style.transform = "scale(0)";
ripple_elmnt.style.transition = "transform 500ms ease, opacity 400ms ease";
ripple_elmnt.style.background = "rgba(255,255,255,0.5)";
button.appendChild(ripple_elmnt);
setTimeout(() => {
ripple_elmnt.style.transform = "scale(1)";
}, 10);
button.addEventListener("mouseup", e => {
ripple_elmnt.style.opacity = 0;
setTimeout(() => {
try {
button.removeChild(ripple_elmnt);
} catch(er) {}
}, 400);
}, {once: true});
button.addEventListener("blur", e => {
ripple_elmnt.style.opacity = 0;
setTimeout(() => {
try {
button.removeChild(ripple_elmnt);
} catch(er) {}
}, 450);
}, {once: true});
}
button {
text-transform: uppercase;
padding: 0.8em;
width: 100px;
background: #0053d9;
color: #fff;
border: none;
border-radius: 5px;
transition: all 0.2s;
font-size: 15px;
font-weight: 500;
position: relative;
overflow: hidden;
}
button:hover {
filter: brightness(80%);
cursor: pointer;
}
button:active {
transform: scale(0.92)
}
.css-only-ripple::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 150%;
aspect-ratio: 1 / 1;
transform: translate(-50%, -50%) scale(0);
pointer-events: none;
border-radius: 999px;
background: rgba(255, 255, 255, .5);
}
.css-only-ripple:focus::after {
animation: scale_up 1000ms forwards;
}
#keyframes scale_up {
0% {
transform: translate(-50%, -50%) scale(0);
opacity: 1;
}
100% {
transform: translate(-50%, -50%) scale(1);
opacity: 0;
}
}
<button>Login</button>
<button class="css-only-ripple">Login</button>
<br>
The first button is the CSS and JS version, and the second is the CSS-only version. For the CSS-only button, you have to unfocus it before you click it again or the ripple will not show (it only gets created on focus)
Is there a possibility to have a transition when adding dynamically a new button to the control group?
For example, in this code, it would be nice to show the new button with a slide-In.
valuesOfParameter.forEach(valueOfParameter => {
// iterative Button
var buttonIterativ = new Autodesk.Viewing.UI.Button(valueOfParameter);
// Click Event
buttonIterativ.onClick = (event) => {
console.log(valueOfParameter);
};
buttonIterativ.addClass(valueOfParameter);
controlGroup.addControl(buttonIterativ);
// controlGroup.addControl(buttonIterativ);
$('#' + valueOfParameter).append('<style>.' + valueOfParameter + ':before{content: attr(data-before); font-size: 20px; color: white;}</style>');
$('#' + valueOfParameter.toString()).attr('data-before', valueOfParameter);
});
Thank you
The easiest way would be to go with CSS3 animation - you can pull it off with no code level changes required, e.g.:
.buttonSlide_in{
animation: slideMe .7s ease-in;
}
#keyframes slideMe{
0%{
transform: skewX(53deg) translateX(-500px);
opacity: 0;
}
60%{
transform: translateX(0px);
}
62%{
transform: skewX(0deg) translateX(30px);
}
70%{
transform: skew(-20deg);
opacity: 1;
}
80%{
transform: skew(0deg) translate(0);
}
90%{
transform: skew(-5deg);
}
100%{
transform: skew(0deg);
}
}
See here to get started and you'd get the attention from the right community if you add more relevant tags such as HTML/CSS animation to your question
I use this code for a menu in my site but now testing it cross-browser I see there is not compatible with firefox.
li {
display: inline-block;
list-style: none inside none;
text-align: center;
}
li a:before {
content:"";
display: block;
border-radius: 50%;
width: 62px;
height: 62px;
background: #F00;
margin: 0 auto 14px;
transition: all .2s;
}
ul.small li a:before {
-webkit-transform: scale(0.7);
-moz-transform: scale(0.7);
-ms-transform: scale(0.7);
-o-transform: scale(0.7);
background: blue;
}
ul.small-zoom li a:before {
zoom: 0.7;
background: green;
}
As you can see in this jsfiddle I tryed multiple solutions but I need the list item change width and heigth based on the a:before element and, with the scale() instruction the li dimention do not change.
There is a solution to have this in Firefow whitout fix the li dimentions?
I mostly use JavaScript to emulate zoom. Since Firefox is the only modern browser not to support it, I occasionally use it in cases where its absence does not negatively impact usability.
Here is a quick and dirty version of a generic solution:
<div data-zoom="0.5" style="zoom: 0.5">
Scaled down element
</div>
if (! ('zoom' in document.createElement('div').style)) {
setInterval(() => {
zoomed.forEach(e => {
const scale = Number(e.getAttribute('data-zoom'))
e.style.transform = 'none !important'
e.style.marginRight = '0 !important'
e.style.marginBottom = '0 !important'
const width = e.clientWidth
const height = e.clientHeight
e.style.transform = `scale(${scale})`
e.style.transformOrigin = '0 0'
const pullUp = height - height * scale
const pullLeft = width - width * scale
e.style.marginBottom = `${-pullUp}px`
e.style.marginRight = `${-pullLeft}px`
})
}, 100)
}
I just found a quick and dirty solution, but it works for my use-case, so it could help someone else too.
.zoomed {
zoom: 0.5;
}
becomes
.zoomed {
transform: scale(0.5);
margin: -50px;
}
where 50px is 1/4 of the .zoomed width.
Of course, there are many limitations of this approach - it overwrites any previous transform and margin, you have to manually insert the negative margin for each element (or calculate it with JS), and probably more.
But like I said, it worked for my specific use-case.
There is no such CSS standard property like zoom.
The reason why you code does not work in modern browsers, is that you are missing the unprefixed (standard) variant of several properties. For example when using transform:
-webkit-transform: scale(0.7);
-moz-transform: scale(0.7);
-ms-transform: scale(0.7);
-o-transform: scale(0.7);
transform: scale(0.7);
When applying a CSS scale transform to an element, is it possible to set the 'from' value as the current scale?
For example, consider the following 2 CSS keyframes used to apply separate growing and shrinking animation transforms:
#-webkit-keyframes grow
{
from { -webkit-transform: scale(0,0); }
to { -webkit-transform: scale(1,1); }
}
#-webkit-keyframes shrink
{
from { -webkit-transform: scale(1,1); }
to { -webkit-transform: scale(0,0); }
}
This will successfully scale the element it's applied to, but always from 0 to 1 (or vice-versa). If the shrink keyframe gets applied before the grow keyframe has finished, it has the effect of 'jumping' the scale to 0 before the transform begins.
You can see this effect in this jsFiddle showing CSS scale transform on mouseover
Notice that if you mouse over the black square and then quickly mouse out, the scale transform is not smooth.
What I'm essentially after is something like the following:
#-webkit-keyframes grow
{
from { -webkit-transform: CURRENT_SCALE; }
to { -webkit-transform: scale(1,1); }
}
Your animation makes the element go from 0% scale to 100% scale on hover, and from 100% to 0% scale on mouseOut.
I think in this case, the solution could be setting the basic scale of the element according to its start point :
#output
{
width: 200px;
height: 200px;
border-radius: 50%;
background: #FF0000;
display: inline-block;
-ms-transform: scale(0,0);
transform: scale(0,0);
-webkit-transform: scale(0,0);
}
In this case, I would harldy recommend using pure CSS solution, using transition on :hover : http://jsfiddle.net/bg6aj/21/
You wont have any "jumping" effect :
#output
{
width: 200px;
height: 200px;
border-radius: 50%;
background: #FF0000;
display: block;
-ms-transform: scale(0,0);
transform: scale(0,0);
-webkit-transform: scale(0,0);
transition: all .2s;
-webkit-transition: all .2s;
}
#touchPad:hover + #output {
-ms-transform: scale(1,1);
transform: scale(1,1);
-webkit-transform: scale(1,1);
}
At this point, you'll have no more jumping effect.
Then : can we do something like :
#-webkit-keyframes grow
{
from { -webkit-transform: scale(0,0); }
to { -webkit-transform: scale(1,1); }
}
Answer : quite easy :
#-webkit-keyframes grow
{
0% { -webkit-transform: scale(1,1); }
50% { -webkit-transform: scale(0,0); }
100% { -webkit-transform: scale(1,1); }
}
Which means: take my element (as scale default is 100%), render it with 0% scale at 50% of the animation, and turn it back at 100%. Trying to set something like current_scale doesn't make sense.
Considering that, I'll definitely choose the Transition solution.
After looking through IE10's developer blog I have found that they do not support the preserve-3d setting.
I found this cube originally made by Paul Hayes which is working with touch screens and quite popular.
Altough preserve-3d setting is a known issue, I couldn't achieved suggested work around because it seems there is no transform property in the parent to maually apply to the child elements.
Here is the link that I simplified so far: http://jsfiddle.net/cC4Py/1/
CSS:
.viewport {
perspective: 800px;
perspective-origin: 50% 200px;
transform: scale(0.75,0.75);
-webkit-perspective: 800;
-webkit-perspective-origin: 50% 200px;
-webkit-transform: scale(0.75,0.75);
-moz-perspective: 800;
-moz-perspective-origin: 50% 200px;
-moz-transform: scale(0.75,0.75);
}
.cube {
position: relative;
margin: 0 auto;
height: 400px;
width: 400px;
transition: transform 50ms linear;
transform-style: preserve-3d;
-webkit-transition: -webkit-transform 50ms linear;
-webkit-transform-style: preserve-3d;
-moz-transition: -moz-transform 50ms linear;
-moz-transform-style: preserve-3d;
}
.cube > div {
position: absolute;
height: 360px;
width: 360px;
padding: 20px;
background-color: rgba(50, 50, 50, 1);
font-size: 1em;
line-height: 1em;
color: #fff;
border: 1px solid #555;
border-radius: 3px;
transition: -webkit-transform 50ms linear;
}
.cube > div:first-child {
transform: rotateX(90deg) translateZ(200px);
-webkit-transform: rotateX(90deg) translateZ(200px);
-moz-transform: rotateX(90deg) translateZ(200px);
}
.cube > div:nth-child(2) {
transform: translateZ(200px);
-webkit-transform: translateZ(200px);
-moz-transform: translateZ(200px);
}
.cube > div:nth-child(3) {
transform: rotateY(90deg) translateZ(200px);
-webkit-transform: rotateY(90deg) translateZ(200px);
-moz-transform: rotateY(90deg) translateZ(200px);
text-align: center;
}
.cube > div:nth-child(4) {
transform: rotateY(180deg) translateZ(200px);
-webkit-transform: rotateY(180deg) translateZ(200px);
-moz-transform: rotateY(180deg) translateZ(200px);
}
.cube > div:nth-child(5) {
transform: rotateY(-90deg) translateZ(200px);
-webkit-transform: rotateY(-90deg) translateZ(200px);
-moz-transform: rotateY(-90deg) translateZ(200px);
}
.cube > div:nth-child(5) p {
text-align: center;
font-size: 2.77em;
margin: 40px;
line-height: 60px;
}
.cube > div:nth-child(6) {
transform: rotateX(-90deg) rotate(180deg) translateZ(200px);
-webkit-transform: rotateX(-90deg) rotate(180deg) translateZ(200px);
-moz-transform: rotateX(-90deg) rotate(180deg) translateZ(200px);
}
object {
opacity: 0.9;
}
object:hover {
opacity: 1;
}
HTML:
<body class="experiment">
<div class="viewport">
<section class="cube" style="transition: 500ms; -webkit-transition: 500ms;">
<div>MELABA!</div>
<div>
<h2>3D cube</h2>
<time>28th September 2010</time>
<p>By Paul Hayes</p>
<p>3D cube built using css, webkit-perspective and webkit-transform. Rotation via webkit-transition.</p>
<p>Use arrow keys to navigate, or click and hold mouse. On touch screens, use one finger to rotate. Press ESC to reset.</p>
<p>Read more »</p>
</div>
<div>
<object width="360" height="360"><param name="movie" value="http://www.youtube.com/v/MY5PkidV1cM?fs=1&hl=en_GB&rel=0"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/MY5PkidV1cM?fs=1&hl=en_GB&rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="360" height="360">
</object>
</div>
<div>
<h2>Learn how to make a cube</h2>
<time>17th July 2009</time>
<p>By Paul Hayes</p>
<p>“A 3D cube can be created solely in CSS, with all six faces.”</p>
<p>Article: Cube explanation</p>
</div>
<div>
<p>I design and build websites in Brighton</p>
</div>
<div>
<small>Nothing down here.</small>
</div>
</section>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="http://www.paulrhayes.com/experiments/cube-3d/js/experiment.js?13"></script>
</body>
I created copies of every property without -webkit- prefix. Am I doing anything wrong? What should I do next?
First of all, dragging and interaction in general usually means JavaScript. Yes, there are CSS hacks and I've used and abused them myself, but in this case it would be absolutely insane not to use JS.
So that means that you need to chain all the transforms from the ancestors (that means the rotation of the cube itself and the perspective you'd normally set on the parent of the cube) onto the faces of the cube via JavaScript.
You can do this in a few ways. In this case, I've used the style property of the face element, but you can also insert the styles into a style element.
Anyway...
demo
Relevant HTML:
<div class='cube'>
<div class='face'></div>
<!-- five more faces -->
</div>
Relevant CSS:
Since I'll be changing transform values via JS, I didn't bother setting them in the CSS.
.cube, .cube * {
position: absolute;
top: 50%; left: 50%;
}
.face {
margin: -8em;
width: 16em; height: 16em;
}
JS:
The code below is quick and dirty and can be improved.
var faces = document.querySelectorAll('.face'),
n = faces.length,
styles = [],
_style = getComputedStyle(faces[0]),
factor = 3,
side = parseInt(_style.width.split('px')[0], 10),
max_amount = factor*side,
unit = 360/max_amount,
flag = false,
tmp, p = 'perspective(32em) ';
for(var i = 0; i < n; i++) {
tmp = ((i < 4) ? 'rotateY(' + i*90 + 'deg)' :
'rotateX(' + Math.pow(-1, i)*90 + 'deg)') +
' translateZ(' + side/2 + 'px)';
faces[i].style.transform = p + tmp;
faces[i].style['-webkit-transform'] = p + tmp;
styles.push(tmp);
}
var drag = function(e) {
var p1 = { 'x': e.clientX - p0.x, 'y': e.clientY - p0.y },
angle = {'x': -p1.y*unit, 'y': p1.x*unit};
for(var i = 0; i < n; i++) {
tmp = 'rotateX(' + angle.x + 'deg)' +
'rotateY(' + angle.y + 'deg)' + styles[i];
faces[i].style.transform = p + tmp;
faces[i].style['-webkit-transform'] = p + tmp;
}
};
window.addEventListener('mousedown', function(e) {
var t = e.target;
if(t.classList.contains('face')){
p0 = { 'x': e.clientX, 'y': e.clientY };
flag = true;
window.addEventListener('mousemove', drag, false);
}
else {
flag = false;
}
}, false);
window.addEventListener('mouseup', function(e) {
if(flag) {
for(var i = 0; i < n; i++) {
_style = faces[i].style;
tmp = _style.transform || _style['-webkit-transform'];
styles[i] = tmp.replace('perspective(32em) ', '');
}
}
flag = false;
window.removeEventListener('mousemove', drag, false);
}, false);
Personally, I prefer using CSS #keyframes, and setting up animations that way, to using JS. JS tends to introduce jank and freeze up pages. CSS, especially in Firefox, but also in Chrome, is very fast and smooth for 3d vizualization and animation. IE has a problem by not including preserve-3d. Until it does, I won't worry about whether things look as intended in IE. Just try to make sure there's an acceptibly graceful degredation if you have to support IE.