Forum Moderators: open

Message Too Old, No Replies

Testing if an element is hidden (display: none)

         

csdude55

6:28 am on Feb 26, 2020 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



A regular occurrence on my site is to use jQuery to see if an element is hidden (eg, CSS is set to display: none). This is primarily used when deciding whether to show a horizontal banner for mobile users, or a right column with 300x250 banners for desktop. On pages with infinite scroll, this could be used dozens of times on a page.

The horizontal banners have a class named ".h_banner" in my stylesheet that I set to display: none for desktop and display: block for mobile. So I've been testing like so:

<div id="banner_0" class="h_banner">
<script>
if ($('#banner_0').css('display') !== 'none') {
// show DFP banner code
}
</script>
</div>

But I recently read that using .css() is the slowest option I could choose... oops!

I found this alternative, but haven't found any speed comparisons:

var isVisible = $('#banner_0').is(':visible');

if (isVisible) {
// show DFP banner code
}

I'm not positive, but I don't think that I could just set the isHidden variable once and reuse it because DFP will hide a banner slot if no ads are available. I haven't been able to test it yet, but wouldn't that appear to be ":hidden"? If so, then no banner available for the first slot would incorrectly hide all of the others.

So which of these do you think would be faster to process? Or would there be a third option that might be better? I'm using jQuery for the infinite scroll, so jQuery or pure JS solutions are fine.

TIA!

lammert

9:53 am on Feb 26, 2020 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



A third option would be to check the offsetParent property. It returns NULL if an element is not visible. I have no information about relative performance compared to other methods though.

NickMNS

1:34 pm on Feb 26, 2020 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



You can use a css class to set the display property, then toggle between block/none states by assigning the class to the element or not as needed. Then to check the state, check to see if className includes the display none class.

Example:

//css
.disp-none { display: none; }

//html
<div>
Hello
<p id="banner" class="disp-none">world!</p>
</div>

//js
const banner = document.querySelector('#banner');
if (banner.className == "disp-none") alert('It is none!');


[jsfiddle.net...]

csdude55

8:09 pm on Feb 26, 2020 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



@NickMNS, I don't know of a way to assign a class when the user is on mobile, can that be done? Right now it's via stylesheet:

.h_banner { display: none }

@media only screen and (max-width: 660px) {
.h_banner { display: block }
}


@lammert, that's an interesting alternative, and since it's pure JS it SHOULD be faster:

if (document.getElementById('banner_0').offsetParent) {
// show DFP banner code
}


I found this speed comparison that was pretty enlightening:

[jsperf.com...]

It compares .is(':hidden' to .css('display') to data('hidden'), and easily found that data('hidden') is fastest (which should probably be the same for Nick's solution) while .is(':hidden') is slowest, so that's good to know. But I don't think I can add an attribute like that just for mobile without using jQuery, and that extra step would probably negate any speed gain.

I don't have a github account, so I can't modify it to test for .offsetParent, but I would bet pennies to dollars that it would be the fastest.

Looking at how I do the CSS, though, I guess that I could just use screen.width to set a global variable:

// in the header, or a separate .js to be cached
var isMobile;
if (screen.width <= 660)
isMobile = true;

// at each banner
if (isMobile) {
// show DFP banner code
}

Not exactly the solution to my original question, but maybe a faster alternative that would suit this particular purpose.

NickMNS

9:14 pm on Feb 26, 2020 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I'm not sure I understand the issue. Am I mistaken that if the DFP's parent div is set to display:none then the DFP code will not run, and thus there is no need for any of this? All you need to do is setup the correct media queries and you're done.

Otherwise your screen.width solution would make the most sense.

lucy24

9:27 pm on Feb 26, 2020 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Similar puzzlement here. Why do you need to check whether anything is set to display: none? If, as implied by the initial post, this is determined by viewport width, then you already know whether it will display or not; you don’t need to check in a different way all over again.

csdude55

11:37 pm on Feb 26, 2020 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I was trying to minimize the original code to keep it simple :-) The actual final code looks like this:

<div id="banner_0" class="h_banner">
<script>
if (isMobile) {
if (disabled) {
// DFP code
}

else (iVal = $('#banner_0')).ajax(includePath + '/alt.php?width=' + (valWidth = iVal.width()));
}
</script>
</div>

If they're using an ad blocker then "disabled = false" and I use Ajax to load an alternative (alt.php). This scripts shows locally sold ads that get past the ad blockers (in addition to their "regular" section), and I give the advertisers a monthly report on how many impressions they had.

If I don't check to see if the element is visible then the script would run and count the impression, even though it wouldn't actually be visible. That would give my local advertisers a falsely inflated number of impressions and a much lower RPM.

I use .css('display'] !== 'none' in a few other places, but this would be the most commonly used on any given page.