Why dynamic css may not apply immediately - javascript

NOTE: I could not replicate the issue in jsfiddle or jsbin, so unfortunately I will demonstrate the issue only via screenshots.
In my work project some JavaScript control is not rendering properly.
I found that it renders properly if I wrap the rendering logic in setTimeout(renderLogicFunction, 30);. Number 30 was found during experiments. If value is less than 10 it always renders incorrectly. If it is greater than 30 it is always correct. For 10-30 it is pretty random.
I started to debug the rendering logic side-by-side and found that one of the columns has wrong width
However in good rendering
Inner HTMLs for both of those controls are the same.
Let's see when the 16px came from
This refers to the inline style
Then I checked that the bad rendering page also has this inline style but for whatever reason it is not applied yet.
If I let debugger go, I can check that the CSS rule was already applied but it's too late as the column width was taken during calculations for rendering and its current width is not being taken into account anymore. The only way to fix it is to trigger control's refresh. But I think it is not elegant at all.
Do you have any ideas why that happens?

When you need a style to become inmune to overwrite, and make it able to overwrite previous rules of the very same style, you can add it !important
div { width:100%; }
div { width:50%; }
Will render your div elements at 50% width, while
div { width:100% !important!; }
div { width:50%; }
will render your div elements at 100%.
If you use this wisely on your CSS styles you'll probably be able to fix your problem.

I guess you are using some 3th party library which resizes columns.
Instead of setTimeout(renderLogicFunction, 30); it could probably be replaced with jQuery's document ready, https://learn.jquery.com/using-jquery-core/document-ready/

Related

How to Reduce CLS (Cumulative Layout Shift) with Slider (CSS/Javascript)?

I am a paid user of the Ninja Slider responsive image slider script (CSS/Javascript) and it always has worked pretty well. Unfortunately, though, Google now is warning that it is causing an unacceptably large CLS (Cumulative Layout Shift) placed in a responsive layout. I am optimistic that someone on Stackoverflow has tweaked this code — or similar code — and can help.
This slider loads quickly enough on my connection that it is difficult for me to even see this shift, but I agree that any shift could be troublesome and I would like to fix it accordingly. Essentially, I would like to modify the code so it quickly outlines a dynamic box the size of the image that will be loaded before loading the image so the following text doesn’t shift down should the user scroll past and start reading before the first image in the slider loads.
In Google’s default Optimize Cumulative Layout Shift advice, the company recommends adding the width and height of an image — like in the pre-responsive days — and adding height: auto to the img code in CSS like so:
img {
width: 100%; /* or max-width: 100%; */
height: auto;
}
This works for images displayed directly in the dynamic layout, but not for images within the slider code because the images are not presented as an img tag, but instead presented as links (a href tags) within list items in an unordered list.
I nevertheless tried dutifully adding height: auto in the applicable CSS file where I thought it could be relevant, within the #ninja_slider div and slider-inner classes. This didn’t break anything, but it didn’t solve the issue, either. Default CSS code is here.
As requested, I believe this this the relevant code, but I could be wrong, and viewing the full code might be useful:
#ninja-slider {
width:100%;
background:#191919;
padding: 30px 0;
margin:0 auto;
overflow:hidden;
box-sizing:border-box;
}
#ninja-slider .slider-inner {
max-width:600px;
margin:0 auto;/*center-aligned */
font-size:0px;
position:relative;
box-sizing:border-box;
}
This post on StackOverflow is the only relevant one I was able to dig up, and the answer suggests that adding display: none on “blocks” using CSS classes would resolve the issue.
Based on my understanding of how display:none works, I assumed this would just prevent the slider from appearing, but I nevertheless tried adding it to the ninja_slider div as well as the slider_inner classes and ul and li elements. It did not work. My code is similar to the default, but if a live implementation is helpful, it is here.
What am I overlooking? How can I alter the slider code to quickly display a box that will soon hold the image so that subsequently placed text will remain in place and not be pushed down when the image loads? Thank you.
Your CLS score is essentially telling you that the layout is shifting as its loading. The best advice one can give in a situation like this is
Hit F12 on the page in question to open Developer Tools
Navigate to the network Tab
Set the Network Speed Select value to 3G
Refresh the page with Developer Tools still open to see a slow motion load of the page which allows you to identify Which elements are "shifting" the layout and changing size as page loads.
You want to be able to define all your element sizing early on in the head of the page using a style tag in the of that page or within the stylesheet (if you must,I believe putting too much inside the stylesheet and depending on things like grid sizes to load defeat this purpose due to sheer size of the css files eventually negates any positive or it wont be seen quick enough as the User is still waiting for the CSS File to load).
Using the above method you can then try to apply CSS that will prevent the Size Shifts , and example of this is with image attribute heights.
This is a tricky topic because you have to also understand CSS casscading (the understanding of style application heirachy essentially) to prevent causing new responsive image issues because the width and height attribute will most like override the current image styling on your page.
What I would honestly suggest is a click function that initates or accesses the slider on click only because the waiting of the entire slider to load and then it shifting the container to a different size is what is causing the actual problem.

Having to remove and re-apply a CSS property to make it work. Possible bug with CSS?

UPDATE: Before reading into this post and saying you need more code to replicate the issue, the simple question I am asking is:
"Have you ever had to remove and re-apply a CSS property on an element in order for that style to apply when that property was already on that element and should have been working by default? If so, what was your solution or did you know what was ultimately causing the problem?"
UPDATE 2: I'm not 100% sure but this may only be an issue with the font-size property and it being changed dynamically using Javascript. The CSS for the outer and/or inner elements that are being re-sized in Javascript works as it should, this problem seems to only occur with font sizing, in particular. Perhaps the surrounding HTML's CSS doesn't catch font-size on memory intensive style changes (like our resize function). Just a guess.
The rest of this post is a means to clarify what I am talking about.
This problem might be exclusive to Chrome. To clarify, our app is used internally by our sales team and the project was specced out to focus exclusively on Chrome, both for development and field use. Already, the styling is totally off when opening this in other browsers, since we've only had to create our CSS to be Chrome-compliant (how I got so lucky to land such a position, I don't know, haha).
I've only encountered this issue a few times in my coding career which I believe to be a bug in CSS but could just be a rare bug between Javascript making style changes in the DOM and parent container CSS not adapting to the change due to possible memory constraints or slight processing lag between Javascript applying a style to the HTML and the CSS not updating to accomdate. I think this is an important question as I think every front-end web developer has or will come across this at some point in their career.
Situation
To put it as short as possible, we have a container inside our body that we use Javascript to size to a 16:9 aspect ratio relative to the window size. Took a screenshot of the entire window. As you can see, we have the inner container sizing proportionally inside our browser window (the black area, which is the body). The inner container is where all the content for our app displays:
Our CSS is built using percentages, wherever possible. We built a 'resizeUI' function that's mainly used to change the font-sizes based on the current width/height ratio of the inner screen, though there are other elements in that function that get re-sized too, on window re-size. The window always re-sizes perfectly and anything needing specific sizing based on the inner window's width/height pixel ratio works as expected, with the child elements' percentage-based CSS adjusting appropriately. But....
The Problem
When the browser window is re-sized by clicking and dragging (incremental re-sizing) everything on the page re-sizes perfectly. However, when the window size changes drastically, and instantly, fullscreen (Maximize) to small (Restore Down), or visa versa, the font-sizes in the top menu will change BUT the CSS of the parent li will not adjust to accommodate the new font-size unless I un-check (remove) it's padding attribute and recheck it (add it back in). When I do that, it works fine. The li container really just has a padding:1% and, thus, normally adjusts it's size correctly based on the inner span's size which changes with the font re-sizes.
The parent li should automatically adjust to the change of the inner span font-size. I'm positive of this because the parent li container will automatically re-size itself when I modify the menu's font-sizes or text lengths, on the fly, in the inspector.
Here's what it normally looks like either on load or with incremental window size changes:
And here is what it looks like when I go from a small window size to full-screen using Maximize:
My (hacky) Fix
Only way I've gotten this to work is to remove the padding for the <li> elements at the top of the re-size function, then re-apply it at the bottom of the re-size function AFTER the line that re-sizes the font. However, this works 50% of the time. Only when placing a 100ms timeout at the bottom of the re-size function to re-apply the padding have I gotten it to work 100% of the time now.
To help, here's a very basic code example of what i'm working with. The ul sizes automatically to it's inner elements:
Relevant HTML
<ul>
<li class="menu-items><span>Item 1</span></li>
<li class="menu-items><span>Item 2</span></li>
<li class="menu-items><span>Item 3</span></li>
<li class="menu-items><span>Item 4</span></li>
<li class="menu-items><span>Item 5</span></li>
</ul>
Relevant CSS
ul {
position:absolute;
top:0;
right:2%;
text-align:center;
}
.menu-items {
padding: 1%;
}
Relevant Javascript
What works about 1/2 the time
function resizeUI(){
$('.menu-items').css('padding','0');
//Random other elements being re-sized
$('.menu-items span').css('font-size', properRatio + "px");
//More elements being resized
$('.menu-items').css('padding','1%');
}
Works every time
function resizeUI(){
$('.menu-items').css('padding','0');
//Random other elements being re-sized
$('.menu-items span').css('font-size', properRatio + "px");
//More elements being re-sized
setTimeout(function(){
$('.menu-items').css('padding','1%');
}, 100);
}
Ultimate Question
Has anyone else encountered similar issues when working with CSS that should adapt to the re-sizing of an element? I sense it's a memory issue or bug between Javascript and CSS, given that having to set a timeout is the only reliable way I have gotten it to work 100% of the time, and, again, this ONLY occurs on a vast, instant change in window size (Maximize to Restore down, or visa versa) but not on manual, smaller, incremental resizing. Sorry for such a verbose post/question but I have encountered this weird bug a few times before with having to remove and reapply a CSS attribute to get it to work properly and I have no doubt other developers have too.
The padding is actually working. Each unit (div or whatever you are using) is overlapping the one previous evenly because you are over 100% of the view width in total. They are being built from left to right and when it gets to the end of the max size allowed, they will all equally push over the ones previous. Also padding affects elements inside of the div and will not affect divs outside of itself. So they are all the correct size but you have not established a rule that would stop divs from overlapping. Margin can do that but if they are over 100% of the desired size you will have to deal with over flow in some way. You can try to use auto for padding, but margin may be better. Otherwise you will have to play with the sizes and percentages to make it fit to the max allowed width. Checkout the CSS Box Model here.
Have you ever had an issue of having to remove and re-apply a CSS
property on an element in order for that style to apply when it was
already there and should have been working by default?
Yes: https://stackoverflow.com/a/34245989/1529630
What was your solution?
Unsetting the styles and resetting them immediately after didn't work, probably because the browser hadn't updated the page yet, and then it detected that I resetted so at the end it did nothing.
Unsetting and resetting in a timeout worked, but caused annoying blinks.
In my case, the solution was removing the element and inserting it back immediately.
window.addEventListener('resize', function() {
// Force a rerender
var parent = element.parentNode,
next = element.nextSibling;
parent.removeChild(element);
parent.insertBefore(element, next);
});
Warning: this will force the browser to do layout, paint and composite operations, which is expensive.

Get HTML element size

I spend couple of hours to try to get width of my div container. I read many questions and answers but none of them seem to work in my case - I always got 0. Finally I found that I can get it through scrollWidth property which wasn't even mentioned in this question and similar.
Now I have what I wanted by I still have no idea how this works.
Why all the other methods fail? Why this is named scrollWidth? I don't want to scroll anything - it's so confusing. Can I get the size of an element before I append it to a document - even scrollWidth don't work in that case. Is there any model I should follow to always get what I see on the screen? I can't see any patterns right now, I write someting, see something different on the screen, and get something even more different in the output. Every time I want to do someting it seem to be 10 different methods I can use but usually only one or two work because it depends on which methods I used earlier. When i work with 2d graphics I used to have x,y,width and height but in html I allways got those smarty CSS which seem to know better what I want to do. Sorry if this sound a little officious but I'm a little annoyed when i need to spend so much time on a trivial task like this. I use to draw graphic on canvas and it was much simpler but now I want to make a simple website so it's probably not a good idea to build it this way.
Here is my example
I understand that i get 0 size becouse those properties refer to element independently of its children and my container has 0,0 size, right? I read that if I set display: inline-block; style it will adapt size to match its children automatically - why this in not working?
The container element in fact has no width. This is why you are getting widths of zero. You can see this if you use dev tools element inspector.
The reason for it being that the container element is absolutely positioned and has no set width. Your child elements are also position: absolute and therefore they will not force the container element to 'grow' to their size.
To get the visible width of the menu, instead you could total up the widths of all the child elements (the first-level menu items). This is probably the best approach to use for the way you currently have things set up. Otherwise, I would suggest completely changing your approach with the html elements you are using, to the CSS properties you are using to position elements where it would not be required to use position: absolute.
I would advise you to open up your dev tools element inspector and start looking at how things react when you change the position from 'absolute' to 'relative'.
Understanding how to position elements and how widths/heights are affected using CSS will save you a lot of headaches - like the one you are having now :)
document.getElementById("mydiv").offsetWidth
This will return the width, including padding.

Best way to switch tab ui on webpage, z-index vs display

The usual way to show\hide block in html is switching it's display property. But in case of performance of rendering, wouldn't it be better to play with z-indexes?
http://jsfiddle.net/WawVH/
Matter of preference really. Display:none removes the element completely, which I think it then is no longer a node in the DOM structure, thus saving memory. Someone correct me if I am wrong.
You could run into a problem with your implementation though if you have overflowing content.
http://jsfiddle.net/yeQfC/
But you could always just turn off overflow with
overflow:hidden;
in your .content CSS definition
http://jsfiddle.net/gF3JC/

How can I get the correct height property of a div without rendering it to the page?

I'm implementing a Wordpress theme where content slides into the page vertically. To do this, I need to measure the size of the div containing the content without visibly rendering it first. I'm attempting to do all of this without Ajax.
Here's what I've discovered so far:
I can easily load the document, read the size, then hide the div with javascript. Unfortunately there's a very obvious (and unacceptable) flicker because javascript doesn't hide the div fast enough. There's also the issue that if images are placed into the content, I have to wait until they're rendered to get the true size... no bueno.
The other option is to hide the content with the CSS, but if the user doesn't have javascript enabled, they'll just be staring at a blank page.
Which brings me to where I am currently.
I have a piece of javascript that runs immediately after the stylesheet is declared that changes the location of the stylesheet link element and then re-renders the page with a javascript specific stylesheet. This solves the problem of having to hide the content before reading the size.
This was accomplished by positioning the div containing the content absolutely and off the page 9999pixels.
#content {
position: absolute;
left: -9999px;
}
At this point, I use jquery to retrieve the height of the content with the following code:
$('#content').height();
The problem is, the number that's coming back is the incorrect size and is much smaller than the actual content. When I change the css to:
#content {
position: absolute;
left: 0px;
}
It renders correctly. What gives?? Is there a bug I don't know about? This happens in both Chrome and Firefox.
You can view it for yourself here http://thethechad.com/wordpress
-- UPDATE --------------------------------------------------------------------------
I figured out my problem. The div I was using had no specified width. When I moved it outside the flow of the document, it expanded to fill that gap, shifting the content and reducing the height of the element. I went back into my CSS and hardcoded the width and everything is working fine. I feel really dumb. I'm sure we all have those moments. Thanks so much for the help guys!
I'm a bit confused by your long explanation, but here's how I measure things without anyone seeing them.
I assign the div a class name I call "measure". Measure has predefined CSS:
.measure {
position: absolute; // doesn't affect layout
visibility: hidden; // not visible, but normal size
left: -1000px; // won't affect scrollbars
top: -1000px; // won't affect scrollbars
}
You are then free to get the divs height. Note: it's width may not be the same as it would be in the layout of the page because divs go full width when position: static.
If you want to make sure that the object is never seen, then you can give it an initial class of "measure" in it's original definition and then remove the class later when you want to use the object in the layout of the page.
I'm not sure what is causing your problem, but you might be able to use something like this:
http://jsfiddle.net/Paulpro/9YBDB/
<div id="thediv">This is the div</div>
<script type="text/javascript">
var $thediv = $('#thediv');
var height = $thediv.height();
$thediv.hide();
$thediv.html('Div\'s height is: '+height);
$thediv.show();
</script>
Were you execute a script to hide the div immediately after the div is rendered, rather than in a script later in your code or on DOMReady etc, so that the flicker doesn't get a chance to occur. However if the user's computer is slow or they are using an older browser the flicker might still appear, I'm not sure. It all depends on if the browsers HTML parser and Javascript engine is fast enough to finish executing $thediv.hide(); before the div is rendered, which I think almost all browsers will be, because rendering is a relatively slow process.

Categories

Resources