If I assume that the background position will always be in the format:
0px 0px; or 10px 11px; So, *number*px *number*px.
How can I get both the x position and the y position in Javascript?
Given the following HTML:
<div id="demo"></div>
And CSS:
div {
height: 500px;
width: 500px;
margin: 0 auto;
background: #fff url(http://placekitten.com/300/300) 50% 50% no-repeat;
}
The following JavaScript works:
var demo = document.getElementById('demo'),
_tmp = window.getComputedStyle(demo,null).backgroundPosition.trim().split(/\s+/),
positions = {
'left' : _tmp[0],
'top' : _tmp[1]
};
console.log(positions, positions.left, positions.top);
JS Fiddle demo.
The above approach does require a browser that supports window.getComputedStyle() (obviously), and trim() (though that could be replaced with a replace(/^\s+|\s+$/g,'')).
To get access to the units, and numbers, independently I'd suggest creating other objects within the overall object to hold those numbers, and units:
var demo = document.getElementById('demo'),
_tmp = window.getComputedStyle(demo,null).backgroundPosition.trim().split(/\s+/),
positions = {
'left' : _tmp[0],
'top' : _tmp[1],
'numbers' : {
'left' : parseFloat(_tmp[0]),
'top' : parseFloat(_tmp[1])
},
'units' : {
'left' : _tmp[0].replace(/\d+/,''),
'top' : _tmp[1].replace(/\d+/,'')
}
};
console.log(positions, positions.left, positions.top, positions.numbers.left, positions.numbers.top, positions.units.left, positions.units.top);
JS Fiddle demo.
As to what would happen if there was no background-position set? Well, why not try that, with the following CSS:
div {
height: 500px;
width: 500px;
margin: 0 auto;
background-color: #fff;
background-image: url(http://placekitten.com/300/300);
background-repeat: no-repeat;
}
In Chromium it seems that you get the default background-position of 0% 0% (and corresponding numbers and units): JS Fiddle demo.
References:
JavaScript Regular Expressions.
String.parseFloat().
String.replace().
String.split().
String.trim().
window.getComputedStyle().
Related
I want to make an animation on my product page. When user clicks "add to cart" the product image will be animated moving and shrinking to the cart icon in the nav bar.
Here is a sample html
$('div.test').on('animationend', (e) => {
$(e.target).remove();
})
//user click
$('div.test').addClass('animateTest');
.test {
position : fixed;
top : 200px;
left : 600px;
background : red;
width : 200px;
height : 300px;
}
#keyframes toCart {
25% {
top : 850px;
left : 550px;
width : 200px;
height : 300px;
}
100% {
top : 100px;
left : 1100px;
width : 0;
height : 0
}
}
.animateTest {
animation : toCart 2s;
/* animation-fill-mode: forwards; */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="test">
</div>
The hard part is, since users' viewports vary, I probably need to use javascript to get the cart icon's position(unless I can get it from CSS which I don't think is possible):
whereIsCart = $('#cartIcon').offset()
and I need to do something like
100% {
top : whereIsCart.top;
left : whereIsCart.left;
width : 0;
height : 0
}
But how can I do this?
Or, is there any better practice to achieve the same goal?
It may be easier to use css transitions instead of keyframe animations:
.test {
// ...
transition: transform 1s ease-in-out;
}
// on click
whereIsCart = $('#cartIcon').offset();
$('div.test').css('transform', 'translate(' + whereIsCart.left + 'px, ' + whereIsCart.top + 'px) scale(0)');
When working with CSS in JavaScript you may want to use the CSSOM API; more specifically, its factory functions for unit values, e.g. CSS.px(), CSS.percent().
Note that parts of the CSSOM API are still experimental, e.g. the factory functions. In production, you should make sure that the target browsers support the features you use.
Regardless of using CSS or JS for the animation itself: To get the element's current position in the viewport you can use Element.getBoundingClientRect(), or more generally Element.getClientRects() for all its relevant boxes.
CSS Custom Properties
You can use custom properties for the initial position. You can set them via JavaScript, and even provide a fallback value in CSS.
If you use them for the animating (not as animated) properties, it should just work:
const divTest = document.querySelector("div.test");
// Example for non-empty custom properties
divTest.style.setProperty("--top", CSS.px(20));
divTest.style.setProperty("--left", CSS.px(80));
// Should happen on click:
toCart(divTest);
function toCart(element) {
const rect = element.getBoundingClientRect();
element.style.setProperty("--top", CSS.px(rect.top));
element.style.setProperty("--left", CSS.px(rect.left));
element.classList.add("animateTest");
}
.test {
position: fixed;
top: var(--top, 10%);
left: var(--left, 10%);
width: 200px;
height: 300px;
background: red;
}
#keyframes toCart {
25% {
top: 80%;
left: 50%;
width: 200px;
height: 300px;
}
100% {
top: 10%;
left: 100%;
width: 0;
height: 0;
}
}
.animateTest {
animation: toCart 2s;
}
<div class="test"></div>
Sidenote: If you want to animate custom properties themselves, you have to define the in a #property rule. Otherwise CSS cannot animate it since its type may be anything (animating e.g. from a length to a color is impossible).
Web Animations API
In JavaScript, you can use the Web Animations API, which is essentially CSS animations but in JS.
You can define keyframes, duration, fill-mode and more. Since Animation.finished is a promise, you can simply react to the animation's end via await or Promise.then().
Example:
const divTest = document.querySelector("div.test");
// Should happen on click:
const animation = animateToCart(divTest);
animation.finished.then(() => console.log("Animation finished. This could start a new animation!"));
function animateToCart(element) {
const rect = element.getBoundingClientRect();
const keyframes = [
{
offset: .25,
top: CSS.percent(80),
left: CSS.percent(50),
width: CSS.px(rect.width),
height: CSS.px(rect.height)
}, {
top: CSS.percent(10),
left: CSS.percent(100),
width: 0,
height: 0
}
];
return element.animate(keyframes,
{
duration: 2000,
easing: "ease" // Is default in CSS, but not in Web Animations...
}
);
}
.test {
position: fixed;
top: 10%;
left: 10%;
width: 200px;
height: 300px;
background: red;
}
<div class="test"></div>
Multi-step animations are also easily done with Web Animations, since you can start another animation after the first animation's promise has resolved.
CSS variables sample code...
const
bluElm = document.querySelector('#blue_elm')
, btAnim = document.querySelector('#bt-anim')
, btMovE = document.querySelector('#bt-movE')
, elTest = document.querySelector('.test')
;
btMovE.onclick = () =>
{
bluElm.classList.toggle('move');
}
btAnim.onclick = () =>
{
let rect = bluElm.getBoundingClientRect();
/* change CSS variables values as style Property ------------- */
elTest.style.setProperty('--p_top', `${rect.bottom}px`);
elTest.style.setProperty('--p_left', `${rect.left}px`);
elTest.classList.add('animateTest');
}
elTest.onanimationend = () =>
{
elTest.classList.remove('animateTest');
}
#blue_elm {
position : fixed;
top : 20px;
left : 300px;
width : 20px;
height : 20px;
border-radius : 10px;
background : cornflowerblue;
}
#blue_elm.move {
top : 50px;
left : 150px;
}
.test {
position : fixed;
top : 200px;
left : 600px;
background : red;
width : 200px;
height : 300px;
--p_top : 0; /* CSS variables declaration */
--p_left : 0;
}
.animateTest {
animation : toCart 2s;
}
#keyframes toCart {
25% {
top : 850px;
left : 550px;
width : 200px;
height : 300px;
}
100% {
top : var(--p_top); /* CSS variables usage */
left : var(--p_left);
width : 0;
height : 0
}
}
<button id="bt-anim"> show animation</button>
<button id="bt-movE"> move element +- 150px</button>
<div id="blue_elm"></div>
<div class="test"></div>
I have a mini-question concerning the return value of transform-origin in javascript :
I have a simple div with a transform-origin set to 0 0 via CSS and i'm trying to console.log() the div.style.transformOrigin but I get nothing, not even an error... What am I doing wrong ?
In here link it says "Return the transformOrigin property: object.style.transformOrigin".
That's what I'm trying to do...
let div_1 = document.querySelector('#div1');
console.log('the transform origin is : ', div_1.style.transformOrigin);
#div1 {
width: 100px;
height: 300px;
transform-origin: 0 0;
background-color: red;
}
<div id="div1">hello</div>
In the reliable source we can read that:
The style read-only property returns the inline style of an element in the form of a CSSStyleDeclaration object that contains a list of all styles properties for that element with values assigned for the attributes that are defined in the element's inline style attribute.
Try using:
getComputedStyle(div_1).getPropertyValue('transform-origin')
element.style works only if you modify it directly, not on the class or id
let div_1 = document.querySelector('#div1');
console.log('the transform origin is : ', getComputedStyle(div_1).getPropertyValue('transform-origin'));
#div1 {
width: 100px;
height: 300px;
transform-origin: 0 0;
background-color: red;
}
<div id="div1">hello</div>
Sidenote: w3schools isn't a reliable source of information
let div_1 = document.querySelector('#div1');
div_1.style.transformOrigin = '0 0'
console.log('the transform origin is : ', div_1.style.transformOrigin);
#div1 {
width: 100px;
height: 300px;
background-color: red;
}
<div id="div1">hello</div>
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
In this case I would need to remove top, background-image, and background-color:
<div id="div1" style="position: relative; font-size: 24px; left: 175px; width: 400px; height: 200px; top: 0; background-image: none; background-color: none; background-position: 50% 50%;" > New Element </div>
you can change style attribute
jQuery('#div1').attr('style','position: relative; font-size: 24px; left: 175px; width: 400px; height: 200px; background-position: 50% 50%;')
You can use attr() with callback to update inline css
$('#div1').attr('style', function(i, v) {
return v.split(';')
// split css value by `;` to get each property
.filter(function(val) {
// filtering values
var str = $.trim(val.split(':')[1]);
// getting property value and trimming to avoid spaces
return !(str == 0 || str == 'none' || str == '');
// checking property value is 0, none or '' , based on this filtering is done
}).join(';');
// joining splitted array and return back for updating style property
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="div1" style="position: relative; font-size: 24px; left: 175px; width: 400px; height: 200px; top: 0; background-image: none; background-color: none; background-position: 50% 50%;">New Element</div>
Using css() with empty string or invalid values will remove those from style attribute
$('#div1').each(function () {
var $el = $(this),
top = $el.css('top'),
bgImg = $el.css('backgroundImage'),
bgColor = $el.css('backgroundColor');
$el.css({
top: top && top === '0px' ? '' : top,
backgroundImage :bgImg =='none' ?'' : bgImg,
backgroundColor:bgColor =='none' ?'' : bgColor
});
});
DEMO
As you can see there is a slide to the left and the with decreases from 100% to 0 at the same time.
I want to get this same effect but from left to right.
I can't get it right!
jQuery('#target').animate({ width: '0', left: '-25%' }, 1500, 'swing');
Example Fiddle: http://jsfiddle.net/RsBNk/
That is pretty simple. Align the image to the right and then decrease it by 25% using jQuery like below:
jQuery:
jQuery('#target').animate({ width: '0', right: '-25%' }, 1500, 'swing');
CSS:
.box {
width: 100%;
position: absolute;
top: 0;
right: 0; /* Modified this line */
height: 200px;
background-image: url('http://images.icnetwork.co.uk/upl/uxbridgegazette/jul2012/0/4/marc-mccarroll-image-2-304314157.jpg');
background-position: right; /* EDIT: This property needs to be set */
}
Updated Demo
May be this helps you
$('#target').animate({
width : '0',
marginLeft: parseInt($('#target').css('marginLeft'),10) == 0 ?
$('#target').outerWidth() : 0
}, 1500, 'swing');
check demo
I'm now in problem about how to animate function in jQuery to expand proportionally. Normally, it expand one-sided only just like expand to bottom or expand to right.
What I want is to expand proportionally left-right-top-bottom by using animate.
Following is my coding. What I said above, it expand to bottom only.
$(document).ready(function() {
var theFrame = $("#FrmPatient", parent.document.body);
theFrame.animate({width: 650, height: 485}, 1000);
});
Try this:
<div id="frame"></div>
#frame {
position: absolute;
left: 50%;
top: 50%;
margin: -100px 0 0 -100px;
width: 200px;
height: 200px;
background-color: #999;
}
$(function() {
var w = 400, h = 400;
$("#frame").animate({
width: w,
height: w,
marginLeft: -w/2,
marginTop: -h/2
}, 1000);
});
http://jsfiddle.net/GVj83/
You'll need to animate the left and top properties as well. If the original width and height of the box are (w0, h0) and the expanded ones are (w1, h1), animate left to left-(w1-w0)/2, and top to top-(h1-h0)/2. Note that would only work with absolute or relative positioning.