Posts Tagged ‘css’

CSS3 gradients, multiple backgrounds and IE7

Saturday, February 26th, 2011

You know how, according to the W3C, CSS selectors that are not understood should be ignored, without error? IE7 doesn’t do that 100% of the time.

How dare it

That’s right. Just when you thought you had a nice system in place IE comes along and stomps all over it. I’m sure more and more people will come up against this as they start using CSS gradients in earnest. I can see it being quite a common situation, too. I have two background images: one, a CSS generated gradient and two, an image to be laid over the top of it. A nice shiny button with an icon, for example.

A button that says Register now and has a gradient and a separate icon for the background

We know that certain browsers can’t render gradients and so we define the background to initially be just a solid colour with the icon image (the users of the older browsers will never miss what they didn’t know was there). Then we go on to define the styles for the modern browsers. These styles use the same selector (background-image) so they will override the initial declaration but according to the rules, browsers that don’t understand the gradient instructions will just ignore the whole declaration leaving us with just the initial icon for the background.

As we know, the backgrounds will appear top down from the order you specify them so we specify the icon first and then the gradient, otherwise the gradient would obscure the icon.

We also define the background-position twice. This is so we can position the gradient+icon background differently from the icon on it’s own. Browsers that don’t support multiple backgrounds should not see this syntax as valid and should ignore it.

Here’s the code:

<a href="#" class="mybutton">Register now</a>
.mybutton{
	background-image: url(icon.png);
	background-image: url(icon.png),
		-webkit-gradient(
			linear,
			left bottom,
			left top,
			color-stop(0, rgb(233, 233, 233)),
			color-stop(0.5, rgb(249, 249, 249)),
			color-stop(0.5, rgb(255, 255, 255)),
			color-stop(1, rgb(255, 255, 255))
		);
	background-image: url(icon.png),
		-moz-linear-gradient(
			center bottom,
			rgb(233, 233, 233) 0%,
			rgb(249, 249, 249) 50%,
			rgb(255,255,255) 50%,
			rgb(255,255,255) 100%
		);
 
	background-position: 5px center;
	background-position: 5px center, left top;
 
	background-repeat: no-repeat;
 
	padding-left: 30px;
}

Here it is in Firefox:
Styles are working well in Firefox

And in IE7:
The icon on the button is missing in IE

Or you can see it for yourself in your browser.

It seems that IE is not behaving as we might expect. It’s not showing the gradient (expected) but it’s not failing back to just showing the icon either. A quick look at the IE developer toolbar (in IE9, IE7 mode; the IE7 dev toolbar would leave you stumped) shows us why:

Screenshot of the IE developer toolbar showing that IE has picked up and is trying to use styles it can't understand

It’s picked up the background image declaration that includes a gradient. In this case it’s the Mozilla-specific gradient and the reason it’s this one and not the Webkit one is that we are defining the Mozilla one last. If they were defined the other way around it would have picked up the Webkit one instead.

Why? Oh why??

I’m no expert on how IE parses CSS but I would presume it’s something like IE recognises the URL part just fine and when it reaches the closing parenthesis it figures that’s it and all’s well. Maybe not. Whatever, for some reason it thinks it’s a valid declaration, scoops up the whole lot gradient and all and tries to render it. And fails.

That’s annoying

Yes it is.

The fix

Importantly, IE correctly recognises the background-image declaration as invalid (for itself) if it starts with a gradient, even if it contains a regular image later on. So we just start the declaration with a gradient. The trouble is, we don’t want to put the gradient first as it’ll obscure the icon, so we define another gradient that is OK to put on top of the icon. That would be an empty or transparent gradient.

We will use the minimum amount of code that is necessary to trigger a gradient in the rendering engine. For Webkit, it is -webkit-gradient(linear, left bottom, left top). No color-stops required. This is good because no colour means no visible gradient. For Mozilla, it requires some colour information, so we just give it completely transparent colours using rgba: -moz-linear-gradient(center bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%).

Putting these gradients first mean that IE7 won’t incorrectly think it can render that style and so it’ll stick with just the icon.

Important: Because we now have 3 background images, we also need to declare a third value for background-position.

.mybutton{
	background-image: url(icon.png);
	background-image: -webkit-gradient(linear, left bottom, left top),
		url(icon.png),
		-webkit-gradient(
			linear,
			left bottom,
			left top,
			color-stop(0, rgb(233, 233, 233)),
			color-stop(0.5, rgb(249, 249, 249)),
			color-stop(0.5, rgb(255, 255, 255)),
			color-stop(1, rgb(255, 255, 255))
		);
	background-image: -moz-linear-gradient(center bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%),
		url(icon.png),
		-moz-linear-gradient(
			center bottom,
			rgb(233, 233, 233) 0%,
			rgb(249, 249, 249) 50%,
			rgb(255,255,255) 50%,
			rgb(255,255,255) 100%
		);
 
	background-repeat: no-repeat;
	background-position: 5px center;
	background-position: left top, 5px center, left top;
 
	padding-left: 30px;
}

Here it is in Firefox:
The styles are working well in Firefox

And in IE7:
The styles are working well in IE7

Or you can see it for yourself in your browser.

But wait, there’s more!

You thought this was over? Of course it’s not! IE9 is a heck of a lot better than previous versions but it’s still not perfect. For example, it does support multiple backgrounds but it doesn’t support CSS gradients. This means that it’ll ignore the gradients but it’ll use the background-position multiple background declaration we made, resulting in the icon being positioned left top as opposed to 5px center.

The styles have regressed in IE9 and the icon is incorrectly aligned

I tried getting around this by inserting another background-image defining three images (two of them transparent spacers) directly after the first background-image and before the first gradient:

.mybutton{
	background-image: url(icon.png);
	background-image: url(spacer.gif),
		url(icon.png),
		url(spacer.gif);
	background-image: -webkit-gradient(linear, left bottom, left top),
		url(icon.png),
		-webkit-gradient(
			linear,
			left bottom,
			left top,
			color-stop(0, rgb(233, 233, 233)),
			color-stop(0.5, rgb(249, 249, 249)),
			color-stop(0.5, rgb(255, 255, 255)),
			color-stop(1, rgb(255, 255, 255))
		);
	background-image: -moz-linear-gradient(center bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%),
		url(icon.png),
		-moz-linear-gradient(
			center bottom,
			rgb(233, 233, 233) 0%,
			rgb(249, 249, 249) 50%,
			rgb(255,255,255) 50%,
			rgb(255,255,255) 100%
		);
 
	background-repeat: no-repeat;
	background-position: 5px center;
	background-position: left top, 5px center, left top;
 
	padding-left: 30px;
}

But that didn’t work as IE7 still parsed it (incorrectly) just as it did in the first instance and therefore didn’t show the icon at all. Back to square one.

At this point I’m sure most people are thinking

“Oh come on, why not just use Modernizr and only apply the gradients to browsers that can use them?”

That’s one way of doing it, although I would rather not use JavaScript if possible. This leaves one option… go back to the original CSS and add this conditional comment in the <head>:

<!--[if IE]>
<style type="text/css" media="screen">
		.mybutton{
			background-image: url(icon.png);
			background-position: 5px center;
		}
	</style>
 
<![endif]-->

As no versions of IE yet support gradients, we just reset the background to be the plain ol’ icon. Problem solved.

Here it is in Firefox:
The styles are working well in Firefox

And in Webkit (Chrome):
The styles are working well in Chrome

And in Opera:
The styles are working well in Opera

And in IE6:
The styles are working well in IE6

And in IE7:
The styles are working well in IE7

And in IE8:
The styles are working well in IE8

And in IE9:
The styles are working well in IE9

Or you can see it for yourself in your browser.

A side serving of gradient

You may have noticed that two of the color-stops have the same percentage/distance value. This effectively give us the ability to have more than one gradient on the same element. The end result is a gradient from the top to the middle, a sudden stop and change of colour and another gradient from the middle to the bottom. It’s useful to be able to change sharply from one colour to another as well as smoothly!

  • If anyone has a better solution, please get in touch in the comments or on Twitter.
  • The images I’ve used come directly from the project I’m working on in my day job. If my employer has any objection to their use here I will of course replace them with something else. But I’m sure they won’t.

The Web in 3D – the Nintendo 3DS web browser

Monday, February 14th, 2011

The Web in 3D – the Nintendo 3DS web browser

Last Sunday my wife and I went and had a sneaky preview of the new games console from Nintendo: the 3DS.

The Nintendo 3DS

Let’s not beat around the bush: this is a very impressive device. It’s tricked out with all the latest technologies (or the latest applications of ‘old’ technologies, wherever you choose to draw the line). The thing people are really talking about, of course, is the 3D aspect of it. I’m sure you have read about it – the top screen is a 3D display which importantly doesn’t require glasses. I can’t stress enough how good the 3D effect looked. It felt completely natural and I didn’t find myself getting any kind of a headache or nausea like some people are worried about.

There were demos available of most of the functionality: Lots of games that’ll be available on launch or shortly thereafter, 3D photography, augmented reality (including the ‘reality’ part shown in 3D due to the 3D cameras on the lid – the most impressive thing for me) and street pass (Nintendo’s social discovery system). But the thing that actually holds the most interest for me wasn’t shown and indeed is barely talked about. I’m hoping that will change.

A complex web

I’m talking, of course, about the web browser which will come built in to the device as part of the extensive suit of software bundled on-board.

*YAWN*

A web browser? What’s so great about that?

I don’t know yet because no-one is talking about it, but I’m hoping it will inspire (even more) innovation and creativity on the web. I’m hoping it will have some semblance of 3D integration and capability. And if not, why not? Surely this is the way the web is going. More and more devices will be 3D enabled in the near future and you can bet that if the 3DS doesn’t kick-start the 3D web some other device will. You can buy a 3D TV to put in your living room for crying out loud – this is 2011! They reckon you’ll be able to buy a HOLOGRAPHIC 3D TV in 2012. I’m all over that. And I want the web to make sure it isn’t left behind. After all, a lot of modern TVs have integrated browsers. It’s the next logical step.

Least they could do

The least I could hope for is support for 3D images displayed in web pages. The LEAST. The standard open format is .mpo and fortunately the same format in which the 3DS saves it’s 3D photos.

That’s not to say you will be able to simply embed the 3D photos in your site and have them work in the 3DS’ web browser though. Think how that would look in a desktop browser… Well it probably wouldn’t show up or show a broken image.

No, no, no, don’t even think about making a separate site for 3D devices. I thought we were past all that. What are you going to have yet another separate site for 3D+Mobile? We want to serve one page that works on all devices.

The trouble is, without images having a similar failover pattern to the one available to video and audio in HTML5, you simply couldn’t use the image inline in your page as non-3D-enabled browsers wouldn’t recognise the format. This just proves that there are always new image formats emerging; they are not all supported by all browsers as it’s easy to assume (if you forget about IE6 and .png’s) so why should we assume that that’s the case with the markup?

This has been discussed by Bruce Lawson and makes sense (no matter how frustrating it is). So until all browsers support the display of 3D images on 2D screens we will have to find another way.

The other way to include images in the page is, of course, CSS background images. This one has legs. The 3DS browser could easily respond to an @media query, something like @media screen and (-3ds-min-device-spatial-dimensions: 3) { ... }. Then you could alter how the page looks on a device that has 3D capabilities. Once you have the 3D background image in place you can mark it up to include a 2D version for the rest of the world:

HTML:

<div class="forest-picture">
    <img src="/static/img/forest-2d.jpg" alt="Pretty forest scene" width="400" height="250" />
</div>

CSS:

@media screen and (-3ds-min-device-spatial-dimensions: 3) {
    .forest-picture{
        background: transparent url(../img/forest-3d.mpo) no-repeat 0 0;
        width: 400px;
        height: 250px;
    }
    .forest-picture img{
        display: none;
    }
}

The best of both worlds! We can dream…

Reality check

Before we go on, I just need to make it abundantly clear (if it isn’t already) that this article is pure speculation. I don’t know if the 3DS browser supports any of this kind of stuff, but imagining the possibilities and how they might work is an interesting exercise. Oh wait, it looks like Google has already looked into 3D browsing. My mistake ;)

Let’s explore further down the rabbit hole…

Going the extra dimension

What if we wanted to move beyond just sticking 3D images in our pages? As awesome as a 3D gallery might be, there are so many more possibilities. Imagine if the whole page could be rendered in 3D; if each element on the page had it’s own depth setting. I think the most obvious thing to do would be to push the background actually into the background giving the site content more prominence, and if you start down that road you should just be able to let your imagination carry you forwards.

I know what you’re thinking, and it’s what I thought at first too… why not use z-index for that? The reason why not is because z-index controls the stacking order of elements on a single plane. If you change the function of z-index to control depth on 3D devices, how would you re-order a group of elements sharing the same depth on a 3D page? It’s clear that we need a separate property to do that. I’m going to be bold and use depth in examples, for want of a better attribute name.

So where are we? We’ve got 3D images and the ability to assign depth to elements. That’s a good start, but it seems a little restricted, doesn’t it? A bunch of flat panels sitting at different depths in a 3D space. We’re not really making the most of the technology. We need to add a little style in there… style that can bridge the gap between depth-levels. Fortunately, Webkit is one step ahead of this game with it’s CSS 3D transforms. These could easily be adapted to show in real 3D instead of 3D rendered in 2D.

Curves would be nice

Yes they would, and so would a mansion on the beach in Barbados. We don’t even have the ability to define curves in 2D CSS yet. But then in 2D we might not have wanted to do crazy things like making a callout or title bow inwards or outwards, which would work pretty well in 3D. But maybe just one step at a time…

What is 3D anyway

To develop in 3D you need to understand how it really works. Fortunately understanding it is a lot simpler than getting your head around designing and developing in it:

3D works by each of your eyes seeing a slightly different image.

Simple enough, and in real life this works pretty well. But when generating your own 3D content you have to be ever-mindful of it.

Mind the gaps

Imagine a blank page. You make the background a fetching pinkish sort of red colour and set the depth to be way back in the distance.

3DS Screen showing plain background

You then have a look at it and wonder why it doesn’t look like it’s way off in the distance. You check to see that your 3D depth slider is turned all the way up and when you find that it is you’re left feeling a little confused.

The reason why this doesn’t appear to be in the background is because your eyes are seeing the exact same image. There needs to be some more detail in there before your eyes can be tricked into thinking that it’s way off in the distance. Here are some suggestions:

1. You could give it a border that makes it look like you’re looking into a box. Of course the edges of the border would need to be firmly in the foreground for it to work.

3DS screen showing a background shaded to look like you are looking into a box

2. You could give it a pattern or image. Beware with repeating patterns though: looking at 3D images forces your eyes to cross slightly and a repeating pattern could cause you to think it’s not at the depth you intended.

3DS screen with a patterned background

3. Lay something else on top of it with a higher depth. For demonstration purposes I’m going to go with this one.

3DS screen with a plain background and a green tile overlayed

But even laying something on top like this isn’t too easy for our brains to process. Have a look what each eye would be seeing.

Side-by-side 3DS screens showing the difference in location of the overlaid panel for each eye

There’s not a great deal to differentiate these two images and while your brain knows it’s seeing different things from each eye it is struggling because there are things missing that it’s used to. Usually when you see an object in front of another object it casts a shadow somewhere. Because they are in different locations your eyes will each see that shadow slightly differently. Also the way the object is lit and how it reflects the light could be different in each eye. To make sure we don’t give people headaches we’ll have to sort this out.

.floating-box{
    box-shadow: 5px 5px 5px #ccc;
}

Now the panel has a nice drop shadow which should make it easier on the eyes and easier to see the 3D effect.

3DS screen with plain background and a green panel overlaid with a drop shadow

But how does it get rendered so that each eye sees the shadow differently?

Seeing the light

The way I see it there are two options:

1. The browser provides a default (override-able) light source:

body{
    light-source: 25% 25% fixed;
}

fixed would position the light source relative to the browser viewport, and as an alternative absolute would position it relative to the document.

2. You, the developer, get granular control over what each eye sees:

If you had control over each eye the possibilities would be endless. Set the difference in box shadow offset, show a different background image to achieve a rippling effect. You would OWN all the dimensions.

@media screen and (-3ds-min-device-spatial-dimensions: 3) and (-3ds-perspective: left-eye) {
    .floating-box{
        box-shadow: 3px 5px 5px #ccc;
    }
}
@media screen and (-3ds-min-device-spatial-dimensions: 3) and (-3ds-perspective: right-eye) {
    .floating-box{
        box-shadow: 7px 5px 5px #ccc;
    }
}

I think a combination of both would probably be in the interests of developer and user alike.

It’s not all giant blue humanoids and bio-luminescent flowers

This technology has it’s disadvantages, and you can be sure that there will be some nasty surprises out there when it comes along. As with most visual effects, subtlety is king. Of course there will always be the developers who are irresponsible with this great power and make some eye-bleeding creations, but that’s just inevitable. No, what I’m really worried about can be summed up in two words: Internet. Advertising. If you thought pop-over ads were intrusive now, you ain’t seen nothing yet.

The waiting game

Who knows what you’ll be able to do with the browser? Nintendo maybe? Or if it’s Opera providing the software again, as they did for the Wii and original DS/DSi then I expect they will know. (Please do get in touch if you have insider knowledge!) But until that information is made available or the 3DS is in our hands we won’t know for sure. I hope it’s got at least a few fun 3D features to play with. I’m sure the full set will develop over time.

Update: Now that the browser is available, I had a little play with it and wrote down a few of my thoughts.

A little something while you wait

Tuesday, February 2nd, 2010

I know, I know it’s been a while since I posted. There’s one on the way, I promise!

While you wait for it to brew, however, why don’t you check out my inaugural post on the BBC Web Developer blog: CSS for Widgets.

Have you ever written some CSS on a page which contains other people’s stylesheets? And have you noticed that either your CSS broke their stuff or theirs messed about with yours? If you have then this post is right down your street. If you haven’t… well have a read just to make sure it never happens.