How to show fixed elements inside a web-animation-api transformed parent - web-animations

I have a parent div transformed with the web-animations-api.
This makes the containing block, of any child fixed elements the parent rather than the viewport (as expected).
The parent transforms to translate3d(0, 0, 0) ... so just removing the animation/transform on complete would be perfect.
I cant find a simple* way to do this through the web-animations-api, is there one?
Previously this was done via CSS, or inlined styles & hence easy to remove on complete.
I have tried ..
amination.cancel(), inside animation.finished, but rapidly applying another animation to the
same el, breaks ... looks like fill mode flips from 'forward' to 'none'
adding an additional transform on animation.finished. This seems to work but messy.
el.animate([
{ transform: 'unset' },
{ transform: 'unset' },],
{
duration: 0,
fill: 'forwards'
}
)

Related

Framer Motion text gets distorted when animating with shared layouts

I am in a Next.js enviornment and have wrapped my _app.js with .
Inside a page I have a basic routing set up to jump from page 1 to page 2.
On each page I have a motion h1 which looks like. So there are two components with matching ID's.
const stats = {
visible: {
opacity: 1,
},
hidden: {
opacity: 1,
},
exit: {
opacity: 0,
y: 50,
},
}
<motion.h1
initial="hidden"
animate="visible"
variants={stats}
layout
className="text-3xl text-gray-800 font-bold"
layoutId={`product-title-${data.title}`}
>
{data.title}
</motion.h1>
When I navigate pages the elements animate from their counter parts previous position.. but the text gets all distorted when animating.
How do I fix the distorted text?
You can try giving the value of "position" to your layout prop, instead of true.
layout="position"
As referred in the framer motion documentation
If layout is set to "position", the size of the component will change instantly and only its position will animate.
Since you are animating only position and opacity, it could solve your issue.

Angular / CSS style change width of row items

I am conceiving a horizontal bar containing items.
They must all be of same width, having the same spacing between them.
They can expand as much as they want vertically (
stackblitz here
Problem:
How to automatically set the width of the row elements? Here I simply put a value that looks good: width:200px.
I want them to have a width dependent on the number of element per row.
What I tried:
Using elementRef in Horizontile (component holding the individual tiles, displaying with *ngFor) to get the width of this element:
currentWidth:number;
constructor(private el:ElementRef) {}
ngAfterViewInit(): void {
this.currentWidth=this.el.nativeElement.offsetWidth;}
it returns 5. (??) Using .width returns nothing. Also this is not recommended, I'd like another solution, less coupling.
I noticed I can make use of width:inherit; in the css of the individual tile component, which allows me to set the style from the horizontal list component.
<app-tile [style.width.px]="0.9*currentWidth/nDisplayedTiles" [tile]="item"></app-tile>
As the currentWidth value is zero, of course it doesn't work;
I tried setting it in % but the inherits css tag keeps the %, which is not the intended effect.
Why is the app-tile styling not cared about if inherits is not set?
I tried using ViewEncapsulation but it had no effect either.
This looks like a trivial matter though: did I just miss something?
You can use the offsetParent (link) width and create a method to return the value on each of the cells and call it in your [style.width.px], something like the following will work.
The HTMLElement.offsetParent read-only property returns a reference to the element which is the closest (nearest in the containment hierarchy) positioned ancestor element.
stackblitz
ngAfterViewInit(): void {
//added this as the compiler was throwing ExpressionChangedAfterItHasBeenCheckedError
setTimeout(() => {
this.currentWidth=this.el.nativeElement.offsetParent.clientWidth;
});
}
getWidth(): number{
let width:number = 0;
//you may need to change this value to better display the cells
let multiplier = 0.7;
width = (this.currentWidth * multiplier) / this.ndisplayTiles;
width = Math.round(width);
return width;
}
<app-tile [class]="'layout-tile'" [tile]="item" [style.width.px]="getWidth()">
</app-tile>

Use Web Animations API to expand div height 0 --> 'auto'

I'm trying to get my head around the web animations standard and their polyfill, as I saw it work nicely in the Angular animations library (you set an animation end value to '*' and this becomes 100% of the div size, but that uses a special Angular Animations DSL).
I thought I would start with something simple, so all I want to do is expand a div from 0 height to 'auto'. i know there are thousands of other ways to do this, but I was trying to use web-animations-js with this code
The code below (which resembles an MDN example) causes the div to expand directly to 'auto' but after a 1 second delay, whereas I want it smoothly to expand.
let formDiv = document.querySelector("#new-present-form");
formDiv.animate([
{ height: 0},
{ height: 'auto'}
], {
easing: 'ease-in-out',
duration: 1000,
fill: 'forwards' // ensures menu stays open at end of animation
})
By contrast this
formDiv.animate({
height: [0, '100%'],
easing: 'ease-in-out'
}, {
duration: 1000,
fill: 'forwards' // ensures menu stays open at end of animation
})
causes the div to expand immediately, but again with no smooth transition.
This does give a smooth transition, but requires a carefully chosen value to replace '300px' and is precisely what I want to avoid.
formDiv.animate([
{ "height": '0px', offset: 0},
{ "height": '300px', offset: 1}
], {
duration: 1000,
iterations: 1,
fill: 'forwards' // ensure form stays open at end of animation
})
Unfortunately, it is not directly possible to do this with Web Animations or CSS animations/transitions yet. That is because CSS does not have a means to represent an intermediate state between an 'auto' length and a fixed length. The proposal to fix this involves allowing 'auto' inside calc(), e.g. calc(auto + 36px). You can follow the progress of this development on the CSS Transitions Github issue.
In the interim, many people have been able to work around this by animating max-height instead. For example, if you expect your 'auto' height to be somewhere between 300px and 600px, then you could leave height as 'auto', and animate max-height from '0' to '700px'. It's not perfect, but for a short animation it's often close enough.
Alternatively, one could set the height to auto, get the used value of the height using getComputedStyle, and, supposing it returned 375px, create an animation from, height: '0' to height: '375px'. If you do not specify a fill on the animation then when it completes, the computed value of the height will switch from height: 375px to height: auto (which should make no visual difference but mean that the element's height responds to future changes in the content size).
Regarding the error about partial keyframes, that is a short-term issue where both Firefox and Chrome have not shipped support for omitting the first or last keyframe. Both Firefox and Chrome have implemented this feature and it should ship this year, however, it still won't fix this issue until auto is permitted in calc().
Update 22 May with (completely untested) code samples as requested:
// Option 1: Use max-height
formDiv.animate(
{ maxHeight: ['0', '700px'] },
{ easing: 'ease-in-out', duration: 1000 }
);
// Option 2: Use used height
//
// (Beware, flushes layout initially so will probably not be very performant.)
formDiv.style.height = 'auto';
const finalHeight = getComputedStyle(formDiv).height;
formDiv.style.height = '0';
formDiv.animate(
{ height: ['0', finalHeight] },
{ easing: 'ease-in-out', duration: 1000 }
);
Of course if you don't actually have anything below the div you might be able to
get away with a transform animation which will definitely be the most
performant.
// Option 3: Use scale-y transform
formDiv.style.transformOrigin = '50% 0%';
formDiv.animate(
{ transform: ['scaleY(0)', 'scaleY(1)'] },
{ easing: 'ease-in-out', duration: 1000 }
);
If height is not mandatory you can try giving padding to the div.
#keyframes example {
from{padding:0px;}
to{padding: 50px;}
}
Vote up if it was help full.

How to override position of primefaces OneMenu?

How to override primefaces OneMenu in order to see it over captcha, ie below? My selectOneMenu have no any changes.
My guess is that the menu panel doesn't have enough space to fit in the lower part, instead it's positioned above, as the aligning of the panel is being set by javascript (PrimeFaces.widget.SelectOneMenu.alignPanel), using the jQuery UI .position() method which allows you to position an element relative to the window, document, another element, or the cursor/mouse, without worrying about offset parents, and the default value for collision attribute is flip (In PrimeFaces 5 it's flipfit) resulting the positioned element overflows the window in some direction, or to move it to an alternative position.
In this case you could implement one of these three solutions:
extend the space on the lower part, maybe adding margin to the
captcha, in this way the panel would fit in bottom.
OR change the hight of the panel
<p:selectOneMenu height="100" >
Making it a bit shorter so it can fit.
OR you can override the PrimeFaces.widget.SelectOneMenu.alignPanel function
to set the collision attribute to none, in the position function:
PrimeFaces 5
PrimeFaces.widget.SelectOneMenu.prototype.alignPanel = function() {
if(this.panel.parent().is(this.jq)) {
this.panel.css({
left: 0,
top: this.jq.innerHeight()
});
}
else {
this.panel.css({left:'', top:''}).position({
my: 'left top'
,at: 'left bottom'
,of: this.jq
,collision: 'none' // changing from flipfit to none
});
}
}
PrimeFaces 4
PrimeFaces.widget.SelectOneMenu.prototype.alignPanel = function() {
var fixedPosition = this.panel.css('position') == 'fixed',
win = $(window),
positionOffset = fixedPosition ? '-' + win.scrollLeft() + ' -' + win.scrollTop() : null;
this.panel.css({left:'', top:''}).position({
my: 'left top'
,at: 'left bottom'
,of: this.jq
,offset : positionOffset
,collision: 'none' // changing from default flip to none
});
}
Of course you should call it in the document.ready, and when you update the component.
I don't recommend this approach too much, but sometimes it's the only solution.
Hope this helps.
For necessary SelectOneMenu add style top find an optimal value and apply it. For me it is:
#registrationForm\:facultyList_panel {
top: 413px !important;
}
UPDATE 09.07: It does not helps for another screen resolution. The question is still relevant.

CSS3 height transition on DOM removal?

Please check the following fiddle: http://jsfiddle.net/tWUVe/
When you click the div, the p's get deleted, and I expect that the div's height will be animted, but no animation happens. How can I achieve an animation with CSS3 only?
The issue is that there is no opportunity for the transition to occur. What I mean by this is that when elements are removed, they are immediately taken out of the document flow, resizing the parent if needed without a transition.
As a fix for this, you could animate the height of the paragraphs instead (or a similar means)
$('div').click(function() {
var $thisDiv = $(this);
$thisDiv.find('p').css({'height':'0px','margin':'0px'}); // Change p height
// Remove after transition
setTimeout(function() { $thisDiv.find('p').remove(); }, 1000);
});
Demo

Resources