I would like to make a website with mouse parallax effect like in this page http://brightmedia.pl background mouse parallax is so smooth..
I have two questions:
When you mouseover on a container from, let's say, the top left corner, the image jumps. How can I make a smooth animation?
When you mouseout of a container, how can I make the image move a little bit and stop with a smooth animation?
What would code to solve these problems be?
Here is basic code:
$('.container').mousemove( function(e){
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').css({marginLeft: -xPos/20});
});
.container {
position: relative;
width: 100%;
height: 800px;
background: grey;
overflow: hidden;
margin: 0 auto;
}
.container img {
width: 110%;
height: 100vh;
position: absolute;
}
body{
height: 1000px;
}
h1{
font-size: 60px;
z-index: 10;
position: absolute;
left: 50%;
top: 30%;
transform: translate(-50%, -50%);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="css.css">
</head>
<body>
<div class="container" id="container">
<img id="par1" src="https://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg" alt="">
<h1>TEXT</h1>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
As I had solved the problem long time ago and I forgot about this post so I decided to update with the answer. Maybe it will be helpful for anyone else.
Problem solved by using GSAP. Below You can see the code that works exactly as I wanted
let wrap = document.getElementById('container');
let request = null;
let mouse = { x: 0, y: 0 };
let cx = window.innerWidth / 2;
let cy = window.innerHeight / 2;
document.querySelector('.container').addEventListener('mousemove', function(event) {
mouse.x = event.pageX;
mouse.y = event.pageY;
cancelAnimationFrame(request);
request = requestAnimationFrame(update);
});
function update() {
dx = mouse.x - cx;
dy = mouse.y - cy;
let tiltx = (dy / cy );
let tilty = - (dx / cx);
TweenMax.to("#container img", 1, {x:-tilty*20, y:-tiltx*20, rotation:0.01, ease:Power2.easeOut});
}
window.addEventListener('resize', function(event){
window.innerWidth / 2;
window.innerHeight / 2;
});
* {
margin:0;
padding:0;
box-sizing:border-box;
}
.container {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
display:flex;
flex-direction:column;
justify-content:center;
align-items:center;
}
.container img {
width: 110%;
height: 120vh;
position: absolute;
}
h1 {
z-index:100;
font-size: 6rem;
z-index: 10;
color:#333;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<div class="container" id="container">
<img id="par1" src="https://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg" alt="">
<h1>GSAP Mouse Parallax</h1>
</div>
You can rely one mouseenter / mouseleave to add animation:
$('.container').mousemove(function(e) {
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').css({
marginLeft: -xPos / 10
});
});
$('.container').mouseenter(function(e) {
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').animate({
"marginLeft": -xPos / 10
}, "slow");
});
$('.container').mouseleave(function(e) {
$('#par1').animate({
"marginLeft": "0"
}, "slow");
});
.container {
position: relative;
width: 100%;
height: 800px;
background: grey;
overflow: hidden;
margin: 0 auto;
}
.container img {
width: 110%;
height: 100vh;
position: absolute;
}
body {
height: 1000px;
}
h1 {
font-size: 60px;
z-index: 10;
position: absolute;
left: 50%;
top: 30%;
transform: translate(-50%, -50%);
}
<div class="container" id="container">
<img id="par1" src="https://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg" alt="">
<h1>TEXT</h1>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
As Temani said, playing with transition and eventually delay should do the job.
For 1st question: transition seems appropriate, associated with a mousein listener. Or even better, use the $(element).animate() function that allows to set the animation duration. That way, you don't set any value for transition duration.
For 2nd question: listener on mouseout > same process, but shorter animation (for the img shifting as well as the animation duration).
This should also give you some ideas:
https://codepen.io/Aldlevine/pen/Jowke
Based on Teemani below code example:
$('.container').mousemove(function(e) {
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').css("margin-left", -xPos / 10);
});
$('.container').mouseenter(function(e) {
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').css("margin-left", -xPos / 10);
});
$('.container').mouseleave(function(e) {
$('#par1').css({"transition": "margin-left 1s ease-in-out", "margin-left": "0"});
setTimeout( function() {
$('#par1').css("transition", "initial");
}, 500);
});
.container {
position: relative;
width: 100%;
height: 800px;
background: grey;
overflow: hidden;
margin: 0 auto;
}
.container img {
width: 110%;
height: 100vh;
position: absolute;
transition: margin-left 0.2s;
/* transition: margin-left 0.2s ease-in-out 0.2s;*/
}
body {
height: 1000px;
}
h1 {
font-size: 60px;
z-index: 10;
position: absolute;
left: 50%;
top: 30%;
transform: translate(-50%, -50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container" id="container">
<img id="par1" src="https://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg" alt="">
<h1>TEXT</h1>
</div>
Related
Below is the demo code which fully represent the actual code
I've placed some content on the red div which I want users to see when the page loads. The problem is that I'm using scrollmagic.js animations on this page. Everything was working perfect but when I tried to use smoothscroll, The .setPin fuctions of scrollmagic stopped working. The animations are still working but the red div is being scrolled with the other divs. I want the red div to stay on it's place until the animation don't finish. The smoothscroll pushes the red div along the other divs before the animation completes.
Can you please help me placing green and blue div under the red one while the red div's position is fixed and stays responsive so that everything will work on all screen sizes?
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Test Code</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.2/TweenMax.min.js"></script>
</head>
<style>
.viewport {
overflow: hidden;
position: fixed;
height: 100%;
width: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.scroll-container {
position: absolute;
overflow: hidden;
z-index: 10;
display: flex;
justify-content: center;
backface-visibility: hidden;
transform-style: preserve-3d;
}
.div1 {
width: 70%;
height: 70vh;
border: 5px solid red;
position: fixed;
transform: translateX(20%);
}
.div2 {
width: 70%;
height: 70vh;
border: 5px solid green;
transform: translateX(20%);
}
.div3 {
width: 70%;
height: 70vh;
border: 5px solid blue;
transform: translateX(20%);
}
</style>
<body>
<div class="div1"></div>
<div class="viewport">
<div id="scroll-container">
<div class="div2"></div>
<div class="div3"></div>
</div>
</div>
</body>
<script>
var html = document.documentElement;
var body = document.body;
var scroller = {
target: document.querySelector("#scroll-container"),
ease: 0.05, // <= scroll speed
endY: 0,
y: 0,
resizeRequest: 1,
scrollRequest: 0,
};
var requestId = null;
TweenLite.set(scroller.target, {
rotation: 0.01,
force3D: true
});
window.addEventListener("load", onLoad);
function onLoad() {
updateScroller();
window.focus();
window.addEventListener("resize", onResize);
document.addEventListener("scroll", onScroll);
}
function updateScroller() {
var resized = scroller.resizeRequest > 0;
if (resized) {
var height = scroller.target.clientHeight;
body.style.height = height + "px";
scroller.resizeRequest = 0;
}
var scrollY = window.pageYOffset || html.scrollTop || body.scrollTop || 0;
scroller.endY = scrollY;
scroller.y += (scrollY - scroller.y) * scroller.ease;
if (Math.abs(scrollY - scroller.y) < 0.05 || resized) {
scroller.y = scrollY;
scroller.scrollRequest = 0;
}
TweenLite.set(scroller.target, {
y: -scroller.y
});
requestId = scroller.scrollRequest > 0 ? requestAnimationFrame(updateScroller) : null;
}
function onScroll() {
scroller.scrollRequest++;
if (!requestId) {
requestId = requestAnimationFrame(updateScroller);
}
}
function onResize() {
scroller.resizeRequest++;
if (!requestId) {
requestId = requestAnimationFrame(updateScroller);
}
}
</script>
</html>
Use z-index to place the red div above the other divs:
https://www.w3schools.com/cssref/pr_pos_z-index.asp
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Test Code</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.2/TweenMax.min.js"></script>
</head>
<style>
.viewport {
overflow: hidden;
position: fixed;
height: 100%;
width: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.scroll-container {
position: absolute;
overflow: hidden;
z-index: 10;
display: flex;
justify-content: center;
backface-visibility: hidden;
transform-style: preserve-3d;
}
.div1 {
width: 70%;
height: 70vh;
border: 5px solid red;
position: fixed;
transform: translateX(20%);
z-index: 10;
}
.div2 {
width: 70%;
height: 70vh;
border: 5px solid green;
transform: translateX(20%);
}
.div3 {
width: 70%;
height: 70vh;
border: 5px solid blue;
transform: translateX(20%);
}
</style>
<body>
<div class="div1"></div>
<div class="viewport">
<div id="scroll-container">
<div class="div2"></div>
<div class="div3"></div>
</div>
</div>
</body>
<script>
var html = document.documentElement;
var body = document.body;
var scroller = {
target: document.querySelector("#scroll-container"),
ease: 0.05, // <= scroll speed
endY: 0,
y: 0,
resizeRequest: 1,
scrollRequest: 0,
};
var requestId = null;
TweenLite.set(scroller.target, {
rotation: 0.01,
force3D: true
});
window.addEventListener("load", onLoad);
function onLoad() {
updateScroller();
window.focus();
window.addEventListener("resize", onResize);
document.addEventListener("scroll", onScroll);
}
function updateScroller() {
var resized = scroller.resizeRequest > 0;
if (resized) {
var height = scroller.target.clientHeight;
body.style.height = height + "px";
scroller.resizeRequest = 0;
}
var scrollY = window.pageYOffset || html.scrollTop || body.scrollTop || 0;
scroller.endY = scrollY;
scroller.y += (scrollY - scroller.y) * scroller.ease;
if (Math.abs(scrollY - scroller.y) < 0.05 || resized) {
scroller.y = scrollY;
scroller.scrollRequest = 0;
}
TweenLite.set(scroller.target, {
y: -scroller.y
});
requestId = scroller.scrollRequest > 0 ? requestAnimationFrame(updateScroller) : null;
}
function onScroll() {
scroller.scrollRequest++;
if (!requestId) {
requestId = requestAnimationFrame(updateScroller);
}
}
function onResize() {
scroller.resizeRequest++;
if (!requestId) {
requestId = requestAnimationFrame(updateScroller);
}
}
</script>
</html>
I have some code that displays 4 divs at a random hight at specified distances from the viewport sides, each div appears with a different delay speed and then moves around the page at random.
I want to add a delay to the movement of each div so they don't all start and stop moving at the same time but every time I add ad .delay() it breaks. Any help?
Thanks
HTML
<div class="content">
<div class="loopbox">
<div id="rand_pos" class="loop mobile box1">L</div>
<div id="rand_pos" class="loop mobile box2">O</div>
<div id="rand_pos" class="loop mobile box3">O</div>
<div id="rand_pos" class="loop mobile box4">P</div>
</div>
<div class="info">
<h1>COMING SOON</h1>
<p>info#loopstudio.uk</p>
</div>
</div>
*CSS
#import url('https://fonts.googleapis.com/css?family=Marcellus&display=swap');
*:focus {
outline: none;
}
html { overflow: hidden; }
body {
margin: 0;
background-color:#FFF9F3;
}
p,h1 {
font-family:sans-serif;
}
h1{
font-weight:100;
}
.loop {
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
font-size:22vw;
font-family:'Marcellus', serif;
font-weight:100;
color: black;
position: absolute;
}
.loop:hover {
animation: shake 0.82s cubic-bezier(.5,.01,.01,.05) 1;
transform: translate3d(0, 0, 0);
backface-visibility: hidden;
perspective: 1000px;
-webkit-animation-fill-mode:forwards;
-moz-animation-fill-mode:forwards;
animation-fill-mode:forwards;
}
.box1{
top:10vh;
left:8vw;
display:none;
}
.box2{
top:20vh;
left:30vw;
display:none;
}
.box3{
top:30vh;
right:35vw;
display:none;
}
.box4{
top:40vh;
right:10vw;
display:none;
}
.content {
position: relative;
height: 100vh;
width: 100vw;
margin: 0 auto;
resize: both;
}
.info {
width: 100%;
height:auto;
transform: translate(-50%, -50%);
position: fixed;
top: 50%;
left: 50%;
resize: both;
text-align:center;
z-index:-1000;
}
JS
$('document').ready(function(){
$('.box1').delay(500).fadeIn(850);
$('.box2').delay(1000).fadeIn(850);
$('.box3').delay(750).fadeIn(850);
$('.box4').delay(1250).fadeIn(850);
});
$('document').ready(function() {
var bodyHeight = document.body.clientHeight;
var randPosY = Math.floor((Math.random()*bodyHeight));
$('#rand_pos').css('top', randPosY);
});
$(document).ready(function(){
animateDiv('.box1');
animateDiv('.box2');
animateDiv('.box3');
animateDiv('.box4');
});
function makeNewPosition(){
var h = $(window).height() - 50;
var w = $(window).width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh,nw];
}
function animateDiv(myclass){
var newq = makeNewPosition();
$(myclass).animate({ top: newq[0], left: newq[1] }, 8000, function(){
animateDiv(myclass);
});
};
I have created a small demo of two boxes animating in and out based on scroll position. But this isn't exactly what I want to achieve. What I want is for the boxes to animate based on scroll position not just transition in and out when a certain point is reached.
For example the scrolling should control the animation so if you scroll down the boxes will animate in, if you scroll up they will animate out. If you stop scrolling mid animation the animation will stop. If you reverse the scroll position the animation will reverse. So the animation only happens as you scroll.
I hope that is clear enough for you to understand. I will try provide a link to what I am trying to achieve. But for now here's my demo just using a transition to animate the boxes.
jQuery(document).ready(function($){
var scroll_pos = $(window).scrollTop();
var box = $('#container').offset().top - 200;
$(window).on('scroll', function(){
scroll_pos = $(window).scrollTop();
$('p').html(scroll_pos);
if(scroll_pos >= box){
$('#left').addClass('animate');
$('#right').addClass('animate');
}else{
$('#left').removeClass('animate');
$('#right').removeClass('animate');
}
});
});
#container{
width: 600px;
height: 300px;
margin: 1000px auto;
overflow: hidden;
font-size: 0;
}
#left{
width: 55%;
height: 300px;
background-color: blue;
display: inline-block;
transform: translateX(-100%);
transition: all 0.5s;
}
#right{
width: 45%;
height: 300px;
background-color: yellow;
display: inline-block;
transform: translateX(100%);
transition: all 0.5s;
}
#left.animate{
transform: translateX(0%);
}
#right.animate{
transform: translateX(0%);
}
p{
position: fixed;
top: 0;
left: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<p></p>
<div id="container">
<div id="left"></div>
<div id="right"></div>
</div>
Here's an example of what I want to achieve. As you can see the scroll controls the animation of the fidget spinner https://ampbyexample.com/visual_effects/basics_of_scrollbound_effects/
Based on this answer you could do someting like:
/**
* inViewport jQuery plugin by Roko C.B.
* http://stackoverflow.com/a/26831113/383904
* 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)
*/
;(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) : Math.min(b, H)));
}
visPx();
$(win).on("resize scroll", visPx);
});
};
}(jQuery, window));
// Now our stuff:
var $container = $("#container");
var $left = $("#left");
var $right = $("#right");
$container.inViewport(function( px ) {
var v = 1 - px / $container.height(); // Value from 1.0 to 0.0 and v.versa
$("p").text(v);
$left.css({transform: `translateX(${ -v * 100 }%)`});
$right.css({transform: `translateX(${ v * 100 }%)`});
});
body {
height: 500vh;
}
#container {
position: relative;
margin: 0 auto;
top: 200vh;
overflow: hidden;
width: 60vw;
height: 60vh;
}
#left,
#right {
width: 50%;
height: 100%;
float: left;
}
#left {
background-color: blue;
transform: translateX(-100%);
}
#right {
background-color: yellow;
transform: translateX(100%);
}
p {position: fixed; top:0; left: 0;}
<div id="container">
<div id="left"></div>
<div id="right"></div>
</div>
<p></p>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
I was creating a parallax effect in which the image and the text move in opposite direction to the movement of the mouse. That is happening inside an element called parallax-wrapper. But when I move out of the element I want the image and the text to return back to their original positions. I have tried to detect the mouse position outside the element but for some reason it not firing properly.
The codepen link is - https://codepen.io/rohitgd/pen/gRLNad?editors=1010
HTML
<div class="parallax-wrapper">
<div class="layer" data-mouse-parallax="0.1">
<img src="https://tympanus.net/Development/MorphingBackgroundShapes/img/1.jpg"/>
</div>
<div class="layer" data-mouse-parallax="0.3">REVERT</div>
</div>
CSS
body {
background-color:#fff;
padding: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.parallax-wrapper {
width: 500px;
height: 300px;
background-color:#0c0c0c;
position: relative;
overflow: hidden;
.layer {
width: 80%;
height: 80%;
position: absolute;
left: 30px;
text-align: center;
line-height: 300px;
font-size: 38px;
color:#FFF;
transition: all 200ms ease-out;
}
}
img {
width: 200px;
height: 200px;
position: relative;
top: 50px;
right: 70px;
}
Javascript
$(".parallax-wrapper").mousemove(function(e) {
var x = e.pageX - $(this).offset().left - $(this).width() / 2;
var y = e.pageY - $(this).offset().top - $(this).height() / 2;
$("*[data-mouse-parallax]").each(function() {
var factor = parseFloat($(this).data("mouse-parallax"));
x = -x * factor;
y = -y * factor;
$(this).css({ transform: "translate3d( " + x + "px, " + y + "px, 0 )" });
});
});
$(document).mouseleave(function(e) {
var target = $(e.target);
if( !target.is("div.layer")) {
alert('out of the element');
e.stopPropagation();
}
});
What I want is when the mouse is outside the parallax-wrapper the Image and the text return back to their original positions.
You're not resetting the transformations when your mouse leaves. You need to add this where you have the alert...
$(".parallax-wrapper").mouseleave(function(e) {
$("*[data-mouse-parallax]").each(function() {
$(this).css({ transform: "translate3d( 0, 0, 0 )" });
});
});
Note that the mouseleave event is triggered when the mouse leaves .parallax-wrapper, not document as you previously had it.
Here's a modified codepen...
https://codepen.io/anon/pen/ZyBgYJ
I think a selector was wrong. Here's a correct version or see code below.
To show better when you are inside/outside I change the background color, that's better than an alert. When you leave the wrapper (the black background) it flips correctly now.
Where RED is set you can reset the transform to the origin.
// Trying to replicate the effect here - https://tympanus.net/Development/MorphingBackgroundShapes/
$(".parallax-wrapper").mousemove(function(e) {
var x = e.pageX - $(this).offset().left - $(this).width() / 2;
var y = e.pageY - $(this).offset().top - $(this).height() / 2;
$(".parallax-wrapper").css("background-color", "#00ff00"); // <-- EXIT
// reset transform here
$("*[data-mouse-parallax]").each(function() {
var factor = parseFloat($(this).data("mouse-parallax"));
x = -x * factor;
y = -y * factor;
$(this).css({ transform: "translate3d( " + x + "px, " + y + "px, 0 )" });
});
});
// this is the selector I changed from "document" to ".parallax-wrapper"
$(".parallax-wrapper").mouseleave(function(e) {
var target = $(e.target);
if( !target.is("div.layer")) {
$(".parallax-wrapper").css("background-color", "#ff0000"); // <-- ENTER
e.stopPropagation();
}
});
body {
background-color:#fff;
padding: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.parallax-wrapper {
width: 500px;
height: 300px;
background-color:#0c0c0c;
position: relative;
overflow: hidden;
.layer {
width: 80%;
height: 80%;
position: absolute;
left: 30px;
text-align: center;
line-height: 300px;
font-size: 38px;
color:#FFF;
transition: all 200ms ease-out;
}
}
img {
width: 200px;
height: 200px;
position: relative;
top: 50px;
right: 70px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parallax-wrapper">
<div class="layer" data-mouse-parallax="0.1">
<img src="https://tympanus.net/Development/MorphingBackgroundShapes/img/1.jpg"/>
</div>
<div class="layer" data-mouse-parallax="0.3">REVERT</div>
</div>
Replace $(document).mouseleave with $(".parallax-wrapper").mouseleave.
$(".parallax-wrapper").mousemove(function(e) {
var x = e.pageX - $(this).offset().left - $(this).width() / 2;
var y = e.pageY - $(this).offset().top - $(this).height() / 2;
$("*[data-mouse-parallax]").each(function() {
var factor = parseFloat($(this).data("mouse-parallax"));
x = -x * factor;
y = -y * factor;
$(this).css({ transform: "translate3d( " + x + "px, " + y + "px, 0 )" });
});
});
$(".parallax-wrapper").mouseleave(function(e) {
alert('out of the element');
});
body {
background-color: #fff;
padding: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.parallax-wrapper {
width: 500px;
height: 300px;
background-color: #0c0c0c;
position: relative;
overflow: hidden;
}
.parallax-wrapper .layer {
width: 80%;
height: 80%;
position: absolute;
left: 30px;
text-align: center;
line-height: 300px;
font-size: 38px;
color: #FFF;
transition: all 200ms ease-out;
}
img {
width: 200px;
height: 200px;
position: relative;
top: 50px;
right: 70px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parallax-wrapper">
<div class="layer" data-mouse-parallax="0.1">
<img src="https://tympanus.net/Development/MorphingBackgroundShapes/img/1.jpg"/>
</div>
<div class="layer" data-mouse-parallax="0.3">REVERT</div>
</div>
I am trying to set a text to overlap an image but the position should stay same on all screen sizes.
Example:
Here is an example of what I have tried demo
.c-txt-on-img{
position: relative;
}
.c-txt-on-img .txt{
font-size: 30px;
font-weight: bold;
font-family: arial, sans-serif;
max-width: 200px;
position: absolute;
top: 80px;
left: 158px;
}
.c-txt-on-img .img {
width: 100vw;
height: 100vh;
background-size: cover;
background-position: center center;
}
<div class="c-txt-on-img">
<div class="txt">Tony where are you !!!!</div>
<div class="img" style="background-image: url(http://theprojectstagingserver.com/stackoverflow/txt-on-img/comic.jpg)"></div>
</div>
It works on a specific screen-size only, I can fix this on different sizes using different media queries but that will take too much time!
There are 2 main challenges:
1) Align the image and text to always stay on the same spot.
2) Aligning will leave extra uneven space on top/bottom & left/right side of the image so we need to increase image size enough that it covers the whole screen.
For first part we can define same top left position to text and image, then give a negative translate percentage to image so that top left origin of image is the same spot where the text bubble is.
Next we can calculate the space on right/left/top/bottom of image & increase its width till no negative space is left.
Below is a GIF image to explain this better:
Here is the DEMO
var viewportOffset = [],
winWidth,
winHeight,
inLoop = false,
resizeTimeout;
$(function(){
init();
});
$(window).resize(function(){
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(function(){
init();
}, 500);
});
function init() {
winWidth = $(window).width();
winHeight = $(window).height();
inLoop = false;
coverImage();
}
function coverImage() {
$('.js-cover-img').each(function (i) {
viewportOffset[i] = getViewportOffset($(this));
if(!inLoop){
$(this).width('auto');
$(this).height('auto');
}
var imgWidth = $(this).width();
var imgHeight = $(this).height();
viewportOffset[i].right = winWidth - imgWidth- (viewportOffset[i].left);
viewportOffset[i].bot = winHeight - imgHeight- (viewportOffset[i].top);
if(viewportOffset[i].top < 0){
var vertViewportOffest = viewportOffset[i].bot;
}else if(viewportOffset[i].bot <= 0){
var vertViewportOffest = viewportOffset[i].top;
}else{
var vertViewportOffest = viewportOffset[i].top + viewportOffset[i].bot;
}
if(viewportOffset[i].right < 0){
var horViewportOffest = viewportOffset[i].left;
}else if(viewportOffset[i].left < 0){
var horViewportOffest = viewportOffset[i].right;
}else{
var horViewportOffest = viewportOffset[i].left + viewportOffset[i].right;
}
if(horViewportOffest > 0 || vertViewportOffest > 0){
$(this).width(imgWidth + 20);
inLoop = true;
coverImage();
return false;
}
});
}
/* Get's the viewport position */
function getViewportOffset($e) {
var $window = $(window),
scrollLeft = $window.scrollLeft(),
scrollTop = $window.scrollTop(),
offset = $e.offset();
return {
left: offset.left - scrollLeft,
top: offset.top - scrollTop
};
}
body, html{
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
.c-txt-on-img {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.c-txt-on-img .txt {
font-size: 30px;
font-weight: bold;
font-family: arial, sans-serif;
max-width: 200px;
position: absolute;
top: 30%;
left: 30%;
z-index: 2;
transform: translate(-50%, -50%);
text-align: center;
}
.c-txt-on-img .img {
transform: translate(-28.5%, -23%);
z-index: 1;
position: absolute;
top: 30%;
left: 30%;
min-width: 870px;
}
.c-txt-on-img img{
display:block;
width: 100%;
}
<script
src="https://code.jquery.com/jquery-1.12.2.min.js"
integrity="sha256-lZFHibXzMHo3GGeehn1hudTAP3Sc0uKXBXAzHX1sjtk="
crossorigin="anonymous"></script>
<div class="c-txt-on-img">
<div class="txt">Tony where are you !!!!</div>
<div class="img js-cover-img">
<img src="http://theprojectstagingserver.com/stackoverflow/txt-on-img/comic.jpg">
</div>
</div>