Feb 13 2010

Using :before/:after for extra background-images

Category: NXT RPG,WebdevelopmentSpiller @ 00:32

First a small introduction you might just as well skip… (actually, just scroll down to the bottom…=

Level files used in NXT RPG are saved in binary of space reason, but this of course is hard to manually create and maintain and very much error prone. So I created my own tools using XML, XSLT, and made a small application to convert values to NXT binary values.

It is pretty simple, the XML file stores data about the level, the XSLT file then creates a visual aid so it is easy to see what is wrong and a text code. The text code is then converted to binary by the application I wrote.

End of story.

The issue

The XSLT file I made works, but it isn’t that efficient. The level is shown using X*Y images (which is often around 200); this really can’t be avoided. However I also include a small preview of the levels it is linked to, which adds another 200 per level. However I might need the preview in 2 places or more, but right now they aren’t reused. Because of this, the total amount of img elements normally adds up to 2000-4000. Ugh…

Optimizing: Small steps first

The level is viewed in two modes: normal and solid. Normal will show the level map as it looks like in the game, solid will show an overlay which tells which blocks on the map are, well, solid.

This overlay is created by adding another X*Y images, where the overlay graphic are loaded on some elements. Not ┬áthat efficient…

The solution became to use :before in CSS to add a absolutely positioned block inside the <img> which contain the overlay graphic.

I tried it, it worked fine in Opera and it simplified the XSLT and resulting HTML a bit. Then I opened it in FireFox and :before didn’t work. Same thing in IE8. After a bit of testing I discovered that :before doesn’t work on <img> elements. After changing it to <div> and background-image the problem disappeared.

I’m not really sure what is correct, but Opera seems to allow generated content everywhere, you can even say “head{display:block;content:”yay”}” and the “yay” appears at the top of the page. So I guess it is Opera that is at fault…

Going crazy

Then I wondered, how many “overlays” could I create with this method? By using both “content:url(‘img.png’)” and “background-image” you would have two. Then you could also add :after to double this to 4. Alternatively you could also create an underlay by setting background-image on the <div>.

To test it out I tried to create a box with rounded corners using only a single <div>.

It is basically the same as previously, however :before and :after is set to display:block. It is just useful for this example since it makes the positioning quite a bit easier…

Box with rounded corners

This will not work in IE6/7, so the advantage of using this instead of border-radius might not be that big… Secondly, positioning the imaged specified by “content:” can be a bit more tricky if the element is flexible in size… But it might be interesting in other cases…

The code is here, without the images though:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<title>Title</title>
<link rel="stylesheet" type="text/css" href="main.css"/>
<style>
.Rbox{
width:25%;
background-color:#6267ff;
padding:0 10px;
}
.Rbox:before, .Rbox:after{
display:block;
height:10px;
background-repeat:no-repeat;
background-position:top right;
line-height:0px; /* remove issue with whitespace... */
margin:0 -10px;
}
.Rbox:before{
content:url('lt.png');
background-image:url('rt.png');
}
.Rbox:after{
content:url('lb.png');
background-image:url('rb.png');
}
</style>
</head><body>
<div>something... texty texty... texty texty... texty texty... texty texty... texty texty... texty texty... texty texty... </div>
</body>
</html> 

Tags: