• CSS Sprite Generator

    Sep 30 2007

    Finally, there is an automated CSS Sprite Generator (via)! Just upload a zip of graphics and it will spit out a single image and a block of CSS you can use.

    What are CSS Sprites? If you use a ton of CSS backgrounds for things like icons, buttons and other non-repeating graphics, then you can combine them into a single graphic and use background-position with width and height to show a slice of the larger graphic. This can make a site load faster since there are less files to download.

    This is generally a pain to do by hand (not only combining the graphics, but calculating and remembering pixel positions), but with a tool like this it should be a cinch!

  • Making a 100% height interface

    Jun 2 2007

    With interfaces on the web that resemble those of the desktop (and better), we often want to get rid of the ubiquitous scroll bar in our web applications. We want all the action to happen directly within the visible browser area. Instead of scrolling, we can offer users new ways to interact with the page like Ajax-based page flipping and sliding panels.

    The basis of most scroll-less 100% height interfaces contain some CSS looking like this:

    html, body {
        /* get rid of default spacing on the edges */
        margin: 0;
        padding: 0;
    
        /* get rid of that 2px window border in Internet Explorer 6 */
        border: 0;
    
        /* fill the height of the browser */
        height: 100%;
    
        /* no more scroll bar */
        overflow: hidden;
    }
    

    This resets the margins and padding of the page, gets rid of the chrome border in IE6, sets the height to 100% of the available space, and hides anything that goes outside the 100%. This needs to happen on both the html and body elements. Having a hidden overflow isn't mandatory, but it makes sure that nothing will cause that scroll bar to pop back up, even if you are dragging things off the edge of the screen.

    Now, anything you put directly into the body can also be given height: 100% and it will do exactly what you expect (fill the page). This way, you can have the interface of the page grow and shrink along with the size of the browser. You can even have multiple layers fill the page like this:

    /* css */
    div.layer {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
    }
    
    <!-- html -->
    <body>
        <div class="layer">
            .. some stuff ..
        </div>
    
        <div class="layer">
            .. some other stuff ..
        </div>
    </body>
    

    You can easily give an element within the page a scroll bar by throwing in overflow: auto on something that has height: 100% and some padding or margins.

    We can also use JavaScript to calculate the size of the browser and use this to decide how much content we display at a time. We can do this with some relatively easy code, now that our body is the exact width and height of the browser "viewport":

    function getPageSize() {
        return [
            document.body.offsetWidth,
            document.body.offsetHeight
        ];
    }
    

    Note that this code only really works with 100% height. On a page with a variable height, it's not reliable at all.

    I've put this stuff to use with a lot of projects lately, most notably PictureSandbox (formerly FlickrCash).

    For more details on calculating the width of the viewport, check out Viewport Properties at QuirksMode.

  • Unitless Line Heights Are Finally Valid

    Jan 15 2007

    It's a miracle! There is a new W3C CSS Validator. I checked, and it's true, Unitless Line Heights are now considered valid!

    Back in February, Eric Meyer wrote about Unitless Line Heights, explaining that you don't need to put px, pt, % or em at the end of a line height, and you don't even need decimals. Unfortunately, for a long time, the W3C CSS validator said that this was invalid:

    body { line-height: 1 }

    Oddly, if you changed it to 1.0, it became valid.

    I took the challenge, and downloaded the Java source code of the validator. After reading through the code for a few hours, I found the problem. At the core of the bug, it was requiring the value to be a Float but not a regular Number.

    Anyway, on February 11th, 2006, I sent in a patch to fix the problem.

    And now, about a year later, the live validator is finally fixed. Now we can all rejoice by having our valid CSS actually validating.

  • Using Animated GIFs with CSS

    Dec 23 2006

    Now that plain old HTML, CSS and JavaScript have made the web quite sophisticated, Flash isn't really as necessary as it once was. Nonetheless, I still see Flash being used to make things, well, flashy. Flash is often used just to add a touch of animation, like things moving around when the user moves their mouse, and other simple effects.

    Well many, if not all, of these kinds of effects can be achieved with plain old CSS and JavaScript, thanks to animated GIFs. Yes, those awful animated GIFs. Just like JavaScript was until recently, animated GIFs are associated with the ugly web of the past (think dancing hamsters). However, if used carefully, animated GIFs can be used to make a web site very lively and feel more interactive in the same way Flash is used.

    To demonstrate this, I've put together probably the most boring proof-of-concept ever. You'll have to use your imagination to see how this technique can be applied in much more creative and better-looking ways.

    First, I created a simple animated GIF of a white bar moving left to right over a transparent background. I actually used Flash to create this. In fact, you could take a Flash interface, and publish the different pieces to animated GIFs in order to eliminate the need to use Flash. Anyway, here is my boring GIF on a black background, so that you can see what's happening:

    Now, I'm going to use this together with CSS to create an animating hover effect. Here is the CSS and HTML I will use:

    <style type="text/css">
    /* IE 6 needs a:hover to be defined */
    a:hover { width: auto } 
    
    a.shine:hover span {
        /* don't take up space, and appear above the text */
        position: absolute;
        display: block;
    
        /* set the background to the animated GIF */
        background: url(shine.gif);
    
        /* the width and height of the animated GIF */
        width: 230px;
        height: 50px;
    }
    </style>
    
    <a href="/blog/cat/javascript" class="shine">
        <span></span>
        JavaScript
    </a>
    

    I'm using an empty span inside the link to act as a placeholder for the animated GIF. When the mouse is hovering over the link, the span comes to life by expanding to an animated GIF which appears above the text. Since the background of the GIF is transparent, and the background of the text is white, the effect is that of a "shine" washing over the text.

    Click here to see the code in action.

    And there you have it. Yes, I know, my demo is boring. But you have to use your imagination to think of all the amazing things you can do by combining animated GIFs with CSS and even JavaScript effects. You can do something as simple as an animated roll-over image, or as complex as an interactive game. The possibilities are only limited by your ability to design them.

  • Using POST with a regular link

    Nov 22 2006

    Here's the problem: According to the principals of Representational State Transfer (REST), GET requests shouldn't change anything on the web server. Only POST requests should. For example, you really shouldn't have an <a> link that deletes an item. When you click a link, it sends a GET request to another page, and deleting an item is definitely a change. You should have a delete button that submits a form using POST instead.

    Why? Well for one, Google Accelerator speeds up your web surfing by downloading all the pages that it knows about through the links on a page. So if there are links that delete items or other horrible things, Google Accelerator will go and delete everything for you. This actually happened to some users of 37 signals.

    So the real solution is to just use a submit button for all the actions that actually do something (delete, save, etc.). And this is totally fine from a technical point of view, but not so great from an asthetic point of view. Buttons can be pretty ugly, right? (I actually like how they look, but then again, I'm not a designer.)

    There is also another solution. You can use JavaScript to make a hidden form, then add an onclick event to a link that submits the form when you click the link. This solution is okay, except for those who don't have JavaScript (like search engine spiders).

    I came up with a solution that tackles the problem from the asthetic angle. We can style the buttons so they look like links! Seriously!

    Okay, it's not so easy. And it's not perfect. But it's pretty close. Here's the code:

    .link-button {
        border: 0;
        padding: 0;
        background: inherit;
        font: inherit;
    
        cursor: pointer;
        text-decoration: underline;
        color: blue;
    
        overflow: visible;
    }
    
    <input type="submit" class="link-button" value="Delete"/>
    <button type="submit" class="link-button">Delete</button>
    

    It's a bit long because buttons have a lot of default styling to them. First, we remove the border, padding, background and font. Next, we change the mouse cursor and colour, and add an underline so that it looks and acts like a link. Last, we add this overflow: visible to force Internet Explorer to get rid of that weird spacing it adds inside buttons.

    You might also have to set the actual font and size of the button to make it match the text around. I don't know why, but font: inherit just doesn't always do the job like it should. If you specifically set font: 12px Arial, it will look fine.

    In Safari, it won't do anything if you're using an <input type="submit"> because you can't style these. However, you can style a <button type="submit"> though. You will just have to set the background colour directly and not use inherit. So as long as you don't have some trippy background image, it will be fine.

    Another thing: it's not perfect in Firefox or Safari. It will still have some weird spacing around it. Have a look at what Firefox does:

    Buttons have some spacing around them in Firefox

    The top is a regular link, the bottom is a button. You can see it's pretty close, but not perfect. Safari has a similar effect with spacing on the bottom.

    Well we can take it to the next level and use JavaScript so that it's perfect for the 90% of people who use JavaScript. The other 10% can see the extra spacing, but that's no big deal (they probably won't even notice). We can use the following function to accomplish this:

    function replaceButtonWithLink(button) {
    	var link = document.createElement('a');
    	link.href = '#';
    
    	// find link text either as value of input or innerHTML of button
    	link.innerHTML = button.value || button.innerHTML;
    
    	link.onclick = function() {
    		button.form.submit();
    		return false;
    	};
    	button.parentNode.insertBefore(link, button);
    	button.parentNode.removeChild(button);
    }
    
    // here's what you do for an <input type="submit"/> or <button type="submit"/>
    var button = document.getElementById("my_button");
    replaceButtonWithLink(button);
    

    Now we have a nearly perfect solution. If the spacing in Firefox isn't a problem for you, you don't even need the JavaScript portion. But it's there just in case you have some pixel-paranoid designers on your team that insist it should look perfect in their browsers (just hope they have JavaScript turned on!)

  • Replace text with an image using CSS

    Nov 7 2006

    Let's say you want to have a logo on a page, but you'd really like to use an <h1> with some text for the header in the HTML. Or maybe you like to use images for all your titles, but would still like to have plain text inside header tags in your HTML.

    There are a number of reasons for wanting to do this, namely accessibility and search engine optimization. I talk more about this in my post Writing Semantic HTML.

    The problem is: How do you hide the text? I think the most popular technique is to wrap the text with a <span> inside the header tag, then use some CSS to 1) hide the text, and 2) use the header tag as an image. Something like this:

    <style type="text/css">
    h1 {
        width: 500px;
        height: 100px;
        background: url(my_header_image.gif);
    }
    
    h1 span {
        display: none;
    }
    </style>
    
    <h1><span>My Great Header</span></h1>
    

    Unfortunately, this technique makes us add an extra tag to our markup, and we all know that every time we use an unnecessary tag, a puppy dies. Either that, or we end up with ugly, unnecessarily bloated HTML.

    Well here's another technique which hides the text just by using CSS. The text will still be readable by screenreaders and search engine spiders, but will disappear like magic for everyone else:

    <style type="text/css">
    h1 {
        width: 500px;
        height: 100px;
        background: url(my_header_image.gif);
        overflow: hidden;
        line-height: 500px;
    }
    </style>
    
    <h1>My Great Header</h1>
    

    This technique works by pushing the text down inside the header with a rather large line-height (it must be at least twice the height). Then the overflow: hidden hides the text since it's overflowing.

    Now isn't that better? No puppies were harmed, and we end up with slightly cleaner and shorter markup.

  • Context-Sensitive Class Names

    Jul 26 2006

    Usually when assigning class names, it's most natural to assign a different class name to each uniquely styled area of the page. Often, there are common words you'll want to use as class names in more than one spot on the page such as 'date', 'section', 'title', etc.

    At first, it seems the solution is to make up unique class names like 'header-date' and 'comment-date' or 'side-section' and 'main-section.

    Instead of doing this, you can just stick to using your simple 'date' and 'section' class names but refer to them in their context. For example, if your mark-up looks something like this:

    <div class="side">
        <h2 class="title">Side Title</h2>
    </div>
    
    <div class="main">
        <h2 class="title">Main Title</h2>
    </div>
    

    Then you could define your CSS like so:

    .side .title { font-size: 1.2em }
    .main .title { font-size: 2em }
    

    Even better, you can get rid of the unnecessary class names and just define styles onto elements within different sections of the page:

    .side h2 { font-size: 1.2em }
    .main h2 { font-size: 2em }
    

    You also have the option of doing element-sensitive definitions. Perhaps an <h2> tag with a 'date' class can mean something different than an <h3> tag. Then, just do this:

    h2.date { color: blue; background: white }
    h3.date { color: green; background: red; }
    

    This is pretty simple stuff, but it opens up all sorts of possibilities for keeping your HTML as clean as possible. Just be careful not to get confused (or confuse others) by using the same class name for more than one purpose.

  • Multiple classes in Internet Explorer

    Jan 16 2006

    I recently discovered the power of using multiple classes. That is, using more than one class on a single element. The class attribute simply accepts multiple classes separated by a space. For example, you can do something like this:

    <style>
    .box { border: 1px solid black; }
    .small { width: 400px; }
    .large { width: 800px; }
    </style>
    
    <div class="small box">
    <div class="large box">

    This is a great way to organize your CSS. For example, you can have a set of classes to define font styles and another set of classes to define box sizes. Then you can use them together in different combinations.

    The class names "small" and "large" aren't totally clear, since they refer specifically to small and large box sizes. It'd be great if I could write "large title" and have it affect the font size instead of the width. So, I tried to change the definition by combining multiple classes in a single selector:

    .box { border: 1px solid black; }
    .box.small { width: 400px; }
    .box.large { width: 800px; }
    
    .title { color: blue; font-family: Arial; }
    .title.small { font-size: 10px; }
    .title.large { font-size: 20px; }

    When I tried this in Firefox, everything worked great. Unfortunately, Internet Explorer doesn't support this. In fact, Internet Explorer will just look at the last class in the list. So, it will interpret the last example as if we had written this:

    .box { border: 1px solid black; }
    .small { width: 400px; }
    .large { width: 800px; }
    
    .title { color: blue; font-family: Arial; }
    .small { font-size: 10px; }
    .large { font-size: 20px; }

    Small boxes will have small fonts, large boxes will have large fonts, small titles will be 400px wide, large titles will be 800px wide. Very unfortunate.

    Once again, Internet Explorer ruins all the fun. Well, there's an up side to this. When we use "small" to affect the width in one place, and the font size in another place, we make it harder to understand and maintain the CSS. And isn't that supposed to be the point of using CSS?

    Besides, not all is lost. We just have to come up with better names. We can still do this:

    .border { border: 1px solid black; }
    .small-box { width: 400px; }
    .large-box { width: 800px; }
    
    .title { color: blue; font-family: Arial; }
    .small-text { font-size: 10px; }
    .large-text { font-size: 20px; }

    It sure isn't as pretty to write something like class="border small-box". But at least then we can use our "small-box" class in places that don't have borders, or use the "border" class to give a border to something without a fixed width.

    In conclusion, avoid the .class1.class2 syntax altogether. It's not supported by Internet Explorer, and it makes code harder to read and manage. However, using multiple classes is completely supported and will make your CSS cleaner and more reusable.