Detecting when styles disabled - javascript

What's the best way to detect, with JS, if the user has disabled your stylesheets? Is there a reliable way even?

How about asking them?
<div style="display:none">This site relies on CSS, please go to our CSS free version of this site</div>

Something easy would be to check the body background color for instance.
However, how likely is it someone disables CSS and not Javascript? (dunno what you use it for obviously)

I would have a small, empty div sit on the screen. When the page loads, use JS to check the 'display' property of that div. If it's 'none', then your css has successfully been loaded. If not, they may have to turned off / changed your styles.

If you're in control of the stylesheet you can have a "calibration" style.
Have a classname that applies some CSS property to an element. A good cross-browser safe property can be background-color.
When loading your JS try to dinamically create an element and apply the classname to it. Check if the properties match (the one on the element with the one you're expecting).
BoltClock's comment comes close. You can use window.getComputedStyles(calibrationElement, null) but that will fail in older IE browser versions.
See documentation for getComputedStyles
Feel free to remove the "calibration" node after you've checked it.

Assuming your primary external or inline stylesheet is loaded before the script, you can use this:
if (document.styleSheets.length){} // stylesheets are disabled
https://developer.mozilla.org/en-US/docs/DOM/document.styleSheets
It's IE5+ compatible too as per: http://www.jr.pl/www.quirksmode.org/dom/w3c_css.html
The caveat is that, if styles are turned off after the window has loaded (which only causes a browser repaint), the document.styleSheets object won't change on the fly. Additionally, as noted in the comments below, this will not work for Firefox when using the View -> Page Style -> No Style feature, for which styles are still loaded, just not applied to the view.
To detect the initial state across browsers, or changes on window.onresize, it can be done with a style reset on the body, with the following code placed after <body> or in a DOMContentLoaded event:
if (document.body.clientWidth !== document.documentElement.clientWidth) {
// Styles are disabled or not applied
}
This works if you use body { margin: 0; } in your stylesheets (with no particular custom width), because it makes the body element the same width as documentElement (a.k.a. the <hmtl> element) while styles are active.
When styles are turned off or disabled, the body.clientWidth will revert to the browser's default body width, which always has a margin (8px by default in CSS 2.1 major browsers ) and therefore different from documentElement.clientWidth.
Should your site design use a specific margin other than 8px for the body, here is an alternative option:
if (document.body.clientWidth === document.documentElement.clientWidth-16) {
// user styles are disabled or not applied (IE8+ default browser style applies)
}

At least in Safari, part of the difficulty is that with CSS off the elements still report CSS attributes. But if you test on the actual rendering of a property then you can tell. Width is probably the simplest (and most common) property you can test on.
Below is a sample script (it uses jQuery, but could easily be un-jQueryfied) that will test for CSS. We just load an empty div on the page, give it a width of 3px using CSS, and then test that div's width. If the width is not 3 then CSS is disabled. Obviously you have to make sure that this doesn't colide with any other styles you might have that could cause the width to be other than 3. But it gives the general idea.
<html>
<head>
<title>Test</title>
<style type="text/css">
#testCSS {width: 3px;}
</style>
</head>
<body>
<div id="testCSS"></div>
<div id="message"></div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
jQuery(document).ready(function(){
if (jQuery("#testCSS").width() != 3) jQuery("#message").html("CSS Disabled");
});
</script>
</body>
</html>
Edit: sorry about the messy code example. It doesn't seem to like my code tags. Here's a JSfiddle with the code. Obviously you won't be able to disable CSS and test there, but you can pull the code from it: http://jsfiddle.net/3FvdL/1/

Related

which HTML tags "support" background-color

How can I get/produce a list of all HTML elements (tagNames) for which background-color is meaningful (that is has an effect) ?
For example DIV should be in the list but LINK should not.
(I need this to optimize a chrome extension that goes over the entire DOM and calculate new background color values)
UPDATE
After much discussion of what the specific behaviour actually is, I think it has been demonstrated that any element (inlcuding made-up ones) will can have the background set, just as it says in the spec.
So, perhaps your chrome extension should check to see if elements have display: none, height: 0, or width: 0 and exclude them from your list by these criteria. That is, exclude elements that are being hidden from displaying in the viewport.
According to the spec, all elements can have a background and background-color. However, some elements are not allowed inside a <body> and so should not ever be displayed on a web page. I don't know which of these (or why!) simply do not render a background or color, but these can be skipped by your extension.
<base>
<link>
<meta>
<noscript>
<script>
<style>
<template>
<title>
There may be more elements that are not generally displayed, but these are from the Metadata section of the HTML5 spec.
The specification said all elements. But you have to think if it make sense or not :)
https://www.w3.org/TR/CSS2/colors.html#background-properties
Value: <color> | transparent | inherit
Initial: transparent
Applies to: all elements
Inherited: no
Percentages: N/A
Media: visual
Computed value: as specified

Use jQuery to get css properties of a class/id that that doesn't exist in the page

As it said in the title. I want this javascript...
$("#mrNotAppearing").css("background-color");
to return "red" based on this css...
#mrNotAppearing {
background-color: red;
}
given that there are no elements in the document that actually have the id mrNotAppearing
I'm using media query checks with jQuery to get window widths as seen here and I thought it might be nice to use some "dummy" css that definitely won't get in the way of anything.
I'm also open to other suggestions that achieve the same result.
Plan B, I'll just go with actual css or add some dummy property to body?
Updating for clarity:
It can be difficult to sync javascript that requires particular window widths with media query widths in the css, which can cause layout problems.
Instead, you can query the status of the css itself. As so:
body {
background-color: blue;
}
#media (min-width: 42em) {
body {
background-color: red;
}
}
Then, in the javascript:
if($(body).css("background-color")==="red"){
// we know down to the pixel that it's safe to trigger the javascript
// because the media query went off.
}
All I'm trying to do is add a dummy entry in the css that will be used solely for triggering the javascript. I could use an existing property--and may have to--but I'd like to make it explicit what I'm doing. Or I'm at least toying with the idea.
I apologize for the confusion. I was going for brevity.
P.S. the whole point of the question is to use a style that will 100% not be appearing in the document. And will never change, even if the layout does.
EDIT: Ha, okay, final answer. em does indeed return as px. So...
I'm going to answer my own question because I'm pretty sure it isn't making sense to anyone. Also, I don't know if this is a good idea, but it seems to work for my purposes. So, my solution:
Style the <style> tag. It's in the DOM, it's not structural, and jQuery can get css properties from it. Like so...
style {
width: 672px;
}
and then...
$("style").css("width");
will return 672px
I'm probably over-thinking this. And still probably not making sense. And I have no idea if this works on any browser but Chrome or if it's a terrible idea for some reason, but I think it's kind of appealing, semantically.
Any other thoughts?
You have access to all css rules through document.styleSheets, there is no need to apply to an element.
https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet
Here is another answer on how to get the style based on a class name:
How do you read CSS rule values with JavaScript?
EDIT
Although, it would be a lot easier to render the element off canvas for a brief moment:
var $dummy = $('<div>').addClass('class1 class2 class3').css({position: fixed, left: 100%}).appendTo('body');
// collect all info you need here;
$dummy.remove();

CSS: specificity not behaving for js injected stylesheets?

As part of a mobile-first build, i am loading the 'desktop' css dynamically in a blocking fashion
<script type="text/javascript">
var mq = window.matchMedia("(min-width: 640px)");
if(mq.matches){
var stylesheet = document.createElement('link');
stylesheet.href = '<?php echo $src ?>';
stylesheet.rel = 'stylesheet';
stylesheet.type = 'text/css';
document.getElementsByTagName('head')[0].appendChild(stylesheet);
}
</script>
However, webkit and ff give more power to the css loaded pre-injection.
Even if SetTimeout 3 seconds before loading mboxes.css, the browsers still favour the css rules that were not injected.
How can i get the css specificity rules to behave?
The problem is the ordering of the CSS that is being loaded, it is loading the values of event_core as the master so to override this you have 2 easy options without rewriting the js.
You can execute the Javascript before the event_core.css or after depending what you have at the moment.
Or the easiest way but depends realistically how much CSS you have in mboxes.css would to use !important within the CSS which will tell the browsers these are most important and become the new master.
For example
.mob p {
color:white!important;
}
Or make the edit the rules so that both are the same, for example .content > .mbox p
Ok, worked this out.
For the CSS to behave "normally" it needs to be injected into the <body> not the <head>.
document.getElementsByTagName('body')[0].appendChild(stylesheet);
The problem has nothing to do with the way the css files is loaded and more to do with the rules of css precedence. Basically, the more specific the selector, the higher priority the rule has. In your case both selectors are the same priority (class and element selector), so some browsers will choose one, other the other the last loaded should override the first, but it's not something I would count on.
The fix is to make the rules in mboxes.css more specific like .mbox.main_content p.
A second option is to add !important after each style like (like color: white !important), but I would recommend against that.

JavaScript Cursor Change (and change back again)

I have this page that does some funky database stuff that takes a couple seconds to process, and in the meantime I'd like to set a "wait" cursor so the user doesn't flip out and keep clicking the button. I've looked at the
document.body.style.cursor = "wait"
thing, the problem with this is that it only works when the mouse is over the body of the page (i.e. still shows normal pointer if it's over a button). How can I set it so that no matter where the mouse is on the page, it shows a wait icon?
A second part to this question is, once it's done it's thing, how do I set it back? If I set it back to "default", this seems to override any "hover" cursor changes I had set in my CSS (so it no longer becomes a hand when over a specified object, etc.).
EDIT: the first answer works nicely, except in IE it doesn't refresh the cursor (so you notice the change of cursor type) until you actually move the cursor. Any fixes?
What I suggest is two things:
a) Better write a CSS like
body.waiting * { cursor: wait; }
b) Use the JS to handle the body class
/* when you need to wait */
document.body.className = 'waiting';
/* to remove the wait state */
document.body.className = ''; // could be empty or whatever you want
You might want to add the class instead of replace the whole class attribute, what I suggest is to use something like jQuery for that.
EDIT 2019: don't use jQuery for just this, use classList
The styling should be handled via CSS, as stated by W3C.com:
CSS is the language for describing the presentation of Web pages, including colors, layout, and fonts. ... The separation of HTML from CSS makes it easier to maintain sites, share style sheets across pages, and tailor pages to different environments. This is referred to as the separation of structure (or: content) from presentation.
As suggested by Tom Rogerro, add a line to your CSS file:
body.waiting * { cursor: wait; }
However, your script should not overwrite the entire list of class names. Tom suggested setting the class names via jQuery, but jQuery is unnecessary in this case. Simple Javascript can do this.
To add a class name 'waiting' to the document body:
document.body.classList.add('waiting');
To remove a class name 'waiting' from the document body:
document.body.classList.remove('waiting');
For your first problem, try using cursor: wait !important;.
For your second problem, the default cursor for elements is cursor: auto;, not cursor: default; or cursor: inherit;.
If you are happy using JQuery then a quick way to solve this would be to use:
$('*').css('cursor','wait')
I don't know how elegant this is but it has been working for me,
Not an answer to the question, but a way of achieving what is wanted.
Make a div (see class below) visible when you are loading.
ensures no element is accessible and dimmed display indicates this.
you can add an animated gif to indicate something is going on instead of the cursor.
.loading{
position:fixed;
height:100%;
width:100%;
left:0;
top:0;
cursor:wait;
background:#000;
opacity:.5;
z-index:999}
Any elements that don't inherit the cursor by default (such as buttons) will need to set the cursor to inherit:
someButton.style.cursor = 'inherit';
To go back to the default for an element (and not break things like :hover with a forced cursor), set it to an empty string:
document.body.style.cursor = '';
I tried everything but finally this jquery worked, especially if you want wait cursor over all elements including buttons and links.
define at the top of angular .ts file
declare var $: any;
and then where ever you want wait cursor:
$('*').css('cursor','wait');
and remove wait:
$('*').css('cursor','auto');
To fully replace the CSS toggling behaviour, we can simply use this inline:
<img
src=https://cdn.sstatic.net/Img/unified/sprites.svg
onmouseover="this.style.cursor = 'crosshair'"
>

Quickly repaint array of unicode symbols in JavaScript

I want to change background/foreground color of many symbols with the same CSS class. Right now I'm doing it with jQuery — like $('back_COLORED').css('background-color', '#00FF00'), but this approach is slow when there are many elements with such class (>900).
Seems it's because jQuery don't change CSS rules itself, but finds all elements one-by-one and applies inline styles to them. At least, this is what I see in inspector. So, the question is:
How can I change the CSS rules itself?
Will it be much faster?
Can I make it cross-browser (IE6 doesn't count)?
UPD: I'm trying to make some kind of color scheme editor. The source is at http://github.com/kurokikaze/cinnabar/. Don't mind PHP things, editor is fully client-side (with just some libraries fetched from the net).
UPD2: Tried canvas approach, still slow. Canvas branch is at http://github.com/kurokikaze/cinnabar/tree/canvas.
The most cross-browser friendly way to override a class definition is to write a new rule and add it to the end of the last stylesheet in the document. You can edit an existing style rule, but even some recent browsers can make it difficult.
function newRule(selector, csstext){
var SS= document.styleSheets, S= SS[SS.length-1];
// this example assumes at least one style or link element
if(S.rules){
S.addRule(selector,csstext,S.rules.length);
}
else if(S.cssRules){
S.insertRule(selector+'{'+csstext+'}'),S.cssRules.length)
}
}
newRule('.someclass','background-color:#0f0');
You can add as many 'property:value;' bits in the csstext as you need.
Remember to prefix a '.' to a class name or a '#' to an id,
and the css must be written as a style rule (with-hyphens, not camelCase).
Of course, it will not override inline styles, and it is overkill for small, local changes.
It also may make the redrawing of the page more obvious than changing one element at a time,
but it may be just what you need here.
There are different ways depending on which browser you are dealing with. This is documented on Quirks Mode.
Some libraries provide an abstraction layer, such as YUI's StyleSheet utility.
There should be a significant performance boost since you aren't using JS/DOM to cycle through all the elements.
Another approach would be to predefine your styles:
body.foo .myElements { … }
And then edit document.body.className
If you can select the parent div by id, maybe you could select by tag inside it? Or are there elements of the same kind that should change color and that should not, inside the parent?
It would be nice to have an idea of what you're building here. 900+ objects seems to be a lot... maybe a completely different approach could be used? Canvas, SVG?
Try hiding the items you want to change before changing them, make the change and then display them again. This is common practice to speed up things as you minimize the repaint events in the viewport. In this case when you only setting one css property it might not be that of a benefit but it´s worth a try I say.
Try:
$('back_COLORED').hide();
$('back_COLORED').css('background-color', '#00FF00');
$('back_COLORED').show();
or
$('back_COLORED').hide().css('background-color', '#00FF00').show();
I would stick in trying changing a CSS property, instead of parsing the DOM.It is about the CSS engine vs. DOM+JS here, and the winner is clear.
It happens I just uploaded a tiny library that replaces CSS by Javascript: jstyle
This is may be an overkill, but you will find in the source code of jstyle.js all the code you need to update cross browser the CSS properties of your page.
I think a better solution would be to write a more specific CSS rule (that would override the normal colour) that can be activated by simply changing one element's css class.
So for example if you had the following structural markup:
<div id="container">
<span class="colored">Test 1</span>
<span class="colored">Test 2</span>
</div>
And CSS:-
.colored { background-color: red; }
.newcolor .colored { background-color: blue; }
Then in your jquery you add the .newcolor class to the container div:-
$('#container').addClass('.newcolor');
When you do that the second CSS rule will override the first because it is more specific.
Inject the css code into a style tag:
var style = $('style').attr({
type:"text/css",
media:"screen",
id:'changeStyle'
}).html('.tempClass { color:red } .tempClass p { background:blue }').prependTo('body');
and on every changes on your color with color picker you only rewrite the html inside of #changeStyle tag.
Have no idea if it works (didn't tested) but you should give a try.
This is jQuery pluggin for work with css rules: http://flesler.blogspot.com/2007/11/jqueryrule.html
not sure about its performance, but worth a try.

Categories

Resources