I am currently using display:none to hide all the divs on my website. Users click on like for example "info" or "contact" and the appropriate div will slide down via JQuery. To support users without Javascript, the links goes to "info.php" and "contact.php" if Javascript is no enabled.
This is quite a hassle to maintain because I have to update both the main page and the non-javascript versions (info.php, contact.php etc) when I make any changes.
What is a sensible back up to JQuery sliding divs for users without Javascript?
When I have understood you right, make a php-file with the static content. (The content on all sites) und include the content (info/contact) per include from another file depending on a GET Param like "page".
Hide the <div>s with jQuery so that users without JavaScript can still see all the <div>s in one long page. Users with JavaScript, on the other hand, can slide the <div>s as usual.
jQuery IS JavaScript - is cannot be a backup plan.
one does not simply use the terms JavaScript and jQuery interchangeably
jQuery is a JavaScript library. By disabling JavaScript, the jQuery scripts will not be able to hide the <div>s. The key is to keep it functional when JavaScript is not available. As long as you do not perform critical manipulation to the page that would render it non-functional without JavaScript, you can cater for those non-JavaScript users. In this case, putting the modification work over to jQuery (or JavaScript) is a way to preserve functionality.
At first add a class to_hide to all divs which should be hidden when javascript is activated.
The simplest way is to hide the divs like this on page load:
$(document).ready(function() {
$('.to_hide').hide();
});
Note that if you do this, the layout will blink when loaded (the full content will be shown at first and then the dynamic divs will be hidden).
To avoid blinking you can add css rule for to_hide class dynamically. Use the following function in the <head> to do that:
function dyn_css_rule(sSelector, sCssText) {
try {
var aSS = document.styleSheets;
var i;
for (i=aSS.length-1; i>=0; i--) {
var oCss = document.styleSheets[i];
var sMedia = (typeof(oCss.media) == "string")?
oCss.media:
oCss.media.mediaText;
if (!sMedia
|| sMedia.indexOf("screen") != -1
|| sMedia.indexOf("all") != -1
) {
break;
}
}
if (oCss.insertRule) {
oCss.insertRule(sSelector + " {" + sCssText + "}", oCss.cssRules.length);
} else if (oCss.addRule) {
oCss.addRule(sSelector, sCssText);
}
} catch(err) {
var tag = document.createElement('style');
tag.type = 'text/css';
try {
tag.innerHTML = sSelector + " {" + sCssText + "}";
} catch(err) {
tag.innerText = sSelector + " {" + sCssText + "}";
}
document.getElementsByTagName('head')[0].appendChild(tag);
}
return sSelector + "{" + sCssText + "}";
};
dyn_css_rule('.to_hide', 'display: none');
A Pure CSS Solution
This may or may not work depending on the situation, but you can actually mimic a drop-down menu's behavior with css selectors in IE8 and up. Here's an example. Click on the menu, and as long as you hover around the content the content will appear, no javascript required.
Functionality
By default, all the content is hidden. However, thanks to the :active pseudoclass, you can change the content to display when the parent is clicked. This is pretty inconvenient though - the user has to hold down the mouse to see anything. However, we can cheat a bit - by adding a :hover pseudoclass that displays the content, if the user clicks and hovers the content will stick around.
So far, we have this css:
.container.content {
display: none;
}
.container:active .content {
display: block;
}
.content:hover {
display: block;
}
This is a little flaky though - you have to move your mouse down over the content to have it persist, and will likely confuse. We can cheat a bit though by making the content larger than it appears. A simple way to do this would to be just to padding (that's what I've done in the example I added), but this can cause some odd reflow issues. A better way I think is to add deliberate spacing divs that add to the size of the content without changing the flow.
If we add this
<div style="position:absolute; top:-50px; height: 50px; width: 100%;"></div>
to the start of the content, there's an invisible div hovering over the menu, which will extend the area on which hover works. A similar thing can be done to the bottom, leaving us with a solution that has a larger hover area, and doesn't trigger reflows beyond the main content.
Remaining Problems
Anyway, this isn't perfect since it certainly isn't as flexible as javascript. There's no sliding, and you can't reliably make the content show up if the user mouses out.
As other people suggested, you can still improve this with javascript after the fact should the user have it enabled though - this can still work as a decent backup to noscript users.
I ended up using a solution that combines Antony's answer and this answer: https://stackoverflow.com/a/8928909/1342461
<html class="no-js">
<body>
<div id="foo"></div>
</body>
</html>
#foo
{
display: none;
}
html.no-js #foo
{
display: block;
}
$(document).ready(
function()
{
$('html').removeClass('no-js');
}
);
All the divs will be seen by people without javascript. Then, I can set my navigation links to a href="#info" for example, to get it to scroll down to the correct div for non-javascript users while doing "slide.down()" etc for javascript users.
Have your info.php main text in an include file. Lets say info.inc.php
When non-js user clicks the link, they go to info.php into which the include file is, well, included.
But when a js user clicks the link, you load the info.inc.php onto your div and only THEN show it with jquery.
Say
$('a.info').click(function(e){
e.preventDefault();
$('#infoDiv').load('info.inc.php')
.show();
return false;
});
When you need to update content, just update the include file.
Related
I am writing an Ember.js web-application, designed to be the user interface of an automation system, that polls data from the LAN server every two seconds in order to have on display always the "live" process data.
This application is accessible from a wirless hotspot, to allow registered users to browse it, so potentially any device (tablets, smartphones, laptops...) could be the actual client.
On some pages, there are icons that change according to some conditions, and to implement this effect I declared several img tags, and I make the ones I dont need invisible by styling it with CSS display: none.
In HTML:
<img class="icon-active" src="/images/icon1.jpg" />
<img class="icon-inactive" src="/images/icon2.jpg" />
In Javascript, every two seconds:
var visibleElement = null;
var invisibleElement = null;
if( this.get("whatever").active == true )
{
visibleElement = this.element.getElementsByClassName("icon-active")[0];
invisibleElement = this.element.getElementsByClassName("icon-inactive")[0];
}
else
{
visibleElement = this.element.getElementsByClassName("icon-inactive")[0];
invisibleElement = this.element.getElementsByClassName("icon-active")[0];
}
visibleElement.style.display = null;
invisibleElement.style.display = "none";
Everything works fine, on laptops and tablets, but on some smarthphones, the images are loaded every time I set visibleElement.style.display = null;, it means, every two seconds, the visible icon is GETted again and again from server.
I dont want it to happen at first to reduce data traffic, that is not a problem at all, but I don't like fetching resources even if not required, second, the image reload generates an annoying flicker effect, that is really unlookable.
How can I force every client to cache images as tablets and laptops do?
----- more info -----
Thanks everyone for your support! Here you have some news:
I tried as suggested to comment-out all the javascript code that works on style.display and modify the HTML (template) as follows:
{{#if whatever.active}}
<img class="icon-active" src="/images/icon1.jpg" />
{{else}}
<img class="icon-inactive" src="/images/icon2.jpg" />
{{/if}}
and I got the same result. So I tried to roll back the HTML and leave the javascript commented, in such way I should have always all the icons visible, and surprise... they are all flickering and being requested every two seconds...
I guess the issue is due to the fact that some (maybe not up-to-date?) smartphone browsers are redrawing completely the images as the ember-views bound data gets updated. I will investigate more on which browser/version has this problem and make sure all of the testing devices use the last version of their browsers - since ember uses the latest javascript features, better cut-out old fashioned clients.
The code used to refresh data every two seconds follows, please notify if you see anything uncommon:
import Ember from 'ember';
export default Ember.Route.extend({
model() {
// record generation code here...
},
afterModel()
{
Ember.run.later(this, function()
{
this.refresh();
}
, 2000);
}
});
----- solution -----
With new up-to-date browsers is not happening, so, this behavior exists only "in the past"... For sake of completeness I should find a solution to make it work properly also on "old" browsers, but I don't have time to spend on this.
If anyone of you figures out a 360 degrees solution an answer is still appreciated.
As I see those icons are static. So my suggestion is to use css:
1) Use spans(or divs) instead if images
2) Add icon as background image
html:
<p><span>active parameter</span><span class="icon active"></span></p>
<p><span>inactive parameter</span><span class="icon inactive"></span></p>
css:
.item
width: 16px //icon dimensions
height: 16px
// you may also add display: inline same as for images and so on
.active
background-image: url('/images/icon1.jpg')
.inactive
background-image: url('/images/icon2.jpg')
Benefit: Images will be loaded once by css engine along with styles.
PS: You can get rid of inactive class if your icon is inactive by default:
html:
<p><span>active parameter</span><span class="icon active"></span></p>
<p><span>inactive parameter</span><span class="icon"></span></p>
css:
.item
width: 16px //icon dimensions
height: 16px
background-image: url('/images/icon2.jpg')
// you may also add display: inline same as for images and so on
.active
background-image: url('/images/icon1.jpg')
PPS: It's really easy to manage classes with Ember by using classNameBindings
You need to set the image display to none.
Set the display to either inline-block or block for visible and none for not visible.
Preferably use css classes, since you are doing it with javascript. It might delay the action of hiding the images while the page loads.
You can use css classes like
.active{
display:block;
}
.inactive{
display:none;
}
Use these classes to add or toggle for a specific img element.
Still there will requests to server for images because you are only hiding the images through styles.
Display MDN
E.g. I have the following layout:
<div contenteditable="true">
<span class="text-block" contenteditable="false">
<span contenteditable="false">Name</span>
<a href="javascript:void(0)">
<i class="small-icon-remove"></i>
</a>
</span>
</div>
So, how to disable this:
and this:
I spent on this a lot of time myself, when trying to completely hide control selections (this is how they are called) in CKEditor's widgets. Unfortunately I don't have a good news.
Solution 1
First of all, there's a mscontrolselect event. When I found it (and the fact that its name has an ms prefix) I was very happy, because according to MS it should be preventable.
But it turned out that it's totally unstable. Sometimes it is fired, sometimes it isn't. It varies between IEs versions, DOM structure, attributes, which element you click, is it a block element, etc. The usual MS's crap. But you can try:
function controlselectHandler(evt) {
evt.preventDefault();
}
document.body.addEventListener('mscontrolselect', controlselectHandler);
However, this will completely block selection (if it worked). So you'll make those elements unselectable at all.
Solution 2
Then there's a second option, more reliable - moving selection somewhere else after such element was clicked. There are few ways this can be implemented. In CKEditor we're fixing selection on mousedown... and mouseup because (again) sometimes it's not enough for IE and it depends on dozen of conditions. You could also listen to selectionchange event and fix selection there.
However, again, we're also talking about blocking selection of such element.
Solution 3
Therefore, the third option is to block not selection, but the resizestart event. CKEditor combines this with enableObjectResizing command: https://github.com/ckeditor/ckeditor-dev/blob/a81e759/plugins/wysiwygarea/plugin.js#L211-L218. This solution will prevent resizing, but of course will not hide those ugly borders.
Solution 4
As I mentioned, I worked on this problem in CKEditor. We managed to make it possible to have non-editable elements inside editable, but with completely controllable and unified behaviour between browsers. The complete solution is too complex to be explained on StackOverflow and it took us months to implement it. We called this feature widgets. See some demos here. As you can see there are no control selection when non-editable element is selected. The selection appears on a short moment only between mousedown and mouseup, but only in specific cases. Except for that everything works as it would be native (although it's a completely fake thing).
Read more in the Introduction to Widgets and in the Widgets Tutorial.
This post was critical when solving this issue for me (works in tinyMCE):
How to Remove Resize handles and border of div with contentEditable and size style
By placing a contenteditable DIV within a non contenteditable DIV the handles do not appear in IE or FF but you can still edit the content
Ex.
<div class="outerContainer" contenteditable="false">
<div class="innerContainer" contenteditable="true">
</div>
</div>
Solution 5
When the focus is moved to child control change the content editable element attribute value to false and same way once your focus leaves from child control again set the content editable to true.
To disable the resize handles, all I had to do was add the following for IE11:
div {
pointer-events: none;
}
For firefox executing this line after the contenteditable element has been inserted works:
document.execCommand("enableObjectResizing", false, false);
What solved the problem for me was removing a max-width: 100% !important; line from the CSS properties of the DOM elements within the contenteditable DIV. Hope it helps!
BTW this does not happen on MS Edge... fingers crossed that this shows a movement in the right direction by MS :)
I had the same problem. It appears that from previous posts here there are certain behaviors that IE recognizes and will add this paragraph focus/resize. For me it was because I had a style for paragraphs within the contenteditible div.
Removing:
div[contenteditble="true"] p{
min-height:1em;
}
Fixed it for me.
SOLVED!
On placing the non content-editable span within a content-editable BODY, it started showing a resize-able SPAN container. What just fix my problem was a simple one-liner CSS style
pointer-events: none; on the inner SPAN tag.
min-width: 1.5cm;
display: inline-block;
pointer-events: none;
<body content-editable="true">
<span>Sample Text</span>
</body>
overflow:hidden also can cause this issue, like:
ul, ol {
overflow: hidden;
}
I have the same problem with CKEditor 4.4.7 in IE11. As a workaround, I save the current dimensions of an element on "mousedown" and set the "min-width", "max-width", "min-height" and "max-height" style properties to it's current dimensions. By that the element will be displayed in it's original size during resize. On "mouseup" I restore the style properties of the modified element. Here is my code:
$('textarea').ckeditor().on('instanceReady.ckeditor', function(event, editor) {
var $doc = $(editor.document.$);
$doc.on("mousedown", "table,img", function() {
var $this = $(this);
var widthAttrValue = $this.attr("width");
if (widthAttrValue) {
$this.data("widthAttrValue", widthAttrValue);
}
var widthStyleValue = this.style.width;
if (widthStyleValue) {
$this.data("widthStyleValue", widthStyleValue);
}
var width = widthStyleValue || widthAttrValue || String($this.width())+"px";
var height = this.style.height || $this.attr("height") || String($this.height())+"px";
$this.css({
"min-width": width,
"max-width": width,
"min-height": height,
"max-height": height,
});
$doc.data("mouseDownElem",$this);
}).on("mouseup", function() {
var $elem = $doc.data("mouseDownElem");
if ($elem) {
$elem.removeAttr("height").css("height","");
var widthAttrValue = $elem.data("widthAttrValue");
if (widthAttrValue) {
$elem.attr("width", widthAttrValue);
$elem.removeData("widthAttrValue");
} else {
$elem.removeAttr("width");
}
var widthStyleValue = $elem.data("widthStyleValue");
if (widthStyleValue) {
$elem.removeData("widthStyleValue");
}
$elem.css({
"min-width":"",
"max-width":"",
"min-height":"",
"max-height":"",
"width": widthStyleValue || ""
});
if (!$.trim($elem.attr("style"))) {
$elem.removeAttr("style");
}
$doc.removeData("mouseDownElem");
}
});
});
Here's what I did to fix this problem. For me this would only happen when the contenteditable element was empty and the resize handles would disappear when there was content so I created the following CSS only solution to go about this:
[contenteditable]:empty:after {
content: " ";
}
The idea behind the solution is whenever the contenteditable field is empty it applies a blank space pseudo element thus removing the resize tags from showing up when the user selects the contenteditable field. Once the user has entered anything then the pseudo element disappears.
Note, because of the use of pseudo elements, this fix only works on IE9 and up.
I had the same problem because I put CSS rules for the max-width onto all child elements within the contenteditable. Removing it or restricting it to images did the trick.
[contenteditable] * { max-width: 100%; } // causes the issue
[contenteditable] img { max-width: 100%; } // works fine for me
Make sure that no <p> elements are affected by the max-width property.
Nothing anyone else recommended here or in other threads really worked for me, but I solved it by doing:
[contenteditable="true"] p:empty {
display: inline-block;
}
This way the resize boxes disappeared, but I could still set my cursor below or in the P blocks to edit them.
Sorry, but I am a complete noob with JS. I am using Bootstrap to try build my first website.
The website has a fixed top navbar. I want to change the navbar's border-bottom properties when it reaches the bottom of the header div (about 480/500px down the page).
Currently the border-bottom is white, but I want to change it to blue when scrolled beyond a certain point (bottom of header) and then change back to white if scrolled back up again. The effect I want is the appearance of the fixed nav 'picking up' the bottom border of the banner section when it scroll's past.
I have given the navbar div an id of id="n1", and created a class .navbar1{border-bottom: 1px solid rgba(46,152,255,1)!Important;} to add to override the existing css.
I am not using jQuery because I don't use much JS and I don't want to call it just for a few things - it is a big file. I have tried various things without any success. Probably because they relied on jQuery? I don't know. For example, the last one was:
$(window).scroll( function(){
if($(window).scrollTop() > 50) $("n1").addClass("navbar1");
else $("n1").removeClass("navbar1");
});
Anyway, I was hoping someone may be able to help me with the plain/pure JS to change the attribute properties as described. Thank you in advance for any assistance.
EDIT:
This has been kindly answered below. But given some comments, I thought it might be useful to clarify my use of JS: My website requires very little JS functionality so I have chosen to inline my JS, rather than call an external JS file or files - such as jquery.js and bootstrap.js which are relatively large files.
Although I lose the benefit of caching the JS, and my HTML is slightly larger, I am happy to do that because in my case I feel those losses are more than made up for the increased initial page load speed from:
not having to make additional http requests,
not having to load relatively large files.
It is certainly not for everyone, but I feel that it suits my case. Having said that, when all is done and my website is up and running I will probably do some testing to see whether a custom external JS file is better again. Basically, I am only using Bootstrap for its CSS functionality, not its JS functionality. I hope that makes sense.
This demo may help you!
It doesn't use jQuery.
Here is the javascript code:
window.onscroll = function() {
var nav = document.getElementById('nav');
if ( window.pageYOffset > 100 ) {
nav.classList.add("navbar1");
} else {
nav.classList.remove("navbar1");
}
}
I did a small change on #radonirina-maminiaina amazing answer.
While it works, I do prefer avoiding doing unnecessary DOM calls during the onScroll event. The onScroll event can be triggered quite often on some devices, so it's best to keep its handler as fast as possible.
In my solution, I cache the nav DOM element on a closure and I only update its classes if the offset changes.
window.onscroll = function () {
let isScrolled = false
const scrollPoint = 100
const nav = document.getElementById('navbar')
function onScroll () {
if ( window.pageYOffset > scrollPoint && !isScrolled ) {
nav.classList.add("scroll");
isScrolled = true
} else if (window.pageYOffset <= scrollPoint && isScrolled) {
nav.classList.remove("scroll");
isScrolled = false
}
}
onScroll() // Makes sure that the class is attached on the first render
return onScroll
}()
I've been using ChocolateChip-UI (http://www.chocolatechip-ui.com/) for a couple of days, and really like the way it manages to map the look to established mobile standards.
One problem I have with adapting my site to CC-UI has been my inability to make the address bar on scrolling. I tried everything, including meta tags, or even the hack with scrolling to 1px at onLoad. Nothing worked. As you can see, even the demo they have does not seem to make the address bar disappear.
How can I fix this? I really need those 40-50px on the top. I think that the address bar, especially on iOS older than v7, breaks the consistency of the design, and consequently lowers the attention of the user
There is a discussion about this in the CHUI Google Group. You can reach it here: https://groups.google.com/forum/#!topic/chocolatechip-ui/XOr7b8HGNK8
From Robert Biggs answer on this
$('body').addClass('hideGlobalNav');
Then have some CSS in your document's header for a custom style:
body.hideGlobalNav #global-nav {
display: none !important;
}
body.hideGlobalNav #articleWithoutGlobalNav {
top: 0 !important;
}
Then, you'd need to remove that class from the body tag when the user
navigates away. I'm not sure how the navigation is set up in your app,
whether the user leaves by going back or forward, but you can handle
that in several ways. You can add event listeners for navigation and
when the user is leaving #articleWithoutGlobalNav, then you would
remove 'hideGlobalNav' from the body tag. You could do something like
this:
$('article').on('navigationend', function(e) {
// e.target is the current article that loaded
if (e.target.id === 'articleWithoutGlobalNav') {
$('body').addClass('hideGlobalNav');
} else {
$('body').removeClass('hideGlobalNav');
}
})
I have a lot of data being placed into a <DIV> with the overflow: auto style. Firefox handles this gracefully but IE becomes very sluggish both when scrolling the div and when executing any Javascript on the page.
At first I thought IE just couldn't handle that much data in its DOM, but then I did a simple test where I applied the visibility: hidden style to every element past the first 100. They still take up space and cause the scrollbars to appear. IE no longer had a problem with the data when I did this.
So, I'd like to have a "smart" div that hides all the nested div elements which are not currently visible on the screen. Is there a simple solution to this or will I need to have an infinite loop which calculates the location of the scrollbar? If not, is there a particular event that I can hook into where I could do this? Is there a jQuery selector or plugin that will allow me to select all elements not currently visible on the screen?
You want to use display: none instead of visibility: hidden
Elements that are hidden using visibility: hidden will still claim their space in the viewport.
As far as using a "smart" div, as you describe it. You may be interested in something like the jQuery autopager plugin.
I was able to achieve the goal in my question but it did not deliver much of a performance gain in IE. I reworked my whole page but here's the unfinished code in case anybody else wants to do something like this and wants to know where to start:
//Where 'child' = element inside of a div ('parent') having overflow: auto style
function isChildOnScreen(child, parent) {
var topOfChild = child.offsetTop;
var bottomOfChild = child.offsetTop + child.offsetHeight;
var topOfParent = parent.scrollTop;
var bottomOfParent = parent.scrollTop + parent.offsetHeight;
var makeVisible = (topOfChild >= topOfParent && topOfChild <= bottomOfParent)
||
(bottomOfChild >= topOfParent && bottomOfChild <= bottomOfParent)
||
(topOfChild < topOfParent && bottomOfChild > bottomOfParent);
return makeVisible;
}