How to target Mac with CSS or Javascript - javascript

I need to use specific styles for Mac in my stylesheet. What is the best way to do it?

In an ideal world you shouldn't need to fork styles for different os. However sometimes a specific design will require it - particularly with styling form elements.
If you really have to, the following script will set a class on the html element:
(function (flags, app) {
os('Win', 'os-win');
os('Mac', 'os-mac');
if (document.documentElement) {
document.documentElement.className += flags.join(' ');
}
function os (s, f) { if (app.indexOf(s) !== -1) flags.push(f); }
}([''], String(navigator && navigator.appVersion)));
You can execute this in the html head which means the page doesn't re-render after the initial loading.
You can then use mac specific css rules like so:
.os-mac #my-element { ... }
Note: The best thing to do is find a solution that doesn't require forking for the OS.

or JavaScript
if (navigator.userAgent.match(/Macintosh/))
// do stuff for Macs here, such as load a stylesheet
But really, this is bad practice and you shouldn't do it.

The navigator.platform property returns 'MacIntel' on OS X Safari, Chrome and Firefox (I don't have any PPC boxes at hand). If I would do it, I would check for that, and probably put in a class named .mac on the <BODY> tag and use that as a basis for the Mac-specific stuff.

Only for mac:
<script>(function(e,t){function n(n,r){if(t.indexOf(n)!==-1)e.push(r)}n("Mac","os-mac");if(document.documentElement){document.documentElement.className+=e.join(" ")}})([""],String(navigator&&navigator.appVersion))</script>
It works like johnhunter's solution, only that it is minified.

Related

Show div on radio button check using JS fallback

I am building a website of which the desktop version displays 10 images all at once (5x2), which obviously doesn't look too good on a small smartphone display. In order to conquer this problem, I made 10 radio buttons (which only display on the mobile version of the website) and only show the image that accompanies the checked radio button. This was very easy to implement with HTML and CSS3 like this:
HTML:
<input type="radio" name='pdr' id="pdr1"><label for="pdr1"> Click here</label>
<div class="populardevice" id="populardevice1">stuff in this div</div>
CSS:
.populardevice {
display: none;
}
input#pdr1:checked ~ #populardevice1 {
display: inline;
}
The problem is that older browsers don't support the :checked selector. My idea was to use the CSS3 way of displaying the div if it's supported, and use JavaScript as a fallback if not. I already found this, which is basically what I want. The only problem is how do I detect if support for the :checked selector is present? I was thinking of Modernizr but it seems like all that would do is create an additional class in my CSS that says no-checked (right?), which would be of no use to me since I want to run a piecie of JS in that case. Or would Modernizr be fit for this case, utilizing it something like this (pseudo-code - I have no idea how to write this yet but if it's the solution, I will find out how):
if (Modernizr.:checked supported) {
use that and terminate this function;
} else {
Execute the JavaScript function from the link above;
}
Or do you guys advise me to implement something completely different?
Thanks in advance.
From the Modernizr website:
Using Modernizr with JavaScript
The Modernizr object
Modernizr keeps track of the results of all of it's feature detections
via the Modernizr object. That means that for each test, a
corresponding property will be added. You just have to test for
truthiness in your code to figure out what you want to do
if (Modernizr.awesomeNewFeature) {
showOffAwesomeNewFeature();
} else {
getTheOldLameExperience();
}
So your pseudo code was pretty close!

Can a CSS code/file load JS code/file?

We know that using Javascript we can load CSS files.
But, can we load Javascript files or run Javascript code using CSS?
If yes, how? Is there any documentation for this?
I think IE and firefox supports CSS expressions which probably you may think of. Something like
width:expression(document.body.clientWidth > 800? "800px": "auto" );
but these are really bad things and you should avoid this
Also you should avoid CSS expression as much as you can.
You can use the CSS like this:
body {
behavior:url(xyz.htc);
}
and now in the xyz.htc file you can write like:
<PUBLIC:COMPONENT TAGNAME="xss">
<PUBLIC:ATTACH EVENT="ondocumentready" ONEVENT="ABC()" LITERALCONTENT="false"/>
</PUBLIC:COMPONENT>
<SCRIPT>
function ABC()
{
alert("Message");
}
</SCRIPT>
No, you can not run Javascript or import Javascript into CSS... not that you would ever need to.
No.
The closest thing I can think of is Netscape 4 had a thing called JavaScript Style Sheets (JSSS)
http://www.w3.org/Submission/1996/1/WD-jsss-960822

css3pie messes up DOM, results in jQuery selector errors

In order to get CSS3 effects (border-radius, box-shadow...) on IE 6/7/8, I'm using css3pie.
However, css3pie generates some css3-container (v1) / css3pie (v2) tags in DOM, which disorders the expected architecture. Here is an example:
CSS
pre {
border: 1px solid #aaa;
border-radius: 5px;
behavior: url(pie.htc);
}
HTML
<div class="foo">bar</div>
<p class="getme">paragraph</p>
<pre>preformatted</pre>
jQuery
// undefined expected: getme
alert($("pre").prev().attr("class"));
// css3-container expected: p
alert($("pre").prev()[0].tagName);
// getme expected: foo
alert($("pre").prev().prev().attr("class"));
// 4 expected: 3
alert($("body").children().size());
// will not set expected: Impact
$("p+pre").css({fontFamily: "Impact"});
// it almost affects all such jQuery selctors
The actual generated source is like this:
<DIV class="foo">bar</DIV>
<P class="paragraph">paragraph</P>
<css3-container...>
<border...>
<shape...><stroke></stroke><stroke></stroke></shape>
</border>
</css3-container>
<PRE>preformatted</PRE>
Has anyone encountered this kind of problems? Any workaround? Is there an alternative to css3pie to get CSS3 working on IE 6/7/8?
I tried using CSS3PIE too, and faced similar problems (mostly with jquery and mediaqueries). I found no easy/practical solution for all the problems it causes, indeed.
My advice would be to use Modernizr's load to progressively enhance older IE's user experience. It requires an harder/longer process, as you've to setup a single polyfill for each and every CSS3 feature. As mario.tco already told you, there's a list of cross-browser polyfills on Modernizr's repo. And here's a list of feature detection snippets.
Also have a look at html5please and caniuse.
In regard to IE6 and 7, unless your site statistics indicate something different, usage rates are below 1% on average (with some exceptions, check ie6countdown), so you can almost ignore them. However, with conditional comments you can target each IE<10 version with specific fallbacks.
Keep in mind that you don't really need to have box-shadows and other visual decorations (unless they are needed for usability) on IE<9. Indeed, any fallback will probably cause a huge performance problem (think about what hardware an IE7 user could have). Websites don't need to look exactly the same in any browser.
CSS3PIE is a very useful and powerful way to simulate CSS3 rounded corners - and in my company it is the one that we chose, but there are many other ways to do it.
The way CSS3PIE creates the rounded corners it will create the <css3-container> tag as the previous sibling to the element that has the behavior attribute, so it will change DOM structure and break your prev() calls. The css-container is important because it is a VML drawing of the rounded corner background behind your <pre> tag.
One way you could do this would be to wrap your <pre> tag in something else like a <div> and then use that <div> to navigate the DOM using the prev() function.
Another way you could do this would be to create a jQuery plugin like this
/* This adds a plugin prevPie and nextPie - it is the same as the
existing prev and next, but it will ignore css3-containers. */
(function($){
function addPlugin(name) {
$.fn[name + 'Pie'] = function() {
var result = [];
this[name]().each(function(i,el){
if (el.tagName == 'css3-container') {
var val = $(el)[name]()[0];
val && result.push(val);
} else {
result.push(el);
}
});
return $(result);
}
}
addPlugin('prev');
addPlugin('next');
})(jQuery);
Now the following should work like you wanted it to in all browsers.
// undefined expected: getme
alert($("pre").prevPie().attr("class"));
// css3-container expected: p
alert($("pre").prevPie()[0].tagName);
// getme expected: foo
alert($("pre").prevPie().prevPie().attr("class"));
// P expected: div
alert($("pre").prevPie().prevPie()[0].tagName));
Have you tried this:
http://blog.reybango.com/2010/10/11/how-polyfills-fill-in-the-gaps-to-make-html5-and-css3-usable-today/
Here is a list of polyfills you can use for other features:
https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills
This is probably not the answer you're looking for, but instead of trying to get jQuery to ignore PIE's injected elements, I recommend (re)writing your jQuery to use classes / IDs more and be less dependent on page structure. This has the benefit of making your code more resilient against other page structure changes, as well as making your code a bit more portable and reusable.
When you must traverse the DOM, most (if not all) of jQuery's traversal methods include a filter selector argument that you can use to exclude PIE's elements, for example:
$("pre").prevUntil('*', 'not(css3-container)')
$("body").children('not(css3-container)')
Instead of just using the raw prev() add a CSS selector to it to narrow down the search
$("pre").prevUntil('p').attr("class");
// OR
$("pre").prevUntil('.paragraph').attr("class");
If you are going to use a CSS3 "hack" to make IE 6/7/8 behave correctly don't try and rely on expected DOM structure when walking the DOM try to be more specific.
EDIT
changed the prev() function call to prevUntil()

How to remove CSS and JS from a certain content-type in Drupal 7

I've come here after looking for how to selectively add a CSS or JS to a given node based on its view mode and content type. That question is answered pretty straightforward here (http://stackoverflow.com/questions/8295498/how-to-add-css-and-js-files-on-node-pages-independent-of-the-theme).
Now I'd love to clear everything: I'm looking for a way to show my desired CSS and JS but only that, with no other JS and CSS. I'm trying to integrate Impress.js (And I don't like the available solutions) and it seems to be conflicting with Jquery, as both scripts are properly loaded but both latest Firefox and Chromium browsers throw the "old browser" message.
Any ideas on how to unset every single CSS and JS so that the CSS and JS I want to use are the only ones really active?
Thanks!
I've tried the following, to no success:
$mycss = $vars['styles'];
unset($micss[drupal_get_path('module','system') .'/system.base.css']);
...
unset($micss[drupal_get_path('module','toolbar') .'/toolbar.css']);
$vars['styles'] = $mycss;
(I added a lot of different css i want to get rid of, but this explains the idea). It didn't work, though :)
Edit. I'm sorry for the bad markup, I'm looking for a way to clean/mark code.
In your custom module use:
function yourmodule_js_alter(&$js) {
unset(
$js['misc/drupal.js'],
$js['misc/jquery.js']
.... etc.
);
}
You say you want to only do this for certain content types, so try:
if(arg(0) == 'node') {
$node = node_load(arg(1));
if($node->type == 'your_content_type') {
unset(
$js['misc/drupal.js'],
$js['misc/jquery.js']
.... etc.
);
}
}
Jonny

In firefox, how can I change an existing CSS rule

In firefox, I have the following fragment in my .css file
tree (negative){ font-size: 120%; color: green;}
Using javascript, how do I change the rule, to set the color to red?
NOTE:
I do not want to change the element.
I want to change the rule.
Please do not answer with something like
...
element.style.color = 'red';
What you're looking for is the document.styleSheets property, through which you can access your css rules and manipulate them. Most browsers have this property, however the interface is slightly different for IE.
For example, try pasting the following in FF for this page and pressing enter:
javascript:alert(document.styleSheets[0].cssRules[1].cssText)
For me that yields the string "body { line-height: 1; }". There are methods/properties that allow you to manipulate the rules.
Here's a library that abstracts this interface for you (cross-browser): http://code.google.com/p/sheetup/
function changeCSSRule (stylesheetID, selectorName, replacementRules) {
var i, theStylesheet = document.getElementById(stylesheetID).sheet,
thecss = (theStylesheet.cssRules) ? theStylesheet.cssRules : theStylesheet.rules;
for(i=0; i < thecss.length; i++){
if(thecss[i].selectorText == selectorName) {
thecss[i].style.cssText = replacementRules;
}
}
};
You can change CSS rules in style sheets through the CSS Object Model (currently known as DOM Level 2 Style). However, if you literally have "tree (negative)" in your style sheet that rule will be dropped and not appear in the Object Model at all.
As there is no HTML element tree I am going to assume that tree is the id or class of another element.
You would first retrieve the DOM element by id:
var tree = document.getElementById("tree");
Now tree represents your DOM element and you can manipulate it any way you like:
tree.style.color = "red";
Here is a great reference for mapping css properties to their javascript equivalent.
I'm not sure you can do actual class/selector overrides. You would need to target each element that used the .tree class and set the CSS. The quickest and easiest way would be through jQuery (or another similar framework):
$('.tree').each(function() { this.style.color = "red"; });
You could even use the built-in CSS functions:
$('.tree').css('color', 'red');
(I did it the first way to show you how standard JS would do it. The $(...) part is jQuery for selecting all elements with the .tree class. If you're not using jQuery, you'd need alternative code.)
If tree is an ID, not a class (there should only be one on the page) so using getElementById should be fine. Your code should look like the other answer.
for( var i in document.getElementsByTagName("tree") ){
document.getElementsByTagName("tree")[i].style.color = "red";
}
As I said in another answer's comment, I've never seen this done how you want. I've only ever targeted elements the same way as the CSS renderer would and changed each element style.
I did see this though: jQuery.Rule
It sounds like it does what you want but the demo causes my browser to flip out a bit. I'd invite you to look at the source to see it really does do what you want, and if you want to use it without jQ, use it as a starting point.
Edit: yes this should work. It works by appending another <style> tag to the page and writing out your overrides within. It's fairly simple to follow if you wanted to port it to plain JS.
For debugging, you can use Firebug to change the CSS rules on-the-fly.
If you want to change the rendered css rules from one page request to the next then some sort of server-side scripting will be required. Otherwise the original style sheet would simply reload at the next page request.
If you want to use an event on the first page to force the server-side action then you can use AJAX to actually change the CSS rule for the user.
"I want to change the rule so that
when I navigate to the next page, I
don't have to make all the changes
again."
It sounds like what you might want then is a remote request ("ajax") back to the server with the request you want to make, and generate a dynamic stylesheet which is sent back to the client?
How/why is this Firefox specific?
I want to change the rule so that when I navigate to the next page, I don't have to make all the changes again.
There are two approaches I can think of here. Namely client side and/or server side.
Client side:
Store the theme setting into cookies and load them up next time by javascript.
Server side:
If your site have an login system, you may also store the user preference into the database and generate the webpages with this inforamtion in mind next time on.
Utimately, you are still writing things like element.style.color =. But, they should get what you want.

Categories

Resources