Archive for the 'CSS' Category

Background repeat and CSS sprites

Thursday, April 3rd, 2008

CSS sprites are a great way to improve the loading speed of your pages. One of the problems you might face with sprites is how to deal with cases when the background repeats.

The rule is pretty simple: if you want the background to repeat vertically (top to bottom), place the images in the sprite horizontally (left to right) and make sure the individual images in the sprite have the same height. For the opposite case: when you want to repeat horizontally, sprite vertically.

Example

» Demo

You have three divs and you want to repeat their background vertically, so that the background takes the whole height of the div, according to the content.

Source images:

  1. 1.png
  2. 2.png
  3. 3.png

Singe image sprite:

sprite8.png

CSS definitions to make this work:

    div {
        background-image:url(sprite8.png);
        background-repeat: repeat-y;
        width: 160px;
        padding: 20px;
        margin: 20px;
        float: left;
    }

    #my {
        background-position: 0px;
    }
    #my2 {
        background-position: -200px;
    }
    #my3 {
        background-position: -400px;
    }

Every image is 200px wide. Because of the 2×20px margin left and right, the width is 160px (=200 - 20 - 20)

The tree divs have IDs: my, my2, my3

Result

Once again, the result

Tested on Windows with IE7, FF, O, S.

 

The Front-end Cerberus

Thursday, October 25th, 2007

Some smart guys picture the distinction of content (HTML), presentation (CSS) and behaviour (JavaScript) as a three-legged stool. This is totally fine, but can't we draw a more heroic picture of today's Front-end developer?

frontend-cerberus.jpg

I found the image here, if anyone knows the original author, let me know so I can give proper credit.

BTW, I never knew what Cerberus meant until 15 minutes ago. The thing is that where I come from, we used this name to refer to some of the teachers that weren't very nice to us at school :)

 

Quick CSSSprites.com stats

Wednesday, September 12th, 2007

Just deleted about 3 gigs of files uploaded to csssprites.com because I'm running out of disk space. I keep the .html results though, just for stats purposes. So ls | wc -l says that there are 3170 files meaning over 3000 sprite images were produced already, nice.

The tool is very primitive, I admit, its main purpose was to raise awareness of the CSS sprites technique. It's missing a lot of features (as any weekend project do), but I'd say it allows developers to start quickly with the sprites and to admire faster loading web sites in less seconds than it takes to say "OK, how I have open Photoshop and to create one big image of all my smaller images and write down the coordinates in a css file".

 

csssprites.com update

Sunday, July 22nd, 2007

Added:
- generation of a GIF sprite in addition to the PNG
- small client-side only check if at least two files are updated
- link to a Yahoo search for "css sprites"
- note begging people not to upload huge files

Only the first thing is a feature, the other three are to raise awareness on what the CSS sprites technique is about. Hopefully it will help people stop uploading 20-30 megs of images in order to create a sprite.

http://www.csssprites.com/

 

phpBB front-end optimization - 1 hour workshop

Friday, July 13th, 2007

Let's go ahead and optimize our phpBB installation for front-end performance. I'll follow Yahoo's 14 optimization rules, but only implement the ones that apply for phpBB. During this short workshop there will be no changes to the phpBB code, we'll create a new template instead, so that in case something bad happens, your board will continue to work normally. As an example, I'll use the bgcanada.com/phpBB2, the board I volunteer to administrate.

The plan

1. creating two subdomains to host assets - images and css, maximizing parallel downloads (also following rule #9)
2. creating a new template (theme) based on the default subSilver template
3. moving CSS to an external file (rule #8), merging the two css files (rule #1)
4. copying images and css to the new subdomains
5. making sure css is served gzipped (rule #4) and also making sure php pages are served gzipped)
6. turning ETags off (rule #13)
7. setting the Expires header (rule #3)
There will be no explanations on the reasoning why these rules exists, but only how to implement the applicable ones in phpBB. It's a good idea though to go through the links above and read the detailed description of the rules. Maybe you'll find something that can be done in addition to the plan above. The suggested implementations were done and tested on a normal $60/year shared host, working around the limitations of such hosting. I'll speculate that at least 90% of the phpBB installations out there use shared host so I hope my implementation will be relevant to your phpBB install as well.

New subdomains

Typically, shared hosts allow subdomains and have their admin interface for doing so. In case your host is an exception, alternatively you can buy one or two extra domains to use for the same purpose - storing page assets.

So in my case, for the domain bgcanada.com I create two sub-domains - i1.bgcanada.com and i2.bgcanada.com (i as in image). Now the question would be how to divide assets between the two domains. I decided that more or less half of the images are multilingual (they don't contain text) so these go to i2. i1 will have all the rest - translatable images found in subSilver/images/lang_english, smilies and the stylesheet.

creating a new template

Let's go ahead and create a new template (theme), based on the default subSilver template. I'll call mine "sso" as in "subSilver optimized" (or the longer mirror-like version "ssoss" as in "stoyan stefanov, oh, so smart" ;) )

For this purpose, just take the contents of path/to/phpbb/templates/subSilver and copy it under the name "sso", so you'll have /templates/sso, an exact subSilver copy.

Now go ahead and modify templates/sso/subSilver.cfg, the theme configuration. First rename it to sso.cfg. Then at the top of the document, replace the line:

$current_template_images = $current_template_path . "/images";

with

//$current_template_images = $current_template_path . "/images";
$i1 = "http://i1.bgcanada.com/sso"; // language and smilies
$i2 = "http://i2.bgcanada.com/sso"; // the rest

use your domain, of course.

Then do a search/replace. All occurrences of:

$current_template_images/{LANG}/

should become

$i1/{LANG}/

And all occurrences of

$current_template_images/

become

$i2/

At the end of the file, just before ?> add a new line:

$board_config['smilies_path'] = 'http://i1.bgcanada.com/smilies';

This will overwrite the path to the smilies you set in the admin interface. This is optional, you can achieve the same by using the admin panel, but we said we wanted to have the board unaffected by the changes.

Now open templates/sso/theme_info.cfg and replace all occurrences of "subSilver" with "sso".

Now the bad news is that some of the template files (.tpl) still contain relative paths to images, we need to make these absolute and pointing to the subdomians. Since these paths are hardcoded in the templates we're sure that they are language independent, so they'll all go to the i2 subdomain. If you have a good text editor that can search/replace in multiple files, go ahead. Alternatively, use the php script I came up with. Download it, copy it to your /templates/sso folder, rename to replace.php and use it like:
C:\path\to\phpbb\templates\sso> php replace.php
It will report what it replaced.
It only searches for templates/subSilver/images and replaces with http://i2.bgcanada.com/sso

Yep, almost done with the template, one last step - the css.

Moving CSS to an external file, merging

In the default subSilver there are style definitions in overall_header.tpl. Remove them, the whole thing between the <style> tags and replace with:

<link rel="stylesheet" href="http://i1.bgcanada.com/sso.css" type="text/css">

Now rename subSilver.css to sso.css. Copy the contents of formIE.css and append it to the end of sso.css. Optionally, you can walk through the new file and strip all comments and white space. Or use my stripped version.

Note that as a side effect, the font of the board will look somewhat different, because the definitions in subSilver.css are not exactly the same as those in the overall_header.tpl. It's not a big difference, but if it's important to you, just ignore the original subSilver.css and create sso.css copying the styles from overall_header.tpl and formIE.css.

We're done with the files, the rest is sysadmin stuff.

copying files to the new subdomains

That's easy, just take everything from templates/sso/images (leave the lang_english or any other language folders) and copy to http://i2.bgcanada.com/sso

Than take all lang_* folders and copy to http://i1.bgcanada.com/sso, so you'll have http://i1.bgcanada.com/sso/lang_english/

Now copy all smilies from phpbbroot/images/smilies to http://i1.bgcanada.com/smilies/

Now take the sso.css you created and copy to http://i1.bgcanada.com/sso.css

Last, take the whole sso directory and copy to the main domain - http://www.bgcanada.com/phpBB2/templates/ so that it's in the same folder next to subSilver.

Login to the admin panel and activate the new theme as usual. Login to your account and change your theme preference to sso. You still want to test before making it a default theme for everyone.

At this point you should be able to browse your forum with the new theme and everything should look like as if you were using subSilver.

Serving gzipped content

The rule is that all served files should be gzipped, with exception for images, because gifs, jpgs, pngs are already compressed.

To serve the normal html (php) pages gzipped, just use the built-in phpBB feature, log on to the admin panel and enable gzip compression.

To serve sso.css gzipped, ideally you should only create an .htaccess file and have Apache do it for you (more info). Unfortunately my host won't allow it, so I took the alternative path - have PHP gzip and serve the css file. To do so I created an .htaccess file http://i1.bgcanada.com/.htaccess and put in it:

AddHandler application/x-httpd-php .css

This affects all CSS files (but we have only one) and makes them php scripts. If your host allows you to use php_value in .htaccess, you can do the rest of the job by only using .htaccess. Otherwise create a http://i1.bgcanada.com/php.ini file and put in it:

[PHP]
default_mimetype = "text/css"
zlib.output_compression = On
zlib.output_compression_level = 6
expose_php = Off
auto_prepend_file = "pre.php"

The first line makes php send text/css header instead of the default text/html. Some browsers won't like CSS files served with text/html header. The second line enables compression and the next line sets the compression level (could be up to 9). 4th line is absolutely optional, just removes an extra header that PHP sends. The last line sets that all served php files should include the file pre.php as if you used include "pre.php" inside every PHP script. This is actually used later for the Expires header.

turning ETags off

That's super easy. Just add .htaccess rules in both i1 and i2 to say:
FileETag none

Expires header

To set the expires header, add these lines to .htaccess on both i1 and i2

ExpiresActive On
ExpiresDefault "access plus 2 years"

This makes all files - images and CSS - on i1 and i2 expire in 2 years, if that's too much/not enough, feel free to change.

If it doesn't work for you (it didn't for me, because of the host), you can go the php auto_prepend route described above and add in the pre.php file
header('Expires: ' .gmdate("D, d M Y H:i:s",time() + (60 * 60)) . ' GMT');
Feel free to set 60 * 60 to whatever you think makes sense for you. Note that this will only affect the CSS file, images will be served "normally". You can also have PHP serve all the images, like we did for CSS, but I think it's probably too much.

Sysadmin summary

There was a lot of if-then above so let me summarize what worked for me, but try your other options first to see how "liberal" your host is in order to do a better job than me.

http://i1.bgcanada.com/.htaccess

AddHandler application/x-httpd-php .css
FileETag none

http://i1.bgcanada.com/php.ini

[PHP]
default_mimetype = "text/css"
zlib.output_compression = On
zlib.output_compression_level = 6
expose_php = Off
auto_prepend_file = "pre.php"

http://i1.bgcanada.com/pre.php

<?php
header('Expires: ' .gmdate("D, d M Y H:i:s",time() + (60 * 60)) . ' GMT');
?>

Done!

We're done! Did it take more than an hour? Hope not, although with these computers and stuff, everything takes more time than expected.

Do you see anything missing? Or something that can be improved? Or something didn't work for you? Please post a comment. The whole posting is a bit fast-paced and written in a rush (I really need to go to bed), so if there's something unclear please ask.

 

CSS Sprites generation tool

Wednesday, June 27th, 2007

Here's my last weekend's project - a web-based tool to generate images for CSS sprites: http://www.csssprites.com. Cool domain name, eh? I couldn't believe it was not taken.

CSS Spr…what?

This is a simple technique used for page load performance purposes. Since HTTP requests are the most expensive thing you can do in regards to front-end performance, you strive for making as little requests as possible. So instead of having the browser download 4 rounded corner images for example, you create one image that has all four. Then you use CSS' background-position to only show the part of the image you want. More on the subject in this ALA article

How does the tool work

You upload as many images as you want and the tool generates a mosaic of all images, gives you the result as PNG and gives you the coordinates you need to use in the background-position declaration. The tool also gives you an html page as an example, so you can save both the PNG and the html page for reference.

Image size

If you properly optimize the big image, you might actually have smaller size than all the individual images combined. In my tool, the PNG image generated is not optimized at all, I leave this to you to use PNGOUT or any other tool you know. Also you can convert the PNG into GIF if that's better for your purposes.

Implementation - PHP

The PHP code is fairly simple. The actual spriting (is that a word?) class takes a list of images and calls getimagesize() on each one to get the dimensions. The image with the biggest height is used as distance between images. The rest is just composing the imagemagick command that will to the work. Here's the important method:

<?php
function combine() {
    if ($this->distance === false) {
        $distance = $this->_biggest;
    } else {
        $distance = (int)$this->distance;
    }

    if ($this->output_dir === false) {
        $output_dir = $this->_dir;
    } else {
        $output_dir = $this->output_dir;
    }

    $half = ceil($distance / 2);

    $coord = array();
    $y = 0;

    foreach ($this->images as $i=>$data) {
        $this->images[$i]['x'] = $half;
        $this->images[$i]['y'] = $half + $y;
        $coord[] = '-page +0+' . $y . ' ' . $i;
        $y += $data[1] + $distance;
    }

    $cmd = 'convert ' . implode(' ', $coord)
         . ' -background none -mosaic -bordercolor none -border '
         . $half . 'x' . $half
         . ' ' . $output_dir . '/result.' . $this->output_format;
    system($cmd, $ret);

    return $ret === 0;

}
?>

Implementation - JS

In the spirit of web2 I couldn't afford a complete page reload :lol: although it would've been much simpler. I just had to get fancy. YUI to the rescue. On page load I set up the form for async request, using YAHOO.util.Connection. In case of file uploads YUI generates an iframe behind the scenes and uploads to the iframe. Then it takes whatever is in the body on the iframe and gives it to you instead of the XMLHttpRequest's responseText property.

So the files are uploaded to upload.php which calls the class that has the method mentioned above then loops through the $images property of the said class and writes the example html file as well as prints out a JSON string with the same image information.

YUI's Connection calls my callback function and I get the invaluable responseText. Parsing the JSON with the json.js, I get a JS object. Looping through it and DOM-generating a table of results is the semi-last step. The last is (we're fancy, remember?) to yellow-fade the background color of the result, using YAHOO.util.Animation.

BTW, I got fancy once again and combined and minified json.js with my JS file, so that there is one less request and a side effect impossible to read. The unminified version of the JS that does all the work is here for reference.

Comments

I hope this tool cane be useful for quickly generating those sprites, if only for prototyping purposes. Any comments, requests, bug reports are all very welcome.

And how do you like the version of the tool? Anyone n00b can do "beta", it takes a true h@x0r (or something) to do a better job :D

Ah, yeah, and the page badly needs a stylesheet, do you want to help?

 

Smart browsers don't download unneeded images

Saturday, June 23rd, 2007

We ofter complain about browsers, browser inconsistencies, quirks, hickups, the list goes on. Let's say something nice to them, and hope for good karma :)

It happens as your web app grows in size and team members that some parts of the stylesheets become obsolete, no one remembers why they were there in the first place, but no one has cojones to remove them, because of fear that removing them might break something you forgot to take into consideration. Same case when you have the same stylesheet for 50 different pages and on some pages only some of the styles are actually used. I was wondering, do you pay performance penalty when you have style rules that refer to images, but the rules are never needed to render the page? Will the browser download all those unneeded images? The answer is No. The browser will try to avoid downloading the image assets as much as possible. And this behavior is pleasantly consistent across IE, FF, Safari (for Windows), Opera.

Test #1

I tried this stylesheet:

body {
    background: url(bg.png);
}
#some-id {
    background: url(ie.png);
}
.some-class-name {
    background: url(o.png);
}
p {
    background: url(image.php);
}

And applied it to a blank page that doesn't have any paragraphs, or elements with class name some-class-name, or ID some-id. The result was that only bg.png was downloaded, which is great.

> test #1

Test #2

I added a button which, when clicked, creates a new P element and sets a 3 seconds timeout before appending the new element to the body. (The background for the P element is the script image.php which only sleeps for 3 seconds for demonstration purposes, before redirecting to ff.png.) The result is that the image is requested only after the element is added to the document flow, not when it was created. Which is smart. It ain't added ’till it's added.

> test #2 (same file as test #1, btw)

Test #3

OK, modified test #2. A P element is created, its visibility is set to hidden and it's added to the document. It's officially in the document flow, although not currently displayed. My guess was that the browsers will download the image at this point. True for FF, IE7, Safari, Opera.

> test #3

Test #4

Here's the only inconsistence in the behavior of the browsers. A P element is created, but with display: none, then added to the document. So it's part of the DOM tree, but not really part of the document flow. Then another button changes display to block.

FF will wait for the display: block before downloading the image background
Opera will also wait until display: block
IE7 begins to crack under the pressure and downloads the image even with display: none
So is Safari

> test #4

So what?

Well, it's nice to know that the browsers won't download the images referred to from our stylesheets unless they are needed for rendering. There is a side effect though. If you happen to create dynamic elements that have some styles with background and no other similar elements already exists on the page, the user experience might suffer slightly as the image will generally be requested after the new element is added. In cases when this is important to you, you might need to take some extra care to make sure the image is downloaded before you add the new element. You might need to do for example a new Image() after initial page load. (reminds me of the good old days of image rollover buttons, those were the days, eh? Seems like no one does image rollover buttons and menus anymore. It's all css this, css that… ;) )

 

Delay loading your print CSS

Sunday, June 17th, 2007

So you have two stylesheets on your page, like this:

<link type="text/css" rel="stylesheet" href="screen.css"
      media="screen" />
<link type="text/css" rel="stylesheet" href="print.css"
      media="print" />

The first one is used to render the page on screen, the other one is used for printing the page and print previewing it. Good.

The thing is, when it comes to performance, the browser won't render any part of the page, until all stylesheets are downloaded (fiddled with here). That includes, unfortunately, stylesheets not designed for the currently rendered media. In other words, the browser won't display your page, until the print stylesheet is also downloaded, although it's not used at all for displaying the page. That sucks and should really be addressed in future browser versions.

Test

I did a test page to check this, it's here - print.php. It includes two stylesheets, the first one intentionally sleep()s for 5 seconds, the second one - for 10 seconds.

The result is that in both Firefox and IE it takes 15 seconds for this page to be rendered. Here's the Firebug picture:

media-print.png

In Safari on Windows, it only took 10 seconds the first time around, as both stylesheets were downloaded simultaneously. Good. The bad is that after refresh, the first CSS was not even requested, I tried it a few times, actually sometimes I got the error "The error was: “unknown error” ((null):10053) ", but hey, this is the first release of the browser, it can't be perfect. Actually after I shut down Fiddler, which is what I used to monitor the HTTP traffic, the page was back to normal, so it's not clear who's to blame.

So?

Well, in order to increase rendering performance, all stylesheets not absolutely needed to initially render a page should be loaded after the page load, in the background. Once the user has a fast rendered page to interact with, you can load the additional CSS (and JavaScripts for that matter) in the background, using script and style DOM includes.

Update: From my comment bellow - a better option is to include the print css as part of the main css:
@media print {…}

 

Center an image with CSS

Monday, February 19th, 2007

Here's one solution to centering an image both horizontally and vertically, when you know the height of the container. Tested in FF, IE6, IE7

The markup:

<div class="container">
    <img src="pearbook.png" />
</div>

Styles for normal browsers:

.container {
    height: 200px;
    width: 300px;
    display: table-cell;
    text-align: center;
    vertical-align: middle;
    border: 1px solid red;
}
.contain img {
    vertical-align: middle;
}

and IE exception:

<!–[if IE]>
<style type="text/css">
    .container {
        font-size: 181px;
    }
</style>
<![endif]–>

You might wonder where 181px come from? Well, this is the height of the div that contains the image, multiplied by 0.905. Crazy, eh? But it works! And why 0.905? No idea, I saw that in a blog posting which I have hard time locating now in order to give proper credit. A guy was experimenting and he came up with this coeficient.

Here's a test page.

 

User stylesheet in IE

Saturday, January 20th, 2007

Let's say you want to quickly try out some small stylesheet changes, but you don't want to (or prefer not to, or for some reason temporarily you just can't) modify your application's CSS file(s). In FF it's easy - you have Firebug and you can play with styles until blue in the face. And in case you do get blue in the face and start making so many changes that you get lost, you can create a new clean and tidy CSS file, place it on your hard drive and use Web Developer extension to load it (Menu CSS->Add User Style Sheet). With WebDev Extension you can also Edit CSS right there, although unfortunatelly it's not always working when you have frames.

OK, there are options for Firefox. But how about IE?

In IE you have IE Developer Toolbar, definitelly helpful, but you can only modify element styles, not the stylesheet rules. So? A tiny little bookmarklet to the rescue!

My bookmarklet assumes you have a file called C:\user.css and loads this stylesheet on demand in your page, in every frame, just in case you use frames. Simple, yet useful, I hope. Here's the (readable) code:

javascript:
var css_file = prompt('Which CSS file you want to load today?','c:/user.css');
function addcss(w) {
    var html_doc = w.document.getElementsByTagName('head')[0];
    var css = w.document.createElement('link');
    css.setAttribute('rel', 'stylesheet');
    css.setAttribute('type', 'text/css');
    css.setAttribute('href', css_file);
    html_doc.appendChild(css);
}
var errors = 0;
function checkFrames(w) {
  if(w.frames && w.frames.length>0){
    for(var i=0;i<w.frames.length;i++){
      var fr=w.frames[i];
      try {
        addcss(fr);
      } catch (e) {
        errors++;
      }
      checkFrames(fr);
    }
  }
}
checkFrames(window);
addcss(window);
if (errors > 0) {
    alert('Could not access ' + errors + ' frame(s)');
}

To install and play around

Right-click this link and add it to your favourites:

Add User StyleSheet

Have in mind that this is IE-only (tested IE7). I don't think FF will allow you to access files on your local drive like this. But for FF you have the tools to do this anyway.

Another option to load local stylesheets in IE is to use the user CSS capability built in the browser, you can find it under Tools/Internet Options/Accessibility, but this will load your user CSS first (as opposed to last as the case is with my bookmarklet), so the "real" style definitions will overwrite yours, unless you always use !important and the "real" styles don't.

Thanks!

Have fun with the custom CSS and let me know how you find it.

 

Y! homepage - CSS sprites in action

Friday, December 1st, 2006

Have you looked at the HTML markup of the new Yahoo homepage? Then you should. The markup (although it won't validate) is a piece of semantic art. Lists are lists, tabs are lists, only one table to be seen (obviously plugged-in coming from a different site)

The total number of markup elements on the page (document.getElementsByTagName(*).length) is 662, which is not bad for such a busy page. Compare that with Google search results page, which is semantically pretty much nothing but a just a list and uses 468 elements to display the content, among which there are 22 tables. Amazon's home page has the stunning 1469 elements.

Anyway, the thing that I saw and liked, was the use of the so-called CSS sprites (tut, tut, demo). It's a technique where instead of creating multiple images (10 little icons for example), you create one image file that has them all. Then you use CSS's background-position to only show the part of the big image that contains the icon you want. This may look like too much of a hassle, but when you think about the number of HTTP requests you save by getting one image instead of ten, then it starts making sense. Y! proves this point by using this technique on its homepage. Since the technique is used on what is probably one of the top visited pages on the web, I would considered it production-ready :)

You can get an idea of how Y! homepage works with its image assets by using Firefox's Web Developer extension: "Images -> View Image Information". In case you don't browse with Firefox packed with Web Developer extension (then you should!), then you can check the copy that I made - copy is here. Get a load of this guy for example.

Updated Dec 02, 2006:
Just deleted one comment by mistake (I got so much spam comments), pointing out that the correct syntax is:
document.getElementsByTagName("*").length
where * is quoted.
This is true, a typo on my part.

Thank you very much Philip, I'm so sorry I deleted your comment :(

 

Rendering styles

Wednesday, October 4th, 2006

The question is - what will a browser do, given a page with several stylesheets, each of them probably overwriting definitions from the previous ones? Will the browser render the page using the first received css file, while downloading the other ones and after that partially re-rendering where required? The answer is: no, the browser will wait until all CSS files are downloaded, (then probably merge all definitions, just a wild guess) and will render once.

Test

I did this test - one page with two stylesheets that contain pretty much the same selectors for different table styles (thanks to this gallery). Each of the CSS files is actually a PHP script and has a call to sleep(), one sleeps for 5 seconds, the other one for 10.

Result

The browser sits there and waits for the both styles, rendering nothing (except for the page title, but that's not really rendering, is it?). So nothing happens for 10 seconds, then the second style is used for the final rendering. This happens in both FF and IE.

Misc

I also tried sleeping in the actual page, and flushing the output after each row. In my home environment FF renders each row as it's received, but in my hosted environment, it waits for the whole table. IE alsways waits for the complete table.

If I put the page to too much sleep so that the php script dies before the second stylesheet is dowloaded, the browser uses whatever is at hand (css1) to render the page.

Demo/download

 

Parent's styles in an iframe

Sunday, September 3rd, 2006

Here's a JavaScript that let's you style an iframe just like its top parent. The script is basically just a proof of concept I did after talking to a friend about similar problem he has had in the past, so feel free to modify and use if you like it.

So I have a page, called big.html and a stylesheet for this page, called big.css. On the page there is an iframe that loads small.html. small.html has its own style, called small.css. What my little Javascript function does is:

  1. Getting all top parent's <link> tags
  2. Looping through the tags and checking if the rel attribute has value stylesheet
  3. For all stylesheets found, makes a copy of the link tag and all its attributes and adds it to the head of the iframed page

Here's the code:

function styleMe() {
  if(window.top && window.top.location.href != document.location.href) {
  // I'm small but I'm not alone

    // all parent's <link>s
    var linkrels = window.top.document.getElementsByTagName('link');
    // my head
    var small_head = document.getElementsByTagName('head').item(0);
    // loop through parent's links
    for (var i = 0, max = linkrels.length; i < max; i++) {
      // are they stylesheets
      if (linkrels[i].rel && linkrels[i].rel == 'stylesheet') {
         // create new element and copy all attributes
        var thestyle = document.createElement('link');
        var attrib = linkrels[i].attributes;
        for (var j = 0, attribmax = attrib.length; j < attribmax; j++) {
          thestyle.setAttribute(attrib[j].nodeName, attrib[j].nodeValue);
        }

         // add the newly created element to the head
        small_head.appendChild(thestyle);

      }
    }

    // maybe, only maybe, here we should remove the kid's own styles…

  } else {
    alert('I hate to tell you that, but you are an orphant :(  ');
  }
}

To see the code in action, see big.html.

 

Opacity for the thumbs

Friday, May 5th, 2006

I've been just toying with the CSS opacity to make fancier image thumbnail rollovers, it's actually quite easy. The idea is when you have a thumbnail photo gallery to make the thumbs semi-transparent and, on mouse over, to remove the transparency and show the real image as is.

All it takes is this little piece of CSS:

a img {
    opacity: 0.55;
    filter:alpha(opacity=55);
}
a:hover img {
    opacity: 1;
    filter:alpha(opacity=100);
}

Here's a demo. CSS file is here.

The demo uses Y!API to get a few images (I never seem to have good images laying aroud when I need them). The API call gets JSON output from the Yahoo! search API to make it easy (and server-side free) to display the results. You may peek into the JS source if you're curious (more Y! JSON search API here), but doesn't have anything to do with the main purpose - the thumbs rollovers.

 

Curly underline

Tuesday, April 4th, 2006

Ever wanted to use un underline on a web page that looks like a spelling mistake in Word? You know, the curly red underline. It's actually very easy.

Here's an example.

All you need is:

  • A small piece of the wavy line, like this Curly underline (it's stretched here for the demo purpose)
  • A style that uses the image as background
  • Align the background at the bottom and repeat only on the x-axis

The style definition would look like:

.curly-underline {
    background: url(underline.gif) bottom repeat-x;
}

And that's it!

I saw this working in TinyMCE, the WYSIWYG editor used by Wordpress, for displaying spelling mistakes. Really cool!

Note: If you're a frequent visitor to my site and the example doesn't work for you, chances are you're using a cached version of the CSS file.

 

CSS coding conventions

Friday, September 30th, 2005

Motivation

Why standards and conventions? Well, it makes the code more predictable. You know where to look when you need to change/debug something and also other coders can pick up easier if they know what conventions you followed. PHP (actually PEAR) has it, Java has it, but I couldn't find anything for CSS, so here are a few ideas.

The important thing to remember is - it's not that important what exactly is a chosen standard or convention, the most important is that there is one. The rest, the details, is just common sense, and since "the common sense is not common to everybody", pick whatever makes sense for you. Below is a suggestion to get you started and build upon.

By example

OK, here's everything this post is about, in a few lines, the rest is just elaborating on this:

.container-subcontainer-general-specific {
    font-family: Verdana, Arial, Helvetica, sans-serif;
    font-size: 1em;
}

Terminology

Before starting to talk about the coding style and conventions, let's quickly review what are the different terms used to describe the elements of the CSS puzzle.

selector {
    property: value;
}

The whole thing above is called "a style" or "a style definition". "Style name" may be used as a synonymous for "selector".
"Property-value pair" needs a better name.

Spacing

Generally spacing promotes readability, so let's take advantage of it.

Empty lines between style definitions

Allow the separate style definitions to breathe, by adding one (and only one) empty line between them, like:

.some-class {
    color: red;
}

.another-class {
   color: blue;

}

1 tab = 4 spaces

Indentation also helps with the readability of the code. So put every property-value pair on a new line and indent it with 4 spaces from the beginning of the line. You can use a tab for indentation, it doesn't matter, this is just a personal preference. To avoid hitting [space] 4 times, configure your editor to do it for you when you hit [tab]. Every half-decent text editor has this configurable (Notepad is not the best choice for a coding editor)

Space after colons

Visually emphasis on the separation between a property and value, by adding a space after the colon, like:

.class {
    prop: value;
}

… and not

.class {
    prop:value;
}

… or

.class {
    prop:      value;
}

Curly brackets

Curly brackets that embrace all property-value pairs in a style definition follow your favourite if-then-else style you'd use in other programming languages. The opening bracket may be on the same line as the selector identifier or it can go alone on the next line

.class-name {
    color: green;
}

or

.class-name
{
    color: green;
}

I personally prefer the first.

Shorthands

The use of shorthands is forbidden, because they are harder to read.I would advise against the use of shorthands, because (for a non-expert) they are harder to read. Again, like I said in the beginning, it's you who decide on the type of style to follow, so if the majority of your team is comfortable with shorthands, by all means, use them. But I think that in most cases, the use of shorthands would cause more troubles (will obfuscate the stylesheets) that outweighs their benefits (less bandwidth).
Consider:

.text {
    font: 1em/1.1em bold italic small-caps Verdana, Arial, Helvetica, sans-serif;
}

and

.text {
    font-size: 10em;
    line-height: 1.1em;
    font-weight: bold;
    font-style: italic;
    font-variant: small-caps;
    font-family: Verdana, Arial, Helvetica, sans-serif;
}

The border style is an exception from that rule, because short handing it is so widespread and because (unlike "font" and others) the order of its properties is not important. For example:

.some-div {
    border: 1px #ff0000 solid;
}

…is the same as…

.some-div {
    border: solid 1px #ff0000;

}

and is just as readable.

End of line

Good practice is to always end the lines (the property-value pairs) with semi-colon, even when not necessary (last pair in a selector). This way it's easier to add more properties later on, without even bothering to check if the previous property-value pair was properly terminated.

Naming selectors

  • The most important thing to have in mind is the content nature of the HTML document, not its presentation. Selector names should describe the content.
  • Avoid presentation-specific words in the name, like "blue", "text-gray", or "light-box". What you decide to change the color? The class "blue" is actually red?
  • Cascade the name, using a dash (-) as a separator. When cascading, have in mind what the content is. What do I mean by cascading? For example: "header" and "header-logo" (you have a page header that contains a logo at, say, the top-left corner) or "footer" and "footer-copyright"
  • Use full descriptive words. Abbreviating a word may save you a few milliseconds to type initially, but may make your code harder to read, costing you more time down the road. Why crypting "product" to "prod" or the so common "txt" (just spell it out as it is, "text")? Being consistent in this will save you the time spent thinking (or trial-error-ing) how exactly you abbreviated a word five days ago. (OK, OK, there are exceptions, you can use "url" instead of "uniform-resource-locator" :D )
  • Names are lowercase. There are browser problems with case sensitivity, so you're safe always lowercasing.
  • Distinct words in the class name are separated by a dash. It's clear, readable and gives the underscore a well-deserved break. Use footer-copyright, not footer copyright, footerCopyright, FooterCopyRight, fOOtercopyRighT (god forbid!) or footer_copyright. Well, if you're attached (married ;) ) to the underscore, I guess it's OK to keep using it, but consider leaving it for your Javascript code. The dash is not allowed in other languages' variable names, so use it when you can (in CSS), plus it's somewhat consistent with the property names (think font-size, background-color, etc.)
  • Once again - use names that describe the content ("footer", "navigation", etc), rather than the presentation ("blue", "left", "big"…)

Font sizes

When possible, use em instead of pix for sizing fonts, line heights, etc. This allows your visitors to use the built-in browser text sizing, without you coding a special text size feature (which will probably limit the user to the choices you decide anyway).

Offtopic

Preferably use HTML tags to describe the content.

<h1 class="content-heading">I'm a heading</h1>

is better (semantically, for SEO, for the human reader) than

<span class="content-heading">I'm a heading</span>

Comments

We all love to read other people's code comments. Writing our own comments is probably not as fun, but is highly encouraged in the name of maintainability. When you comment, use the /* comment here */ style. Line comments (the ones with // at the beginning) are not part of the CSS2 standard and may cause issues in some browser (or alternatively used as a workaround hack for some browsers, but this is another story)

Conclusion

I can only hope this has inspired you to adopt a CSS coding style convention/standard in your daily work. I'd love to hear you opinion on this topic. Are you currently using a standard? Do you know of any available on the web?