Everything In Between

The brutally honest, first-person account of Meitar Moscovitz's life.

Archive for the ‘CSS’ Category

14 Hour Coding Session

4 comments

Oh my god, fourteen hours playing with XHTML, CSS, and PHP to get Maymay Media to what it is now. (And it’s still not done, though I’m constantly looking for feedback!)

Much, if not most of that time was spent writing and editting new content, and beating down CSS bugs in Internet Explorer. Those of you who know my work habits are likely to be surprised by the fact that I could spend 14 hours dealing mostly with client-side coding issues.

Normally I can’t spend more than a few hours—at the most—dealing with CSS problems because browser bugs tick me off too much. (Ahem, MicroSucks.) Nevertheless, for some miraculous reason, I kept swatting bug after bug after bug this session and the enthusiasm just fueled more coding. Needless to say, I was very very productive last night.

I also didn’t sleep a wink, however, so now I’m dead tired. Here’s a short recap before my memories fall down behind the waterfall in my mind.

Last Night’s Call-a-thon and Digital Departure

  • Last night I was Mr. Popular. I got literally countless phone calls (I can’t remember them all) from folks who wanted to chat it up. I spoke to a few Meetup group members, Danica, my parents, and others. Christine called and wanted to hang out today but she canceled this afternoon. (I didn’t mind, I’m exhausted.)

  • Danica came over from about 8:30 PM to 10:30 PM so that she could give me back the apartment keys and transfer her digital posessions (computer files) off of my computers and onto her own. She also gave me a Moldy Peaches album to import into my iTunes Library. (Cool.)

    So that’s pretty much it. We said goodbye, she seemed sad, and I asked her to call me so I knew she’d gotten home okay. She did, and we said goodbye again. And that’s that; we are finally going our separate ways and have no more connection to each other whatsoever.

    I’m not even thinking about the future, but I do admit that remaining friends is something I’d probably like—if it were not emotionally draining. We’ll see what happens, but the path for right now is very clear: I’m trekking it solo yet again!

The Geeky Parts

  • Back to the tech realm, I’ve implemented my dynamic relevancy message API on this blog. What does that mean for you? Probably nothing, but it does mean you’ll likely see relevancy messages change and grow in abundance over time. As always, use a modern browser to see the full effect.

  • Still in the tech realm, I squashed a number of annoying IE CSS bugs on this blog with the somewhat-magical application of position:relative;. This means visitors using IE will finally get a near-perfect browsing experience, with no annoying vanishing backgrounds anymore.

  • Also, Google SiteSearch has been implemented, so you’ll be seeing that on the top banner for the time being. It’s nothing special, just a way to make it look like you can do more than you can here. It might also make me some more money via clickthroughs, but that’s unlikely. (Oh, which reminds me, those ads on the right side of the window, yeah, if you click on those I get money. Don’t be shy.)

  • A not-so-new but still interesting point of note is that I’ve started using MyBlogLog.com to keep track of which hyperlinks people are clicking on. This has been somewhat informative because it means I get to see which hyperlinks induce clicks and which don’t. Anchor text is important, and this is a useful tool to learn how you can manipulate the effect of a link.

Flickr Photos from the Past!

Finally, I’ve been wanting to get more value out of my digital camera. I haven’t been taking pictures, but backing up and transfering a bunch of Danica’s things last night inspired me to dig through some of my old photo collections to see what could turn up. Well, here it is:

  • Here’s me almost a year ago, during last year’s Passover at my mother’s:

    Me sitting at the table during Passover, 2004

  • Me at San Francisco’s Exploratorium with Danica during the Summer of 2004, on my trip to meet her family. Look at the face I’m making, I had so much fun there.

    Me sitting on the big chair at the San Francisco Exploratorium.

  • Yeah, I was gonna eat that piece of toast. Obviously, my dinner plans were foiled.

    I look at the camera sadly, holding burnt toast in my hands.

  • This is what happens to my face if I don’t shave.

    Me smiling, sunlight clearly showing my unshaven face.

Written by Meitar

March 19th, 2005 at 7:13 pm

Targetting Relevance in Long Web Pages with the CSS :target Pseudo-Class

5 comments

The Importance of Context and Relevance

Context and relevance are two of the most important aspects of effective communication. If the context of a message is not understood then the commuication will likely be disregarded, or worse—misinterpreted. If the message isn’t relevant to the topic at hand then it will be useless to everybody involved.

In order to ensure that a message is successfully received and has the desired effect, one must first ensure that the context for that message is properly set up and that the message itself is relevant to the subject matter.

An excellent example of a scenario where a loss of context and/or relevance can easily cause communication problems is receiving email messages. Surely everyone has recieved an email that they simply don’t know what to do with or why they’ve gotten it. (By the way, for some unbelievably insightful tips on composing effective email messages, read this article [via 43 Folders].)

The same thing can—and does—happen on the web. For example, let’s say you’re reading a page which has a link in its text to another page. You decide to follow the link but once you’ve arrived at the new page you find yourself staring at an enormous amount of other text that doesn’t have anything to do with why you followed the link in the first place. Suddenly you’re confused, you feel lost, and you quickly push the “Back” button of your browser.

What went wrong here? Context was lost; the destination page had no relevance to the source page. If it did, you couldn’t find it because it wasn’t clearly identified. This is a confusing and frustrating situation, and one that I’m willing to bet happens way too often on the web.

On my own blog, I frequently link to entries I’ve previously written. Sometimes these entries can be quite long, and I’m not always referencing the entire entry in my link. But by pointing the link to a specific “intra-page” anchor by using a fragment identifier and clearly marking the relevance of this information in both the link itself (with a descriptive title) and in the landing page (with what I’ve come to call a relevancy message), context is preserved and confusion is eliminated.

To see what I’m talking about in practice, check out my experiment pages. It’s a demo of the problem and relevancy messages in action.

CSS2 The Rescue

There’s only one problem left. How does one insert text into the landing page which will be viewable when someone follows a specially-crafted link to it, but not when they arrive at the page via any other link? Though it is possible to program this into your pages using PHP or another web scripting language, CSS level 2 offers a much simpler and maintainable solution: the :target and :before pseudo-classes.

When used in combination, the :target and :before pseudo-classes can be used to generate text on a page at a specific point in the document when your page is linked to in a certain way. By using an additional CSS2 function, attr(), we can also generate customized text for each landing spot within the document. Let’s take a look at each component separately.

The HTML You’ll Need

Let’s say you’re writing about apples. In your text, you link to a previous article you wrote about oranges. Your link in the article on apples might look like this:

<a href="oranges.html" title="Oranges have a thick, white pith beneath their skin." >oranges</a>

And your text in the article on oranges might look like this:

<p>[…] The skin of an orange is thick, porous, and varies in color from deep to light orange. There is a bitter-tasting white pith underneath the outter-most layer of the fruit's skin. […]</p>

In order to link directly to the paragraph mentioning the orange’s pith you need to insert a named anchor just after the opening paragraph tag where that content was written. You also need to append this name to the URI of the link, as a fragment identifier. The resulting HTML for the link might look like this:

<a href="oranges.html#skin" title="Oranges have a thick, white pith beneath their skin." >oranges</a>

The resulting HTML for the paragraph about oranges might look like this:

<p><a id="skin"></a>The skin of an orange is thick, porous, and varies in color from deep to light orange. There is a bitter-tasting pith underneath the outter-most layer of the fruit's skin.</p>

The CSS You’ll Need

Once the HTML is in place, you need to create a style rule to generate the text you’ll want to display before the paragraph. Your style sheet might look like this:

a:target::before { content: "Here's what I referenced with my link on the last page: "; font-size: larger; font-weight: bold; }

You can even take it one step further. By adding a title attribute with some helpful text in your named anchor, you can actually display that text (specific to the reference you’re making) instead of the generic “Here’s what I referenced…” text. The CSS for that would look like this, and it would display whatever you write as the title for each named anchor you use:

a:target::before { content: attr(title); }

Limitations

The major drawback to this technique is that you need to change the code of the destination document for it to work. Specifically, you need to insert named anchors (though you can also target any element by giving it an unique id), and you need to insert a style rule. (However, see below for another experiment that will let site owners allow people to get around this limitation.)

Another major drawback is that it requires a fully CSS2-compliant browser. That means Internet Explorer 5 and 6 (both Macintosh and Windows versions) will not show the special content on the destination page. They will, however, move focus to the point in the document at which the anchor resides.

Looking to the Future

I have been playing with this technique recently on my blog (can you find the links I’ve used this on? ;). The obvious benefit is creating a far more seamless transition from one page to another and maintaining the same context across web pages. This is invaluable for me and my readers in particular, since I tend to enjoy writing and end up writing far longer entries than I probably should. (Even though I use headings to divide my entries into logical chunks, it’s still good to have another trick up my sleeve to help usability!)

However, this technique is ripe for expansion. For instance, I have created another experiment to dynamically generate the content of the CSS rule based upon a variable in a GET querystring. (It uses three lines of PHP, and that link itself is a proof-of-concept.) This will allow people to write links that point to my documents and insert their own special relevance-describing blurbs in front of the fragment they’ve linked to. (Yes, I realize this may pose XSS security problems, I’m still just playing with the concept.)

Exploring all of this is a lot of fun. The crux of this technique relies upon accessible and clever hypertext copywriting to enhance usability when linking to web pages and referencing information across pages or, one day, sites. As is the case with most things Web, simple is better.

I’m very eager to hear about comments on this technique. Are there dangers I haven’t seen yet? Can you think of another way to use it that I haven’t mentioned here? Are you already using it on your own site? All feedback welcome. :)

Written by Meitar

March 11th, 2005 at 3:24 pm

Browser Developer Insight and Nightmares

leave a comment

Dave Hyatt, a developer of Apple’s Safari web browser offered some amazingly enlightening insight into the nightmares of browser developers the other day. The only thing I can think to say is: Dave, thanks for trying.

This is a great example of how IE‘s inconsistent rendering behavior has long-lasting negative effects on the adoption of CSS not only by web page authors, but web browser authors. As Dave himself says,

So now I really have no choice. This is an example of where the CSS2 standard simply can’t be followed because buggy layout engines have set a bad precedent that the rest of us have no choice but to follow.

It’s a shame that Gecko does not do the right thing in strict mode at least, but I suppose they had no choice in the matter either.

This is reminiscent of back when Opera was beginning to look more and more like Internet Explorer, but at least it’s not a bug this time.

Written by Meitar

January 10th, 2005 at 7:02 am

Posted in CSS,Web Standards

Broken CSS on KVMGalore

leave a comment

Tonight I spent much of my time exploring the remains of one of the two PC machines my father gave me for my up-and-coming “computer lab.” There wasn’t much of interest on the machine, but as I was looking around the apartment I realized I had more computers than monitors.

Hardware Countdown

My oldest machine, an ancient first-generation Apple iMac DV:SE (do you remember those?), obviously contains the CRT screen along with the computer hardware in one box. So for the most part I consider that one unit. I also have my laptop which falls under the same category, but then I have two PC towers, and I’m getting ready for yet another from my mother along with a G3 tower soon. All of them are headless.

I only have one stand-alone monitor. So that means up to four computers need to share one monitor. Since I’m planning on using at least one or two computers as dedicated servers, I’m not going to need those connected to monitors all the time. For instance, I could VNC in and look around on the rare occasions when I have to. The others, however, are probably going to need something more scalable. I don’t have the space or the money for more monitors, so the best solution here is undoubtedly a KVM switch.

Broken CSS Can Lead to Unuseable Sites

As I was browsing, I came upon KVM Galore, retailers of every kind of KVM switch imagineable. Unfortunately, when I arrived I couldn’t read any product description because the bottom two-thirds of each line of text was chopped off, disappearing behind a white background. Here’s a screen shot.

KVMGalore.com's product catalog is unreadable in Gecko-based browsers.

My first thought was confusion, but my second was to see if I could fix it. So I dived into the source and traced the problem to a <span></span> element that was pretending to be a block-level box. Their CSS had given the span a width, background and border, but no display property.

Without the proper display rule, CSS-compliant browsers treated the span as an inline element, which is obviously not what the designer had intended. So I created a local style-sheet of my own and fixed the problem for the duration of my stay on their site. Here is the style sheet I used:

.detspecs { display: block; }

Believe it or not, that’s it. That’s all it took to fix the problem. I was using Firefox to browse the site, but after a while I became curious about the other browsers. It turns out that the site looks like this on Firefox for Mac, Netscape on both Mac and Windows, and while it’s mostly better in Safari, nasty black lines cut into the text on that browser as well. Opera 7.5 on both Mac and Windows, along with Internet Explorer 6 for Windows and 5.2 for the Mac looked fine. I’ve emailed the site owner and hope that they will fix the problem as soon as they can.

This isn’t the first time an e-commerce site has had broken CSS. Not long ago I wrote about another savvy web developer who fixed the Sainsbury home shopping web site just like I did for KVM Galore. On the bright side, it’s good to see CSS being used more and more thoroughly throughout the online business world.

I still haven’t chosen a KVM switch yet as I’m still researching the topic. If anyone has any advice, I’d love to hear it.

Update: I just heard back from the site owner today (January 19th), and am glad to see that the CSS has been fixed. Good job, KVM Galore!

Written by Meitar

January 10th, 2005 at 4:03 am

Posted in CSS,Tech/Computing

User Stylesheets to the Rescue

leave a comment

I was just heading to bed (well, kinda) but this was too blogworthy to pass up.

Browsing my newsfeeds, I happened upon this post from Andy Budd which points to this Mac OS X Hints post regarding a CSS-savvy web developer trying to do some online shopping. Unfortunately for the online store owners, their pages are unusable due to a serious rendering bug caused by their stylesheets. But rather than shop elsewhere, Lee Noble fixed the problem using a quick user stylesheet applied via Safari.

I’ve said it before, and I’ll say it again: the Web puts the users in control, the way it always should be!

Written by Meitar

December 4th, 2004 at 2:21 am

Centering, Absolute Positioning, and Document Flow

3 comments

The question of how to center an absolutely positioned element came up recently in a CSS forum I frequent. It’s a relatively old question that has several answers, but it’s been asked often enough imho to warrant a short discussion. CSS has given Web Designers a powerful tool to create breathtaking layouts. However, some things in CSS have necessitated a change in our workflow. Centering is a great example of such a change.

Two Forms of Centering in CSS

There are two kinds of centering that CSS can accomplish, independant of each other. One kind is center-aligning text, achieved through the use of the text-align property. The other is centering an entire block, and not the text within that block, inside its containing element. We’ll be talking about the latter.

Centering a Block-Level Element Using the Document Flow

In CSS, to center an element horizontally within its containing block its left and right margins must be set to auto. This will make the element’s left margin length equal to the length of its right margin, thus keeping the element in the center of its parent. For example, you might center your main content div like this.

div#content {
    width: 600px; margin: 0 auto;
}

(The width is necessary; it has nothing to do with being centered, but if you leave it out the div will be as wide as its containing block and will not have any margins to speak of. The margins are what cause the centering effect.)

This will work because the main content div is in the flow of the document. That is, its margins are “pushing against” their parent, so they affect the layout of the div.

Taking the Block Out of the Flow

But what happens if we take the div out of the flow, with, say position: absolute;?

div#content {
    width: 600px; margin: 0 auto;
    position: absolute;
}

Suddenly, we find that the div is no longer centered. This is because we’ve taken it out of the document flow, out from within its parent element, and now its margins have nothing to push against. So how can we center this element?

Centering the Absolutely Positioned Box

The trick is to use its positioning to center one edge of the div, and then use margins relative to its width to push it into center-alignment. Thus, you can center any absolutely positioned element that has a fixed width by giving it, for example, left: 50% and then adding a negative margin-left equal to half of the element’s width. (You could also use right: 50% and then use a negative margin-right value.)

div#content {
   width: 600px; margin: 0 0 0 -300px;
    position: absolute; left: 50%;
}

Now the content div will be centered horizontally in the browser viewport, and it will stay centered even on a window resize.

Written by Meitar

November 20th, 2004 at 2:08 am

Posted in CSS,Web Design

Observations on the CSS3 Box-Sizing Property and How Designers Use Style Sheets

3 comments

Recently, I became aware of CSS3‘s box-sizing property. This property can have two values, content-box and border-box. The content-box value is what we’re all used to. It causes the selected box’s dimensions to be sized by setting the specified width of the box equal to the width of the content area of the box. Any horizontal borders or padding that the box has is then added to the content area’s width. The border-box value sets the selected box’s width equal to the content area and any horizontal borders and padding, effectively subtracting the width of the padding and border from the declared width in order to calculate the content area’s width.

In other words, the border-box value to the box-sizing property makes the selected box use Internet Explorer’s non-standard box model. At least, it was non-standard until it became part of the CSS3 spec. The spec even notes this itself, saying “This is the behavior of width and height as commonly implemented by legacy HTML user agents for replaced elements and input elements.”

This is somewhat annoying, because this means that rather than fix their “Web browser,” Microsoft can now say that their browser supports this property of CSS. In the end however, I do see the necessity of the property for compatibility reasons, as much as that necessity (caused by one browser vendor’s lack of support for Web standards) bothers me.

The most direct application of this technique comes in the form of making two child elements who have borders and/or padding fit precisely within one larger parent element whose width is flexible. For example, making floated, columnar layouts.

So while taking all this in I took some time to familiarize myself as best I could with Firefox’s implementation, the -moz-box-sizing property, and its effects. Some of my observations:

  1. Most interesting uses for three column liquid layouts (or more). Two column layouts can use a (more complicated) balancing of float: left and float: right to achieve a similar effect in a liquid layout, though a small, variable amount of space between columns is nearly unavoidable.

    Also, experienced designers usually keep a certain degree of whitespace in their layouts, making such tightly fitted floats largely unnecessary and/or impractical implementations for certain designs. (I.e., positioning would be a more appropriate solution.)

  2. Border-boxes offer no help for linking the height of a box to the height of its neighbor. Considering this is the biggest failing of CSS-based columnar layouts to date, I would stick with an accessible table where absolutely necessary, which can be and often is sized just like a border-box.

  3. When confronted with left-floated boxes such as in the case of a columnar layout, IE/Win versions that use the border-box method of calculating width and height will drop a tightly-fitted floated box below its neighbor on a window resize. This creates either a trippy experience or cause for frustration depending on your mood. Considering this property is at least partially intended to help IE/Win, that’s quite an embarassing thing to have happen, methinks.

  4. All in all, I’m still not convinced of the necessity of this property, except to support IE. While it can certainly be a useful “option” when attempting to create (arguably simplistic) column layouts using strictly semantic markup and CSS, tables are still going to be necessary in some designs. In the situations where they are not, a combination of existing techniques can still be used to achieve any desired effect.

Furthermore, this certainly doesn’t help make CSS a more approachable topic for Web designers who are new to the technology. The single largest obstacle to CSS‘s widespread adoption are the many various and often extreme browser bugs and quirks present in the majority of browsers. When a CSS newbie begins writing some stylesheets, they are greeted with horrendous results thanks to these misbehaving browsers. I know of several Web design projects that have begun using stylehseets, only to abandon all but their most basic capability due to frustration on the designer’s part. Some CSS concepts are not easy to grasp for beginners, the box model being one of them, and I am not fond of the idea of presenting designers with yet more differences in the way their pages can be rendered.

Moreover, most CSS beginners I have encountered use a GUI such as Dreamweaver or GoLive to create their stylesheets. In this case, a question arises for the developers of these interfaces: how do I visually show which kind of box-sizing is being used for this particular box on the screen? Do I show a little icon in the corner of the box’s display? Do I hide it in a dialog box?

In my opinion, these interfaces are not very good for creating style sheets. There is currently no application whith which you can actually draw, with your mouse, a rectangle of padding onto an element. You have to type a number into the “Padding” input box and then select the unit you’d like to use from a drop down menu. Designers do not think this way. Coders and programmers do. But coders and programmers aren’t the ones who really need CSS. Designers do. And they need their tools and their web browsers to speak their own language to them.

Written by Meitar

October 28th, 2004 at 2:16 pm

View the Web Your Way with Edit CSS

2 comments

For a while I have been using the Web Developer Toolbar in Firefox for various puroses. It’s extremely helpful, allowing me to quickly and easily outline custom elements, display the rendered sizes of block-level elements, provide an overview of the page’s structure without fiddling with the DOM inspector (choose CSS → View Style Information… and then look at the status bar as you move your mouse over the page), and much more.

However, I’ve also actually been using it to make my experience on the Web more my own.

Introducing Edit CSS

One especially useful option in the Web Developer Toolbar for the Firefox and Mozilla Web browsers is the “Edit CSS” option. You can get at it from the Tools Menu → Web Developer → CSS → Edit CSS or by pressing CTRL + SHIFT + E. This will show the browser sidebar and, if any exist, load the existing styles applied to the page you’re viewing in a large text-entry field.

To use the feature, simply start typing in some applicable CSS. On each keypress, Firefox evauluates your style rules and applies any changes as appropriate. In other words, you can edit the styles of any page you visit faster and easier than ever before, and your changes are displayed live, as you type!

I like this a lot, because it further develops the application of the philosophy that giving the user more control over his or her environment is a good thing. Here are some examples of how to start making this new power work for you right away.

Exercise Your Power

  1. The next time you come across a web site whose entire textual content is centered on the page (we all know how annoying that is), open your Edit CSS sidebar and type the following:

    * { text-align: left; }

    This will immediately left-justify all text on the page. Now you can read with ease!

  2. To further help readability on pages whose line lengths span the whole screen, add a suitable maximum width for your reading pleasure:

    * { max-width: 40em; }

    Now all elements on the page won’t be wider than 40 em’s which should be comfortable for most people. Of course, feel free to substitute your own value in place of mine. That’s the beauty of it.

  3. If the author of the page you’re viewing has chosen a horrendously annoying shade of pink or yellow to display text in (often coupled with an equally unreadable choice of background color), just open your Edit CSS sidebar and type the following:

    * { color: black; background: white; }

    Now you have easy-to-read text and you don’t have to strain your eyes. Again, simply swap the values for white text on a black background to inverse the colors, or feel free to use your own preffered colors.

What if the page doesn’t change?

If the page you’re viewing hasn’t changed after typing these lines in the Edit CSS sidebar, then you’ve either mistyped something or another rule later down in the style sheet is overriding the one you just added. In this case, you can either go hunting for the stubborn culprit in the original CSS or try increasing the weight of your own rule by doing one of the following:

  • Increase your rule’s specificity by adding html>body to the front of your selector (in my examples above, the asterisk (*) symbol is your selector). That is to say, your modified rule becomes:

    html>body * { text-align: left; }
  • Make your rule !important by adding that text after the rule. Your modified rule, marked as important, would look like this:

    * { text-align: center !important }

According to the creators of CSS, one of their goals was to make the Web more customizable to the end user. Thanks to tools like Firefox’s Edit CSS option in the wonderful Web Developer Toolbar, this is finally an easily-achieveable reality!

Create Personal Stylesheet Preferences in Other Browsers

If you’re not using a Mozilla-based browser (why aren’t you?) and don’t have access to this extension, try writing your own style sheets with your specific display preferences in it and applying them through your browser software.

Your style sheet is just a plain text file which can be written in any text editor.

Safari on the Mac allows this by going to the Safari Menu → Preferences → click the Advanced pane → select Other… from the Style Sheet drop down menu and select your style sheet.

Internet Explorer for Windows also supports this technique but the option is a little more cleverly hidden. Go to the Tools Menu → select Internet Options… → click on Accessibility → check “Format documents using my style sheet” in the “User Style Sheet” section → click Browse and open your style sheet.

(Internet Explorer 5 for the Mac also supports this option but that browser is so bad, so old, so slow, so buggy, and so insecure that finding the option is left as an exercise to any reader who dares to still use it.)

Opera for Windows and Mac also let you choose your own style sheet. Go to Preferences (from the Opera menu on a Mac or from the Tools menu on Windows) → click Page Style in the left column → click Choose next to the text box that reads “My style sheet.”

Here’s a recommendation for what to put in your new personal style sheet. Remember, however, it’s your style sheet, so feel free to start with this but add your own preferenes as well!

/* make pages dark-on-light and use a big-enough text size */
body { background: white; color: black; font-size: medium; }
/* keep paragraphs narrow and left-justified */
p { max-width: 40em; text-align: left !important }
/* I want headings in the Times font */
h1, h2, h3, h4, h5, h6 { font-weight: bold; font-family: Times; }
/* show me what the access keys are! */
[accesskey]:after { content: "(Access key: " attr(accesskey) ")" }
/* show me which images are actually links */
a img { border: 2px solid blue; }

Try browsing the Web with your new stylesheet. I’d be very interested to hear how it goes. Which sites could you use your new preferences in without any problem? Which did you break?

Written by Meitar

October 15th, 2004 at 5:16 pm

Posted in CSS,Tech/Computing

Make Marked-Up Lists Look Like Paragraph Text

leave a comment

Here’s a useful little snippet of CSS2 lifted straight off a personal project I’ve been working on. The following four rules display, find, and insert appropriate punctuation for making unordered lists read like English prose.

ul, ul li {
    display: inline; list-style: none; margin: 0; padding: 0;
}
li:after { content: ", "; }
li:last-child:after { content: "."; }
li+li:last-child:before { content: "and "; }

Here’s what’s happening.

  1. First they display the entire list and each list item as an inline element. This causes them to show up right up against any other text around them.
  2. Then they add a comma and a space after each list item.
  3. The last list item, however, gets a period and no space.
  4. Finally, the word “and” followed by a space is inserted before the last list item if, and only if, there is a list item before it (it has a sibling).

There you have it. List markup that looks just like a normal paragraph, complete with proper punctuation! A great little tip that makes lists a whole lot more flexible!

Note that as of this writing this won’t work in Internet Explorer because it can’t understand the last three rules. Since it does understand the first, the result will merely be an inline box for the whole list, sans punctuation.

Written by Meitar

October 6th, 2004 at 5:03 pm

Posted in CSS,HOWTO

Keeping Presentation out of Behavioral JavaScripting

leave a comment

Lately I’ve been working on a personal project of mine, redesigning and revitilizing my website about Bipolar Disorder. It’s still deeply entrenched in the redesign and I’m not even done with the site templates yet, but I was anxious to get some content rolling out quickly so I went ahead with it anyway.

Some elements of the design, however, relied on dynamic scripting to style appropriately. The key thing here, however, is that I wanted to avoid accessing or manipulating style elements from within the JavaScript script. In other words, I wanted to ensure that all my style rules, the visual declarations for the presentation of these links, would be kept in the site’s CSS.

There were several reasons for this:

  1. To keep presentation clearly separated from behavior and structure.
  2. To keep the JavaScript unobtrusive and portable.
  3. To ensure that both aspects, presentation and behavior could be easily updated or altered in the future.
  4. To allow for various styling without touching the script.

Typically, a JavaScript script with a line similar to elem.style.property = 'value'; is used to create so-called “dynamic styles.” Unfortunately, this would not do for me.

So I fiddled and found that the best way to go about this was to simply tag links that I wanted to style by adding a word to their class name and then write styles for the selected elements inside my stylesheets. In effect, links in my page will be transformed from <a href="http://some.other.site/"></a> to <a class="external" href="http://some.other.site/"></a> So I sat down and wrote this little plug-and-play JavaScript to tag the links I wanted. Let’s go over it line-by-line. (If you’re antsy, here’s the whole script.)

First, we define a function named catchExternalLinks. Then we set a variable, extClassName, to hold the class name we’re going to add to the links. While not strictly necessary to hold in a variable, it does make for easy editing later. Don’t like the word “external” for a class name? Change it to something else.

function catchExternalLinks()
{
    var extClassName = 'external';

Next, we do some object detection. This is to ensure that the browser can handle what we’re going to ask of it. Browsers that can’t handle it won’t try to, which is good because it means visitors won’t see an error when they visit the site. They just won’t see the dynamic styling.

if (document.links && document.getElementById) {

Now that we know we’re talking only to browsers which can handle our instructions, we define a variable, h (for host), which will store the beginning of the web address that we’re at. On www.maymay.net, h now contains the string http://www.maymay.net.

var h = window.location.protocol + '//' + window.location.host;

Next, we need to gather all the links in our page. We assign the links array to the variable l.

var l = document.links;

We need to work with each link separately, so we loop through the links…

for (var i = 0; i < l.length; i++) {

…and assign the value of the href property to the target variable after turning the string toLowerCase text.

var target = l[i].href.toLowerCase();

We only want to work with real links, so first we make sure we’re not dealing with javascript: directives.

if (target.substr(0, 11) != 'javascript:') {

Then we search the target string of the link for the h string. If we don’t find it…

if (target.substr(0, h.length).indexOf(h) == -1) {

…then this link is an external link so we tag it as such by adding the extClassName to its className preceded by a space. We do this instead of using setAttribute() because this way we can keep any pre-existing values for the class attribute already in the link. The key here is to know that className accesses the class attribute of an element.

    l[i].className += ' ' + extClassName;}

Finally, after closing all our blocks properly, we set the catchExternalLinks function to execute onload.

            }
        }
    }
}
window.onload = catchExternalLinks;

Of course, as per the requirements for this script being as unobtrusive as possible, it won’t do anything to the style properties of the link. All it did was add a class value, so we’ll need to declare our styles in our stylesheet. In my CSS page, I write the following to display a little icon for these links.

a.external {
    padding-right: 15px;
    background: transparent url(extlink.gif) center right no-repeat;
}

The styling possibilities are really rather endless now. Since I can instantly identify external links via the class external, I can also write context-specific styles. For instance, I can limit my styles to only one part of the page with a selector such as

#main a.external { ... }

or I could write different styles for external links for the sidebar and a comment on my entry with

#sidebar a.external { ... }
.blogComment a.external { ... }

or any other styling I see fit. In addition, from the script, it’s very easy to test for links that meet a specific criteria, say, Google definition searches, simply by adding another if clause inside the main loop. Here’s a version that does just that.

All together, it goes like this:

function catchExternalLinks()
{
    var extClassName = 'external';  // the class to set for external links
    var defClassName = 'defSearch'; // the class to set for definition searches
    if (document.links && document.getElementById)
    {
        var h = window.location.protocol + '//' + window.location.host;
        var l = document.links;
        for (var i = 0; i < l.length; i++)
        {
            var target = l[i].href.toLowerCase();
            if (target.substr(0, 11) != 'javascript:') // only work on links that aren't JavaScript directives
            {
                // tag external links
                if (target.substr(0, h.length).indexOf(h) == -1)
                {
                    l[i].className += ' ' + extClassName;
                }
                // tag Google definition search links
                var anchor = l[i].childNodes[0].nodeValue; // anchor now contains the anchor text of the link
                var s = '?q=define:' + anchor;
                if (target.substr(0, target.length).indexOf(s) != -1) // use != to ensure that the string (var s) EXISTS in target
                {
                    l[i].className += ' ' + defClassName;
                    l[i].title = 'Definitions for ' + anchor + ' on the Web.'; // for the link tooltip
                }
            }
        }
    }
}
window.onload = catchExternalLinks;

Feel free to steal this snippet. Just remember to write your styles in a stylesheet that you connect to your page, or the script won’t have any noticeable effect. Of course, that’s the whole point. Enjoy! ;)

Written by Meitar

September 22nd, 2004 at 9:02 am