Parallax with mouse - javascript

I'm trying to 'transform' elements, img here when the mouse moves on the page. I have integrated a vanilla code to create this effect and thought I understoond it but it seems I was wrong. The element from the code snippet is the orange square (3.png), but I want to apply this effect on the human pic (2.png) behind aswell and can't figure out how. (here's the full code as I don't rly know what's messed up except for my whole architecture prbly: https://github.com/KPq66dw8L/b-code-fiverr)
<section class="container bot-container-img">
<img class="layer closeUp" src="images/1.png" data-speeed="2" alt="">
<img class="layer ellipse2" src="images/2.png" data-speeed="-5" alt="">
<img class="layer" src="images/images/3.png" data-speed="2" alt="">
</section>
CSS:
.bot-container-img {
grid-row-start: 3;
grid-column-start: 1;
grid-column-end: 3;
width: 100%;
height: 100%;
}
section {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
align-items: flex-end;
justify-content: flex-start;
}
section img {
position: absolute;
object-fit: cover;
width: 100%;
height: 100%;
}
JS:
document.addEventListener("mousemove", parallax);
function parallax(e){
this.querySelectorAll('.layer').forEach(layer => {
const speed = layer.getAttribute('data-speed')
const x = (window.innerWidth - e.pageX*speed)/100
const y = (window.innerHeight - e.pageY*speed)/100
layer.style.transform = `translateX(${x}px) translateY(${y}px)`
})
}

There were a few minor errors I corrected:
typo data-speeed="2" corrected to data-speed="2"
I preferred getBoundingClientRect() over window.innerWidth / window.innerHeight
The items being effected by parallax are centered using left, top, width, height, and negative margin-left and margin-top - this allows the transform.translate property to translate them relative to their centers
I wrapped all the logic into a nice applyParallax function, in case you wish to apply it to multiple section elements
I also had to make some changes to get this to work with stackoverflow's snippet system:
Instead of <img> I used <div class="img"></div>, with css to colour different div.img elements distinctly
I decreased the size of the div.img elements to make the effect more visible in the small window
I increased the values for data-speed to make the effect more obvious
I made the html and body elements fill the whole viewport (and the section element fills the whole body element)
let applyParallax = section => {
section.addEventListener('mousemove', e => {
let { width, height } = section.getBoundingClientRect();
let offX = e.pageX - (width * 0.5);
let offY = e.pageY - (height * 0.5);
for (let layer of document.querySelectorAll('.img')) {
const speed = layer.getAttribute('data-speed')
const x = (offX * speed) / 100;
const y = (offY * speed) / 100;
layer.style.transform = `translateX(${x}px) translateY(${y}px)`
}
});
section.addEventListener('mouseleave', e => {
for (let layer of document.querySelectorAll('.img')) {
layer.style.transform = `translateX(0px) translateY(0px)`
}
});
};
applyParallax(document.querySelector('section'));
html, body { position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; }
section {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
align-items: flex-end;
justify-content: flex-start;
}
section > .img {
position: absolute;
left: 50%; top: 50%;
width: 120px; height: 120px;
margin-left: -60px; margin-top: -60px;
}
section > .img.r { background-color: rgba(200, 0, 0, 0.5); }
section > .img.g { background-color: rgba(0, 200, 0, 0.4); }
section > .img.b { background-color: rgba(0, 0, 200, 0.3); }
<section class="container bot-container-img">
<div class="img r" data-speed="22"></div>
<div class="img g" data-speed="-5"></div>
<div class="img b" data-speed="32"></div>
</section>

Related

How to create an image that repeats for a js fade in and out background slideshow?

I am currently building a website and I want a aesthetically pleasing landing page with a background fade in and out slideshow comprised of pictures that repeat y and x. I have the fading slideshow working perfectly and all I need is to repeat the image across the screen. Adding background: repeat to the CSS does not work. Below is may code:
HTML:
<div class="mybody" id="slider">
<div>
<h2>Dog Adoption</h2>
<p>Find the perfect match for your new four legged companion</p>
</div>
</div>
JavaScript:
var curIndex = 0,
imgDuration = 3000,
slider = document.getElementById("slider"),
slides = slider.childNodes; //get a hook on all child elements, this is live so anything we add will get listed
imgArray = [
'../../static/main/images/slideshow/dog2.jpg',
'../../static/main/images/slideshow/dog3.jpg',
'../../static/main/images/slideshow/dog4.jpg',
'../../static/main/images/slideshow/dog1.jpg',
];
//
// Dynamically add each image frame into the dom;
//
function buildSlideShow(arr) {
for (i = 0; i < arr.length; i++) {
var img = document.createElement('img');
img.src = arr[i];
slider.appendChild(img);
}
// note the slides reference will now contain the images so we can access them
}
//
// Our slideshow function, we can call this and it flips the image instantly, once it is
called it will roll
// our images at given interval [imgDuration];
//
function slideShow() {
function fadeIn(e) {
e.className = "fadeIn";
};
function fadeOut(e) {
e.className = "";
};
fadeOut(slides[curIndex]);
curIndex++;
if (curIndex === slides.length) {
curIndex = 0;
}
fadeIn(slides[curIndex]);
setTimeout(function () {
slideShow();
}, imgDuration);
};
buildSlideShow(imgArray);
slideShow();
CSS:
.mybody{
width: 100%;
min-height: 100vh;
max-height: fit-content;
top: 0px;
left: 0px;
padding: 0px;
/*background: url(../images/slideshow/dog1.jpg);*/
display: flex;
justify-content: center;
align-items: center;
text-align: center;
margin: 0px;
position: relative;
background-repeat: repeat;
}
.mybody img {
transition: opacity 1.5s;
position: absolute;
left: 0;
top: 0;
opacity:0;
background-repeat: repeat;
}
.mybody img.fadeIn {
opacity:1;
}
When I just set the background image as a fixed image (no JS) I get the desired result:
However when I comment out the backgorund image (as in above code) and just have the JS slideshow as the background, this is the result:
I essentially just need this image from the second picture to repeat as in the first picture and cannot figure out how to make this happen although I am sure there is a simple fix/solution. If anyone could be of help it would be much appreciated. Thanks in advance!
You can't repeat an image without duplicating it. But you can repeat background so, you can make the slide using divs with background. Note the usage of css classes instead of jquery fade.
slide = 1;
setInterval(function() {
$(".slide").removeClass("active");
$(".div" + slide).addClass("active");
slide++
if (slide == 4) {
slide = 1;
}
}, 1000)
body {
height: 100vh;
width: 100%;
position: relative;
padding: 0;
margin: 0;
text-align: center;
padding: 30px;
}
.slide {
background-repeat: repeat;
background-size: 100px;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
opacity: 0;
transition: 1000ms all;
}
.slide.active {
opacity: 1;
}
.div1 {
background: url('https://picsum.photos/id/101/200');
}
.div2 {
background: url('https://picsum.photos/id/102/200');
}
.div3 {
background: url('https://picsum.photos/id/103/200');
}
.text {
position: relative;
z-index: 2;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<body>
<div class="slide div1">
</div>
<div class="slide div2">
</div>
<div class="slide div3">
</div>
<div class="text">
<h1>dog trainer</h1>
<p>best in the world</p>
</div>
</body>

How to make info text appear and follow the cursor when hovering over image?

For my portfolio website, I want to include info text that becomes visible when hovering over the according image and I want the text to follow along the cursor.
I'm by no means a coding expert, so I tried to achieve the effect by replacing the default cursor with an image of the text on white background via css and the cursor-property.
However, this left me with weird gray edged around the image that the image originally doesn't have.
So I figured that this was a sloppy approach anyway and that I should rather try solving it via javascript... which left me with the following code:
$(document).bind('mousemove', function(e){
$('#tail').css({
left: e.clientX + 20,
top: e.clientY + document.body.scrollTop
});
});
#tail {
position: absolute;
background-color: #ffffff;
padding: 5px;
opacity: 0;
}
#tail p {
margin: 0px;
}
.project-01:hover > #tail {
opacity: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="project-01">
<a href="project-site-01.html">
<img src="images/project-cover-01.png" alt="Project description">
</a>
<div id="tail">
<p>Project description</p>
</div>
</div>
I am now left with text that appears when hovering over the image and it follows the cursor properly, even if the cursor position changes due to scrolling (which it didn't do properly at first, which is why I added the 'document.body.scrollTop').
The only problem: The info text is way to far away from the cursor. I tried adjusting the offset, adding '- 900' after 'document.body.scrollTop' but that only makes it look right with my specific browser height – if I switch to a smaller or bigger screen, the '- 900' of course doesn't fit anymore.
Is there anyone who can explain what I'm doing wrong on a dummy level or even better – tell me how to fix the problem? I've been trying to get that hover text effect working for literally the past two days. HELP!
PS: You can see the effect I want to create on https://playgroundparis.com
I hope this can help you!
Edit: Technically this is a duplicated. I realized the problem with scrolling that you talking about. I've found a solution in this post and I readaptated it for
your specific case.
var mouseX = 0, mouseY = 0, limitX, limitY, containerWidth;
window.onload = function(e) {
var containerObjStyle = window.getComputedStyle(document.querySelectorAll(".project-01")[0]);
containerWidth = parseFloat(containerObjStyle.width).toFixed(0);
containerHeight = parseFloat(containerObjStyle.height).toFixed(0);
var follower = document.querySelector('#tail');
var xp = 0, yp = 0;
limitX = containerWidth;
limitY = containerHeight;
var loop = setInterval(function(){
//Change the value 5 in both axis to set the distance between cursor and text.
xp = (mouseX == limitX) ? limitX : mouseX + 5;
xp = (xp < 0) ? 0 : xp;
yp = (mouseY == limitY) ? limitY : mouseY + 5;
yp = (yp < 0) ? 0 : yp;
follower.style.left = xp + 'px';
follower.style.top = yp + 'px';
}, 15);
window.onresize = function(e) {
limitX = parseFloat(window.getComputedStyle(document.querySelectorAll(".project-01")[0]).width).toFixed(0);
}
document.onmousemove = function(e) {
mouseX = Math.min(e.pageX, limitX);
mouseY = Math.min(e.pageY, limitY);
}
};
//Change the 100 value to set the fade time (ms).
$(".project-01").hover(function () {
$(this).find('#tail').fadeIn(100);
},
function () {
$(this).find('#tail').fadeOut(100);
});
#tail {
position: absolute;
background-color: #ffffff;
padding: 5px;
overflow: hidden;
}
#debug {
position: absolute;
right: 0;
top: 100px;
width: 100px;
height:100px;
background-color: red;
color: black;
}
#tail p {
margin: 0px;
}
.project-01 {
width: 300px;
overflow: hidden;
}
.project-01 img {
height: 100%;
width: 100%;
}
.project-01 a {
height: 100%;
width: 100%;
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="project-01">
<a href="project-site-01.html">
<img src="https://picsum.photos/200/300" alt="Project description">
</a>
<div id="tail">
<p>Project descriptions</p>
</div>
</div>
You can use the below code's
.description {
display: none;
position: absolute;
z-index: 2000 !important;
color: black;
padding: 15px;
margin-left: 32px;
margin-top: -200px;
top: auto;
height: auto;
width: 500px;
}
.image {
height: 200px;
width: 200px;
}
.my-image:hover + .description {
display: block;
position: absolute;
background-color: black;
color: white;
}
.description:hover {
display: block;
background-color: black;
color: white;
}
<div class="project-01">
<a href="project-site-01.html" class="my-image">
<img src="https://homepages.cae.wisc.edu/~ece533/images/monarch.png" alt="Project description" class="image">
</a>
<div id="tail" class="description">
Butterflies are insects in the macrolepidopteran clade Rhopalocera from the order Lepidoptera, which also includes moths. Adult butterflies have large, often brightly coloured wings, and conspicuous, fluttering flight.
</div>
</div>
I hope this helps i recenty made one myselff for my website a few days ago
No info cursor:
.info:hover .tooltip {
color: red;
visibility: visible;
opacity: 1;
transition: opacity 1s
}
.tooltip {
visibility: hidden;
opacity: 0;
transition: opacity 1s
}
}
.tootip:hover {
visibility: visible
}
<span class="info"><img src="https://google.com/favicon.ico">Hover Me</img> <span class="tooltip">Welcome</span></a></span>
With info cursor:
.info:hover .tooltip {
color: red;
visibility: visible;
opacity: 1;
transition: opacity 1s
}
.tooltip {
visibility: hidden;
opacity: 0;
transition: opacity 1s
}
}
.tootip:hover {
visibility: visible
}
.info {
cursor: help
}
<span class="info"><img src="https://google.com/favicon.ico">Hover Me</img> <span class="tooltip">Welcome</span></a></span>

How to make a background change its position based on the position on the cursor

I am wanting to make a website that uses a background that moves based on the position that the curser is on the website. I have found this website that gives a visual representation of what I want to do. http://www.alexandrerochet.com/I just need to know how to make the letters move. I will replace them with images later.
You can achieve that using css properties.
Based on Lea Verou's talk
const root = document.documentElement;
document.addEventListener("mousemove", evt => {
let x = evt.clientX / innerWidth;
let y = evt.clientY / innerHeight;
root.style.setProperty("--mouse-x", x);
root.style.setProperty("--mouse-y", y);
});
html {
height: 100%
}
:root {
--mouse-x: .5;
--mouse-y: .5;
}
body {
height: 100%;
background-image: radial-gradient( at calc(var(--mouse-x) * 100%) calc(var(--mouse-y) * 100%), transparent, black);
}
You may want to try using parallax.js to achieve the desired effect.
Demo site.
Quick jsfiddle.
var scene = document.getElementById('scene');
var parallaxInstance = new Parallax(scene);
parallaxInstance.friction(0.2, 0.2);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
background-color: #F9F871;
width: 100vw;
height: 100vh;
}
.scene {
top: 30%;
}
.layer {
width: 100%;
height: 200px;
}
.item {
width: 50px;
height: 50px;
border-radius: 200px;
background-color: red;
position: relative;
}
.item-1 {
background-color: #FF9671;
left: 30%;
}
.item-2 {
background-color: #D65DB1;
left: 60%;
}
.item-3 {
background-color: #FF6F91;
left: 40%;
}
.item-4 {
background-color: #FFC75F;
left: 70%;
}
<div class="container">
<div id="scene" class="scene">
<div data-depth="0.2" class="layer layer-1">
<div class="item item-1"></div>
<div class="item item-2"></div>
</div>
<div data-depth="0.6" class="layer layer-2">
<div class="item item-3"></div>
<div class="item item-4"></div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/parallax/3.1.0/parallax.min.js"></script>

Resizing a rotated item with javascript (interact.js)

I have spent many days trying to make an item resizable that is rotated with interact.js.
This is the code that I have at this moment, I will try to explain the concept.
We have a selector item for two reasons, because the container could be scaled with css transform (like a zoom), and we need to have the selector outside and because we have a multiselection, and the selector grow if I have two rectangle selected, but in this case this is not the main problem and we have calculated the scaled proportion without problems and other things.
When the selector is resize, it take the rectangle, and make the same with the width, height, left, top and rotation.
Javascript:
// TAP - CLICK EVENT (just for positioning the selector)
interact('#rectangle').on('tap', event => {
console.log('Tap Box!');
event.stopPropagation();
const $rectangleCloned = $('#rectangle').clone();
const previousTransform = $rectangleCloned.css('transform');
$rectangleCloned.css('transform', 'none');
$rectangleCloned.css('opacity', '0');
$rectangleCloned.css('display', 'block');
$('#container').append($rectangleCloned);
const values = $rectangleCloned[0].getBoundingClientRect();
// This is just a trick for fast implementation:
$('#selector').css('top', values.y);
$('#selector').css('left', values.x);
$('#selector').css('width', values.width);
$('#selector').css('height', values.height);
$('#selector').css('transform', previousTransform);
$rectangleCloned.remove();
return values;
});
interact('.pointer9').draggable({
max: 1,
onmove: event => {
const angleDeg =
Math.atan2(
centerRotate.posY - event.pageY,
centerRotate.posX - event.pageX
) *
180 /
Math.PI;
console.log(this.rotate);
const prevAngle = this.rotate - angleInitial;
const angle = parseInt(angleDeg) + prevAngle;
this.$rectangle.css({
transform: 'rotate(' + angle + 'deg)'
});
this.$selector.css({
transform: 'rotate(' + angle + 'deg)'
});
},
onstart: event => {
const data = event.interactable.getRect(event.target.parentNode);
this.centerRotate = {
posX: data.left + data.width / 2,
posY: data.top + data.height / 2
};
this.angleInitial =
Math.atan2(
centerRotate.posY - event.pageY,
centerRotate.posX - event.pageX
) *
180 /
Math.PI;
this.$rectangle = $('#rectangle');
this.$selector = $('#selector');
this.rotate = $rectangle.attr('angle') || 0;
},
onend: event => {
const $box = $('#selector');
const matrix = $box.css('transform');
const values = matrix
.split('(')[1]
.split(')')[0]
.split(',');
var a = values[0];
var b = values[1];
var angle = Math.round(Math.atan2(b, a) * (180 / Math.PI));
$rectangle.attr('angle', angle);
}
});
interact('#selector')
.resizable({
// resize from all edges and corners
edges: {
left: true,
right: true,
bottom: true,
top: true
},
// keep the edges inside the parent
restrictEdges: {
outer: 'parent',
endOnly: true,
},
// minimum size
restrictSize: {
min: {
width: 100,
height: 50
},
},
inertia: true,
})
.on('resizemove', function(event) {
var target = event.target,
x = parseFloat($(target).offset().left) || 0,
y = parseFloat($(target).offset().top) || 0;
// update the element's style
target.style.width = event.rect.width + 'px';
target.style.height = event.rect.height + 'px';
// translate when resizing from top or left edges
x += event.deltaRect.left;
y += event.deltaRect.top;
target.style.left = x + 'px';
target.style.top = y + 'px';
$('#rectangle')[0].style.left = target.style.left;
$('#rectangle')[0].style.top = target.style.top;
$('#rectangle')[0].style.width = target.style.width;
$('#rectangle')[0].style.height = target.style.height;
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
});
CSS:
#container {
width: 500px;
height: 400px;
top: 0;
left: 0;
position: absolute;
background-color: #CCC;
}
#rectangle {
top: 50px;
left: 50px;
width: 120px;
height: 60px;
background-color: red;
position: absolute;
}
#selector {
display: inline-block;
position: absolute;
pointer-events: none;
z-index: 9999;
top: -1000px;
/*Not showing at start*/
}
#selector .pointers {
display: inline-block;
position: absolute;
z-index: 2;
width: 10px;
height: 10px;
pointer-events: all;
}
#selector .pointers .point {
width: 10px;
height: 10px;
background-color: #fff;
border: 2px solid rgba(0, 0, 0, 0.9);
border-radius: 50%;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
#selector .pointers.pointer1 {
top: -5px;
left: -5px;
}
#selector .pointers.pointer2 {
bottom: -5px;
left: -5px;
}
#selector .pointers.pointer3 {
top: -5px;
right: -5px;
}
#selector .pointers.pointer4 {
bottom: -5px;
right: -5px;
}
#selector .pointers.pointer-north {
top: -5px;
left: calc(50% - 5px);
}
#selector .pointers.pointer-south {
bottom: -5px;
left: calc(50% - 5px);
}
#selector .pointers.pointer-east {
right: -5px;
top: calc(50% - 5px);
}
#selector .pointers.pointer-west {
left: -5px;
top: calc(50% - 5px);
}
#selector .pointer-rotate {
border: 2px solid rgba(0, 0, 0, 0.9);
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 50%;
cursor: rotate;
}
#selector .pointer9 {
bottom: -70px;
left: calc(50% - 11px);
display: inline-block;
width: 20px;
height: 20px;
background-color: #fff;
pointer-events: all;
position: absolute;
}
#selector .rotate-line {
border-left: 1px dashed #5f5f5f;
height: 40px;
position: absolute;
top: -40px;
left: calc(50% - 1px);
width: 1px;
}
HTML:
<div id="container">
<div id="rectangle">
</div>
<div id="selector">
<div class="pointers pointer1">
<div class="point"></div>
</div>
<div class="pointers pointer2">
<div class="point">
</div>
</div>
<div class="pointers pointer3">
<div class="point">
</div>
</div>
<div class="pointers pointer4">
<div class="point">
</div>
</div>
<div class="pointers pointer-north">
<div class="point">
</div>
</div>
<div class="pointers pointer-east">
<div class="point">
</div>
</div>
<div class="pointers pointer-south">
<div class="point">
</div>
</div>
<div class="pointers pointer-west">
<div class="point">
</div>
</div>
<span class="topline lines-resize" />
<span class="rightline lines-resize" />
<span class="botline lines-resize" />
<span class="leftline lines-resize" />
<div class="pointer-rotate pointer9" />
<div class="rotate-line" />
</div>
</div>
Fiddle for testing:
https://jsfiddle.net/ub70028c/46/
I have read about other people trying to make the same without not results...
Thanks!
I checked your code and a similar library for resizable and rotatable and I figure out your problem.
First, checking similar library:
Please see this fiddle that I created by jquery.freetrans.js.
If you inspect on <div class="shape">, you can see
transform: matrix(1, 0, 0, 1, 0, 0);
If you rotate it, transform changed like below:
transform: matrix(0.997373, -0.0724379, 0.0724379, 0.997373, 0, 0);
In similar case, your code uses transform that at first, it doesn't transform and after rotating, it has like below:
transform: rotate(-2.49576deg);
If you can use matrix instead of rotate in transform, your code will work properly. If you can't change it, you can use similar library like jquery.freetrans.jsthat work properly with rotate and resize together.
https://github.com/taye/interact.js/issues/569
https://github.com/taye/interact.js/issues/499
https://github.com/taye/interact.js/issues/394
I am afraid you have chosen a library whose author has clearly stated his intent
There's no built-in way. As I mentioned in #137 I'm not really interested in handling scaled or rotated elements
So the question you should ask yourself is
Do I want to find a workaround to make this library work or choose a different library perhaps?
Update-1: 28-Apr-2018
In case you want to do it in canvas instead of normal elements then I found fabric.js a good option
we are very close to finish the work after five days... we need to optimice all the mathematical calculations... but yes, this is what I was looking for:
Sorry, but we don't have the code ready... I will post all with comments for other people.
Comments: For a mathematician, this task is not very complex because all the angles are rectangular (90º). I will try to make a PR to the Interact.js, even to other libraries to implement this feature by default. Hope this work help to other developers ;)

maintain aspect ratio of a child div with both height and width changes of the parent

I want to create a div that maintains aspect ratio with height and width changes of the parent.
In the above gif, you can see that I was able to maintain the box div's aspect ratio when changing width but I'm unable to maintain it when changing height of the parent.
.box {
width: 100px;
background-color: #dfdfdf;
max-width: 100%;
}
.box:after {
content: '';
display: block;
width: 100%;
height: 100%;
padding-bottom: 160%;
}
.wrap9 {
width: 125px;
height: 190px;
}
<div class="wrap9">
<div class="box"></div>
</div>
I want the grey box to behave like the following:
With your default width and height:
.box {
width: 100px;
background-color: #dfdfdf;
max-width: 100%;
max-height:100%;
}
.box:after {
content: '';
display: block;
width: 100%;
height: 100%;
padding-bottom: 160%;
}
.wrap9 {
width: 150px;
height: 200px;
border: 1px solid black;
}
<div class="wrap9">
<div class="box"></div>
</div>
width lower width and height:
.box {
width: 100px;
background-color: #dfdfdf;
max-width: 100%;
max-height:100%;
}
.box:after {
content: '';
display: block;
width: 100%;
height: 100%;
padding-bottom: 160%;
}
.wrap9 {
width: 100px;
height: 120px;
border: 1px solid black;
}
<div class="wrap9">
<div class="box"></div>
</div>
Is this the desired effect?
I'd have to say that this is not currently possible. While you can use calc() and variables, there is no way to keep a dynamic reference to object's current width nor height.
When I looked at doing this with js there was no clean way either. You'll just have to write an interval to periodically check if width or height of parent element has changed.
Google is pushing a dom element observer but the spec is currently very limited.
The funny thing is, just like in your example, images do this by default. However, there seems to be absolutely no clean way of doing this with another element.
You can use JavaScript to calculate the ratio of the width and the height between you object and the parent object. Then your can either scale to FILL the parent object (think CSS background-size: contain;) or scale to FIT the parent object (CSS: background-size: cover;)
Example of the two type of scaling methods.
(A) The left shows SCALE-TO-FILL and (B) on the right we are using SCALE-TO-FIT.
// Find the ratio between the destination width and source width.
RATIO-X = DESTINATION-WIDTH / SOURCE-WIDTH
// Find the ratio between the destination height and source height.
RATIO-Y = DESTINATION-HEIGHT / SOURCE-HEIGHT
// To use the SCALE TO FILL method,
// we use the greater of the two ratios,
// let's assume the RATIO-X is greater than RATIO-Y.
SCALE-W = RATIO-X * SOURCE-WIDTH
SCALE-H = RATIO-X * SOURCE-HEIGHT
// To use the SCALE TO FIT method,
// we use the lesser of the two ratios,
// let's assume the RATIO-Y is less than RATIO-X.
SCALE-W = RATIO-Y * SOURCE-WIDTH
SCALE-H = RATIO-Y * SOURCE-HEIGHT
When your parent object scales, you will need to determine these ratios.
Take a look at the embedded example and you can see how it works.
var $parent = $('.parent'),
$child = $('.child'),
w = $parent.width(),
h = $parent.height(),
cw = $child.width(),
ch = $child.height(),
winc = -10,
hinc = -5;
/*
This function is what you need.{
First we grab the ratio for the width (rx).
Then the ratio for the height (ry).
To scale to FIT, we want the MIN of the two.
To scale to FILL, we want the MAX of the two.
r is used to calculate the new size for ther child obj.
*/
function calcChildSize() {
var rx = w / cw,
ry = h / ch,
r1 = Math.min(rx, ry),
r2 = Math.max(rx, ry);
$('.child.fit').css({
width: r1 * cw,
height: r1 * ch
});
$('.child.fill').css({
width: r2 * cw,
height: r2 * ch
});
}
// just a simple function to change the size
// of the parent object
window.setInterval(function() {
if (w < 70) {
winc = 10;
} else if (w > 200) {
winc = -10;
}
if (h < 50) {
hinc = 5;
} else if (h > 200) {
hinc = -5;
}
w += winc;
h += hinc;
$parent.css({
width: w,
height: h
});
calcChildSize();
}, 100);
.parent {
display: inline-block;
width: 200px;
height: 200px;
border: 1px solid #aaa;
margin-right: 50px;
}
.child {
box-sizing: border-box;
width: 50px;
height: 70px;
background: rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 0, 0, 0.5);
text-align: center;
font-family: monospace;
font-size: 11px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent fit">
<div class="child fit">FIT</div>
</div>
<div class="parent fill">
<div class="child fill">FILL</div>
</div>
Edit #2: I also went ahead and added an example of the two different scale methods in action.
Add max-width: 100% and object-fit:cover, here's a link https://jsfiddle.net/jv1f4bhL/1/
body {
position: relative;
background-color: wheat;
padding: 0;
margin: 0;
}
img {
object-fit: cover;
max-width: 100%;
width: auto;
}
<img src="https://mdbootstrap.com/img/Others/documentation/img%20(7)-mini.jpg" />
.box {
max-height: 100%;
}
....worked perfect.

Categories