Performance css rules vs. jQuery .toggleClass - javascript

I'm running a wordpress theme, which has a sticky header. I've built a subnav, which is displayed right below the header. Whenever I use this subnav, the header should not stay sticky, instead the subnav should be sticky (already made with simple javascript addClass). I am only interested how to turn off the stickiness of the header the best way.
(1) Using CSS:
One way is to use css and to override the classes, which make the header sticky. This already works, I've just changed the position fixed to static and disabled the placeholder, which avoids a gap in the content, when the position is set to fixed and the header is taken out of the flow. Based on the circumstance that I want to use the subnav on many pages (ca. 70%) I would have to write one big css rule for targeting the relevant pages by their ids. This leads to my thought that javascript may better on resources.
(2) Using Javascript:
I've wrote a small snippet of javascript, which easily removes the whole css-classes, when the ID of the subnav is present on the page:
if(document.getElementById('subnavfullwidth')){
jQuery( '.header-sticky-height' ).toggleClass( 'header-sticky-height', 'false' );
jQuery( '.header-wrapper' ).toggleClass( 'header-is-sticky', 'false' );
jQuery( '.header' ).toggleClass( '.header-sticky-shadow', 'false' );
}
Simple as the title: Would the javascript be better or one big css-rule for the site performance? Is there a way to optimize my javascript or is it just okay?
Kind Regards!

I'd be more inclined to have one class added to '.header' (assuming that's the root element of the relevant area) named sticky, and change the class header to an id of header.
The way you have it written, you could gain a little performance by adding an id to '.header', and then chain methods together to limit the number of elements to have to search through.
$('#header')
.toggleClass('header-sticky-shadow', false)
.find('.header-wrapper')
.toggleClass('header-is-sticky', false)
.end()
.find('.header-sticky-height', false)
.toggleClass('header-sticky-height', false);

Related

disable css scroll smooth on scrollTo

My element has css scroll-behavior:smooth, which I'm using in order to smooth the hash "a href" links.
I want the page to first load on a fixed position on the page, which means it won't "smooth" the scroll on the first load to that position and only use it after.
I don't want to use any setTimeOut hack, I know that scrollTo has "options" that are widely supported, but I can't find any type of "behavior" that will override the css smoothness.
If I got your question right - Without any setTimeout - the first thing that pops my mind is to simply add using JS a class (like i.e: smoothScroll-init) to all the class="smoothScroll" elements:
HTML:
<div class="smoothScroll">Still not smooth...</div>
CSS:
/* Will be added by JS on DOM ready */
.smoothScroll-init {
scroll-behavior: smooth;
}
JS:
// DOM is ready
// Add class "smoothScroll-init" to all class "smoothScroll" elements:
document.querySelectorAll(".smoothScroll").forEach(EL => EL.classList.add("smoothScroll-init"));
If you're targeting a specific Element that you want to target and snap-scroll into view use: Element/scrollIntoView using the {behavior: "auto"} option.

Persistent css rule changes for dynamically created elements

I want to permanently modify a css rule (such that new elements will take on this css rule). It appears that all jquery modifications using css do not persist (Say modifying a background color for future elements does not persist when they are created):
$(".red").css("background-color", "blue");
See my fiddle here:
https://jsfiddle.net/Lvm0c7m6/
I would like all future elements to now have the new rule created by css, is there a way to do this (with good cross browser support).
You order javascript at execution time to add an inline style to all elements with class 'red', coloring them blue. After that you add new elements to the DOM. They have no knowledge of the earlier command an therefore are not influenced by them.
This solves your problem, as this adds a style rule to the document. This influences all elements and is 'persistent':
$( "<style>.red { background: blue; }</style>" ).appendTo( "body" );
See: https://jsfiddle.net/aLghL2ke/
Note that if you want to run this command multiple times, it would be nice to remove the old style block from your code. This can be done with jQuery too using this command:
$( "body style" ).remove();
See: https://jsfiddle.net/4duxsz0a/

jQuery Add & Remove Class Div Width

How can i add/remove class according as div width ? I tried some codes but I have no idea about jquery codes. I'd like add div class according as antoher div width. Just i need add class like that. If container is smaller than 600px "add class" to content div else "remove class" from content div. These are my codes;
<div class="container">
<div class="content"></div>
</div>
$(window).resizeboxes(function() {
if ($(".container").width < 600){
$( ".content" ).addClass( ".content_600" );
}
});
else{
removeClass('.content_600')
}
$(window).trigger('resizeboxes');
This works, though the code is changed slightly. There were some problems with the syntax also, so I've corrected those (for instance the else statement was slightly misplaced). Here is a working example:
https://jsfiddle.net/vt0nbx36/3/
Here is the code:
var resizeboxes = function() {
if ($(".container").width() < 600)
{
$(".content").addClass("content_600");
}
else
{
$(".content").removeClass("content_600")
}
};
resizeboxes();
$(window).resize(function(){
resizeboxes();
});
For this need exactly, you have jQuery's .toggleClass() function. It takes the class name as a first parameter, and optional second boolean parameter that states wether the class name should be added or removed. You can find the documentation here
$(".content").toggleClass("content_600", ($(".container").width() < 600));
Even tho your question is a JS related question, CSS as a matter of fact can handle this like no other beast can (mostly)!
CSS allows you to use media-queries to resize your content based on the width of the viewport.
The upside of this is that the browser will handle this for you within the rendering engine rather than having JS between your change and the rendering engine.
The major downside is that you can't define the width of element A based on element B but are unfortunately locked to using the viewport as an indicator.
Before I explain why you'd want to use CSS I'd like to point out why you don't want to use JS for this if possible.
The jQuery.resize eventhandler fires inconsistently across browsers and it fires alot of times usually.
This causes your scrolling to clog up and make your webpage feel laggy.
If there's anything your users will dislike it's the fact that scrolling is controlled by something they don't even know of which is slowing you down.
As for a CSS solution, a media query looks like this:
.my-selector {
width: 900px;
}
#media all and (max-width: 600px) {
.my-selector {
width: 600px;
...
}
}
You wrap your code in a sort-of conditional that allows you to be very flexible with manipulating elements on the page.
What happens in the above piece of code is that when the parser reads the CSS it sees the first selector not in a media query so it applies width: 900px; then it sees a media query and sees the other rule for my-selector however it will only apply that rule when the screen is at that width we defined in the #media ... rule. When you resize CSS handles things differently behind the scenes so it's much faster than JS in that case.
I'm not sure if it actually applies to your situation but if your container is sized by the viewport rather than parent elements this should be possible and I thought it'd be nice atleast to show you a good way of playing with element dimensions.
Also, you can use #media to for instance make a webpage print friendly by changing the all to print for example and setting the background-color: transparent for an element - saves ink ^.^ which is an additional extra on top of the general awesomeness of media queries.
Hope it helps, good luck if you wish to make your webpage 5 times faster ;)

javascript, change class but only when it meets certain criteria

I have a class that is used ~~120 times on a page. I would like to change the margin-bottom only if other things affecting that class meet a certain criteria. The problem with the below code is that it changes everything associated with that class...not just the ones that meet the criteria.
if (actualCharacters > charactersCanFitInContainer) {
$("#Full .t16").each(function () {
$(this).css('margin-bottom', '1.25em');
});
$("#Full .t8").each(function () {
$(this).css('margin-bottom', '4.4175em');
});
}
I want to help you with your problem, but the premise is wrong. You shouldn't be trying to do this in jQuery. Maybe there is something wrong with your CSS, and it would be better to try to resolve it using CSS.
Having said that let's go over some of the problems with your code:
(1) Don't use $( selector ).each()
When you do a call to jQuery
$( selector );
This little guy returns an array of all elements that match the css of the selector.
There may be 200 elements, or even a thousand, but never, ever, do an .each() call unless you tend to explicitly change every individual element in a unique way.
$( selector ).each() runs a for loop on the array of matched selectors, which will give you performance problems if your matched set is too large.
To change all matched elements you need only to do this:
$( selector ).css('margin-bottom', '1.25em');
Read more about .each()
(2) Do not use Javascript (or jQuery), to do CSS's job
From your question it seems like you're having a problem with spacing. CSS has a number of ways to resolve this using rules like overflow, white-space, text-overflow that you should explore before resorting to scripting.
(3) Avoid using .css()
You should avoid using the $( selector ).css() function since it also introduces performance problems, especially on large sets. Instead, you should create a class that you can apply to the set and use:
$( selector ).toggleClass( 'myclass' );
//or
$( selector ).addClass( 'myclass' ); //and
$( selector ).removeClass( 'myclass' );
since these functions are more performant.
To take it a step further, do not apply a class to every set of matching elements, rather, add the class to a parent element and let the children inherit their styles from the updated parent class.
Read more about toggleClass()
(5) Stick to conventions
While it's perfectly OK to use capital letters in naming your CSS rules, you should probably avoid that since it's not standard practice. The whole point of having a standard practice is so that everyone can look at your code and know exactly what is going on, which makes your code easier to debug and share.
(6) Don't try to compensate for bad design with over-engineered solutions
Also consider that, sometimes, the requirements need to be changed if your only solution is to script the styles.
I've run into situations where what a project manager wanted to accomplish was not technically feasible. If they want a large body of text to display in a limited area, they need to allow for things like scrollbars or consider keeping a standard size limitation on blocks of text.
Go back to the stakeholder for this project and tell them that what they want to do is not reasonable, and make decisions together to design this widget better.
As a developer, you should not allow for unreasonable requirements, some things simply need to be redesigned instead of making you come up with a messy way to resolve bad design.
Conclusion
In terms of your problem, play around with the CSS rules that specifically address the spacing problem you're having (overflow, text-overflow, etc). You may need to look deeper into the styles to find a better way to do this.
In case anyone stumbles across this question and answer, I wanted to post what I ended up doing - special thanks to Qodeninja for setting me straight.
Rather than change CSS via javascript, I went with simple #media queries to handle the various font and spacing changes below. There are a variety of differing methods to do responsive design. This worked best for my requirements
#media all and (max-width: 1500px)
{
body
{
font-size:1.1em;
}
#Full
{
width:1200px;
background-color:Blue;
}
.theTeams
{
width:8.925em;
padding-left:.238em;
padding-right:.238em;
}
.t8{margin-bottom:4.75em;}
.t4{margin-bottom:11.75em;}
.t2{margin-bottom:26.5em;}
.tend{margin-bottom:0em;}
.rtR{margin-left:19em;}
#media all and (max-width: 1200px)
{
body
{
font-size:0.9em;
}
#Full
{
width:900px;
background-color:Orange;
}
.theTeams
{
width:7.75em;
padding-left:.14em;
padding-right:.14em;
height:2.1em;
}
.t8{margin-bottom:4.95em;}
.t4{margin-bottom:12.25em;}
.t2{margin-bottom:27.75em;}
.tend{margin-bottom:0em;}
.rtL{margin-left:16em;}
}

How to improve JS scroll performance?

I'm working on revamping my website, and the new one can be found on http://beta.namanyayg.com/
There are mainly two things related to scroll on the site:
To check on which 'page' the user is on, by calculating the top offset and scroll position, then adding a class to the page.
To smooth scroll on menu click.
I've written code for both, but there is a lot of lag.
The first one almost always results in lagging. The second one, as a result, lags too. I have included a boolean to check if it's smooth scrolling and disabled the normal scroll events then, but there's not much change.
Do you have any advice on how to improve performance so there is no (or at least, less) lag? Thank you in advance! :)
...Or is it not related to JS at all? I've optimized everything else...
EDIT: Unminified JS at http://beta.namanyayg.com/js/main.js
If you are using underscore, it has an awesome _.debounce function that is excellent for this sort of thing.
To check how much the user has scrolled from the top of the page (i.e. on which 'page' he is at the moment) can be achieved with:
$(window).scroll(function () {
var scrollAmount = $(window).scrollTop(); // in pixels
if(scrollAmount > SOME_AMOUNT)
{
// add required css class
}
});
To scroll smoothly, to some id for example, you could use:
$("html, body").animate({ scrollTop: $("#someID").scrollTop() }, 1000);
These are both jQuery solutions, so you should have jquery library included. There is also a nice jQuery plugin called waypoints that performs these calculations. It might prove useful to you and it has some other nice features and examples.
I have the same problem. I have a scrollable div with thousands of smaller divs. Every time I call scrollTop to get the scroll-position or set it, it sometimes waits at least 1 second.
I read these slides: http://www.slideshare.net/nzakas/high-performance-javascript-2011 (especially slides 138-139) and now I realize that every call to scrollTop, even as a getter, makes javascript relayout the page. This is most likely the cause of delay, but unfortunately I have not found a solution yet, as in a way to call scrollTop without causing relayouts.
Note: I've only been testing on Chrome.
Also read 'Browsers are smart' section of this article: http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/
I've found an easy solution to the lag with getting scrollTop, just call it inside a scroll-handler and save the result in a variable.
for example in jQuery:
var scrollPos = 0,
element = $('.class');
element.scroll(function(){
scrollPos = element.scrollTop();
});
For the second problem, setting the scrollTop, I reduced the amount of DOM elements by only showing the visible elements. In your case make sure only the visible page(s) are added to the DOM. when scrolling to the next page, in the scroll handler remove the top one (use jQuery .detach) and append the next one to the DOM.

Categories