I am trying to apply a class name based on the width of the viewport such that it doesn't "flash" before the JavaScript gets loaded and processed.
For example, I have a Bootstrap sidebar that I want to hide by default if the user is on a mobile device. If I just add some logic to document.ready event, then the menu is visible for a split second before disappearing, which is annoying.
To circumvent that behavior, I used document.write to create the open tag for my sidebar:
<script type="text/javascript">
// Prevent flicker of menu before collapsing on small screens
if (window.outerWidth < 768) {
document.write('<aside class="collapse" id="primary-sidebar">');
} else {
document.write('<aside class="collapse in width" id="primary-sidebar">');
}
</script>
...
</aside>
While this resolves the problem, I do get warnings in Firefox about unbalanced trees and I've read that document.write should not really be used in this manner.
Is there another way to add the in width class based on the window size without waiting until after the page is all loaded?
Instead of putting the Javascript in document.ready, put the <script> tag immediately after the element in question.
<aside class="collapse" id="primary-sidebar">
...
</aside>
<script type="text/javascript">
if (window.outerwidth >= 768) {
document.getElementById("primary-sidebar").className = "collapse in width";
}
</script>
While this will briefly display the wrong size, it should resize so quickly that the flicker should be unnoticeable. I put this logic in the desktop version, since the processing should be faster.
You can use:
var aside = document.querySelector("#primary-sidebar");
if (window.outerWidth < 768) {
aside.className = "collapse";
} else {
aside.className = "collapse in width";
}
You're going to cause yourself a lot of stress by using JavaScript to handle things like hiding/showing based on screen size.
The standard way to hide/show things based on screen size is with the #media CSS rule
For example:
#media (min-width: 768px) {
#primary-sidebar {
display:none;
}
}
If you want to prevent your menu from being shown initially, set the element to
display: none;
or
visibility: hidden;
On the other hand you don't need to put it inside $(document).ready(); if your only condition is the width of the window.
Related
I want to remove a div element on mobile devices only (based on window size).
The element is an advertisement and by using CSS (display:none) is still registered on mobile devices even though the ad does not show (is just hidden), and this is making a fake impression.
My ads are inserted trough Wordpress theme options (where the ad code itself is added). And from the function I get the code in the page.
<div class="topad">
<div class="adh" id="adbox"><?php echo get_option('amn_topad'); ?></div>
</div>
I probably have the right code for this but it may be placed in the wrong place.
I have used in the header.php (where the div is located):
if ($(window).width() < 700) {
$('.topad').remove();
}
and
$(document).ready(function () {
if ($(window).width() < 700) {
$('.topad').remove();
}
});
I have also tried to make a custom.js with the same codes as before and add to functions.php
function my_scripts_method() {
wp_register_script('custom_script',
get_template_directory_uri() . '/js/custom.js',
array('jquery'),
'1.0' );
wp_enqueue_script('custom_script');
}
add_action('wp_enqueue_scripts', 'my_scripts_method');
I don't know if it's possible but a simpler and efficient way would be to prevent the div to appear by inserting an "if" directly in element
<div class="adh" id="adbox"><?php if() {echo get_option('amn_topad');} ?></div>
Removing the element completely is not the way that the industry is going - you might want to do that still, but please consider the counter-arguments:
The element won't be showing back if the screen gets resized up over the threshold
To remove the element after the user resizes down under the threshold, you must detect this behavior with JS, which complexifies the code
The element might be useful to other parts of your code
The way that is widely adopted in the industry to change display based on size width is to use media queries. Here's a quick demo to show/hide elements based on the screen size (over or under 700px) - resize your window to make it work!
#media (max-width: 700px) {
/* mobile CSS: hide .desktop div */
.desktop {
display: none
}
}
#media (min-width: 700px) {
/* desktop CSS: hide .mobile div */
.mobile {
display: none
}
}
<div class="mobile">
I appear only on mobile devices! (screen width less than 700)
</div>
<div class="desktop">
I appear only on desktop devices! (screen width over 700)
</div>
Objective: Change the properties of CSS Stylesheet instead of HTML CSS using Javascript.
Current Issue: using document.getElementById("foo").style.display = "none" causes changes in HTML document that removes Media Query functionality
My website has a button that changes the display of a sidenav bar on smaller screens. This button is not available on screen sizes greater than 768px. The website is dynamic, so the button shows up when the screen is small enough. When the button is clicked, the sidenav (initially set to display:none), is set to display:block, which can then be closed again.
Once the sidenav is closed in a screensize < 768px, and the screen is increased to a size > 768px, the media query no longer changes the display to block because the Javascript changes the HTML, which overwrites the CSS media query.
Below is the code and changes the Javascript does to the HTML.
HTML Before:
<div id="sidenav">foo</div>
<!-- button to change sidenav -->
<div id="menu-button" onclick="openCloseNav(this)"></div>
Javascript
function openCloseNav(x){
if(x.classList != "change"){
document.getElementById("sidenav").style.display = "none";
}
else{
document.getElementById("sidenav").style.display = "block";
}
}
CSS
#sidenav{
display:none;
}
#media only screen and (min-width: 768px){
#sidenav{
display:block
}
}
HTML After div id="menu-button" is clicked twice
<div id="sidenav" style="display:none">foo</div>
<!-- button to change sidenav -->
<div id="menu-button" onclick="openCloseNav(this)"></div>
I have tried a few different things such as attempting to detect screenwidth in Javascript like this:
var currentWidth = window.screen.availWidth;
function showSideNav(){
if (currentWidth >= "768"){
document.getElementById("sidenav").style.display = "block";
}
}
to no avail. If the snippet above does work, I don't know where to place it in my HTML.
Question:
What can I do to make it so that the sidenav will show even after the menu-button div is clicked on screen sizes > 768px?
Whenever possible, change styling via the addition/removal of CSS classes, rather than affecting the element.style object. This not only makes the code cleaner and reduces code duplication, but it eliminates the issue you are having with the CSS being added directly to the HTML element as an inline style, which is the most specific way to add CSS and difficult to override.
You can easily add/remove/toggle and more with CSS classes with the element.classList API.
Here's a simplified example:
document.querySelector("button").addEventListener("click", function(){
document.getElementById("element1").classList.add("hidden");
document.getElementById("element2").classList.remove("special");
// Just to show that classList modifications don't alter the inline HTML style
console.log(document.getElementById("element1"), document.getElementById("element2"));
});
.hidden { display:none; }
.special { background-color:#ff0; color:#800080; }
<div id="element1">Now you see me...</div>
<div id="element2" class="special">Something else</div>
<button>Click to change styles</button>
You could use an extra attribute that controls your navbar, so you can use you JavaScript independent of you CSS. I am not sure that the css I put here is correct but I think you get the idea.
EDIT I just noticed thanks to #Doug that you can just use a class instead.
function openCloseNav(x) {
if (x.classList != "change") {
document.getElementById("sidenav").setAttribute("hideme", true);
} else {
document.getElementById("sidenav").setAttribute("hideme", false);
}
}
#sidenav[hideme=true] {
display: none;
}
#media only screen and (min-width: 768px) {
#sidenav {
display: block
}
}
<div id="sidenav">foo</div>
<!-- button to change sidenav -->
<div id="menu-button" onclick="openCloseNav(this)"></div>
I have a javascript function that is called when the user resizes the window and that does different things depending on whether a CSS media query (max-width) is true. In order to do that, I have a div that is made visible when the media query is triggered. The javascript code then checks the div's visibility (inside the resize event). This works great in Chrome and Firefox, but is giving me minor issues in Safari (7.0.5). If the window is resized and is around the width at which the condition is triggered, the js code is sometimes out of sync with the CSS: when I inspect the div I can see that it's showing (meaning the media query is working correctly), but the js conditional that checks visibility still returns false. The code is pretty simple:
JQuery:
if ($("#is-mobile").css("display") === "none") {
$("#site-nav").show();
} else {
$("#site-nav").hide();
}
CSS:
#is-mobile {
width: 0;
height: 0;
display: none;
}
#media screen and (max-width: 500px) {
#is-mobile {
display: block;
}
}
This mismatch only happens if the CSS width of the window is roughly between 485px and 499px. That makes me thing it's related to the ~15-20px mismatch between $(window).width() and the CSS viewport width that can occur when a vertical scrollbar is visible (see e.g. here). I do have a vertical scrollbar in my window so I wonder if that's what is causing the issues. Ironically, that scrollbar weirdness is why I'm checking the visibility of the div instead of using $(window).width() in the first place!
EDIT: just tested this code in an otherwise empty html (so no vertical scrollbar), and the problem is indeed gone. So must be related to the scrollbar.
I'm trying to use jQuery to only load certain content if the viewport is above a specified width.
This works, but not quite right. Check out the JsFiddle link at the bottom for a working demo.
Here's what I have so far;
If the viewport is below 500px #wrapper is hidden with a media query.
Above 500px #wrapper is set to visibility: visible;
jQuery is looking for element.is(':visible'). When this happens jQuery loads the image.
Resizing the browser window activates the media query, but not the jQuery.
The jQuery only fires on a page refresh.
I've tried using $( window ).resize(function() but this fires every time the viewport changes size, duplicating the content.
Is there a way to activate jQuery without a page refresh?
The ideal solution would be;
up to 500px load nothing,
when the viewport is resized above 500px load the jQuery.
If the viewport is resized below 500px unload the jQuery content.
HTML
<p>CSS hides <strong>#wrapper</strong> if viewport is below 500 pixels.</p>
<div id="wrapper">
<p>jQuery checks CSS to see if <strong>#wrapper</strong> is visible and loads image on page refresh.</p>
<p>I'm looking for a way to run this function without needing to refresh the page. I've looked into using (resize) function, but this duplicate the content.</p>
CSS
#wrapper {
visibility: none;
display: none;
}
#media only screen and (min-width: 500px){
#wrapper {
visibility: visible;
display: block;
}}
JQuery
$(function() {
var element = $(this).find('#wrapper');
if (element.is(':visible')) {
$('#wrapper').prepend('<img src="http://cache.desktopnexus.com/thumbseg/1134/1134934-bigthumbnail.jpg" alt="Demo image">');
}
JsFiddle link:
https://jsfiddle.net/tu60wbbu/13/
You can use window.matchMedia() instead of $(window).resize() to have your javascript respond to a media query match in your CSS.
https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia
It's fairly well supported across browsers.
http://caniuse.com/#search=matchmedia
If you need to support IE 9 or lower, you might have to fall back to using $(window).resize() for those browsers.
Here is the code for my comment:
$(function() {
var large = false;
var barrier = 1000;
$( window ).resize(function() {
if(!large && $(window).width() > barrier) {
large = true;
$('#wrapper').prepend('<img src="http://cache.desktopnexus.com/thumbseg/1134/1134934-bigthumbnail.jpg" alt="Demo image">');
} else if(large && $(window).width() < barrier) {
large = false;
$('#wrapper img').remove();
}
});
});
Working Fiddle: https://jsfiddle.net/tu60wbbu/14/
I used 1000px as the barrier in the demo.
You should initialize large properly by the window width on load. For demo purposes i used false as initial value.
Sorry for the long time, I was at vaccation :-)
I am trying to get a smooth transition when I redirect users. First by fading out the page then redirecting and and fadeIn.
Here is my redirect
if ( data.redirect != undefined )
{
$("#toppanel").slideUp(1000);
$("#content").fadeOut(2000, function() {
window.location = data.redirect;
});
My next page has a javascript in the header like this:
jQuery(function ($) {
$("div.container_16").first().hide();
$(".grid_16").first().hide();
$("div.container_16").first().fadeIn(2000);
$(".grid_16").first().slideDown(4000);
This almost work except for a few milli sec where the second page loads then turns blank and fades in. How do I fix this? Do I need to change the css or html?
A simple fix to this would be:
CSS
body{
display:none;
}
JS
jQuery(function ($) {
$('body').show();
$("div.container_16").first().hide();
$(".grid_16").first().hide();
$("div.container_16").first().fadeIn(2000);
$(".grid_16").first().slideDown(4000);
}
You should know that 1 second is a lot of time for a web user. And basically taking 6s extra to just move to another page could be very costly to your user base. I hope you offer a solution without these kind of effects.
UPDATE
CSS
/*
* overflow => so you don't get a scrollbar
* visiblity => so all content is hidden
* background => so you get a black background
*/
.bodyExtra{
overflow:hidden;
visibility:none;
background:#000;
}
JS
jQuery(function ($) {
$(document).ready(function(){
$("div.container_16").first().hide();
$(".grid_16").first().hide();
$('body').removeClass('bodyExtra');
$("div.container_16").first().fadeIn(2000);
$(".grid_16").first().slideDown(4000);
});
}
The logic behind this is to make your page work as a buffer zone. You then hide the elements you want to fade in, remove the class from body and fade everything in.
UPDATE 2013.09.01
I see this answer is still generating some traffic and I have to admit, since the initial answer in 2011, I have an addition to make
HTML/CSS
<noscript>
<style type="text/css">
.bodyExtra{
overflow:auto !important;
visibility:visibile !important;
}
</style>
</noscript>
This can also be done with a <link rel="stylesheet" type="text/css" href="no-js.css" /> tag.
The idea behind this is to fix the disabled javascript issue described by theazureshadow in the comments.
You're getting what is called a "flash of unstyled content" or FUC. You could wrap your second page in a container and hide that via css (display: none;) and then fade in when it's loaded.
Don't use pure css to hide the content originally. If you do, users with JavaScript turned off will not see your content. Instead, only hide when javascript is available.
.js-enabled div.container_16,
.js-enabled .grid_16 {
display: none;
}
Include this line of javascript at the very top of the body:
$(document.body).addClass('js-enabled');
Then in your animation function, after you've hidden .grid_16, include this line to return things to normal:
$(document.body).removeClass('js-enabled');
If you want, you can be more specific and target the hiding styles to the particular elements you want to hide. But I don't know if that's practical for your case -- too few details.