I have some div tags on the page and once they are in a viewport, I want them to animate in a certain way. I already got the 'in viewport' part working with waypoint.js so now I am stuck with the animation.
Basically, I want to have a grey underline on all h1 tags at all times. Once they are in view, I want a black line to run on top of that grey line from right to left and almost leave the scene afterwards, stopping at about 25% of grey line.
To demonstrate it, I've changed the effect to work on hover and as you can see, I've got the part when it runs through the grey line, but I'm stuck with the part when it should leave the scene (almost leave the scene - stopping at 25% of grey line):
HTML:
<div class="section-header">
<span>Hello</span>
</div>
CSS:
.section-header {
text-transform: uppercase;
font-weight: 700;
font-size: 2em;
letter-spacing: 5px;
position: relative;
text-align: center;
> span {
display: inline-block;
position: relative;
border-bottom: 1px solid #ccc;
&:before {
content: "";
position: absolute;
width: 0;
height: 1px;
bottom: -1px;
right: 0;
background-color: #000;
visibility: hidden;
-webkit-transition: all 0.9s ease-in-out 0s;
transition: all 0.9s ease-in-out 0s;
}
&:hover {
&:before {
visibility: visible;
width: 100%;
}
}
}
}
http://codepen.io/anon/pen/RWoxBv
Is this possible to do in CSS at all? Or should I use Javascript for it?
To demonstrate the animation further, imagine that this is the black line:
- (starts from right hand side and goes to left)
--
---
----
-----
------
-------
--------
---------
----------
-----------
------------ (point when it covers the grey line and starts to 'leave the scene')
-----------
----------
---------
--------
-------
------
-----
----
--- (stopping there)
So animate an element from left 100% to left -75% (= 25% visible!)
jsBin demo playground
Here's a small nice example that uses a small jQuery plugin taken from here and a bit of standard CSS:
/**
* inViewport jQuery plugin by Roko C.B. stackoverflow.com/questions/24768795/
*
* Returns a callback function with an argument holding
* the current amount of px an element is visible in viewport
* (The min returned value is 0 (element outside of viewport)
* The max returned value is the element height + borders)
*/
;(function($, win) {
$.fn.inViewport = function(cb) {
return this.each(function(i,el) {
function visPx(){
var elH = $(el).outerHeight(),
H = $(win).height(),
r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
return cb.call(el, Math.max(0, t>0? Math.min(elH, H-t) : (b<H?b:H)));
}
visPx();
$(win).on("resize scroll", visPx);
});
};
}(jQuery, window));
// Let's rock!
$("h1 span").inViewport(function(px){
$(this).toggleClass("animateLine", !!px);
});
p{height:900px;}/*FOR DEMO ONLY*/
h1{
text-align:center;
}
h1 span{
display:inline-block;
position:relative;
overflow:hidden;
}
h1 span:after,
h1 span:before{
content:"";
height:1px;
width:100%;
position:absolute;
bottom:0px;
left:0;
transition: 3s;
}
h1 span:before{
background:#ccc;
}
/* We'll animate this one to -75% */
h1 span:after{
background:#000;
left:100%;
}
h1 span.animateLine:after{
left: -75%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1><span>This is title 1</span></h1>
<p>1 Scroll down to find more titles</p>
<h1><span>This is title 2</span></h1>
<p>2 Scroll down to find more titles</p>
<h1><span>This is title 3</span></h1>
<p>3 Scroll down to find more titles</p>
<h1><span>This is title 4</span></h1>
<p>4 Scroll down to find more titles</p>
<h1><span>This is title 5</span></h1>
<p>5 Scroll down to find more titles</p>
Basically set the pseudo :after to initial 100% left, and trigger the CSS3 class that will apply the left -75% transition using the jQ plugin like in the demo.
https://stackoverflow.com/a/26831113/383904
CSS3-Animate elements if visible in viewport (Page Scroll)
Related
function toggle(){
var button=document.querySelector('.toggle');
var bar=document.querySelector('.slide');
if(bar.className==='slide up'){
bar.className='slide down';
}else{
bar.className='slide up';
}
}
*{
margin:0px;
padding:0px;
height:100%;
width:100%;
}
.box{
overflow:hidden;
background-image: url('http://tombricker.smugmug.com/Travel/San-Francisco-California/i-jk2Z7D7/0/L/san-francisco-golden-gate-bridge-morning-sun-bricker-L.jpg');
background-size: cover;
background-position:center;
}
.slide{
position: relative;
left:39vw;
width: 55vw;
height: 75vh;
background: red;
}
.slide:before {
content: '';
position:absolute;
top:-3vh;
width: 0px;
height: 0px;
border-left:27.5vw solid transparent;
border-right:27.5vw solid transparent;
border-bottom:3vh solid white;
}
.slide.down{
transform:translateY(100vh);
}
.slide.up{
transform:translateY(25vh);
}
.slide{
transition:transform 0.4s ease-out;
}
<div class='box'>
<div class='slide up' onclick='toggle()'></div>
</div>
The white triangle on top of the red rectangle is made with pseudo element :before. What I am trying to do is when the sliding tag is up, the white triangle should be pointing down. To do that, I want to write a JS code that will add a transform CSS to that class with pseudo element that will translate triangle down by its height and rotate by 180deg.
I find on this developer blog the JS code to add, but it does not work and I don't know how to delete that code when the tag is down.
function toggle(){
var button=document.querySelector('.toggle');
var bar=document.querySelector('.slide');
if(bar.className==='slide up'){
bar.className='slide down';
//Here is where I need to add the line to delete CSS
}else{
bar.className='slide up';
//This is to add CSS
//3vh is the height of that white triangle
document.styleSheets[0].addRule('.slight:before','transform:translateY(3vh) rotateX(180deg)');
}
}
You can add the transformation to the CSS class, and simply toggle it.
CSS
.slide.up:before {
transform: translateY(3vh) rotateX(180deg);
}
JS
var bar = document.querySelector('.slide')
function toggle() {
var cl = bar.classList
cl.toggle('down', cl.contains('up'))
cl.toggle('up', !cl.contains('down'))
}
JSFiddle demo: https://jsfiddle.net/htq8ouyn/2/
Resources
Element.classList - Web APIs | MDN
I'm using Stick-Kit to keep some images in place while scrolling, and it seems to be affecting another script that initiates a CSS animation by adding a class to a div when it enters the viewport. I assume the Sticky-Kit script is 'reseting' the other, as the animation only occurs once when Sticky-Kit is removed. The issue is visible when the animated div gets to the top of the screen. How do I ensure the animation occurs only one time (when it first appears in the viewport)?
http://codepen.io/SeanLindsay1/pen/ZBVyLZ
HTML
<div id="bg">
<h2 class="header-title"><span>HEADER</span></h2>
<div id="pic1">
1
</div>
<div id="pic2">
2
</div>
<div id="pic3">
3
</div>
</div>
CSS
/* STICKY-KIT */
#bg {
background-color: white;
width:100%;
height:1500px;
padding:0;
margin:0;
font-size:30px
}
#pic1 {
position:relative;
width:60% ;
height:500px;
background-color:blue;
}
#pic2 {
position:relative;
width:60% ;
height:500px;
background-color:green;
}
#pic3 {
position:relative;
width:60% ;
height:500px;
background-color:red;
}
/* HEADER TITLES */
.header-title span {
display: inline-block;
position: relative;
}
.change:after {
content: " ";
position: absolute;
height: 5px;
border-bottom: 1px solid #bebebe;
-webkit-animation: extend .1s 1 forwards;
animation: extend 1s 1 forwards;
margin-left: 4px;
top: 1.2em !important;
}
#-webkit-keyframes extend {
0% {
width: 0;
}
100% {
width: 200px;
}
}
#keyframes extend {
0% {
width: 0;
}
100% {
width: 200px;
}
}
jQuery
// Check to see if element is in viewport
function isElementInViewport(elem) {
var $elem = jQuery(elem);
// Get the scroll position of the page.
var scrollElem = ((navigator.userAgent.toLowerCase().indexOf('webkit') != -1) ? 'body' : 'html');
var viewportTop = jQuery(scrollElem).scrollTop();
var viewportBottom = viewportTop + jQuery(window).height();
// Get the position of the element on the page.
var elemTop = Math.round( $elem.offset().top ) + 200 ;
var elemBottom = elemTop + $elem.height();
return ((elemTop < viewportBottom) && (elemBottom > viewportTop));
}
// Check if it's time to start the animation
function extendLine() {
var $elem = jQuery('.header-title span').each(function() {
var $elem = jQuery(this);
// If the animation has already been started
if ($elem.hasClass('change')) return;
if (isElementInViewport($elem)) {
// Start the animation
$elem.addClass('change');
}
});
}
// Capture scroll events
jQuery(window).scroll(function(){
extendLine();
});
$("#bg").stick_in_parent();
$("#text").stick_in_parent({offset_top: 390});
$("#pic1").stick_in_parent();
$("#pic2").stick_in_parent();
$("#pic3").stick_in_parent();
If possible, you can use a CSS Transition instead of an Animation. It'll have better browser support, and will work. I can't really find out what's happening in your code, but if you change a couple of lines, it'll work as expected.
Here is a forked codepen: http://codepen.io/ddanielbee/pen/BQbQqj
Here are the specific lines:
.header-title span::after {
content: " ";
transition: all 1.5s ease-out;
width: 0;
}
.header-title span.change::after {
position: absolute;
height: 5px;
border-bottom: 1px solid #bebebe;
width: 200px;
margin-left: 4px;
top: 1.2em !important;
}
Removing this line of code:
$("#bg").stick_in_parent();
ensures that the header text block is not influenced by Stick-Kit and eliminates the problem of repeated execution of the animation, as shown in this codepen.
I haven't observed any ill effects caused by that change, but I cannot guarantee that there aren't any, since I don't know why this line was in the original code.
I'm trying to create a slider of images (previous/next) so the images slide to the left when I click "previous" and to the right when I click "next" with 0.5s of slowness, so it takes some animation. And when I reach the last image and click "next", I want images to "run backwards" to the first one, the same when I'm in the first one and click "previous", so it "run forward" until the last one.
I want the same behaviour this JSFiddle shows. (but I don't need the timer to move images automatically and don't need the "triggers" buttons, just "previous" and "next").
The problem here is that my images don't have fixed size. I define a width in percentage and can't define a height because I have responsive design, the image resizes as I resize the browser window.
The jQuery to previous/next actions is pretty easy, but I just can't find a way to add this animation when I remove/add the "active" class to my images (so they become visible or not).
I have already tried putting all images side by side and showing only the first one (setting container width equals to image width), so when I click "next" I just "move" the container to the left so it begins to display the next image, but it doesn't work because once I can't define the height of the images, they will appear underneath each other, not side by side.
JSFiddle
HTML
<div class="images">
<img class="active" src="1.jpg">
<img src="2.jpg">
<img src="3.jpg">
</div>
<div class="previous">previous</div>
<div class="next">next</div>
CSS
img {
width: 100px;
display: none;
float: left;
}
img.active {
display: block;
}
jQuery
$('.next').on('click', function() {
var active = $('img.active');
var next = active.next('img');
if (next.length) {
active.removeClass('active');
next.addClass('active');
} else {
active.removeClass('active');
$('.images img:first').addClass('active');
}
});
Well the problem is the height for sliding.
First you need to have an element which is the "picture frame" which hold all the other images. That's important.
For better imagination a picture:
Now you have several technics to show and hide images. One could be to set the opacity. When using transition: opacity .15s ease-in-out; The one Picture is fading out and the next on is fading in.
For the slideshow effect is given to the position of the visible image to its width to the left and the image previously purely new to his wide to the right and then to 0. Thus, moves the current picture on the left the frame out and the new comes out right in.
And here is the difficulty if the height is not the same. If the current image 300px high and the new 400px, so the image frame here would adjust his height immediately once the new image start to be visible.
The content below would start to jump with each slide.
Is that so desired???
If yes, I can make you an example how it works.
You can actually do this in Pure CSS!
You use an ID and a label (with a for attribute=for the targeted id)
That's basically it. All you have left is to style it! (Forked from Joshua Hibbert's Pen)
body {
background: #f7f4e2;
}
/* Slides */
.slider input {
display: none;
}
/* Buttons */
.slider label {
display: none;
cursor: pointer;
position: absolute;
top: 6em;
left: 50%;
transform: translateX(-50%);
color: #fff;
background: #000;
padding: 1.36em .5em;
opacity: .6;
font-size: 19px;
font-family: fantasy;
font-weight: bold;
transition: .25s;
}
.slider label:hover {
opacity: 1;
}
.previous {
margin-left: -188px;
}
.next {
margin-left: 188px;
}
#slide1:checked ~ .buttons .slide1 {
display: block;
}
#slide2:checked ~ .buttons .slide2 {
display: block;
}
#slide3:checked ~ .buttons .slide3 {
display: block;
}
#slide4:checked ~ .buttons .slide4 {
display: block;
}
/* Images */
.slider {
position: absolute;
top: 50%;
left: 50%;
width: 400px;
height: 300px;
margin-top: -150px;
margin-left: -200px;
white-space: nowrap;
padding: 0;
float: left;
transition: .25s;
overflow: hidden;
box-shadow: 0 0 0 3.12px #e8e8e8,
0 0 0 12.64px #eaebe4,
0 0 0 27.12px #000,
0 24px 3.824em 5.12px #000;
}
.slide {
width: 500em;
transition: .25s;
}
.slider img {
float: left;
width: 400px;
height: 300px;
}
#slide1:checked ~ .slide {
margin: 0;
}
#slide2:checked ~ .slide {
margin: 0 0 0 -400px;
}
#slide3:checked ~ .slide {
margin: 0 0 0 -800px;
}
#slide4:checked ~ .slide {
margin: 0 0 0 -1200px;
}
<div class="slider">
<input type="radio" name="slide" id="slide1" checked="true" />
<input type="radio" name="slide" id="slide2" />
<input type="radio" name="slide" id="slide3" />
<input type="radio" name="slide" id="slide4" />
<div class="buttons">
<!-- Slide 1 -->
<label for="slide4" class="slide1 previous"><</label>
<label for="slide2" class="slide1 next">></label>
<!-- Slide 2 -->
<label for="slide1" class="slide2 previous"><</label>
<label for="slide3" class="slide2 next">></label>
<!-- Slide 3 -->
<label for="slide2" class="slide3 previous"><</label>
<label for="slide4" class="slide3 next">></label>
<!-- Slide 4 -->
<label for="slide3" class="slide4 previous"><</label>
<label for="slide1" class="slide4 next">></label>
</div>
<div class="slide">
<img src="http://dribbble.s3.amazonaws.com/users/322/screenshots/872485/coldchase.jpg">
<img src="http://dribbble.s3.amazonaws.com/users/322/screenshots/980517/icehut_sm.jpg">
<img src="http://dribbble.s3.amazonaws.com/users/322/screenshots/943660/hq_sm.jpg">
<img src="http://dribbble.s3.amazonaws.com/users/322/screenshots/599584/home.jpg">
</div>
</div>
Although this method is the most compatible (except for old versions of IE) and depending on how you animate it this method can be more time consuming than a JS method, but can also be faster, it just depends on how you want the animations to go, or you could use a css library that does this for you.
Here are some css image sliders I recommend.
10 Amazing Pure CSS3 Image Sliders
http://bashooka.com/coding/pure-css3-image-sliders/
Pure CSS Image Slider Without Javascript #Codeconvey is a good solution for what you're looking for, but lots of CSS
http://codeconvey.com/pure-css-image-slider/
The downside to these along with what you're working on is that you can't touch to slide on a phone or tablet which is more common now a days with photo galleries.
I recommend checking out Fotorama it's amazing! :)
Perhaps not the ideal situation but at least it will give you an idea. you can use the animation function of jQuery and I also changed your code a bit. See demo here
Within your HTML I would say this:
<div id="images">
<div class="images-wrapper">
<img src="http://www.cutestpaw.com/wp-content/uploads/2016/02/In-the-spotlight.jpg">
<img src="http://www.cutestpaw.com/wp-content/uploads/2016/02/Bath-time-with-ducky.jpg">
<img src="http://www.cutestpaw.com/wp-content/uploads/2016/03/FB_IMG_1452981788903.jpg">
<img src="http://www.pictures-of-cats.org/images/Pixiebob-cat-list-of-cat-breeds-pictures-of-cats.jpg" />
</div>
</div>
<div class="previous">
previous
</div>
<div class="next">
next
</div>
and within your jQuery code you can animate the width:
$('.images-wrapper img:gt(0)').hide();
$('.next').click(function() {
$('.images-wrapper img:first-child').animate({width:'toggle'},350).next().fadeIn().end().appendTo('.images-wrapper');
});
$('.previous').click(function() {
$('.images-wrapper img:first-child').animate({width:'toggle'},350);
$('.images-wrapper img:last-child').prependTo('.images-wrapper').fadeOut();
$('.images-wrapper img:first-child').fadeIn();
});
With this implementation the whole process of changing and adding the active class to the image is removed and replaced by animation functions
Simplest solution (I think) is to force the items to be of the same size, by placing them in a div. You can even have the div show the image without the use of an img tag, by using the background-image CSS feature (see http://www.w3schools.com/css/css3_backgrounds.asp for more details).
The item CSS could look like:
.item {
background-size: contain;
background-position: center;
}
and in each item in the HTML:
<div class='item' style='background-image: url(img1.jpg)' />
<div class='item' style='background-image: url(img2.jpg)' />
<div class='item' style='background-image: url(img3.jpg)' />
I finally got there.
HERE is the fiddle with the solution I developed.
The main problem in the implementation of this image slider was that images, althought were all the same size, have dynamic width (defined in % on CSS) and dynamic height (not defined on CSS).
The solution was basically put an "fake" image (with opacity: 0) inside my container so the container get the actual size of images I will use in the slider; put a div to "hold" the real images with position: absolute and give it a width calculted by number of images * 100%; and for last, give each image in my slider a width of x%, based on number of images.
In the jQuery, I "move" the "images holder div" always by %, never by static values, once the width of everything can change if I resize the window.
If you start to slide the images to the left and right and then resize the window, you will see that it continues to work perfectly.
I have implemented using css3 animations. However this will require manipulating animation values in css every time a slide gets added or removed.
#keyframes slideAnim {
0% {
transform: translateX(0)
}
12.5% {
transform: translateX(0%);
}
25% {
transform: translateX(-25%);
}
37.5% {
transform: translateX(-25%)
}
50% {
transform: translateX(-50%)
}
62.5% {
transform: translateX(-50%)
}
75% {
transform: translateX(00%);
}
89.5% {
transform: translateX(00%)
}
100% {
transform: translateX(00%)
}
}
Here the animation values are set such that there is a pause between slide transitions. I have added a parent frame to show only one slide at a time.
Please refer this fiddle.
I have a page which i need to dim a certain area (div) instead of the entire page. How can I achieve this?
I have googled some answer but all of them is about dimming the whole page. Below is the sample code that I got but it dimmed the entire page.
<div id="dimmer"></div>
#dimmer
{
background:#000;
opacity:0.5;
position:fixed; /* important to use fixed, not absolute */
top:0;
left:0;
width:100%;
height:100%;
display:none;
z-index:9999; /* may not be necessary */
}
It covered the whole page because you set the width and height to 100%. If you were to make it 100px or 50%, that would work, but if you set it to 100%, it will cover 100% of the page.
.area-to-dim {
position: relative;
}
.dimmer {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba(0,0,0,0.5);
}
HTML
<div class="area-to-dim">
<div class="dimmer"></div>
</div>
Two ways, one really simple but I'm not 100% sure this is what you wanted.
First way, use CSS
.genericClassGivenToDivs, #idOfDiv {
background:#fff;
}
/* on mouse over, change the background colour */
.genericClassGivenToDivs:hover, #idOfDiv:hover {
background:#aaa;
}
The second way is more complex. Basically, reposition a div using javascript on mouse over. This requires some CSS and javascript. The following could be a lot cleaner with some work.
<html>
<head>
<style>
body {
margin:1em;
background:#ddd;
}
#contain {
margin:auto;
width:100%;
max-width:720px;
text-align:center;
}
#row1, #row2, #row3 {
width:100%;
height:48px;
line-height:48px;
color:#000;
background:#fff;
}
#row2 {
background:#eee;
}
#dim {
position:absolute;
top:0px;
left:0px;
width:100%;
height:100%;
background:rgba(0,0,0,0.5);
display:none;
}
</style>
</head>
<body>
<div id="contain">
<div id="row1">Row 1</div>
<div id="row2">Row 2</div>
<div id="row3">Row 3</div>
</div>
<div id="dim"></div>
<script>
var dimEl = document.getElementById('dim');
function over() {
//console.log('over:['+ this.id +']');
dimEl.style.top = this.offsetTop +'px';
dimEl.style.left = this.offsetLeft +'px';
dimEl.style.height = this.offsetHeight +'px';
dimEl.style.width = this.offsetWidth +'px';
dimEl.style.display = 'block';
}
window.onload = function() {
var list = ['row1', 'row2', 'row3'];
var e;
for(x in list) {
e = document.getElementById(list[x]);
if (e) {
e.onmouseover = over;
}
}
}
</script>
</body>
</html>
Not entirely sure what "dimming a certain area" means, but I recently created a solution that might be applicable in some extent.
I had a div with a background image and some overlaid text, and the background (but not the text) should darken slightly on mouse over.
I solved it by having two containers and a textfield, so that the outermost div had the background image, the inner div expanded to 100% height and width and had a transparent black solid-color background, and then there was some text in that div.
Then, simply, on hover, I change the inner div background-color from rgba(0, 0, 0, 0) to rgba(0, 0, 0, .3), dimming the background image.
If this sounds applicable, see this jsFiddle
Why the display is none?
Check this?
#dimmer {
background: #111;
top: 0;
left: 0;
width: 100px;
height: 100px;
z-index: 9999;
/* may not be necessary */
}
#dimmer:hover {
background: #000;
opacity: 0.5;
transition: opacity 1s ease;
cursor: pointer;
}
<div id="dimmer">ok</div>
I'm trying to gradually fade in the scroll-bar. Currently, how I am making the scroll-bar appear is by adding a class to the body that changes the overflow to auto, but it looks very jerky / abrupt.
Here is the JS code that abruptly adds the class that shows the scroll-bar:
var bodywidth = $('body').width();
var scrollwidth = 10;
$('body').mousemove(function(e){
var x = e.pageX - this.offsetLeft;
if(x>bodywidth-scrollwidth)
$('body').addClass("auto");
else
$('body').removeClass("auto");
});
And here is the CSS corresponding to those clases:
body
{
margin:0;
overflow:hidden;
}
.auto
{
overflow:auto;
}
How can I make this transition less abrupt? Is there a better way to do it that adding the class and removing the class.
The scrollbars can be customized via -webkit-scrollbar, but this can not be animated (or at least I didn't succeded at it), and support in other browser is poor.
An alternative is to set a div just over the scrollbar, make it the same color than the base div, and make it gradually transparent to show the scrollbar
the html is:
<div class="container">
<div class="base">
<p>aaa aaaaa aaaaa aaaaaaaa aaaa aaa aaa aaaa bbbbbb bbbbbb cccc cccc cccc
</p>
</div>
<div class="hide">
</div>
</div>
the CSS is:
.base {
width: 100px;
background-color: white;
top: 0px;
position: absolute;
height: 130px;
overflow: hidden;
padding-right: 20px;
}
.base.clipped {
overflow: auto;
}
.hide {
position: absolute;
width: 19px;
height: 100%;
right: 0px;
background-color: white;
top: 0px;
-webkit-transition: all 2s;
z-index: 10;
}
.hide.clipped {
background-color: transparent;
}
I am keeping the class of the elements all the time, but adding a second class clipped to both. I set a padding in the element that will have the scrollbars so that there space for it without rearranging the layout. The hide element can be transitioned with css, the overflow not.
the javascript is
$("*").click(function(){
var obj = $(".base");
var hid = $(".hide");
if (obj.hasClass("clipped")) {
hid.removeClass("clipped");
setTimeout(function() {
obj.removeClass("clipped");
}, 2000);
} else {
hid.addClass("clipped");
obj.addClass('clipped');
}
});
demo