Detect support for background-attachment: fixed? - javascript

Is there a way to detect browser support for background-attachment: fixed?
Edit: Although this feature is widely supported on desktop browsers it is poorly supported on portable devices which I why I would like to be able to detect the feature.

When you use { background-attachment:fixed } current mobile devices will not display the background image at all! To ensure the image is displayed on all mobile devices, you need to test for support, and if not supported to set the background-attachment property to either 'initial' (i.e. default state) or 'scroll' (which is the default state).
The bad news:
It's currently impossible to directly and specifically test for support of fixed backgrounds because mobile browsers will incorrectly report that they do support it. To see this bug for yourself, load this test in a mobile browser:
http://codepen.io/mattthew/pen/PwEqJa
function supportsCSS(value) {
try {
var style = document.body.style;
if (!("backgroundAttachment" in style)) return false;
var oldValue = style.backgroundAttachment;
style.backgroundAttachment = "fixed";
var isSupported = (style.backgroundAttachment === value);
style.backgroundAttachment = oldValue;
return isSupported;
}
catch (e) {
return false;
}
}
var el = document.getElementById('result');
var txt = '<b>This device & broswer supports:</b><br>';
txt += '{ background-attachment:fixed; } : ' + supportsCSS('fixed') + '<br>';
txt += { background-attachment:foo; } : ' + supportsCSS('foo');
el.innerHTML = txt;
based on code originally written by: #chao
The limited options:
It is possible to indirectly test for support with multiple methods.
Option 1: Remove fixed background on small screens
This option uses a CSS media query to target smaller screens to overwrite the style on devices with screen widths of 1024px or smaller (devices likely to render fixed backgrounds as invisible). The advantages of this option are: it's very lightweight and only requires a little bit of CSS:
#some_element {
background-attachment: fixed;
}
#media all and (max-device-width: 1024px) {
/*
overwrite property for devices with
screen width of 1024px or smaller
*/
#some_element {
background-attachment: scroll;
}
}
Unfortunately, there are a small number of tablet brands with screen widths of 1280px and 1366px, which overlap with the smallest desktop screens (sort this list by CSS Height). The safest play is to use a scrolling background for this overlap area so that the background image is guaranteed to display. If you want to play it safe, use max-device-width: 1366px. However, the number of people using these giant tablets is much smaller than the number of people with small screen laptops.
Option 2: test for touch events and mouse events
This option uses JS to test if the browser supports the touch events API, and is therefore more likely than not to be on a touch screen device (a device more likely than not to render fixed backgrounds as invisible). This is the heavy weight option. It requires Modernizr and jQuery:
if(Modernizr.touch) {
// this browser claims to support touch, so remove fixed background
$('#some_element').css('background-attachment','scroll');
}
Unfortunately, this option also has a gray area. Some browsers give a false positive and some give a false negative. You could test for a mouse event, such as:
$('body').mousemove(function(event){
// this device (touch or not) has a mouse, so revert to fixed background
$('#some_element').css('background-attachment','fixed');
$('body').unbind('mousemove');
});
However, it's possible that a mouse has been attached to a touch-screen laptop that doesn't support fixed backgrounds, so that code adds risk.

You might look at document.body.style and make sure that
there's a property there called "backgroundAttachment", and
you can set it to "fixed", and it retains its value when you do so.
Chrome, FF, Opera, and Safari all ignore attempts to set the property to an invalid value. IE9 throws an exception when you try. So if either one happens, that value definitely isn't supported. (If the browser just blindly sets the value and retains it, then it still might not work. But at that point, you really can't the browser to tell you much anyway.)
function supportsFixedBackground() {
try {
var style = document.body.style;
if (!("backgroundAttachment" in style)) return false;
var oldValue = style.backgroundAttachment;
style.backgroundAttachment = "fixed";
var isSupported = (style.backgroundAttachment === "fixed");
style.backgroundAttachment = oldValue;
return isSupported;
}
catch (e) {
return false;
}
}
I don't bother with IE6 anymore, and don't have another browser handy that doesn't support fixed backgrounds, so i'm unable to test setting "fixed".

I think I've got the solution for all devices. It's possible to detect clip-support, so I did just that and made a change in the DOM for when clip is supported. If it isn't, it falls back on background-attachment: fixed;
See the code at https://codepen.io/AartdenBraber/pen/gGmdWK

Support for any CSS property value can be detected via following steps:
create a temporary element (e.g. DIV);
set value of its style DOM property (element.style.backgroundAttachment in your case) to value to check (fixed in your case);
compare actual style value with specified string.
Something like this in your case:
var elem = document.createElement('div');
elem.style.backgroundAttachment = 'fixed';
var isSupported = 'fixed' === elem.style.backgroundAttachment;

#supports (background-attachment: fixed) will report true because the browser engine interpreted the property and value successfully. Then, mobile webkit decides to bind your background to the same stacking context (same rendering plane) as the element it is applied to for "better performance". (All z-indexes have their own stacking layer, and on desktop browsers, fixed backgrounds get their own layer.)
One could use JS to detect browsers with this rendering pattern, by checking for iPhone iPad iPod & Android in the user agent, which may target mobile browsers that render fixed backgrounds correctly, such as mobile Firefox which is constantly evolving. However, I found a better way in pure CSS:
CSS Only Solution for Mobile Safari & Chrome:
#supports (-webkit-overflow-scrolling: touch) targets all the same versions of mobile webkit that refuse to bind backgrounds to the viewport.
So with that in mind, you can fix your background by default, then append this #supports rule to apply a sort of mobile polyfill:
Example:
body {
background-image: url('bg.png');
background-size: cover; background-attachment: fixed;
}
#supports (-webkit-overflow-scrolling: touch) {
/* Detach problematic background */
body { background: none !important; }
/* Insert empty div at bottom of page */
#lonelyDiv {
position: fixed; top: 0px; left: 0px; z-index: -1;
width: 100%; height: 100%;
/* Using same background with size=cover may be possible in some situations */
background-image: url('bg.png'); background-size: cover;
/* Other designs may require a stretchable background...
or cropped versions for mobile aspect ratios applied after #media (orientation) rules */
background-image: url('mobile-bg.png'); background-size: 100%;
}
}

http://www.w3schools.com/cssref/pr_background-attachment.asp
There are pictures of the major browser icons a little bit down the page. The images aren't greyed out for any of the icons. It says that it is supported in all browsers

fixed is supported in all desktop browsers, except IE6 and older.
It is supported by most mobile browsers, but you may see some discrepencies due to viewport handling.
Source

Related

CSS specificity beat inline with !important

Here is my site: http://stage.samkeddy.com/
It's responsive using a couple media queries and a mobile menu button powered by javascript.
Here is the javascript for the menu button:
function toggleMenu () {
if (menuIsVisible == false) {
collapsibleMenu.style.height = 'auto';
content.style.paddingTop = '290px';
menuIsVisible = true;
}
else {
collapsibleMenu.style.height = '0';
content.style.paddingTop = '80px';
menuIsVisible = false;
}
}
so you can see that I need to adjust the padding at the top of the content div, in order to offset the menu
But if resize to the mobile size, open the menu, and then resize back to the desktop size, the padding isn't fixed by the media query, because there's still an inline style from the javascript. I tried making the padding on the desktop version !important, but it the padding still doesn't change when resized, even though according to this !important beats inline.
You can test for yourself by opening the size (how it should look), resizing to a mobile width(the nav will disappear, and you will see the menu button), clicking the menu button (leave the menu open), then resize the site back to a desktop width. You will see the padding is still there. If you inspect it, you can see the original padding is crossed out in favor of the inline style.
I know this would be possible by monitoring the width with javascript and setting the padding then, but I really don't want to do that, and don't think I should have to.
EDIT: solved
First, I should have been adding classes, rather than adding CSS with my javascript.
Then I assumed that putting !important outside of a media query would make it only show up on desktop, but it took over all media queries. So placing just this in a query made it work. Note that if I was using 2 separate menus (mobile/desktop), I wouldn't need this, but since it was fixed and the #content needed padding, it had to be done. But using this technique you can also use only a single menu, but doing the height for the menu this way. I've demonstrated the technique in a codepen: http://codepen.io/anon/pen/JFvay
Adding this code to your stylesheet should solve the problem, I just tried this on your website using the Developer Tools and it's working:
#media only screen and (min-width: 643.2px) {
#content {
padding-top: 80px !important;
}
}
Although I'd strongly recommend you to create a separate navigation menu for mobile devices and resort to using #media-queries to display it.
Your problem at heart is that you're mixing CSS and in-line styles. As a general rule, avoid placing specific CSS properties directly on elements, whether in HTML, by using element.style.<property> =, or via jQuery's .css() feature. Instead, you should define the properties you want as CSS rules, using classes:
#collapsible-menu { height: auto; }
#content { padding-top: 290px; }
#someelt.menu-visible #collapsible-menu { height: 0; }
#someelt.menu-visible #content { padding-top: 80px; }
where someelt is some higher-level ancestor element. Then, your JS becomes simply
function toggleMenu() {
document.getElementById('someelt').classList.toggle('menu-visible');
}
If you are targeting browsers which do not support classList (see CanIUse), jQuery provides its own version of class toggling.
CSS is not an imperative language, but if you want, you can think of the #someelt.menu-visible part of the last two rules above as a kind of if statement: "If menus are visible, then shrink collapsible-menu to zero height", etc. In this metaphor of CSS as a kind of programming language (which it is), the presence of the menu-visible class of #someelt could be thought of as a kind of boolean "variable", I suppose. Most likely, you will no longer need a corresponding variable in your JS.
Anyway, the advantage of this is that people looking at your code can see all your CSS-related logic just by looking at the CSS file, instead of having to look at both CSS and JS, and you can change CSS-related things in just one place.

See through effect with CSS (like iOS 7/Aero)

I am trying to design an application that runs on Node-Webkit. I have this crazy idea for the background, but I have no idea how I should approach implementing this with CSS.
This is the app how it looks right now:
I would like to give all dark green/blue backgrounds a see through effect (there are two, the darker for the top and the slightly lighter for the toolbar). Like this: (mock up, background is maybe a little too blurred)
I do not aim for a solution that has real see-through windows (like aero and iOS 7/OS X 10.10). A faked effect with a predefined, static background image is fine (which does not have to move when the window position change).
The implementation has to be memory and performance efficient.
I want to specify the type of background (dark or light) by setting the class of each element (like the tabs, toolbars, etc) to 'bg-dark' and 'bg-light'.
The approach I would take is this:
create two images, one for the darker background and one for the lighter background. (1920x1080px each, because my app must handle full screen nicely)
give each element a background class 'bg-dark' or 'bg-light'. This class defines a CSS background image.
with javascript, for each element in a certain class, calculate a value for background-position.
The issue that I see with this approach is that for each element, webkit/blink has to load the entire background image to memory. Is this true? Is there a better, more sane way to do this? It doesn't have to be cross-browser friendly, as I only need it for a Node-Webkit app (which uses one of the latest blink engines).
Edit:
Note that CSS opacity does not do the trick. I want the background to be kind of blurred, so simple transparency is not sufficient. Also, if the selected tab was actually translucent (opacity < 1), the dark topbar whould show through (which is not what I want).
Please monitor #issue132.
It would be a feature later.
In CSS there is a feature called transparency. Maybe this will get you through this.
.transparent {
/* Required for IE 5, 6, 7 */
/* ...or something to trigger hasLayout, like zoom: 1; */
width: 100%;
/* Theoretically for IE 8 & 9 (more valid) */
/* ...but not required as filter works too */
/* should come BEFORE filter */
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
/* This works in IE 8 & 9 too */
/* ... but also 5, 6, 7 */
filter: alpha(opacity=50);
/* Older than Firefox 0.9 */
-moz-opacity:0.5;
/* Safari 1.x (pre WebKit!) */
-khtml-opacity: 0.5;
/* Modern!
/* Firefox 0.9+, Safari 2?, Chrome any?
/* Opera 9+, IE 9+ */
opacity: 0.5;
}
With this you don't need to load another image which will consume memory and bandwith.
€dit: missed source: http://css-tricks.com/css-transparency-settings-for-all-broswers/
opacity is a way to do that.
But beware that it'll make entire container transparent.
ex:
container{
/* IE 4-8 */
filter: alpha(opacity=50);
/* Older than Firefox 0.9 */
-moz-opacity:0.5;
/* Safari 1.x (pre WebKit!) */
-khtml-opacity: 0.5;
/* All Modern Browsers */
opacity: 0.5;
}
In order to make only background transparent, I'll Suggest You to use transparent background-color.
AS:
container{
background:rgba(150,255,255,0.5); /*IE 9+*/
}
rgba stands for red,green,blue & alpha. I think that's what you're looking for.
Hope it'll help you.

-ms-high-contrast-adjust equivalent in IE9

One of our CSS files uses -ms-high-contrast-adjust: none to make sure some background features show up even under high contrast mode. It works fine on IE10 and IE11. Now we're trying to port the same CSS to IE9, and obviously it's not supported.
What's the equivalent of the -ms-high-contrast-*** property under IE9? Is there some other way to trick the browser to not change features with the "high contrast mode" setting?
There ain't an equivalent.
Remarks
The -ms-high-contrast media feature was introduced in Windows 8.
It's for ie10.
You can test it with media-queries like:
#media screen and (-ms-high-contrast: active) {/* ... */}
#media screen and (-ms-high-contrast: black-on-white) { /* */ }
#media screen and (-ms-high-contrast: white-on-black) { /* */ }
http://msdn.microsoft.com/en-us/library/windows/apps/hh465764.aspx
Some developers use it to target IE10 with media queries :
#media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
/* i-love-ie */
}
PS, this is kind of freaky, you want a browser to force an OS to display in a specific way, or display in a specific way over the OS.
[HOLD ON]
i JUST found this article from Steve Faulkner : http://blog.paciellogroup.com/2010/01/high-contrast-proof-css-sprites/
CSS sprites using the before: pseudo element
An alternative to implementing CSS sprites using the traditonal
background-image method is available and it resolves the issue of
images not being displayed in high contrast mode. This alternative
method makes use of the CSS before: pseudo element (note: the after:
pseudo element could also be used). Example:
Link with a home icon and text with default display colors. Link with
a home icon and text with windows high contrast colors.
CSS
span.test1:before {
margin-right: -10px;
content: url(icons.png);
position:relative;
left:-2px;
top:-109px;
}
span.test1 {width:17px;
height:18px;
display:inline-block;
overflow:hidden;}
HTML
<span class="test1"></span>Home
I have no time to test it. Give it a try and come back to us so i can 'correct' this answer if needed.

How can I change a CSS attribute by Javascript when a certain minimum screen resolution size is detected

I have this code:
function AUTADIV () {
var BRW = window.outerWidth;
x = (BRW/1280) * 20
document.getElementsByTagName("a").style.fontSize = x
}
and the tag <a> is already under this class in a .css file:
a {
position:relative;
z-index:1;
color:White;
background-color: transparent;
font-size:20pt;
text-decoration: none;
text-shadow: blue 0em 0em 0.4em
}
When someone with a larger screen sees my site, the background does fill it all, but the font is too small. Is there any way to make it automatically resize? If not, how can I change font-size:20pt by JavaScript? My code only works if the font-size style is inline, and I need it in the CSS script.
I have found that the code I need activates with the onResize event.
If it needs to be in the CSS then it might be difficult to do. If however, it's able to be changed dynamically with JS then you can accomplish this with a simple test like:
(I'm using jquery)
$.getDocHeight = function(){
return Math.max(
$(document).width(),
$(window).width(),
/* For opera: */
document.documentElement.clientWidth
);
};
if($.getDocHeight>threshhold){ // some threshhold of a max width
$('a').style('font-size','40pt');
}
This can be done in regular js as well. It's hard to determine the width on all different browsers, thats why I included the function. But once you have the width, you just need to do a simple check and you can bump up the font-size style for your anchor tags. I suggest having static sizes so that the font is more predictable and doesn't scale with your page size.
This is a best practice when considering different types of users (like mobile users where you definitely do not want the font to be so small that all of it fits on one page).
Src for code: http://james.padolsey.com/javascript/get-document-height-cross-browser/
You may modify the rules by accessing the CSSRule-Object.
Details:
IE<9 : http://help.dottoro.com/ljcufoej.php
Others: http://help.dottoro.com/ljdxvksd.php
You might get better results using a media query:
#media all and (max-width: 1280px) {
a{font-size:12pt;}
}
You can repeat this for increasingly smaller sizes. It won't smoothly transition, but it doesn't require JavaScript (and besides so much changes when you resize a window that a jump in text size probably won't be noticed).

How can I detect (and correct?) various scroll bar visibilities cross-browser?

Basically, I need to have (or fake) scrollbars showing up exactly at the same times in textarea and in a div (with white-space: pre-wrap, so as to treat whitespace the same), when their contents are the same.
In Webkit, this is easy:
textarea.foo, div.foo {
overflow: auto; /* show scrollbars exactly when needed */
/* also match padding, height, width, font, line-height, etc. */
}
But some other browsers (Firefox on OS X, I think, and IE7) will actually show a scrollbar on only the textarea and not the div (or vice versa) when the content isn’t long enough to require scrolling.
For clarity, I am not demanding that scrollbars show the same across all browsers. I need this to be true in all major browsers: A div and a textarea show scrollbars exactly whenever the other element does, given the same content, within the same browser. If that’s sometimes, always, or (on Safari/OS X Lion) never is inconsequential.
Configure the scroll bar to show up all the time
textarea.foo, div.foo {
overflow-y: scroll; /* Show vertical scroll bars at all time
}

Categories