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>
Related
I have this website: https://lapassion.000webhostapp.com/
My question is about the logo, it is white and when I scroll down a white bar appears, making the logo "disappear".
I have this code on index.html
<div class="navbar-header">
<img src="images/logo.png">
</div>
And the css
.navbar img {
margin-top: 15px;
width: 100px;
height: 50px;
}
And I need to change that img to another one that I already have in black.
What do I need to do?
Using this CSS you can handle it
.navbar.navbar-default.navbar-fixed-top.affix .navbar-header img {
background-color: black;
}
Instead of background , use the code to change the image src - if you wish to change the logo.
This CSS is set during sticky header / scrolling the class .affix-fixed changes to .affix. So you can target your CSS style their, no need of JS changes.
.navbar.navbar-default.navbar-fixed-top.affix .navbar-header img {
content: url(https://www.google.com/logos/doodles/2019/joseph-plateaus-218th-birthday-5462347081580544-s.png);
}
Not a very efficient way, but one of the ways could be this :
<html>
<body onscroll="changeHeaderImage()">
<!-- body text -->
</body>
<script>
count = 0
function changeHeaderImage() {
//check so that it does not change every time you scroll,
//you can change this condition as per your requirement.
if(count == 0)
document.getElementById("imageelement").src = "image.jpeg";
count = 1
}
</script>
</html>
or other way would be to add/remove class on scrolling, and class is attached to different image sources.
You can also make use of IntersectionObserver API which is better because you can skip onscroll event call which happens at each scroll.
I have a page where it will query the list of all users, and displays it in a design based on Cards component. In case screen size is small, I want to list users with all attributes using a different design. I can have two <div>s; one for large screens and other for small screen and hide <div> using media query (CSS). The question is, will there be any performance disadvantage for this case? I mean, will server side codes inside the div for large screen gets executed when screen is small, even though it is not displayed?
For example, you are browsing this page in large screen.
<div class ="show-for-small-only">
//some for loop in php and other code (A)
</div>
<div class ="show-for-small-only">
//some for loop and other php code (B)
</div>
Will code section (A) be executed but not displayed? or it will never hit that section? Note that css class "show-for-small/large-only is a media css query to display:none based on screen size.
Use CSS media queries, it's way faster that JQuery.
#media screen and (min-width: 480px) {
.show-for-small-only {
display: none;
}
}
but you should adapt the design of your card depending on viewport size and/or screen orientation instead of loading it twice with 2 different styles like :
.title-section {
position:absolute;
top:2%;
left:0%;
}
#media screen and (min-width: 480px) {
.title-section {
left: auto;
right: 0%;
}
}
The answers that you have been given are both good, yet i'll recommend you to take a look at bootstrap (http://getbootstrap.com/), with it you can do what you want just by adding a css classes to your divs.
You can try using this http://mobiledetect.net/
<?php
// Include and instantiate the class.
require_once 'Mobile_Detect.php';
$detect = new Mobile_Detect; ?>
// Execute only if the device is mobile
<?php if ( $detect->isMobile() ) { ?>
<div class ="show-for-small-only">
//some for loop in php and other code (A)
</div>
<?php } ?>
<div class ="show-for-small-only">
//some for loop and other php code (B)
</div>
Or maybe append stuff from the larger display div to the smaller display div if the screen size is small using jquery and style accordingly.
Html
<div class ="show-for-small-only" id="mobile">
// append here if mobile
</div>
<div class ="show-for-small-only">
<div id="wrapper">
//some for loop and other php code (B)
</div>
</div>
Jquery
if($(document).width() <= 450){
$("#wrapper").appendTo("#mobile");
}
I am attempting to use an accordion slidetoggle nav when the screen width is less than 1200px and then want to disable/remove the slidetoggle functionality when it is greater than 1200px wide.
The problem: When I load the page in Desktop width, all is well because I'm not triggering the slideToggle until screen width is "mobile" sized... <1200px.
If I then resize the screen to mobile, my toggled divs are already visible without even clicking on them. If I resize to Desktop width all is well - the toggle divs have disappeared. If I again resize to mobile and then click on the primary link to toggle the divs and leave one toggled open and then resize to Desktop, my content is invisible, but the nav links are out of alignment. When I look at the css I see that there is an inline css display:block for the toggled div.
Despite my many attempts to override that inline style (.css, .removeClass, .addClass, .attr, etc.) that damn line of code persists.
UPDATE: I wrote an IF statement to check whether the toggled div is display:block whenever there is a screen resize and it is greater than 1200px wide. This test comes back false every time, but I can see the inline css for the element: display:block. How can this happen? Here is the code for the test. Also see images.
if ( $('mobile-child-nav-links').css('display') == 'block') {
console.log("tested true");
$('mobile-child-nav-links').css('display', 'none');
} else {
console.log("tested false");
}
Dev Tools showing that the element has inline style set to display:block
Dev Tools console showing my if statement is not detecting display:block when it is clearly there
What is the deal? Please see code below:
<script>
// Responsive accordian menu jquery
$( document ).ready(function() {
var win = $(this); //this = window
var currentScreenWidth;
var mobileLinksDiv = $('mobile-child-nav-links');
var mobileLinksDivs = $('mobile-child-nav-link');
function getScreenWidth() {
return currentScreenWidth = $(window).width();
}
function enableMobileNav() {
// toggle on click of primary nav link
$('.primary-nav-link').off('click').on('click', function(e) { // prevents multiple click events from screen resizes
e.preventDefault();
$('.primary-nav-link').addClass('mobile-active-primary-link');
// locate the next sub menu div containing sub nav links and toggle it into view
var subNavContainer = $(this).nextAll('.mobile-child-nav-links').eq(0).toggle();
});
}
function disableMobileNav() {
$('.mobile-child-nav-links').addClass('hideEls');
$('.primary-nav-link').removeClass('mobile-active-primary-link');
$('.primary-nav-link').off('click'); // remove click binding to avoid multiple .click events at once
$('mobile-child-nav-links').hide(); // ensure that sub nav div and links are hidden
}
// Checking page width on initial page load
if (getScreenWidth() >= 1200) {
// do nothing
} else {
enableMobileNav();
}
// Screen resizing triggers this function
$(window).on('resize', function(e){
currentScreenWidth = $(window).width();
if (currentScreenWidth >= 1200) {
$('.mobile-child-nav-links').addClass('hideEls');
disableMobileNav();
} else {
enableMobileNav();
}
});
});
</script>
CSS
/* ================= Mobile Accordian Sub Nav ======================= */
/*Sub nav links for mobile device nav */
div.mobile-child-nav-links, div.mobile-child-nav-link {
display: none;
/*visibility: hidden;*/
background-color: #AF251F !important;
color: white !important;
letter-spacing: .1em;
text-transform: uppercase;
padding: .5em;
font-size: .8em;
font-weight: 400;
padding-left: 1em;
}
#media screen and (max-width: 1200px) {
div.mobile-child-nav-links, div.mobile-child-nav-link {
display: block;
/*visibility: visible;*/
}
}
.hideEls {
display: none;
/*visibility: hidden;*/
}
.showEls {
display: block;
/* visibility: visible;*/
}
Inline style and jQuery's .css are different things. You cannot rely on that. Use modernizr media queries.
You could try setting the style attribute to an empty string to remove any inline styles.
$('.styled-nav-link').attr('style', '');
Edit: Be careful with your jQuery selectors. I see several places in your code where there isn't a specification of whether you are selecting a class versus an id. This could be the reason your test is failing. Try double checking your code for errors. I believe the above should work.
For example, this section:
if ( $('mobile-child-nav-links').css('display') == 'block') {
console.log("tested true");
$('mobile-child-nav-links').css('display', 'none');
} else {
console.log("tested false");
}
Should be:
if ( $('.mobile-child-nav-links').css('display') == 'block') {
console.log("tested true");
$('.mobile-child-nav-links').css('display', 'none');
} else {
console.log("tested false");
}
There are other places in your code where periods need to be added too. Double check this and see if this changes anything for you.
Also, yes. jQuery's .css function is just applying the styles inline. Unless I'm mistaken, please let me know how they differ. Adding Modernizr would only add extra page weight.
After countless tests... the only thing that superseded jQuery's inline display:block was specifying an #media screen query for everything greater than 1200px wide. If you look at my CSS, I already specified display:none in the element's css and you would think this would be the style unless overriden, which is exactly what jQuery was doing. However, specifying display:none for Desktop screen widths was the only thing that worked.
/* Overrides jQuerys inline style of display:block at runtime. */
#media screen and (min-width: 1200px) {
div.mobile-child-nav-links, div.mobile-child-nav-link {
display: none!important;
}
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.
In my page design, I have put a menu button on the small resolutions, which onclick I show the menu items. If the items are in the show state (which is done by JS) and I maximize the browser (it would change to another query conditions) the items did not hide. Even I add the display:none to the css to hide them, but it did not hide. To overcome I put !important there. But it caused another issue: the menu items would not shown by the menu click.
It is appreciated if someone could help me.
Edit for better understanding.
The menu click js is as following:
$("#mobilemenu").click(function(){
var dis = $("#menuitems li").css('display');
if(dis == 'none') {
$("#menuitems li").slideDown("slow");}
else {
$("#menuitems li").slideUp("slow");
}
});
On my media query:
#media {
#menuitems li {display:none;}
}
And on the main css:
#menuitems li {display:none;}
Rather than directly setting the style in your JavaScript code, you should instead give the element a class which allows it to be styled with CSS.
For example, instead of directly setting display: block, you can show the element like this:
JavaScript
myElem.className = 'show';
CSS
myElem.show {
display: block;
}
Then with your media query, you can simply override this:
CSS
#media screen {
myElem.show {
display: none;
}
}