I am having an issue with CSS transitions and different browsers. The following Fiddle works fine on IE (the text on the right hand side correctly fades in when you hover over the items on the left and you can switch to other items with the transition still firing on every new hover), but for some reason FF and Chrome will no longer do the transition after selecting one of the items on the left.
jsfiddle link
The CSS transition code:
.FAQItemText.active, .FAQItemTextDark.active, .solutionText.active {
-webkit-transition: opacity 1500ms ease;
-moz-transition: opacity 1500ms ease;
-o-transition: opacity 1500ms ease;
transition: opacity 1500ms ease;
opacity: 1;
}
Please can anyone help me fix it to make it work on all browsers?
Thanks
A CSS transition can't repeat. if you want something that repeat, use a CSS animation
Link : http://www.w3schools.com/css/css3_animations.asp
Your code was overly complicated and there are much simpler ways of doing what you're trying to achieve. I rewrote your JS to work like it should, altered your CSS classes and rules to better suit the purpose and cleaned up your DOM a little bit also.
Check out the code below, where I have explained what changes I've made:
$(function(){
//select all the link elements and add needed event handlers:
$(".leftSlidePanel>a")
.mouseenter(preview)
.mouseleave(preview)
.click(selectSlide);
});
function preview(event){
// This is the slide the element you clicked on links to:
var targetSlide=$(event.currentTarget).attr("href");
// Let's make a selector to select the .leftItem inside the link you hovered and our target slide:
var previewedItem=$(event.currentTarget).find(".leftItem").add(targetSlide);
// and another selector to select all the .leftItems and .FAQItemTexts aparat from the ones being targeted:
var hiddenItems=$(".leftItem, .FAQItemText").not(previewedItem);
// Next add or remove classes from our selected items depending on wheter it was mouseeneter or mouseout:
if(event.type=="mouseenter"){
previewedItem.addClass("previewed");
hiddenItems.addClass("hidden");
}else{
previewedItem.removeClass("previewed");
hiddenItems.removeClass("hidden");
}
}
function selectSlide(event){
// Prevent default behaviour of clicking a link:
event.preventDefault();
// Remove class selected from all .leftItems and .FAQItemTexts:
$(".leftItem, .FAQItemText").removeClass("selected");
// And add said class to targeted elements:
$(event.currentTarget).find(".leftItem").add($(event.currentTarget).attr("href")).addClass("selected");
}
.slideContentContainer {
width:70%;
height:100%;
min-width:1050px;
margin-left:auto;
margin-right:auto;
padding-top:80px;
}
.leftSlidePanel {
float:left;
width:30%;
padding-top:29px;
}
.rightSlidePanel {
float:right;
width:70%;
padding-top:29px;
}
.leftItem {
color: transparent;
width: 100%;
margin-top:0;
text-align: left;
padding-bottom: 23px;
font-family:"Helvetica W01 Cn" !important;
}
.leftItem h4 {
margin: 0;
padding-top:5px;
}
/* this is how your links on the left will look like when they're selected or previewed: */
.leftItem.selected, .leftItem.previewed {
color: rgb(227, 114, 22);
}
.dark.selected {
color: rgb(49, 49, 50);
}
/* This is the style your FAQItemText has normally and when another item is being previewed: */
.FAQItemText, .FAQItemText.selected.hidden {
width: 95%;
opacity: 0;
float:right;
font-size: 20px;
padding-top:29px;
text-align: justify;
color: rgb(227, 114, 22);
font-family:"Helvetica W01 Cn" !important;
display:none;
}
/* Instead of creating another class with almost the same rules as another, create a subclass: */
.FAQItemText.dark {
color: rgb(49, 49, 50);
}
/* This is the style your FAQItemText will have when it's either selected or previewed: */
.FAQItemText.selected, .FAQItemText.previewed{
opacity: 1;
display:block;
/* Firefox and IE support animations without vendor prefixes, so -webkit- is the only one you'll need */
-webkit-animation: fade 1.5s 1;
animation: fade 1.5s 1;
}
/* using display:block wile transitioning opacity can often doesn't give you the effect you'd want, but this can be fixed by using an animation instead: */
#-webkit-keyframes fade{
0% {display:none; opacity:0;}
1% {display:block; opacity:0;}
100% {display:block; opacity:1;}
}
#-keyframes fade{
0% {display:none; opacity:0;}
1% {display:block; opacity:0;}
100% {display:block; opacity:1;}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="section" id="faqs">
<div class="slideContentContainer">
<div class="leftSlidePanel">
<div id="menuItem11" class="leftItem selected"><h4>1</h4></div>
<div id="menuItem12" class="leftItem"><h4>2</h4></div>
<div id="menuItem13" class="leftItem"><h4>3</h4></div>
<div id="menuItem14" class="leftItem"><h4>4</h4></div>
<div id="menuItem15" class="leftItem"><h4>5</h4></div>
<div id="menuItem16" class="leftItem"><h4>6</h4></div>
</div>
<div class="rightSlidePanel">
<div id="slideItem11" class="FAQItemText selected">BLAH 1 BLAH.</div>
<div id="slideItem12" class="FAQItemText">BLAH 2 BLAH.</div>
<div id="slideItem13" class="FAQItemText">BLAH 3 BLAH.</div>
<div id="slideItem14" class="FAQItemText">BLAH 4 BLAH.</div>
<div id="slideItem15" class="FAQItemText">BLAH 5 BLAH.</div>
<div id="slideItem16" class="FAQItemText">BLAH 6 BLAH.</div>
</div>
</div>
</div>
Thank you all for your suggestions, after a while of googling I came across this which seems to do the trick.
So I changed my js code from this:
function ShowSlide(slide, slideItem) {
//Reset page
resetAllHighlights(slide);
//Show needed ones.
jQuery('#slideItem' + slide + slideItem).show();
jQuery('#slideItem' + slide + slideItem).addClass("active");
jQuery('#menuItem' + slide + slideItem).addClass("itemSelected");
}
To this:
function ShowSlide(slide, slideItem) {
//Reset page
resetAllHighlights(slide);
//Show needed ones.
jQuery('#slideItem' + slide + slideItem).show(0);
jQuery('#slideItem' + slide + slideItem).addClass("active");
jQuery('#menuItem' + slide + slideItem).addClass("itemSelected");
}
And it now works in all browsers.
Related
As I was playing around trying to build a simple text carousel, I came across an issue I am having a difficult time understanding.
The layout is simple. I have a wrapper and the text I want the carousel to cycle through.
The issue I am having, however, seems as far as I can tell to be coming from the setInterval method. After the animation cycles through all the text and returns to the beginning, there is a strange overlap between the first and second text that is displayed. The first text will animate, but then will return to replace the second text temporarily.
Any help in understanding what is causing this error to render in this way would be greatly appreciated.
let animateSlide = setInterval(moveSlide, 1200);
function moveSlide() {
let carousel = document.getElementById("wordCarousel");
let firstSlide = carousel.children[0];
let createID = document.createAttribute("id");
createID.value = "active";
firstSlide.setAttributeNode(createID);
carousel.appendChild(carousel.firstChild);
carousel.children[carousel.children.length - 1].removeAttribute("id");
}
/* Carousel Styles */
#wordCarousel {
height: 36px;
overflow: hidden;
}
.carouselSlide {
color: #555;
font-size: 36px;
}
#active {
margin-top: 0px;
animation-name: example;
animation-duration: 1.2s;
animation-timing-function: ease;
}
#keyframes example {
from {
margin-top: 0px;
}
to {
margin-top: -40px;
}
}
<div id="wordCarousel">
<div class="carouselSlide">
Item 1
</div>
<div class="carouselSlide">
Item 2
</div>
<div class="carouselSlide">
Item 3
</div>
<div class="carouselSlide">
Item 4
</div>
</div>
Don't rely on setInterval when dealing with CSS animation. You will never have a perfect synchronization. Better consider events like animationiteration/animationend/animationstart
Here is a better idea will less of code an easier to handle.
let carousel = document.querySelector('#wordCarousel div');
carousel.addEventListener('animationiteration', () => {
carousel.appendChild(carousel.children[0]);
});
#wordCarousel {
height: 36px;
overflow: hidden;
}
.carouselSlide {
color: #555;
font-size: 36px;
line-height:100%; /* line-height will make sure the height is equal to 36px, font-size alone isn't enough */
}
#wordCarousel > div {
height:100%;
animation: example 1s infinite;
}
#keyframes example {
to {
transform: translateY(-100%);
}
}
<div id="wordCarousel">
<div>
<div class="carouselSlide">
Item 1
</div>
<div class="carouselSlide">
Item 2
</div>
<div class="carouselSlide">
Item 3
</div>
<div class="carouselSlide">
Item 4
</div>
</div>
</div>
There's a trick in JS I can't achieve, it relies on stopping a slidding animation made in CSS. In the moment, I have a long div with a random images content that slides in from the top and then out from the bottom. The animation runs at page load thanks to a 'slide down' class, calling the desired slide effect. I also set a scroll effect that allows the user to scroll in this div, BUT I'd like the scroll to take priority over the animation. The animation is finally only a way to encourage the user to scroll. I tried the following code but it has no effect :
$(window).scroll(function() {
('#scroller').removeClass("slidedown");
});
Could that be linked to the animation, like if it was considered as a 'scroll action' ? I attempt to handle this with 'if (ScrollTop < = >)' parameters but it simply has no effect or it just cancels the animation, which is unwanted.
'.on('mousewheel', function(){' doesn't seem to work. Replace '$(window)' by $('#scroller') has no effect either. I'm just thinking on the best way to settle this, but I need at least some advices to understand what I'm doing wrong (and I have to precise that I'm a beginner) !
Please find some key codes below :
----
HTML
----
<div id="scroller-wrapper">
<div id="scroller" class="slidedown">
<div id="img-defile1" class="img-defile">
<img src="img/ceaac.jpg"/>
</div>
<div id="img-defile2" class="img-defile">
<img src="img/ceaac2.jpg"/>
</div>
</div>
</div>
---
CSS
---
#scroller-wrapper {
top:0;
left:0;
width:102vw;
height:100%;
position:absolute;
overflow-y:scroll;
overflow-x:hidden;
transform: scale(1, -1);
z-index:2;
}
#scroller {
max-width:100%;
width:60%;
height:1250%;
position:relative;
z-index:800;
display:block;
transform: scale(1, -1);
}
.slidedown {
animation-duration:120s;
animation-name: slidedown;
animation-timing-function:linear;
animation-iteration-count:1;
animation-fill-mode: forwards;
}
#keyframes slidedown {
0% {
bottom: -75%;
}
100% {
bottom: 1150%;
}
}
.img-defile {
display:block;
max-width:100%;
height:auto;
position:absolute;
overflow:hidden;
}
.img-defile img {
width:600px;
}
.custom-scroll {
height: calc(80% - 20px);
}
---------
JS/Jquery
---------
$('#scroller').scroll(function () {
if ($(this).scrollTop() > 0) {
$('#scroller').addClass("custom-scroll");
return false;
} else {
$('#scroller').removeClass("custom-scroll");
}
});
$('.img-defile').each(function(i) {
$pT=$("#scroller").height();
$pL=$("#scroller").width();
$(this).css({
top:Math.floor(Math.random()*$pT),
left:Math.round(Math.random()*$pL)
});
});
Many thanks in advance !
I am using angular and angular animate to hide and show content with a slide up/down effect - similar to jQuery show.
However, this worked well when i had one slide. Now i have multiple, with varying sizes, how can i adjust the code so the height of the element to show (div or form) is automatially calcuated and adjusted rather than being predefined?
HTML:
<h2 ng-click="showSpoons = !showSpoons">Show Spoons +</h2>
<div ng-show="showSpoons" class="animate-slide-up">
<p>Spoon</p><p>Spoon</p><p>Spoon</p>
<p>Spoon</p><p>Spoon</p><p>Spoon</p>
<p>Spoon</p><p>Spoon</p><p>Spoon</p>
<p>Spoon</p><p>Spoon</p><p>Spoon</p>
</div>
<br>
<h2 ng-click="showForks = !showForks">Show Forks +</h2>
<div ng-show="showForks" class="animate-slide-up">
<p>Fork</p><p>Fork</p><p>Fork</p>
<p>Fork</p><p>Fork</p><p>Fork</p>
</div>
<br>
<h2 ng-click="showCups = !showCups">Show Cups +</h2>
<div ng-show="showCups" class="animate-slide-up">
<p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p>
<p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p>
<p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p>
<p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p>
<p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p><p>Cups</p>
</div>
CSS:
.ng-hide-add, .ng-hide-remove {
/* ensure visibility during the transition */
display: block !important; /* yes, important */
}
.animate-slide-up {
transition: .25s linear all;
height: 10em;
overflow: hidden;
}
.animate-slide-up.ng-hide {
height:0;
}
Plunker: https://plnkr.co/edit/t7oVw3n3oTxuPaPLo38a?p=preview
You are pretty much defining a fixed height value for your slides. Instead of using fixed values, you may use height: auto;. This will provide your slide an automagically generated height value, according to the slides content. So basically, what you need is this:
.animate-slide-up {
transition: .25s linear all;
height: auto;
overflow: hidden;
}
plnkr
Use this,
.animate-slide-up {
transition: .25s linear all;
min-height: 10em;
overflow: hidden;
}
I'm trying to program a scrolling text that runs smooth. The <marquee>..</marquee> tag doesn't work without jolting and I don't think it is good programming. I would like to do it in JavaScript but I'm a total beginner in it.
I found some codes that are easy to understand but the scrolling text that I think looks best isn't coherent to me.
Perhaps someone can explain the parts to me I don't understand.
CODE:
var marqueewidth="2400px"
var marqueeheight="45px"
var speed=1
var pause=1 //stop by mouseover 0=no. 1=yes
var marqueecontent='<nobr><span style="font-size:40px">*** Wir wünschen einen guten Start in den Dezember!!! ***</span></nobr>'
var newspeed=speed
var pausespeed=(pause==0)? newspeed: 0
document.write('<span id="temp" style="visibility:hidden; position:absolute; top:0px; left:-9000px">'+marqueecontent+'</span>')
var actualwidth=''
var cross_marquee, ns_marquee
function populate(){
cross_marquee= document.getElementById("marquee")
cross_marquee.style.left=parseInt(marqueewidth)+8+"px"
cross_marquee.innerHTML=marqueecontent
actualwidth=document.getElementById("temp").offsetWidth
lefttime=setInterval("scrollmarquee()",20)
}
window.onload=populate
function scrollmarquee(){
if (parseInt(cross_marquee.style.left)>(actualwidth*(-1)+8))
cross_marquee.style.left=parseInt(cross_marquee.style.left)-newspeed+"px"
else
cross_marquee.style.left=parseInt(marqueewidth)+8+"px"
}
with (document){
write('<div style="position:relative; top:655px; width:'+marqueewidth+'; height:'+marqueeheight+'; overflow:hidden">')
write('<div onMouseover="newspeed=pausespeed" onMouseout="newspeed=speed">')
write('<div id="marquee" style="position:absolute; left:0px; top:0px; "></div>')
write('</div></div>')
}
Question: Why do I need the temp div ? And how can I swap the styles in CSS ?
Well, marquee isn't only deprecated, it's also obsolete now.
Of course you can create a JavaScript function that simulates the effect. But it's simpler and certainly smoother to use CSS for that.
Here's an example:
HTML
<div class="wrapper">
<p>Hey, how you're doing? Sorry you can't get through.</p>
</div>
CSS
.wrapper {
position: relative;
overflow: hidden;
height: 25px;
width: 100px;
border: 1px solid orange;
}
.wrapper p {
position: absolute;
margin: 0;
line-height: 25px;
white-space: nowrap;
animation: marquee 5s linear infinite;
}
#keyframes marquee {
0% { transform: translateX(100%); }
100% { transform: translateX(-100%); }
}
Demo
Try before buy
I just would use CSS3-animations. It works in every modern browser like a charm. You don’t need JavaScript to move an element.
If you want to switch it on and off, just add and remove a CSS class.
I just built an example in codepen: http://codepen.io/anon/pen/LGEBbx
This is the animation code:
#keyframes marquee {
0% { transform: translateX(100%); }
100% { transform: translateX(-100%); }
}
I hope this was the solution you’re looking for.
This is the code I'm currently working with. It works to my purposes of layering the two images. What I am trying to do is have the layer0 opacity lower to 0 as the layer1 opacity increases to 100 over a few seconds. {and then on to layer1 with layer2 and so on eventually looping back to layer0}
Any help would be appreciated.
<head>
<style>
div.layer0
{
width: 371px;
height: 345px;
background:url(image2.jpg);
opacity:1;
filter:alpha(opacity=100); /* For IE8 and earlier */
}
div.layer1
{
width: 371px;
height: 345px;
background:url(image3.jpg);
opacity:0;
filter:alpha(opacity=0); /* For IE8 and earlier */
}
</style>
</head>
<body>
<div class="layer0">
<div class="layer1">
</div>
</div>
</body>
To continually do this in a loop, you'll need some javascript to add an appropriate active class to the image you want displayed. Then using CSS transitions you can achieve the fading between images that you require.
I created a jsfiddle to give you an example of this working: http://jsfiddle.net/pacso/H6dqq/
The basics are as follows.
Some simple HTML divs which you'll be fading:
<div class='red square active'></div>
<div class='yellow square'></div>
<div class='green square'></div>
<div class='blue square'></div>
These are just going to be coloured squares, but yours could contain images.
Next, some CSS markup:
.red {
background-color: red;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
.yellow {
background-color: yellow;
}
.square {
width: 200px;
height: 200px;
position: absolute;
top: 20px;
left: 20px;
opacity: 0;
transition: opacity 2s;
-webkit-transition: opacity 2s; /* Safari */
}
.active {
opacity: 1;
}
Note that my transition will alter the opacity of the div itself. You may need to change this as needed.
Now the javascript to make it work on an endless loop:
jQuery(function() {
window.setInterval(function () {
activeSquare = $('.active');
nextSquare = activeSquare.next()
if (nextSquare.length == 0) {
nextSquare = activeSquare.siblings().first();
}
nextSquare.addClass('active');
activeSquare.removeClass('active');
}, 3000);
});
Fairly straightforward. Click the link to my fiddle and hit the run button if you want to see a working demo.
Short answer: not easily.
You're probably better off with javascript for the looping. You could make a delayed keyframe animation, but that won't allow you to loop from the start again: jsfiddle.net/G4PTM (firefox/ie10) -- You could make a lot of keyframes with different timings and you can make it work, but it would require quite a bit of code and not scale well (say you wanted to add another layer/image the code would quickly become unmanagable)
With some javascript, you can just loop through the divs and add and remove a classname to trigger the transitions, like Jon mentioned. Here is a working demo (using jQuery for simplicity, let me know if you need vanilla js)
html
<div class="layer0">
</div>
<div class="layer1">
</div>
<div class="layer2">
</div>
css
div {
width: 371px;
height: 345px;
opacity: 0;
position: absolute;
transition: opacity 2s;
}
div.active {
opacity: 1;
}
div.layer0 {
background:url(http://lorempixel.com/373/345);
}
div.layer1 {
background:url(http://lorempixel.com/372/345);
}
div.layer2 {
background:url(http://lorempixel.com/374/345);
}
js+jquery
var firstDiv = $(".layer0");
var current;
function loopsie() {
// if first iteration or reached end, use first div
if (!current || !current.length) current = firstDiv;
current.addClass("active");
setTimeout(function() {
current.removeClass("active");
setTimeout(function() {
current = current.next();
loopsie(); // recurse
}, 2000);
}, 2000);
}
//initialize
loopsie();
Working demo at http://jsfiddle.net/G4PTM/2/
Plain JavaScript (Without jQuery):
var firstDiv = document.querySelector(".layer0"); // IE 8+
var current;
function loopsie() {
// if first iteration, use first div
if (!current) current = firstDiv;
current.classList.add("active"); // IE 10+, shim at https://developer.mozilla.org/en-US/docs/Web/API/Element.classList
setTimeout(function() {
current.classList.remove("active");
// account for text node (if there is whitespace in html)
if (current.nextSibling && current.nextSibling.nodeName == "DIV") {
current = current.nextSibling;
} else if (current.nextSibling && current.nextSibling.nextSibling && current.nextSibling.nextSibling.nodeName == "DIV") {
current = current.nextSibling.nextSibling;
} else {
// reached end
current = firstDiv;
}
loopsie(); // recurse
}, 2000);
}
//initialize
loopsie();
http://jsfiddle.net/G4PTM/6/
You can use CSS transitions. The example below fades .layer0 in and out in a timespan of 500 ms:
div.layer0 {
opacity: 1;
-webkit-transition:opacity 500ms ease-out;
-moz-transition:opacity 500ms ease-out;
-o-transition:opacity 500ms ease-out;
transition:opacity 500ms ease-out;
}
div.layer0:hover {
opacity: 0;
}