I have the following css rules:
-webkit-transform: scale(0.5); /* Saf3.1+, Chrome */
-moz-transform: scale(0.5); /* FF3.5+ */
-ms-transform: scale(0.5); /* IE9 */
-o-transform: scale(0.5); /* Opera 10.5+ */
transform: scale(0.5);
Which I intend to apply to a div in order to scale it, including all its contents, images, etc, to 50% its size while keeping the same center. As you probably know the rules I listed do exactly that, except for IE7-8.
According to this site, the equivalent, MS proprietary rule would be:
/* IE8+ - must be on one line, unfortunately */
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.5, M12=0, M21=0, M22=0.5, SizingMethod='auto expand')";
/* IE6 and 7 */
filter: progid:DXImageTransform.Microsoft.Matrix(
M11=0.5,
M12=0,
M21=0,
M22=0.5,
SizingMethod='auto expand');
However these don't seem to actually resize the contents of the div, it seems to shift its position but that is all.
CSS3Please.com reports different matrix values to be the equivalent for scale(0.5):
filter: progid:DXImageTransform.Microsoft.Matrix(/* IE6–IE9 */
M11=0.9999619230641713, M12=-0.008726535498373935, M21=0.008726535498373935, M22=0.9999619230641713,SizingMethod='auto expand');
I've tested these aswell, but the effect was the same; the div seemed to change its position, but the actual size of its contents remained unchanged.
Finally I've tried transformie.js, which calculates the matrix via sylvester.js automatically as you assign the transform property, but the end result was still:
M11=0.5, M12=0, M21=0, M22=0.5
Exactly the same as the one I tried first, which seemingly did do nothing other than shift the position of the div.
I would try cssSandpaper.js, but it looks pretty bloated for what I intend to do, plus there's no jQuery port and I don't feel like adding cssQuery to the project only for that. Chances are the results would be the same as what transformie.js generates though, because it seems to use sylvester.js aswell.
Edit: I also tried this which seems to come from microsoft directly, and suggests the following matrix calculation method:
function resizeUsingFilters(obj, flMultiplier) {
// If you don't do this at least once then you will get an error
obj.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingmethod='auto expand')";
// Resize
obj.filters.item(0).M11 *= flMultiplier;
obj.filters.item(0).M12 *= flMultiplier;
obj.filters.item(0).M21 *= flMultiplier;
obj.filters.item(0).M22 *= flMultiplier;
}
Unfortunately this does not scale the contents of the div itself either. It looks like this may not be possible at all, but:
How can the modern transform: scale be simulated in IE8-7, in such a way that it actually resizes inner div contents aswell?
Perhaps I'm looking for something that doesn't exist, but I wanted to be sure. All the tests have been done using IE9 in compatibility mode for IE8 and IE7 (so far it has always done the job, I don't believe it's unreliable but feel free to correct me if you think otherwise)
I'm a little confused by your explanation. This fiddle in IE7-8 scales the inner elements down for me just fine with the first set of code you posted (though you indicate it was not scaling, only changing position). What that code does not do (and cannot do) is scale it from the center point (it is from the upper left), and the matrix transform cannot accommodate a translation (it only "Resizes, rotates, or reverses the content of the object"), so it is not "keeping the same center" as you indicate you desire.
There is a page I found similar to the transformie.js you noted in performing transform, but this other page speaks to the issue of the transform origin being centered. Ultimately, to get the appearance of being scaled on center, you must include a calculation of some kind to do a shift of the element using position: relative.
In this fiddle I've made it easy on myself to do such a calculation manually by setting a width on the wrapping div and knowing the height based on the inner sizes. This could get complicated with any dynamic sizing, but the link above I believe gives the calculations to do it dynamically using javascript (JQuery) with the sylvester.js as well.
You can also use IE's zoom property:
zoom: 0.5
This should do what you want it to do.
Related
Most of us know the simple opacity CSS rule, but recently I stumbled upon filter which can have opacity(amount) as it value - among other things. But what exactly is the difference between the two?
filter: opacity() is similar to the more established opacity property; the difference is that with filter: opacity(), some browsers provide
hardware acceleration for better performance. Negative values are not
allowed.
filter: opacity() applies transparency.
A value of 0% is completely transparent. A value of 100% leaves the
input unchanged. Values between 0% and 100% are linear multipliers on
the effect. This is equivalent to multiplying the input image samples
by amount. If the “amount” parameter is missing, a value of 100% is
used.
Source: https://css-tricks.com/almanac/properties/f/filter/
/*
* -----------
* filter: opacity([ <number> or <percentage> ])
* -----------
*/
.filter-opacity {
filter: opacity(0.3);
height: 5rem;
width: 5rem;
background-color: mediumvioletred;
}
/*
* -----------
* standard opacity
* -----------
*/
.just-opacity {
opacity: 0.3;
height: 5rem;
width: 5rem;
background-color: lawngreen;
}
<div class="filter-opacity">
filter-opacity
</div>
<div class="just-opacity">
just-opacity
</div>
I've found some difference between them both, especially in the Chrome browser.
If we set the CSS opacity property to an iframe tag, then we'll not be able to click any links inside this frame (I guess, it's a protection from clickjacking attack) while filter: opacity(0) allows us to click any links. I don't know, maybe it's an omission from Chrome developers' side.
filter in CSS had some different runs, namely for FireFox and MSIE.
In MSIE 5.5 on through 7, filter, also known as Alpha Filter, actually makes use of MSIE's DX Filter (no longer supported). However, in order to be more CSS2.1 compliant, in IE8 MS introduced -ms-filter to replace filter. The syntax is different in that the value of -ms-filter must be encased in quotes. Eventually, IE9 brought deprecation to this method and as of IE10, it is no longer used.
Another interesting note here, if you're wanting full compatibility for older IE, then you must make sure use of filter and -ms-filter must be very specific. For example, the following does not work in IE8 running IE7 compat mode:
element {
filter: alpha(opacity=50);
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
}
-ms-filter must come before filter in order to get more out of older IE compatibility.Like so:
element {
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
filter: alpha(opacity=50);
}
FireFox made use of filter as an experiment gone awry. I believe the original idea was to mock what IE was doing in using the Direct X engine. There was even a browser specific version, as there was for most browsers at one time. Eventually, HTML5/CSS3 announced use of the filter namespace and it now has a new purpose.
As of CSS3, filter now has a whole new meaning! Firefox docs stay open as if they plan to expand on this, though I've yet to see it (however they do crash JS if your CSS is not to its liking now!). Webkit (which will probably become standard in next update to CSS3) has started to implement filter to the point you can almost "photoshop" images for your site!
Since filter is changing so much, opacity would be the preferred method to use, however, as you can see, to be completely cross-browser compatible means being very thorough.
Browser specific alternates:
-webkit-filter: filter(value);
-moz-filter: filter(value);
-o-filter: filter(value);
-ms-filter: "progid:DXCLASS.Object.Attr(value)";
See Also:
What's compatible with opacity?
What's compatible with the newer filter?
keep in mind, not the same as Older IE's filter
This works well for browsers that support background-size. Otherwise the 2x image is zoomed.
.a {
background-image: url(img2x.jpg); /* 1000x1000 */
background-size: 100%;
height: 500px;
width: 500px;
}
This should be used for browsers without background-size support.
.a {
background-image: url(img1x.jpg); /* 500x500 */
height: 500px;
width: 500px;
}
Is it possible to trick the browser to fallback when background-size is not supported? I know I can use #supports but it's much less supported than background-size so quite pointless in this case. I don't want to use JavaScript either.
Basically like so, except work!
.a {
background-image: url(img1x.jpg); /* 500x500 */
height: 500px;
width: 500px;
/* stop parsing this rule when background-size is not supported */
/* otherwise continue parsing and set different background-image */
background-size: 100%;
background-image: url(img2x.jpg); /* 1000x1000 */
}
This doesn't work obviously, but is there a trick which could make it work? Thanks.
A CSS-only fallback for background-size is tricky, but yes it can be done.
The trick is to use the short-form background style to set the various background properties, rather than using the individual styles like background-size, background-image, etc.
So in your case, you would have something like this:
background: url(img2x.jpg) 0% 0%/100%;
(The 0% 0% is for background-position (0% 0% is default) which is required before the background-size value when using the short-form style).
So far, all I've done is condense your existing code into a single short-form CSS line, but the clever bit is that now we've done this, a browser that doesn't recognise background-size will throw away the whole line, rather than just throwing away the background-size on its own.
This means that we can specify an entirely different set of background values for older browsers.
background: url(ie8bg.jpg); /* Shown by IE8 and other old browsers */
background: url(img2x.jpg) 0% 0%/100%; /* shown by new browsers with background-size support*/
You can see a demonstration of this in action here. Modern browsers will get the one background image, stretched by a 100% background-size setting, and older browsers (like IE8) will get the an entirely different image, without any stretching.
Since you get to define an entirely separate background for old browsers, you can even do things like have a solid background colour for IE8 rather than an image while still providing an image for other browsers.
So yes, a fully CSS solution that gives you a fallback for browsers that don't support background-size.
Hope that helps.
[EDIT]
Browser compatibility may be a minor issue here. Some browsers may support background-size but not support it as part of the background short syntax. For the most part this applies only to older browsers (eg Firefox 7), but it is still a problem in current versions of Safari. What this means is that with this technique, Safari will see the fall-back background, even though it does actually support background-size.
This obviously isn't ideal, but it is mitigated by the fact that it will at least get the fallback image, which means the page ought to at least look okay, if not quite as good as in other browsers. Hopefully this issue in Safari will be fixed in a future version.
In the meanwhile, this point doesn't detract from the fact that this answer is a valid solution to the question - it does indeed provide a fallback option in pure CSS.
In light of this question I've written a blog post on the subject, which hopefully covers it in more detail and provides other options if this CSS fall-back solution isn't sufficient.
You already mentioned #supports. You could define imgx1.jpg as default and if background-size is supported, you set it to img2x.jpg
For browsers like Chrome you could parse your CSS file with PHP and decide according to the User-Agent if the browser supports this or not.
You get the User-Agent in PHP with $_SERVER['HTTP_USER_AGENT']
I might not completely understand what exactly the problem is with the lack of support of the 'background-size' property, but here is my thinking:
If you want to use a double sized background image, probably that is for high density (retina) displays. If so, I'd try to define my basic style with the single background image and the 'background-size', which will be ignored by older IE versions. However, browsers handling the pixel-density media query will try to render the double density background image.
.a {
background-image: url(img1x.jpg); /* 500x500 */
background-size: 500px 500px;
height: 500px;
width: 500px;
}
#media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min--moz-device-pixel-ratio: 1.5),
only screen and (min-device-pixel-ratio: 1.5) {
.a {
background-image: url(img2x.jpg); /* 1000x1000 */
}
}
I hope it makes sense and that's what you've been looking for.
Here are some more nice ideas about CSS/JS retina background sizing: http://coding.smashingmagazine.com/2012/08/20/towards-retina-web/
EDIT: I have tried to implement user1737909's advice. Using classes (i.e., .pie.size-{size}:BEFORE) instead of attribute selectors (i.e., .pie[data-value={size}]:BEFORE) has gotten me past the first step and does not prevent the .css file from loading. Unfortunately, I have been unable to set the amount to rotate because of difficulties concatenating strings onto variables in stylus. None of the following work. What is the correct syntax?
transform rotate(size+1+'deg')
transform rotate({size}+1+'deg')
foo = size+1+'deg'
transform rotate(foo)
bar = 'rotate('+size+1+'deg)'
transform bar
-webkit-transform bar
Failing that, does anyone have any ideas for making a css/html gauge?
I am making a radial gauge in CSS which will be displayed for every post in a mixin. I'm using this code for making pie charts in CSS as an example. Setting the values of the pie-chart-wedges is as simple as changing the 'data-value' in the below code:
<div class="pie" data-start="0" data-value="30"></div>
Unfortunately the code corresponds to static css:
.pie[data-value="30"]:BEFORE {
-moz-transform: rotate(31deg); /* Firefox */
-ms-transform: rotate(31deg); /* IE */
-webkit-transform: rotate(31deg); /* Safari and Chrome */
-o-transform: rotate(31deg); /* Opera */
transform:rotate(31deg);
}
This works for the static illustration, but my page will have a variety of different sized wedges. The simplest solution would be to make new entries for all 360 degrees, but this seems like a terrible idea.
My idea is to define the style for each gauge inside the jade mixin at the same time I'm setting the 'data-value'. Something like:
pieStyle = '-moz-tranform: rotate('+ degreesPlusOne + 'deg); -ms-tranform: rotate('+ degreesPlusOne + 'deg); -o-tranform: rotate('+ degreesPlusOne + 'deg); -webkit-tranform: rotate('+ degreesPlusOne + 'deg); tranform: rotate('+ degreesPlusOne + 'deg)'
.pie2(data-start='0', data-value=degrees, style=pieStyle)
Unfortunately, the style to be set isn't for '.pie' but rather '.pie:BEFORE'. Is there any way I could set a style with this pseudo-element within a mixin?
Alternatively is there a way to solve this within stylus? The site I'm working on is a news aggregator and any user will see dozens and likely hundreds of these gauges. In such an environment would I be better off in the not-so-long-term to simply transmit all 360 sets as part of the css and reference them in cache in the future?
Thanks in advance.
You can definitely do that with stylus
for size in 30 60 180 360
.pie.size-{size}
transform: rotate(size+1)
With nib, transform will have all its prefix :).
I have this :
background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,rgba(255,255,255,0.56)), color-stop(100%,rgba(210,210,210,1)));
Its working for all browsers and for IE9 , but not working for IE6
Can someone tell me what to use else
Regards
You need to use IE's old filter rules, the rule you mentioned in the question has a vendor prefix which is targeting webkit (chrome, safari etc) browsers only. - there's a neat generator here which will help you out in making cross-platform gradients. IE6-9's rules look like this:
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#1e5799', endColorstr='#7db9e8',GradientType=0 ); /* IE6-9 *
The webkit prefix only works in Webkit browsers, which are Chrome, Safari, and Android and iPhone. For example, you'd need to use -moz for Firefox, and -o for Opera.
IE6 doesn't have any gradient support at all, so you'll need to use an image instead, or drop IE6 support, which is probably a good choice; not many users are still on IE6. (Unless this is meant for use specifically in for example governments, they're often stuck.)
Internet Explorer gradient filter doesn't support color-stop, gradient angle, and radial gradient. That means you can only specify either horizontal or vertical linear gradient with 2 colors: StartColorStr and EndColorStr.
Internet Explorer 8 and lower aren't the only browsers that don't support gradients, so using filters won't catch all browsers.
Another approach is to use Modernizr to feature detect support and use a fallback image or solid colour.
For example:
#box {
// Normal gradient syntax
}
.no-cssgradients #box {
// Fallback image
}
I want to rotate the DIV to a certain degree. In FF it functions but in IE I am facing a problem.
For example in the following style I can set rotation=1 to 4
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
This means that the DIV will be rotated to 90 or 180 or 270 or 360 degree. But if I need to rotate the DIV only 20 degrees, then it doesn't work anymore.
How may I solve this problem in IE?
To rotate by 45 degrees in IE, you need the following code in your stylesheet:
filter: progid:DXImageTransform.Microsoft.Matrix(sizingMethod='auto expand', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476); /* IE6,IE7 */
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"; /* IE8 */
You’ll note from the above that IE8 has different syntax to IE6/7. You need to supply both lines of code if you want to support all versions of IE.
The horrible numbers there are in Radians; you’ll need to work out the figures for yourself if you want to use an angle other than 45 degrees (there are tutorials on the internet if you look for them).
Also note that the IE6/7 syntax causes problems for other browsers due to the unescaped colon symbol in the filter string, meaning that it is invalid CSS. In my tests, this causes Firefox to ignore all CSS code after the filter. This is something you need to be aware of as it can cause hours of confusion if you get caught out by it. I solved this by having the IE-specific stuff in a separate stylesheet which other browsers didn’t load.
All other current browsers (including IE9 and IE10 — yay!) support the CSS3 transform style (albeit often with vendor prefixes), so you can use the following code to achieve the same effect in all other browsers:
-moz-transform: rotate(45deg); /* FF3.5/3.6 */
-o-transform: rotate(45deg); /* Opera 10.5 */
-webkit-transform: rotate(45deg); /* Saf3.1+ */
transform: rotate(45deg); /* Newer browsers (incl IE9) */
Edit
Since this answer is still getting up-votes, I feel I should update it with information about a JavaScript library called CSS Sandpaper that allows you to use (near) standard CSS code for rotations even in older IE versions.
Once you’ve added CSS Sandpaper to your site, you should then be able to write the following CSS code for IE6–8:
-sand-transform: rotate(40deg);
Much easier than the traditional filter style you'd normally need to use in IE.
Edit
Also note an additional quirk specifically with IE9 (and only IE9), which supports both the standard transform and the old style IE -ms-filter. If you have both of them specified, this can result in IE9 getting completely confused and rendering just a solid black box where the element would have been. The best solution to this is to avoid the filter style by using the Sandpaper polyfill mentioned above.
You'll need to do a matrix transform as follows:
filter: progid:DXImageTransform.Microsoft.Matrix(
M11 = COS_THETA,
M12 = -SIN_THETA,
M21 = SIN_THETA,
M22 = COS_THETA,
sizingMethod = 'auto expand'
);
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(
M11 = COS_THETA,
M12 = -SIN_THETA,
M21 = SIN_THETA,
M22 = COS_THETA,
SizingMethod = 'auto expand'
)";
Where COS_THETA and SIN_THETA are the cosine and sine values of the angle (i.e. 0.70710678 for 45°).
There exists an on-line tool called IETransformsTranslator. With this tool you can make matrix filter transforms what works on IE6,IE7 & IE8. Just paste you CSS3 transform functions (e.g. rotate(15deg) ) and it will do the rest.
http://www.useragentman.com/IETransformsTranslator/
http://css3please.com/
Scroll down to '.box_rotate' for the Microsoft IE9+ prefix.
Similar discussion here: Rotating a Div Element in jQuery
Just a hint... think twice before using "transform: rotate()", or even "-ms-transform :rotate()" (IE9) with mobiles!
I've been knocking hard to the wall for days. I have a 'kinetic' system going on, that slides images and, on top of it, a command area. I did "transform" on an arrow button so it simulates pointing up and down... I've reviewd the 1.000 plus code lines for ages!!! ;-)
All ok, once I removed transform:rotate from the CSS.
It's a bit (not to use bad words) tricky the way IE handles it, comparing to other borwsers.
Great answer #Spudley! Thanks for writing it!
Usefull Link for IE transform
This tool converts CSS3 Transform properties (which almost all modern browsers use) to the equivalent CSS using Microsoft's proprietary Visual Filters technology.
For IE11 example (browser type=Trident version=7.0):
image.style.transform = "rotate(270deg)";