How to fix position of mat-select-panel in Angular Material - javascript

I have a project in which I use Angular Material Components and I would like to customize mat-select. I want to achieve select input which mat-select-panel looks like it's dropdown as in native html select. I accomplished good effect using only CSS styles but I have one problem.
The problem is that my mat-select looks different depending on the size of the browser window. More specifically, mat-form-field and mat-select-panel sometimes are not aligned (there left sides are not in line) and this is not acceptable in my project.
This link is how it should look (example: Firefox browser, window size 100%):
This link is what I want to fix(example: Firefox browser, window size 90%):
My predictions why it does not work:
mat-select-panel has a position absolute and is set to position depending on cdk-overlay-panel. Cdk-overlay-panel position is calculated dynamically. Sometimes fractional width and height values are truncated and hence the difference of one pixel between mat-form-field and mat-select-panel. This is an example:
What I want to achieve?
I am looking for a way to make my input always look good regardless of the browser window size. Line between mat-form-field and mat-select-panel must always be straight.
Stackblitz for my input is here:
a link

Love the attention to detail in your observation... I've had a customer with such an eye also :) ... on checking your stackblitz, we observe the following which is a bigger issue which needs resolution:
Commented your CSS .container>*{ position: absolute; top: 30vh; left: 30vw; } with the following to observe the effect of mis-aligned few pixels on zooming in/out on the browser:
.myMatOptions{ position: absolute; top: 30vh; left: 30vw; }
::ng-deep .cdk-overlay-container{left: 30vw;}
::ng-deep .cdk-overlay-pane { left:0 !important; transform:none !important;}
::ng-deep .mat-select-panel{left: 0}
on a zoom of 80%, we see:
on a zoom of 90%, we see a minor mis-alignment in the rendered output:
on a zoom of 100%, we see:
on a zoom of 110%, we see a minor mis-alignment in the rendered output:
on a zoom of 125%, we see:
These minor visual issues (on 90% and 110%) are on the rendered output - the css behind these is exact so there is nothing fundamental to resolve. working stackblitz here

Related

How to use innerHeight for div on both window load & resize?

I am trying to determine the top/bottom padding of a div (.content) based on it's height, and to recalculate it based on load AND resize of the window. This is supposed to align nicely centered next to another div (.character) beside it.
I've tried using CSS calc, but in this case it doesn't do exactly what I want it to do since the syntax doesn't support operators and I have a few media queries that change the size of the font based on the viewfinder, so the height of the .content div is somewhat dynamic.
Below is the JS portion, but here is the JSFiddle of what I've done so far: https://jsfiddle.net/inochiishtal/a9z13fb2/62/
$(function(){
$.w = $(window);
$.w.on('load resize', res);
res();
});
function res() {
$('.content').css('height',($.w.innerHeight()/2)+'px');
}
Any help or suggestions are appreciated. I'm not 100% dedicated to using innerHTML if there is a better solution.
It's a little unclear exactly how you want the items aligned, but based on what you said it seems like you want the .content and the .character to be vertically center aligned with each other.
In your snippet you have both of them absolutely positioned. If that's the way you want to go, you can just ignore their margins and JavaScript in general with this little vertical centering trick applied to both:
top: 50%;
transform: translateY( -50% );
The first line says "Put the top of this element 50% of the way down the element that it's positioned based on." Since it goes by the top, the second line says "Scoot me back up 50% of my height." That's just the way those CSS properties work -- the "top" % is about its parent, and the translateY % is about itself.
Since both of your elements would be vertically centered in their parent, they'd be aligned.
https://jsfiddle.net/qowxezpy/
HOWEVER if you don't need the elements to overlap like they do in this example (which I think looks nice and modern) there's a much easier way, using flex.
The parent would get:
display: flex;
align-items: center;
And the two children get:
flex-basis: 50%; //just to give them some width, since one is empty

Chart.js in flex element overflows instead of shrinking

I have tried setting the min-width to 0 on the wrapper div for chart.js, but the chart will grow and then not shrink back down if you drag the window around.
I can't figure it out! The only thing I can do is set width to 99% but then the chart is no longer aligned with my other divs. I've been working on this for days, please help!
Q: How can I get chart.js to be 100% width, and grow/shrink to it's bounding size.
to reproduce, go to the example and if you close the menu, the chart grows, and if you open it, the chart does not shrink back down. it maintains it's size and overflows to the right.
note: my actual project has two separate components for the chart and side bar. So a calc solution doesn't work in this case, I don't want to tightly couple any components to maintain good practice.
Here is my StackBlitz working example
here are pictures to show the reproduction:
chart is the right size, menu open
chart grows when you close the menu (the size is still correct)
open the menu, and the chart overflows right
(Copied from my comment.)
I can't get StackBlitz to run (JS errors due to tracking protection in Firefox) so I can't verify this, but I had that exact issue in my flex layout and solved it by ensuring overflow: hidden was set on the parent (and ancestor) flex elements. A cursory look at your CSS shows this is only done on .page-wrapper.
Update: This solution stopped working with chart.js 3
I had similar problems with a markup like this:
<div style="display: flex; flex-direction: column">
<h2>...</h2>
<div class="chart-container" style="position: relative; flex: 1">
<canvas></canvas>
</div>
<span>...</span>
<span>...</span>
</div>
My outermost div was in a css-grid, maybe that also played a role.
Anyhow, I diagnosed the problem to be this: Even though I applied { responsive: true, maintainAspectRatio: false } to the options of chart.js, the chart had a fixed size, which caused the chart-container not to shrink (even when overflow: hidden was applied, I don't fully understand why). This caused the div element chartjs inserts to detect size changes to never change its height.
So the solution was to simply override the height on the canvas to 100%: canvas {height: 100%!important}.
This allows the canvas container to shrink, causing the size-detection div to shrink, causing a re-render of the canvas, which prevents aspect-ratio issues.
Wrapping the canvas in a div with width 100% and and setting the canvas to max-width 100% works for me:
<div style="width: 100%; position: relative;">
<canvas id="chart" style="max-width: 100%;"></canvas>
</div>
Here your canvas is having width inside absolute parents so its recommended to change the values dynamically using JavaScript (angular in your case). But since you are looking for CSS based solution here is what you can add in your app.components.css file:
.sidebar-wrapper.shrink + div.main-wrapper canvas {
width: calc(100vw - 40px) !important;
}
.sidebar-wrapper:not(.shrink) + div.main-wrapper canvas {
width: calc(100vw - 230px) !important;
}
Here is the working example : https://chartjs-overflow-ex-vlsqmn.stackblitz.io/

Angular Material - md-virtual-repeat in list - scroll/loading/display issue

When scrolling down a list under md-virtual-repeat there is an inconsistency between scroll and display speed. Items are not being displayed fast enough to keep up with the scroll speed. It also scrolls 'past the list' so that white space is displayed at the bottom (whereas it should have stopped scrolling).
See codepen: http://codepen.io/sweatherly/pen/PzKRLz
md-list-item, md-list-item ._md-list-item-inner {
min-height: 32px;
}
The problem is aggravated by changing min-height on "md-list-item, md-list-item ._md-list-item-inner" away from it's default value. On codepen, the problem is non-existent when the min-height is not changed (running on my local machine with Chrome it is worse but not terrible. However, it is more problematic at certain screen sizes).
I played with the CSS and googled for a few hours but found nothing that solved the problem. Any ideas?
I noticed a similar problem a while ago and came across the md-item-size attribute of md-virtual-repeat.
Its description in the docs is as follows:
The height or width of the repeated elements (which must be identical
for each element). Optional. Will attempt to read the size from the
dom if missing, but still assumes that all repeated nodes have same
height or width.
I've added this to your example
<md-list-item md-virtual-repeat="test in testings" class="repeated-item" flex="" md-item-size="48">
where 48 is the height of the md-list-item, and removed
md-list-item, md-list-item ._md-list-item-inner {
min-height: 32px;
}
CodePen
The scrolling appears to be smooth and without a white space at the bottom.
I also changed this CSS so that the scroll within the md-virtual-repeat-container works correctly
.md-virtual-repeat-container.md-orient-vertical {
height: calc(100% - 100px);
}

Referencing another element in CSS / doing math in CSS

I have two divs nested inside of a div.
<div id='outter' class='one'>
<div id='inner'></div>
<div id='button' class='bttn'>Click me!</div>
</div>
The outter div's height is a percentage of the page. I'd like one of the inside div's height to be a fixed difference away the outter div (i.e. $('#inner').height($('#outter').height() - 35)), because the second inner div is essentially a button with fixed height (35). I'd like this to happen even when I change the height (through CSS triggers (:hover/adding a class/etc. so I can use Transitions) or otherwise).
I googled around a bit and saw Less might be an answer, but from what I can tell it compiles in to static values, but I still need to use percentages, since I want this app to work/feel the same on any screen size.
I have examples of what I'm currently doing/how I'm thinking about it in some jsfiddles.
Current 'solution': http://jsfiddle.net/L9NVj/5/ (End heights are what I want them to be, but the transition looks terrible)
Idealistic 'solution': http://jsfiddle.net/L9NVj/6/ (End heights are wrong, but the inner div hugs appropriately)
Potential solution: http://jsfiddle.net/L9NVj/7/ (This hides the inner div on click and then shows it again when the appropriate size has been reached)
Any help/thoughts/insights would be greatly appreciated!
Consider absolute-positioning the inner elements, since the outer's size isn't controlled by their size/position.
#inner {
position: absolute;
top: 2px;
left: 2px;
right: 2px;
bottom: 35px;
/* ... */
}
.bttn {
position: absolute;
bottom: 2px;
left: 2px;
/* ... */
}
Example: http://jsfiddle.net/L9NVj/9/
How about conflicting absolute positioning. To do it, you'd just need to set the top, bottom, left and right of the #inner element and then transition those. That will maintain the distances around the edges of the element, and allow other positioning as well.
Note that while you don't need to actually calculate the value in this case, in the future, calc() can be used to calculate a dynamic value in CSS. In that case, you could do something like height: calc(100% - 37px); to get the same effect.
CSS3's calc() is the answer you're looking for, in combination with a JavaScript fallback for browsers that don't support calc(). In your 'Idealistic solution' fiddle, change your CSS height definition to the following:
height: -webkit-calc(100% - 35px);
height: calc(100% - 35px);
While normally you should include all prefixes (and you still may need to, depending upon your level of browser support), according to Can I Use, the only browsers that currently need prefixing are -webkit browsers.
What I would do with this knowledge is the following: grab a feature detection script, I really like Modernizr and detect to see if calc() is available in the browser. Modernizr has a non-core detect for calc() that you can use. Use that CSS in your CSS file as the default, then using a resource loader such as yepnope (comes with Modernizr), load in a JS solution if calc() isn't available.
Of your JavaScript solutions, I'd probably suggest your "Potential Solution" option, but instead of jQuery's hide() and show(), set opacity to 0 and 1 and use a CSS3 transition to transition between the two. I'd also not rely upon a timeout, but rather use the transitionend JavaScript event.
I edited your first jsfiddle little bit i think that's what you wanted. Just added line.
$(window).resize(function(){$('#inner').height($('#outter').height() - 35)});
jsfiddle:http://jsfiddle.net/Qqb3g/
You may have to some workaround to make transition smooth when button the button is clicked.
you need to calculate the inner div in %, so it can resize belong outer div, change your js code to this :
//calculating inner div'x height in % of outer
$('#inner').height((100 - (33/$('#outter').height() * 100)) + '%');
$('#button').click(function () {
$('#outter').toggleClass('two');
});
give a try to DEMO

CSS Triangle Positioning

Basically what I want is a CSS Triangle that is vertically aligned in the center of my content, positioned at the right of my content with a slight padding without using explicit measurements based on the triangle's border-width.
The wrapper should expand to contain the CSS Triangle if the triangle is huge like in this example and the CSS Triangle should always be vertically aligned in the middle of the wrapper. If there is a large amount of text, the CSS Triangle should just overlap the text if they cross.
This seems perfectly reasonable, but I ran into some problems; check out this JsFiddle for where I'm at now.
If I assign a min-height, I can get to 1. below. The problem with 1. is that I have to choose an arbitrary height. Moreover, if content grows, it won't be perfectly vertically centered because of the top: 25% which doesn't truly put it in the middle. To allow multiple different sizes of arrows easily, I really don't want to assign a min-height or any height for that matter, I just want it to calculate its size on its own.
I also had to use an overflow: hidden to prevent the scrollbar from appearing because doing a right: -45px will push the "right side" of the CSS Triangle box, so I can't use an overflow: visible anywhere too.
If I remove the fixed height, then I end up with 2.
Is this possible to do without using an explicit height and other explicit measurements; how would you go about correctly vertically aligning it? If you have ideas using jQuery to grab widths and so forth, that's fine too - I've tagged it.
Here is some jQuery to get rid of the hard-coded heights after assigning an arrowBox class to your div:
$(document).ready(function(){
$(".arrowBox").each(function(){
var border = $(this).height()/4;
var right = "-"+(border-5)+"px";
$(this).find(".arrow").css("border-width",border).css("right",right);
});
});
http://jsfiddle.net/wzzRC/1/
That said, the difficulty with any pure CSS solution is that you can't specify border-width in %. So with pure CSS, use one of the other solutions to force the box to grow to accommodate the arrow. If you want a working arrow in smaller boxes, you need JS.
Set position: relative; on the white box container.
Set position: absolute; on the triangle with a top of 50% and margin-top: of half the height of the triangle.
That will make sure that the triangle is always in the middle.
Change the triangle css to have:
top: 50%;
margin-top: -50px;
http://jsfiddle.net/QuwEc/4/

Categories