Related
I am using the lightbox jquery plugin to open a lightbox when a user clicks on a product. Often the lightbox content stretches below the fold, and at the moment the right scrollbar moves the entire page when you scroll down.
I'd like it to work like the pinterest lightbox, whereby the right scrollbar only scrolls the lightbox, and the rest of the page stays fixed. I've seen a few posts on this, but nothing seems to work for me.
Problem is I want the lightbox to scroll if the content is bigger than the viewport of the browser but not the background.
CSS:
#lightbox{ position: absolute; left: 0; width: 100%; z-index: 100; text-align: center; line-height: 0;}
#lightbox img{ width: auto; height: auto;}
#lightbox a img{ border: none; }
#outerImageContainer{ position: relative; background-color: #fff; width: 250px; height: 250px; margin: 0 auto; }
#imageContainer{ padding: 10px; }
#loading{ position: absolute; top: 40%; left: 0%; height: 25%; width: 100%; text-align: center; line-height: 0; }
#hoverNav{ position: absolute; top: 0; left: 0; height: 100%; width: 100%; z-index: 10; }
#imageContainer>#hoverNav{ left: 0;}
#hoverNav a{ outline: none;}
#prevLink, #nextLink{ width: 49%; height: 100%; background-image: url(data:image2/gif;base64,AAAA); /* Trick IE into showing hover */ display: block; }
#prevLink { left: 0; float: left;}
#nextLink { right: 0; float: right;}
#prevLink:hover, #prevLink:visited:hover { background: url(../images2/prevlabel.gif) left 15% no-repeat; }
#nextLink:hover, #nextLink:visited:hover { background: url(../images2/nextlabel.gif) right 15% no-repeat; }
#imageDataContainer{ font: 10px Verdana, Helvetica, sans-serif; background-color: #fff; margin: 0 auto; line-height: 1.4em; overflow: auto; width: 100% ; }
#imageData{ padding:0 10px; color: #666; }
#imageData #imageDetails{ width: 70%; float: left; text-align: left; }
#imageData #caption{ font-weight: bold; }
#imageData #numberDisplay{ display: block; clear: left; padding-bottom: 1.0em; }
#imageData #bottomNavClose{ width: 66px; float: right; padding-bottom: 0.7em; outline: none;}
#overlay{ position: absolute; top: 0; left: 0; z-index: 90; width: 100%; height: 500px; background-color: #000; }
JS:
// -----------------------------------------------------------------------------------
//
// Lightbox v2.04
// by Lokesh Dhakar - http://www.lokeshdhakar.com
// Last Modification: 2/9/08
//
// For more information, visit:
// http://lokeshdhakar.com/projects/lightbox2/
//
// Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
// - Free for use in both personal and commercial projects
// - Attribution requires leaving author name, author link, and the license info intact.
//
// Thanks: Scott Upton(uptonic.com), Peter-Paul Koch(quirksmode.com), and Thomas Fuchs(mir.aculo.us) for ideas, libs, and snippets.
// Artemy Tregubenko (arty.name) for cleanup and help in updating to latest ver of proto-aculous.
//
// -----------------------------------------------------------------------------------
/*
Table of Contents
-----------------
Configuration
Lightbox Class Declaration
- initialize()
- updateImageList()
- start()
- changeImage()
- resizeImageContainer()
- showImage()
- updateDetails()
- updateNav()
- enableKeyboardNav()
- disableKeyboardNav()
- keyboardAction()
- preloadNeighborImages()
- end()
Function Calls
- document.observe()
*/
// -----------------------------------------------------------------------------------
//
// Configurationl
//
LightboxOptions = Object.extend({
fileLoadingImage: 'images2/loading.gif',
fileBottomNavCloseImage: 'images2/closelabel.gif',
overlayOpacity: 0.8, // controls transparency of shadow overlay
animate: true, // toggles resizing animations
resizeSpeed: 7, // controls the speed of the image resizing animations (1=slowest and 10=fastest)
borderSize: 10, //if you adjust the padding in the CSS, you will need to update this variable
// When grouping images this is used to write: Image # of #.
// Change it for non-english localization
labelImage: "Image",
labelOf: "of"
}, window.LightboxOptions || {});
// -----------------------------------------------------------------------------------
var Lightbox = Class.create();
Lightbox.prototype = {
imageArray: [],
activeImage: undefined,
// initialize()
// Constructor runs on completion of the DOM loading. Calls updateImageList and then
// the function inserts html at the bottom of the page which is used to display the shadow
// overlay and the image container.
//
initialize: function() {
this.updateImageList();
this.keyboardAction = this.keyboardAction.bindAsEventListener(this);
if (LightboxOptions.resizeSpeed > 10) LightboxOptions.resizeSpeed = 10;
if (LightboxOptions.resizeSpeed < 1) LightboxOptions.resizeSpeed = 1;
this.resizeDuration = LightboxOptions.animate ? ((11 - LightboxOptions.resizeSpeed) * 0.15) : 0;
this.overlayDuration = LightboxOptions.animate ? 0.2 : 0; // shadow fade in/out duration
// When Lightbox starts it will resize itself from 250 by 250 to the current image dimension.
// If animations are turned off, it will be hidden as to prevent a flicker of a
// white 250 by 250 box.
var size = (LightboxOptions.animate ? 250 : 1) + 'px';
// Code inserts html at the bottom of the page that looks similar to this:
//
// <div id="overlay"></div>
// <div id="lightbox">
// <div id="outerImageContainer">
// <div id="imageContainer">
// <img id="lightboxImage">
// <div style="" id="hoverNav">
//
//
// </div>
// <div id="loading">
// <a href="#" id="loadingLink">
// <img src="images/loading.gif">
// </a>
// </div>
// </div>
// </div>
// <div id="imageDataContainer">
// <div id="imageData">
// <div id="imageDetails">
// <span id="caption"></span>
// <span id="numberDisplay"></span>
// </div>
// <div id="bottomNav">
// <a href="#" id="bottomNavClose">
// <img src="images/close.gif">
// </a>
// </div>
// </div>
// </div>
// </div>
var objBody = $$('body')[0];
objBody.appendChild(Builder.node('div',{id:'overlay'}));
objBody.appendChild(Builder.node('div',{id:'lightbox'}, [
Builder.node('div',{id:'outerImageContainer'},
Builder.node('div',{id:'imageContainer'}, [
Builder.node('img',{id:'lightboxImage'}),
Builder.node('div',{id:'hoverNav'}, [
Builder.node('a',{id:'prevLink', href: '#' }),
Builder.node('a',{id:'nextLink', href: '#' })
]),
Builder.node('div',{id:'loading'},
Builder.node('a',{id:'loadingLink', href: '#' },
Builder.node('img', {src: LightboxOptions.fileLoadingImage})
)
)
])
),
Builder.node('div', {id:'imageDataContainer'},
Builder.node('div',{id:'imageData'}, [
Builder.node('div',{id:'imageDetails'}, [
Builder.node('span',{id:'caption'}),
Builder.node('span',{id:'numberDisplay'})
]),
Builder.node('div',{id:'bottomNav'},
Builder.node('a',{id:'bottomNavClose', href: '#' },
Builder.node('img', { src: LightboxOptions.fileBottomNavCloseImage })
)
)
])
)
]));
$('overlay').hide().observe('click', (function() { this.end(); }).bind(this));
$('lightbox').hide().observe('click', (function(event) { if (event.element().id == 'lightbox') this.end(); }).bind(this));
$('outerImageContainer').setStyle({ width: size, height: size });
$('prevLink').observe('click', (function(event) { event.stop(); this.changeImage(this.activeImage - 1); }).bindAsEventListener(this));
$('nextLink').observe('click', (function(event) { event.stop(); this.changeImage(this.activeImage + 1); }).bindAsEventListener(this));
$('loadingLink').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
$('bottomNavClose').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
var th = this;
(function(){
var ids =
'overlay lightbox outerImageContainer imageContainer lightboxImage hoverNav prevLink nextLink loading loadingLink ' +
'imageDataContainer imageData imageDetails caption numberDisplay bottomNav bottomNavClose';
$w(ids).each(function(id){ th[id] = $(id); });
}).defer();
},
//
// updateImageList()
// Loops through anchor tags looking for 'lightbox' references and applies onclick
// events to appropriate links. You can rerun after dynamically adding images w/ajax.
//
updateImageList: function() {
this.updateImageList = Prototype.emptyFunction;
document.observe('click', (function(event){
var target = event.findElement('a[rel^=lightbox]') || event.findElement('area[rel^=lightbox]');
if (target) {
event.stop();
this.start(target);
}
}).bind(this));
},
//
// start()
// Display overlay and lightbox. If image is part of a set, add siblings to imageArray.
//
start: function(imageLink) {
$$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'hidden' });
// stretch overlay to fill page and fade in
var arrayPageSize = this.getPageSize();
$('overlay').setStyle({ width: arrayPageSize[0] + 'px', height: arrayPageSize[1] + 'px' });
new Effect.Appear(this.overlay, { duration: this.overlayDuration, from: 0.0, to: LightboxOptions.overlayOpacity });
this.imageArray = [];
var imageNum = 0;
if ((imageLink.rel == 'lightbox')){
// if image is NOT part of a set, add single image to imageArray
this.imageArray.push([imageLink.href, imageLink.title]);
} else {
// if image is part of a set..
this.imageArray =
$$(imageLink.tagName + '[href][rel="' + imageLink.rel + '"]').
collect(function(anchor){ return [anchor.href, anchor.title]; }).
uniq();
while (this.imageArray[imageNum][0] != imageLink.href) { imageNum++; }
}
// calculate top and left offset for the lightbox
var arrayPageScroll = document.viewport.getScrollOffsets();
var lightboxTop = arrayPageScroll[1] + (document.viewport.getHeight() / 10);
var lightboxLeft = arrayPageScroll[0];
this.lightbox.setStyle({ top: lightboxTop + 'px', left: lightboxLeft + 'px' }).show();
this.changeImage(imageNum);
},
//
// changeImage()
// Hide most elements and preload image in preparation for resizing image container.
//
changeImage: function(imageNum) {
this.activeImage = imageNum; // update global var
// hide elements during transition
if (LightboxOptions.animate) this.loading.show();
this.lightboxImage.hide();
this.hoverNav.hide();
this.prevLink.hide();
this.nextLink.hide();
// HACK: Opera9 does not currently support scriptaculous opacity and appear fx
this.imageDataContainer.setStyle({opacity: .0001});
this.numberDisplay.hide();
var imgPreloader = new Image();
// once image is preloaded, resize image container
imgPreloader.onload = (function(){
this.lightboxImage.src = this.imageArray[this.activeImage][0];
this.resizeImageContainer(imgPreloader.width, imgPreloader.height);
}).bind(this);
imgPreloader.src = this.imageArray[this.activeImage][0];
},
//
// resizeImageContainer()
//
resizeImageContainer: function(imgWidth, imgHeight) {
// get current width and height
var widthCurrent = this.outerImageContainer.getWidth();
var heightCurrent = this.outerImageContainer.getHeight();
// get new width and height
var widthNew = (imgWidth + LightboxOptions.borderSize * 2);
var heightNew = (imgHeight + LightboxOptions.borderSize * 2);
// scalars based on change from old to new
var xScale = (widthNew / widthCurrent) * 100;
var yScale = (heightNew / heightCurrent) * 100;
// calculate size difference between new and old image, and resize if necessary
var wDiff = widthCurrent - widthNew;
var hDiff = heightCurrent - heightNew;
if (hDiff != 0) new Effect.Scale(this.outerImageContainer, yScale, {scaleX: false, duration: this.resizeDuration, queue: 'front'});
if (wDiff != 0) new Effect.Scale(this.outerImageContainer, xScale, {scaleY: false, duration: this.resizeDuration, delay: this.resizeDuration});
// if new and old image are same size and no scaling transition is necessary,
// do a quick pause to prevent image flicker.
var timeout = 0;
if ((hDiff == 0) && (wDiff == 0)){
timeout = 100;
if (Prototype.Browser.IE) timeout = 250;
}
(function(){
this.prevLink.setStyle({ height: imgHeight + 'px' });
this.nextLink.setStyle({ height: imgHeight + 'px' });
this.imageDataContainer.setStyle({ width: widthNew + 'px' });
this.showImage();
}).bind(this).delay(timeout / 1000);
},
//
// showImage()
// Display image and begin preloading neighbors.
//
showImage: function(){
this.loading.hide();
new Effect.Appear(this.lightboxImage, {
duration: this.resizeDuration,
queue: 'end',
afterFinish: (function(){ this.updateDetails(); }).bind(this)
});
this.preloadNeighborImages();
},
//
// updateDetails()
// Display caption, image number, and bottom nav.
//
updateDetails: function() {
// if caption is not null
if (this.imageArray[this.activeImage][1] != ""){
this.caption.update(this.imageArray[this.activeImage][1]).show();
}
// if image is part of set display 'Image x of x'
if (this.imageArray.length > 1){
this.numberDisplay.update( LightboxOptions.labelImage + ' ' + (this.activeImage + 1) + ' ' + LightboxOptions.labelOf + ' ' + this.imageArray.length).show();
}
new Effect.Parallel(
[
new Effect.SlideDown(this.imageDataContainer, { sync: true, duration: this.resizeDuration, from: 0.0, to: 1.0 }),
new Effect.Appear(this.imageDataContainer, { sync: true, duration: this.resizeDuration })
],
{
duration: this.resizeDuration,
afterFinish: (function() {
// update overlay size and update nav
var arrayPageSize = this.getPageSize();
this.overlay.setStyle({ height: arrayPageSize[1] + 'px' });
this.updateNav();
}).bind(this)
}
);
},
//
// updateNav()
// Display appropriate previous and next hover navigation.
//
updateNav: function() {
this.hoverNav.show();
// if not first image in set, display prev image button
if (this.activeImage > 0) this.prevLink.show();
// if not last image in set, display next image button
if (this.activeImage < (this.imageArray.length - 1)) this.nextLink.show();
this.enableKeyboardNav();
},
//
// enableKeyboardNav()
//
enableKeyboardNav: function() {
document.observe('keydown', this.keyboardAction);
},
//
// disableKeyboardNav()
//
disableKeyboardNav: function() {
document.stopObserving('keydown', this.keyboardAction);
},
//
// keyboardAction()
//
keyboardAction: function(event) {
var keycode = event.keyCode;
var escapeKey;
if (event.DOM_VK_ESCAPE) { // mozilla
escapeKey = event.DOM_VK_ESCAPE;
} else { // ie
escapeKey = 27;
}
var key = String.fromCharCode(keycode).toLowerCase();
if (key.match(/x|o|c/) || (keycode == escapeKey)){ // close lightbox
this.end();
} else if ((key == 'p') || (keycode == 37)){ // display previous image
if (this.activeImage != 0){
this.disableKeyboardNav();
this.changeImage(this.activeImage - 1);
}
} else if ((key == 'n') || (keycode == 39)){ // display next image
if (this.activeImage != (this.imageArray.length - 1)){
this.disableKeyboardNav();
this.changeImage(this.activeImage + 1);
}
}
},
//
// preloadNeighborImages()
// Preload previous and next images.
//
preloadNeighborImages: function(){
var preloadNextImage, preloadPrevImage;
if (this.imageArray.length > this.activeImage + 1){
preloadNextImage = new Image();
preloadNextImage.src = this.imageArray[this.activeImage + 1][0];
}
if (this.activeImage > 0){
preloadPrevImage = new Image();
preloadPrevImage.src = this.imageArray[this.activeImage - 1][0];
}
},
//
// end()
//
end: function() {
this.disableKeyboardNav();
this.lightbox.hide();
new Effect.Fade(this.overlay, { duration: this.overlayDuration });
$$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'visible' });
},
//
// getPageSize()
//
getPageSize: function() {
var xScroll, yScroll;
if (window.innerHeight && window.scrollMaxY) {
xScroll = window.innerWidth + window.scrollMaxX;
yScroll = window.innerHeight + window.scrollMaxY;
} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
xScroll = document.body.scrollWidth;
yScroll = document.body.scrollHeight;
} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
xScroll = document.body.offsetWidth;
yScroll = document.body.offsetHeight;
}
var windowWidth, windowHeight;
if (self.innerHeight) { // all except Explorer
if(document.documentElement.clientWidth){
windowWidth = document.documentElement.clientWidth;
} else {
windowWidth = self.innerWidth;
}
windowHeight = self.innerHeight;
} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
windowWidth = document.documentElement.clientWidth;
windowHeight = document.documentElement.clientHeight;
} else if (document.body) { // other Explorers
windowWidth = document.body.clientWidth;
windowHeight = document.body.clientHeight;
}
// for small pages with total height less then height of the viewport
if(yScroll < windowHeight){
pageHeight = windowHeight;
} else {
pageHeight = yScroll;
}
// for small pages with total width less then width of the viewport
if(xScroll < windowWidth){
pageWidth = xScroll;
} else {
pageWidth = windowWidth;
}
return [pageWidth,pageHeight];
}
}
document.observe('dom:loaded', function () { new Lightbox(); });
Here's a class that'll allow you to do just that:
class ScrollLock {
constructor () {
this.pageBody = document.querySelector('body');
this.scrollY = 0;
}
saveScrollY = (num) => {
this.scrollY = num;
}
setScrollY = (num) => {
window.scroll(0, num);
}
setScrollOffset = (vOffset) => {
this.pageBody.style.top = `-${vOffset}px`;
}
freezeBodyScroll = () => {
this.saveScrollY(window.scrollY);
this.setScrollOffset(this.scrollY);
this.pageBody.classList.add('is-fixed');
}
unfreezeBodyScroll = () => {
this.pageBody.classList.remove('is-fixed');
// Don't reset scroll position if lock hasn't occurred
if (this.scrollY === 0) return;
this.setScrollOffset(0);
this.setScrollY(this.scrollY);
this.saveScrollY(0);
}
}
Include the following style declaration:
// In your CSS
body.is-fixed {
position: fixed;
max-width: 100%;
}
Use:
const { freezeBodyScroll, unfreezeBodyScroll } = new ScrollLock();
// Call when you open your modal
freezeBodyScroll();
// Call when you close your modal
unfreezeBodyScroll();
I'm trying to implement a text fade in on scroll similar to this https://codepen.io/hollart13/post/fade-in-on-scroll.
$(function(){ // $(document).ready shorthand
$('.monster').fadeIn('slow');
});
$(document).ready(function() {
/* Every time the window is scrolled ... */
$(window).scroll( function(){
/* Check the location of each desired element */
$('.hideme').each( function(i){
var bottom_of_object = $(this).position().top + $(this).outerHeight();
var bottom_of_window = $(window).scrollTop() + $(window).height();
/* If the object is completely visible in the window, fade it it */
if( bottom_of_window > bottom_of_object ){
$(this).animate({'opacity':'1'},1500);
}
});
});
});
However, I do not want to use JQuery. I want to accomplish this using plain JavaScript. Unfortunately, most of the examples online are JQuery based and there's very little with plain JavaScript.
This is what I've attempted so far to "translate" this JQuery into plain JS. It's not working. Could anyone point at where I went wrong?
window.onscroll = function() {myFunction()};
function myFunction() {
var elements = document.getElementsByClassName("target");
for(var i = 0; i < elements.length; i++){
var bottomOfObject = elements[i].getBoundingClientRect().top +
window.outerHeight;
var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset :
(document.documentElement || document.body.parentNode ||
document.body).scrollTop;
var bottomOfWindow = scrollTop + window.innerHeight;
if(bottomOfWindow > bottomOfObject){
$(this).animate({'opacity': '1'}, 1500);
}
}
console.log(bottomOfObject);
}
Thanks in advance!
Try this simple vanilla JavaScript solution
var header = document.querySelector("#header");
window.onscroll = function() {
if (document.body.scrollTop > 50) {
header.className = "active";
} else {
header.className = "";
}
};
#header {
background-color: black;
transition: all 1s;
position: fixed;
height: 40px;
opacity: 0;
right: 0;
left: 0;
top: 0;
}
#header.active {
opacity: 1;
}
#wrapper {
height: 150vh;
}
<html>
<body>
<div id="header"></div>
<div id="wrapper"></div>
</body>
</html>
Essentially there is an element positioned on the top of the screen which is invisible at first (with opacity 0) and using javascript I add an class to it that makes it visible (opacity 1) what makes it slowly visible instead of instantly is the transition: all 1s;
Here's my version with dynamic opacity based on scroll position, I hope it helps
Window Vanilla Scroll
function scrollHandler( event ) {
var margin = 100;
var currentTop = document.body.scrollTop;
var header = document.querySelector(".header");
var headerHeight = header.getBoundingClientRect().height;
var pct = (currentTop - margin) / ( margin + headerHeight );
header.style.opacity = pct;
if( pct > 1) return false;
}
function addListeners() {
window.addEventListener('scroll' , scrollHandler );
document.getElementById("click" , function() {
window.scrollTop = 0;
});
}
addListeners();
I'm trying to create a div which will get a class only on scrolling and when the value of scroll is 210. I have next code :
$(document).ready(function() {
var pageWidth = $(window).width();
if(pageWidth > 700){
var contentLeft = $('#content-left');
var height = 210;
$(window).scroll(function () {
if ($(window).scrollTop() < height) {
contentLeft.attr('class', 'content-left');
} else {
contentLeft.attr('class', 'content-left leftContentFixed');
}
});
}
});
I try to apply this only on desktops.
Thus, I do not need the class leftContentFixed if it's on a smartphone or tablet.
If I try something like :
$(document).ready(function() {
var pageWidth = $(window).width();
if(pageWidth > 700){
alert("Bigger than 700");
}else{
alert("Smaller than 700");
}
});
Than it works perfect, but with my code it isn't working. The class leftContentFixed is added although the screen is smaller than 700.
Any advice?
You need to check screen size on resize event and check for its value when user scrolls the page. You could create mobile variable and make it true/false depends on screen size, then in scroll callback check for its value and choose correct class.
$(document).ready(function() {
var pageWidth = $(window).width(),
height = 210,
contentLeft = $('.content-left'),
mobile = false;
$(window).on('load resize', function() {
pageWidth = $(this).width();
// Save mobile status
if (pageWidth > 700) {
mobile = false;
} else {
mobile = true
}
})
$(window).on('scroll', function() {
if ($(window).scrollTop() > height) {
// Set default class
var _class = 'content-left leftContentFixed';
// If mobile then modify class
if (mobile) {
_class = 'content-left';
}
contentLeft.attr('class', _class);
} else {
var _class = 'content-left';
contentLeft.attr('class', _class);
}
});
});
html {
height: 2000px
}
.content-left {
background: gold;
width: 50px;
height: 100px;
}
.content-left.leftContentFixed {
position: fixed;
top: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="content-left"></div>
Please take a look at this fiddle: http://jsfiddle.net/dhcyA/
Try clicking on a block. What I want is that when the other elements disapear, the selected block will animate/ease to his giving position instead of just jumping like it does now. Then the same animation repeats itself when clicking again on the box, but then back to place.
Maybe to keep in mind:
I'm using a reponsive design, which means those blocks can be vertical and horizontal after scaling the window.
Any redevisions on the fiddle or suggustions would be great!
Here is my solution.
On your existing markup, I added a wrapper division to calculate the position of boxes inside the wrapper. Like this
<div id="wrapper">
<div class="block">
<h2>I'm block 1</h2>
</div>
....
</div>
To maintain the fluidness of the block, I created a function to position the block on the wrapper. Here is the function for position of the blocks:
var reposition = function() {
wrapper = $("#wrapper");
console.log(wrapper.innerWidth());
pLeft = 0;
pTop = 0;
maxRowHeight = 0;
$(".block").each(function(){
if($(this).data('active')) {
$(this).data('top', pTop);
$(this).data('left', pLeft);
} else {
$(this).stop(0,0).animate({
'top' : pTop + 'px',
'left' : pLeft + 'px'
});
}
pLeft += $(this).outerWidth() + parseInt($(this).css('marginLeft'));
if($(this).height() > maxRowHeight) maxRowHeight = $(this).outerHeight() + parseInt($(this).css('marginTop')); //Find out the longest block on the row
if(pLeft + $(this).next().outerWidth() + parseInt($(this).next().css('marginLeft')) >= wrapper.innerWidth()) {
pLeft = 0;
pTop += maxRowHeight;
maxRowHeight = 0;
}
});
};
Finally, the script to toggle the block
$(".block").click(function() {
$(this).siblings().slideToggle('slow'); //Toggle other blocks
if(!$(this).data('active')){ //if the block is not active
$(this).data('left', $(this).position().left); //sets its left
$(this).data('top', $(this).position().top); // and top position
$(this).animate({ //animate at the top and bottom
top:0,
left:0
},'slow');
$(this).data('active',true);
}else{
$(this).animate({ //animate to its last known position
top:$(this).data('top'),
left:$(this).data('left')
},'slow');
$(this).data('active',false);
}
});
Demos
Demo[Full] (Resize this to see the fluidness maintained)
Demo[Full] (version showing variable heights)
Here is what this solutions gives:
Remembers the last position and gradually animate to/from this position
Block positions are calculated and animated on load and every resize
Repositioning happens on $(window).resize() thus maintaining the fluid nature of the block, despite the use of position absolute
Support variable heights
Minor change on existing markup & CSS
Also fixed two issues extended by Gaby
Accounts for each block margin independently
Recalculates the position of the element after resize
Final Update
Here is a full working solution (pretty straight forward in my opinion) with JS to set the positioning (a simple calculation) and CSS transitions for the rest..
Demo at http://jsfiddle.net/gaby/pYdKB/3/
It maintains the fluidity of float:left and works with any number of elements, and you can keep the :nth-child for the styling, and it will also work if you want to leave more than one element visible..
javascript
var wrapper = $('.wrapper'),
boxes = wrapper.children(),
boxWidth = boxes.first().outerWidth(true),
boxHeight = boxes.first().outerHeight(true);
function rePosition(){
var w = wrapper.width(),
breakat = Math.floor( w / boxWidth ); // calculate fluid layout, just like float:left
boxes
.filter(':not(.go)')
.each(function(i){
var matrixX = ((i)%breakat)+1,
matrixY = Math.ceil((i+1)/breakat);
$(this).css({
left:(matrixX-1) * boxWidth ,
top: (matrixY-1) * boxHeight
});
});
}
$('.box').click(function(){
$(this)
.siblings()
.toggleClass('go');// just add the go class, and let CSS handle the rest
rePosition(); // recalculate final positions and let CSS animate the boxes
});
$(window).resize(rePosition);
$(window).trigger('resize');
CSS
.wrapper{
position:relative;
}
.box{
width:200px;
height:100px;
position:absolute;
margin:5px;
cursor:pointer;
overflow:hidden;
text-align: center;
line-height: 100px;
-moz-transition-property: top,left,width,height;
-webkit-transition-property: top,left,width,height;
-ms-transition-property: top,left,width,height;
-o-transition-property: top,left,width,height;
transition-property: top,left,width,height;
-moz-transition-duration: 1s;
-webkit-transition-duration: 1s;
-ms-transition-duration: 1s;
-o-transition-duration: 1s;
transition-duration: 1s;
}
.go{
height:0;
width:0;
}
note: As #Athari correctly mentioned in the comments, you should include all browser prefixes for the widest support. (my initial answer only included moz / webkit and the standard)
Original Answer
You can not do it directly with your current HTML structure. The floated concept does not support it.
But if you can afford an extra wrapper, then it is no problem..
Just slide the contents of your extra wrapper element..
Put the float code on the wrapper element and use
$(document).ready(function() {
$(".block-wrapper").click(function() {
$(this).siblings().find('.block').slideToggle("slow");
});
});
Demo at http://jsfiddle.net/gaby/t8GNP/
Update #1
If you need to move the clicked element to the top left and back, then you cannot really do it with CSS.
You will need to manually position them (through JS), set CSS transitions (or jquery), and apply the new positions once you click.
Later on you might want more than one to remain visible and reposition as well..
So you might want to take a look at the great Isotope plugin which can handle this and a multitude of more situations/layouts
Here is my version:
http://jsfiddle.net/selbh/dhcyA/92/
(only javascript is changed, and it's responsive)
$(document).ready(function() {
$(".block").click(function() {
var $this = $(this);
var pos = $this.offset();
var $siblings = $(this).siblings().add(this);
var marginTop = $this.css('marginTop').replace(/[^-\d\.]/g, '');
var marginLeft = $this.css('marginLeft').replace(/[^-\d\.]/g, '');
var $clone = $this.clone();
$siblings.slideToggle("slow");
$clone.css({
position: 'absolute',
left: pos.left - marginLeft,
top: pos.top - marginTop,
'background-color': $this.css('background-color')
});
$('body').append($clone);
$this.css('opacity', 0);
$clone.animate({
'left': 0,
'top': 0
});
$clone.click(function() {
$siblings.slideToggle("slow", function() {
$clone.remove();
$this.css('opacity', 1);
});
$clone.animate({
left: pos.left - marginLeft,
top: pos.top - marginTop
});
});
});
});
I'm kind of sleepy(It's 2:30 AM here) so I leave the half done answer here to give you an idea (I did it in 30 minutes so I guess with 30 minutes more you can get something really nice)
http://jsfiddle.net/LuL2s/2/
The trick comes by the block-holder which make the ease animation and making a difference between when they appear and disappear
JS
$(document).ready(function() {
var open = true;
$(".block").click(function() {
var $this = $(this);
var count = 0;
if (open) {
$this.parent().siblings().children().slideToggle("slow", function(){
if (count++ == 2) {
$this.parent().siblings().animate({width: 'toggle', height:'toggle'});
}
});
} else {
$this.parent().siblings().animate({width: 'toggle', height:'toggle'}, function(){
if (count++ == 2) {
$this.parent().siblings().children().slideToggle("slow");
}
});
}
open = !open;
});
});
HTML
<div class="block-holder">
<div class="block">
<h2>I'm block 1</h2>
</div>
</div>
<div class="block-holder">
<div class="block">
<h2>I'm block 2</h2>
</div>
</div>
<div class="block-holder">
<div class="block">
<h2>I'm block 3</h2>
</div>
</div>
<div class="block-holder">
<div class="block">
<h2>I'm block 4</h2>
</div>
</div>
CSS
.block {
width: 100%;
height: 100%;
text-align: center;
line-height: 100px;
cursor: pointer;
}
.block-holder:nth-child(1) .block {
background: green;
}
.block-holder:nth-child(2) .block {
background: red;
}
.block-holder:nth-child(3) .block {
background: orange;
}
.block-holder:nth-child(4) .block {
background: pink;
}
.block-holder {
width: 200px;
height: 100px;
float: left;
margin: 20px;
}
Great Challenge!
New Version:
Here is a much better version as it makes the blocks stay in their rows. I added a css function so that your nth-child styles could be applied even in the rows. Even maintains same HTML Structure.
Demo: http://jsfiddle.net/MadLittleMods/fDDZB/23/
The jQuery for this new revision looks like:
$('.block').on('click', function() {
var block = $(this);
// Keep the blocks in line
makeRows($('body'));
$('.block').not(this).each(function() {
// If sibling on the same level, horizontal toggle
// We also want ignore the toggleMethod if it is shown because we might need to reassign
if (($(this).position().top == block.position().top && (($(this).data('toggle') == -1) || $(this).data('toggle') == null)) || ($(this).data('toggle') != -1 && $(this).data('toggleMethod') == 'side'))
{
$(this).data('toggleMethod', 'side');
// Hide block
if ($(this).data('toggle') == -1 || $(this).data('toggle') == null)
{
// Set properties for later use in show block
$(this).data('overflowBefore', $(this).css('overflow'));
$(this).css('overflow', 'hidden');
$(this).data('marginBefore', $(this).css('margin'));
var width = $(this).width();
$(this).animate({
width: 0,
margin: 0
}, function() {
$(this).data('toggle', width);
});
}
// Show block
else
{
$(this).css('overflow', $(this).data('overflowBefore'));
$(this).animate({
width: $(this).data('toggle'),
margin: $(this).data('marginBefore')
}, function() {
$(this).data('toggle', -1);
});
}
}
// Do a normal vertical toggle
else
{
$(this).data('toggleMethod', 'top');
$(this).slideToggle('slow');
}
});
});
// Make rows to make the blocks in line
function makeRows(container)
{
// Make rows so that the elements stay where they should
var containerWidth = container.width();
var currentRowWidth = 0;
// Add styles first so nothing gets messed up
container.children().each(function() {
var itemCSS = css($(this));
$(this).css(itemCSS);
});
// Now assemble the rows
container.children().each(function() {
var blockWidth = $(this).outerWidth() + parseInt($(this).css('margin-left')) + parseInt($(this).css('margin-right'));
if((currentRowWidth + blockWidth) < containerWidth)
{
currentRowWidth += blockWidth;
}
else
{
Array.prototype.reverse.call($(this).prevUntil('.row')).wrapAll('<div class="row"></div>');
$(this).prev().append('<div class="row_clear" style="clear: both;"></div>');
currentRowWidth = 0;
}
});
}
// Remove the rows added
function deleteRows()
{
var content = $('.row').contents()
$('.row').replaceWith(content);
$('.row_clear').remove();
}
$(window).resize(function() {
deleteRows();
});
// Functions courtesy of marknadal
// https://stackoverflow.com/a/5830517/796832
function css(a)
{
var sheets = document.styleSheets, o = {};
for(var i in sheets) {
var rules = sheets[i].rules || sheets[i].cssRules;
for(var r in rules) {
if(a.is(rules[r].selectorText)) {
o = $.extend(o, css2json(rules[r].style), css2json(a.attr('style')));
}
}
}
return o;
}
function css2json(css)
{
var s = {};
if(!css) return s;
if(css instanceof CSSStyleDeclaration) {
for(var i in css) {
if((css[i]).toLowerCase) {
s[(css[i]).toLowerCase()] = (css[css[i]]);
}
}
} else if(typeof css == "string") {
css = css.split("; ");
for (var i in css) {
var l = css[i].split(": ");
s[l[0].toLowerCase()] = (l[1]);
};
}
return s;
}
I added a makeRows and deleteRows functions so that the blocks would stay in their rows instead of getting smaller and moving into the row above. I call deleteRows whenever the window resizes so that it can maintain a responsive layout. Then if the blocks need to be toggled, I recreate the rows.
css and css2json functions are courtesy of marknadal
Old version:
I came up with a solution with .animate so that it could ease horizontally.
Here is a demo: http://jsfiddle.net/MadLittleMods/fDDZB/8/
The jQuery looks like:
$('.block').on('click', function() {
var block = $(this);
$(this).siblings().each(function() {
// If sibling on the same level, horizontal toggle
// We also want ignore the toggleMethod if it is shown because we might need to reassign
if (($(this).position().top == block.position().top && ($(this).data('toggle') == -1) || $(this).data('toggle') == null) || ($(this).data('toggle') != -1 && $(this).data('toggleMethod') == 'side'))
{
$(this).data('toggleMethod', 'side');
// Hide block
if ($(this).data('toggle') == -1 || $(this).data('toggle') == null)
{
// Set properties for later use in show block
$(this).data('overflowBefore', $(this).css('overflow'));
$(this).css('overflow', 'hidden');
$(this).data('marginBefore', $(this).css('margin'));
var width = $(this).width();
$(this).animate({
width: 0,
margin: 0
}, function() {
$(this).data('toggle', width);
});
}
// Show block
else
{
$(this).css('overflow', $(this).data('overflowBefore'));
$(this).animate({
width: $(this).data('toggle'),
margin: $(this).data('marginBefore')
}, function() {
$(this).data('toggle', -1);
});
}
}
// Do a normal vertical toggle
else
{
$(this).data('toggleMethod', 'top');
$(this).slideToggle('slow');
}
});
});
The key was to separate the blocks that were toggled with .slideToggle and .animate because you have to apply the same when they show and hide.
I'm trying to find a very simple and smooth, lightweight javascript or jquery marquee. I already tried silk marquee or something, but it wouldn't work with the application I was using. So the simpler and shorter, the better - and easier to debug. Does anybody know of a easy to implement javascript replacement for the marquee?
Pastebin
Code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript">
var tWidth='300px'; // width (in pixels)
var tHeight='25px'; // height (in pixels)
var tcolour='#ffffcc'; // background colour:
var moStop=true; // pause on mouseover (true or false)
var fontfamily = 'arial,sans-serif'; // font for content
var tSpeed=3; // scroll speed (1 = slow, 5 = fast)
// enter your ticker content here (use \/ and \' in place of / and ' respectively)
var content='Are you looking for loads of useful information <a href="http:\/\/javascript.about.com\/">About Javascript<\/a>? Well now you\'ve found it.';
var cps=-tSpeed; var aw, mq; var fsz = parseInt(tHeight) - 4; function startticker(){if (document.getElementById) {var tick = '<div style="position:relative;width:'+tWidth+';height:'+tHeight+';overflow:hidden;background-color:'+tcolour+'"'; if (moStop) tick += ' onmouseover="cps=0" onmouseout="cps=-tSpeed"'; tick +='><div id="mq" style="position:absolute;right:0px;top:0px;font-family:'+fontfamily+';font-size:'+fsz+'px;white-space:nowrap;"><\/div><\/div>'; document.getElementById('ticker').innerHTML = tick; mq = document.getElementById("mq"); mq.style.right=(10+parseInt(tWidth))+"px"; mq.innerHTML='<span id="tx">'+content+'<\/span>'; aw = document.getElementById("tx").offsetWidth; lefttime=setInterval("scrollticker()",50);}} function scrollticker(){mq.style.right = (parseInt(mq.style.right)>(-10 - aw)) ?
mq.style.right = parseInt(mq.style.right)+cps+"px": parseInt(tWidth)+10+"px";} window.onload=startticker;
</script>
</head>
<body>
<div id="ticker">
this is a simple scrolling text!
</div>
</body>
</html>
hiya simple demo from recommendations in above comments: http://jsfiddle.net/FWWEn/
with pause functionality on mouseover: http://jsfiddle.net/zrW5q/
hope this helps, have a nice one, cheers!
html
<h1>Hello World!</h1>
<h2>I'll marquee twice</h2>
<h3>I go fast!</h3>
<h4>Left to right</h4>
<h5>I'll defer that question</h5>
Jquery code
(function($) {
$.fn.textWidth = function(){
var calc = '<span style="display:none">' + $(this).text() + '</span>';
$('body').append(calc);
var width = $('body').find('span:last').width();
$('body').find('span:last').remove();
return width;
};
$.fn.marquee = function(args) {
var that = $(this);
var textWidth = that.textWidth(),
offset = that.width(),
width = offset,
css = {
'text-indent' : that.css('text-indent'),
'overflow' : that.css('overflow'),
'white-space' : that.css('white-space')
},
marqueeCss = {
'text-indent' : width,
'overflow' : 'hidden',
'white-space' : 'nowrap'
},
args = $.extend(true, { count: -1, speed: 1e1, leftToRight: false }, args),
i = 0,
stop = textWidth*-1,
dfd = $.Deferred();
function go() {
if(!that.length) return dfd.reject();
if(width == stop) {
i++;
if(i == args.count) {
that.css(css);
return dfd.resolve();
}
if(args.leftToRight) {
width = textWidth*-1;
} else {
width = offset;
}
}
that.css('text-indent', width + 'px');
if(args.leftToRight) {
width++;
} else {
width--;
}
setTimeout(go, args.speed);
};
if(args.leftToRight) {
width = textWidth*-1;
width++;
stop = offset;
} else {
width--;
}
that.css(marqueeCss);
go();
return dfd.promise();
};
})(jQuery);
$('h1').marquee();
$('h2').marquee({ count: 2 });
$('h3').marquee({ speed: 5 });
$('h4').marquee({ leftToRight: true });
$('h5').marquee({ count: 1, speed: 2 }).done(function() { $('h5').css('color', '#f00'); })
I've made very simple function for marquee. See: http://jsfiddle.net/vivekw/pHNpk/2/
It pauses on mouseover & resumes on mouseleave. Speed can be varied. Easy to understand.
function marquee(a, b) {
var width = b.width();
var start_pos = a.width();
var end_pos = -width;
function scroll() {
if (b.position().left <= -width) {
b.css('left', start_pos);
scroll();
}
else {
time = (parseInt(b.position().left, 10) - end_pos) *
(10000 / (start_pos - end_pos)); // Increase or decrease speed by changing value 10000
b.animate({
'left': -width
}, time, 'linear', function() {
scroll();
});
}
}
b.css({
'width': width,
'left': start_pos
});
scroll(a, b);
b.mouseenter(function() { // Remove these lines
b.stop(); //
b.clearQueue(); // if you don't want
}); //
b.mouseleave(function() { // marquee to pause
scroll(a, b); //
}); // on mouse over
}
$(document).ready(function() {
marquee($('#display'), $('#text')); //Enter name of container element & marquee element
});
I just created a simple jQuery plugin for that. Try it ;)
https://github.com/aamirafridi/jQuery.Marquee
The following works:
http://jsfiddle.net/xAGRJ/4/
The problem with your original code was you are calling scrollticker() by passing a string to setInterval, where you should just pass the function name and treat it as a variable:
lefttime = setInterval(scrollticker, 50);
instead of
lefttime = setInterval("scrollticker()", 50);
Why write custom jQuery code for Marquee... just use a plugin for jQuery - marquee() and use it like in the example below:
First include :
<script type='text/javascript' src='//cdn.jsdelivr.net/jquery.marquee/1.3.1/jquery.marquee.min.js'></script>
and then:
//proporcional speed counter (for responsive/fluid use)
var widths = $('.marquee').width()
var duration = widths * 7;
$('.marquee').marquee({
//speed in milliseconds of the marquee
duration: duration, // for responsive/fluid use
//duration: 8000, // for fixed container
//gap in pixels between the tickers
gap: $('.marquee').width(),
//time in milliseconds before the marquee will start animating
delayBeforeStart: 0,
//'left' or 'right'
direction: 'left',
//true or false - should the marquee be duplicated to show an effect of continues flow
duplicated: true
});
If you can make it simpler and better I dare you all people :). Don't make your life more difficult than it should be. More about this plugin and its functionalities at: http://aamirafridi.com/jquery/jquery-marquee-plugin
I made my own version, based in the code presented above by #Tats_innit .
The difference is the pause function. Works a little better in that aspect.
(function ($) {
var timeVar, width=0;
$.fn.textWidth = function () {
var calc = '<span style="display:none">' + $(this).text() + '</span>';
$('body').append(calc);
var width = $('body').find('span:last').width();
$('body').find('span:last').remove();
return width;
};
$.fn.marquee = function (args) {
var that = $(this);
if (width == 0) { width = that.width(); };
var textWidth = that.textWidth(), offset = that.width(), i = 0, stop = textWidth * -1, dfd = $.Deferred(),
css = {
'text-indent': that.css('text-indent'),
'overflow': that.css('overflow'),
'white-space': that.css('white-space')
},
marqueeCss = {
'text-indent': width,
'overflow': 'hidden',
'white-space': 'nowrap'
},
args = $.extend(true, { count: -1, speed: 1e1, leftToRight: false, pause: false }, args);
function go() {
if (!that.length) return dfd.reject();
if (width <= stop) {
i++;
if (i <= args.count) {
that.css(css);
return dfd.resolve();
}
if (args.leftToRight) {
width = textWidth * -1;
} else {
width = offset;
}
}
that.css('text-indent', width + 'px');
if (args.leftToRight) {
width++;
} else {
width=width-2;
}
if (args.pause == false) { timeVar = setTimeout(function () { go() }, args.speed); };
if (args.pause == true) { clearTimeout(timeVar); };
};
if (args.leftToRight) {
width = textWidth * -1;
width++;
stop = offset;
} else {
width--;
}
that.css(marqueeCss);
timeVar = setTimeout(function () { go() }, 100);
return dfd.promise();
};
})(jQuery);
usage:
for start: $('#Text1').marquee()
pause: $('#Text1').marquee({ pause: true })
resume: $('#Text1').marquee({ pause: false })
My text marquee for more text,
and position absolute enabled
http://jsfiddle.net/zrW5q/2075/
(function($) {
$.fn.textWidth = function() {
var calc = document.createElement('span');
$(calc).text($(this).text());
$(calc).css({
position: 'absolute',
visibility: 'hidden',
height: 'auto',
width: 'auto',
'white-space': 'nowrap'
});
$('body').append(calc);
var width = $(calc).width();
$(calc).remove();
return width;
};
$.fn.marquee = function(args) {
var that = $(this);
var textWidth = that.textWidth(),
offset = that.width(),
width = offset,
css = {
'text-indent': that.css('text-indent'),
'overflow': that.css('overflow'),
'white-space': that.css('white-space')
},
marqueeCss = {
'text-indent': width,
'overflow': 'hidden',
'white-space': 'nowrap'
},
args = $.extend(true, {
count: -1,
speed: 1e1,
leftToRight: false
}, args),
i = 0,
stop = textWidth * -1,
dfd = $.Deferred();
function go() {
if (that.css('overflow') != "hidden") {
that.css('text-indent', width + 'px');
return false;
}
if (!that.length) return dfd.reject();
if (width <= stop) {
i++;
if (i == args.count) {
that.css(css);
return dfd.resolve();
}
if (args.leftToRight) {
width = textWidth * -1;
} else {
width = offset;
}
}
that.css('text-indent', width + 'px');
if (args.leftToRight) {
width++;
} else {
width--;
}
setTimeout(go, args.speed);
};
if (args.leftToRight) {
width = textWidth * -1;
width++;
stop = offset;
} else {
width--;
}
that.css(marqueeCss);
go();
return dfd.promise();
};
// $('h1').marquee();
$("h1").marquee();
$("h1").mouseover(function () {
$(this).removeAttr("style");
}).mouseout(function () {
$(this).marquee();
});
})(jQuery);
Responsive resist jQuery marquee simple plugin. Tutorial:
// start plugin
(function($){
$.fn.marque = function(options, callback){
// check callback
if(typeof callback == 'function'){
callback.call(this);
} else{
console.log("second argument (callback) is not a function");
// throw "callback must be a function"; //only if callback for some reason is required
// return this; //only if callback for some reason is required
}
//set and overwrite default functions
var defOptions = $.extend({
speedPixelsInOneSecound: 150, //speed will behave same for different screen where duration will be different for each size of the screen
select: $('.message div'),
clickSelect: '', // selector that on click will redirect user ... (optional)
clickUrl: '' //... to this url. (optional)
}, options);
//Run marque plugin
var windowWidth = $(window).width();
var textWidth = defOptions.select.outerWidth();
var duration = (windowWidth + textWidth) * 1000 / defOptions.speedPixelsInOneSecound;
var startingPosition = (windowWidth + textWidth);
var curentPosition = (windowWidth + textWidth);
var speedProportionToLocation = curentPosition / startingPosition;
defOptions.select.css({'right': -(textWidth)});
defOptions.select.show();
var animation;
function marquee(animation){
curentPosition = (windowWidth + defOptions.select.outerWidth());
speedProportionToLocation = curentPosition / startingPosition;
animation = defOptions.select.animate({'right': windowWidth+'px'}, duration * speedProportionToLocation, "linear", function(){
defOptions.select.css({'right': -(textWidth)});
});
}
var play = setInterval(marquee, 200);
//add onclick behaviour
if(defOptions.clickSelect != '' && defOptions.clickUrl != ''){
defOptions.clickSelect.click(function(){
window.location.href = defOptions.clickUrl;
});
}
return this;
};
}(jQuery));
// end plugin
Use this custom jQuery plugin as bellow:
//use example
$(window).marque({
speedPixelsInOneSecound: 150, // spped pixels/secound
select: $('.message div'), // select an object on which you want to apply marquee effects.
clickSelect: $('.message'), // select clicable object (optional)
clickUrl: 'services.php' // define redirection url (optional)
});
Marquee using CSS animations.
`<style>
.items-holder {
animation: moveSlideshow 5s linear infinite;
}
.items-holder:hover {
animation-play-state: paused;
}
#keyframes moveSlideshow {
100% {
transform: translateX(100%);
}
}
</style>`
I try use only css for it this link.
<style>
.header {
background: #212121;
overflow: hidden;
height: 65px;
position: relative;
}
.header div {
display: flex;
flex-direction: row;
align-items: center;
overflow: hidden;
height: 65px;
transform: translate(100%, 0);
}
.header div * {
font-family: "Roboto", sans-serif;
color: #fff339;
text-transform: uppercase;
text-decoration: none;
}
.header div img {
height: 60px;
margin-right: 20px;
}
.header .ticker-wrapper__container{
display: flex;
flex-direction: row;
align-items: center;
position: absolute;
top: 0;
right: 0;
animation: ticker 30s infinite linear forwards;
}
.header:hover .ticker-wrapper__container{
animation-play-state: paused;
}
.ticker-wrapper__container a{
display: flex;
margin-right: 60px;
align-items: center;
}
#keyframes ticker {
0% {
transform: translate(100%, 0);
}
50% {
transform: translate(0, 0);
}
100% {
transform: translate(-100%, 0);
}
}
</style>