How to Reduce CLS (Cumulative Layout Shift) with Slider (CSS/Javascript)? - 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.

Related

Parent DIV's CSS interferes with SVG animation

We've moved an SVG/JS animation created with the Adobe After Effects Bodymovin plugin from one Wordpress site to another. On the old site (which I unfortunately can't show you), the animation works flawlessly. On the new site, depending on the size of the browser window, the animation contains glitches that appear to be caused by some sort of rounding error in the animation mask.
On one or more edges of the globe, you can occasionally (depending on viewport width) see a one pixel-wide bit of the scrolling background graphic appear. See image.
I've isolated the animation in CodePen. It works fine here, no matter what size the viewport is set to.
However, when I introduce this tiny bit of CSS such as this...
margin: 0 auto;
width: 70%;
... into the style of the parent DIV, the glitch starts happening. See here.
On the original animation, the mask extends a lot further than the edges of the globe, so I suspect the fact that the mask now just reaches to the edges of the globe is some sort of Bodymovin optimization.
Given that this doesn't happen on the old site, I suspect there is some sort of CSS, or perhaps a setting in Bodymovin, that stops this from happening.
The Wordpress site is built with Divi, and the animation sits in a DIV nested inside many other DIVs (ie a module sitting in a column sitting in a row sitting in a section), and most of these DIVs have the width set to various percentages. So I don't think the solution will lie in simplifying the CSS.
Has anyone experienced a problem like this before? Or have suggestions that might help eliminate it?
I have also created an Issue in the Bodymovin GitHub page, but the response times there seem to vary greatly.
I have made some testning on the codepen and was able to make it work when i removed
transform: translate3d(0px, 0px, 0px);
so removing this line of the script should fix the problem
this.svgElement.style.transform="translate3d(0,0,0)")
Why are you trying to transform the svg, when its already transforming automaticly.
This is a possible fix if you still want to retain the settings with margin and width %.
You can avoid this issue by giving a width in pixels to #container the responsiveness of percentages sometimes causes pixels to be just slightly off. Use media-queries if you need to have different sizes for other screen dimensions.
#container {
margin: 0 auto;
width: 400px;
}

Why dynamic css may not apply immediately

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/

Loading new content into a responsive slider

How does this slider reload new content as the page is resized?
http://www.herschelsupply.com/
I stumbled across this whilst shopping and their slider is a good facsimile of what I want to create for my own site. Their slider loads new content at a certain point when the window is resized. I have had troubles doing that using BxSlider because I am new to JS.
More info
The problems I have had are these:
I can use css media query or jQuery to hide certain slides, but they remain in the DOM so the slider still displays them in the pager and sometimes it just stops rotating/breaks.
If I create two different sliders to be loaded at different widths the change does not occur as the page is resized. Also this seems wasteful.
If I remove and replace elements from the DOM on $(window).resize(), I am not sure how to return them to the DOM if the window is resized back and forth continuously.
Overall I am just asking what approach you would take to do this? Im sorry if this is verging more towards discussion than a specific question, but I'm not sure where else to ask.
The website you showed simply has two completely separate slideshows. One is hidden and another is shown when the window resizes.
<div id="slider-one" class="hide-for-mobile">
/*Slider here*/
</div>
<div id="slider-two" class="show-for-mobile">
/*Slider here*/
</div>
Then in your media query for mobile...
.hide-for-mobile {
display: none;
}
.show-for-mobile {
display: block;
}
Now, as for a solution that's more along the lines of what you were trying to do... What you need to do is get away from HTML <img> tags. Instead, your sliding elements should be <div>'s with a CSS background image. In this way, in your media queries you can change the background image of the <div>'s. I am unsure whether or not the slider you are using can support this, some are dependent on sliding an actual HTML <img> tag. Some can slide whatever you want. You should be able to manage what I've described with Flexslider (a quick google search will get you where you need to be).

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.

add header when page breaks when using page-break-inside: avoid wth css or javascript or from browser?

i have a page that has sections as divs with inner divs and content. The numberof divs varies alot from less than a page to many pages when printing.
I am using page-break-inside: avoid on every section div so that all sections are never printed / split accross 2 pages. (This i only get to work in firefox but that whole other story....!).
Problem is i want to add a header image to the top of each page when printed but using the page-break-inside: avoid css property i dont know where to add the headersasthis is worked ou when printing.
Any one know ow i can acheive this ? can i somehow find out where the page breaks are going to be and add header there ? or is there a way of setting header image in the brower like you can to word documents etc ?
please help
thanks alot
rick
It's impossible to control the printed page from JS/HTML/CSS because you don't have any access to the print driver so you can not know what paper size or margins the user has set.
To get around this you could use a component to create a PDF from your HTML so you will have more control of the layout. That would have to be done server-side.
I don't see any way of add header information using CSS2 (spec). There is a way to add TEXT to a "page header" using CSS3 (link, spec). I'm not sure if this will also cover images, but it's a start. You will need to consider CSS3 adoption and if it suits your business needs (from wikipedia link it looks like only Opera supports the #page option, but that info could be stale).
I don't think you could use javascript to inject headers onto each page when it's being formatted for print. I don't see how that could be done (but I could be wrong on this one).
What you could do, is define a div that is invisible on a browser page, but shows up on a printed page. Something like this should do it:
<STYLE type="text/css">
#media print {
div.header {display:block;}
}
#media screen {
div.header {display:none;}
}
</STYLE>
You could then place a div containing your header after a forced page break. This should work for you, further CSS could probably be used to force this div to align with the top of the page etc. Of course, this then also requires you to use forced page breaks, which means you need to know in advance how much data you can fit to a page, not ideal.
Hope this helps.

Categories

Resources