Skip navigation.

Claws, fangs, fur...

...the bear essentials

Posts tagged with "CSS"

Testing how browsers react to changing element attribute values

, , , ...

Result: poorly.

http://www.omegajunior.net/code/tests/test_img_checkbox.html

Selecting a checkbox does select the checkbox... but it doesn't cause ANY tested browser to update the checkbox styling. To change the styling, authors must resort to scripting, like changing the class attribute using javascript.

This behaviour follows the HTML4 and CSS2 recommendations... which I consider quite disappointing. I'd love to see browsers react to attribute value changes by applying the CSS specified for the varying values. That way, less javascript is needed.

I can understand why browsers don't, and why their behaviour is recommended in HTML4 and CSS2: reacting to changes in several attributes for the same element may cause confusion and headaches for the author, let alone the browser programmers.

As if that ever stopped either of those groups from implementing something...

CSS 3 Media Queries

, , , ...

Today I tried my hand at CSS 3 Media Queries.

Media Query Support in Opera/Presto 2.1.1
Media Query Specification at W3.org

These can adjust CSS settings depending on the properties of the media. For instance, one can make sections narrower or wider, or choose not to display some sections, depending on the window width and device type.

For the homepage of my web site, I added CSS Media Queries like the following:

@media all and (max-width:45em){ 
 /* html,body{background-color:#ccffcc} */
 dl{max-width:40em;min-width:5em;padding:0;float:none;position:static}
 .watermark{padding-top:0}
 .tlt,.trt,.tlb,.trb{display:none}
 .tlt a span,.trt a span,.tlb a span,.trb a span{display:none}
 #frmGoogleSearch input#q{max-width:37em;min-width:3em}
}


This means that the regular 3 column layout on that page is reduced to a single-column layout when the width of the window drops beneath 45em, and that the images (tlt etc.) in the top table are hidden.

Browser comparison:
  • Opera Mini 4.2 reacts to these queries mostly. (It seems to ignore a specific query for handheld devices. I have to look into that.)
  • Opera 9.6 and Firefox 3.1 (Shiretoko) react to these queries on the fly: resize the window and you will notice the changes immediately.
  • Firefox 3 and Internet Explorer 6 ignore them. (Internet Explorer 6 does not understand "max-width" and "min-width".) (Firefox 3 does not understand CSS sent in the UTF-8 charset when generated by PHP: it assumes the page is sent as text/html instead of text/css. The file has to be saved and identified as using the iso-8859-1 charset to solve. The other browsers tested do not have this problem.)
  • Google Chrome reacts to the Media Queries after reloading the page.


Other browsers will be tested when available.

Harmonica script for BBCode, the OmegaJunior way

, , , ...

So... you implemented a CMS (content management system) that allows for BBCode in an article text... and you want to employ a Harmonica effect to make your article better readable? But since your article contains BBCode you can't set ID's nor Classes... can we still do it?

Yes, we can!
Harmonica Example
Harmonica Javascript
(Edited: the security certificate problem should be solved.)

It takes a small bit of unobtrusive javascript, primarily manipulating the DOM, to ensure the original text is available unharmed to visitors who can't use javascript. Let's break down what the script does:

1. It finds the container for the Harmonica. Luckily, that part is a div with an ID... it's the container of the BBCode article. The page is generated using PHP, which picks up the BBCode article, parses the BBCode to HTML and spits it out over the net.

2. It walks through the container's DOM tree, looking for HTMLElements. Because I created the BBCode article, I can predict in what order those elements will appear: a B element followed by text, and that several times in a row.

3. It starts converting the elements into Harmonica elements... B elements will become the Harmonica titles, and the texts in between will be the Harmonica bodies. Unfortunately the texts themselves aren't elements... they're text nodes: blocks of text without elements, thrown into the container div. So we can't collect all P elements, for instance. Instead, we have to walk the DOM tree and look for any node, then figure out whether it's an element or a text node, and react accordingly. The text nodes are converted into P elements, after which we can traverse them the normal way, and we can apply CSS.

4. My BBCode parser turns empty lines into BR elements. They look good outside of a Harmonica, but inside it they only confuse. So they have to go.

5. Because I want to have some kind of animation, collapsing and expanding the Harmonica bodies, I need each P element to hold several bits of information. This is stored in a special, custom object, added to each P element. Since the B elements and the new P elements are all siblings, owner identifications are applied to the P elements as well, in the same custom object. That way, when someone clicks the Harmonica titles to expand its body, we can recognise the correct P elements to expand.

6. To make the animation run smoothly, a window.setInterval is used. That way, the animation shouldn't lock up the browser window nor the visitor's entire computer. To make the animation stop, that interval handle has to be removed. That requires saving the interval handle in a place from where it can be retrieved. Initially I tried saving it in the same custom object as before... I could save it, but not retrieve it. So I had to make a global array to hold all the separate intervals.

7. A bit of CSS and image application creates a different look for the Harmonica, helping the seeing visitors recognise it. I applied separate styles for screen, mobile and print media.

To see what a similar script can do when applying a different bit of CSS, take a look at this
Tab Page Example

Have a look!

I hate MSIE

, , ,

Again.

Why?

First of all, because even the latest version (7) of this browser thinks it is impossible to hover a cursor over anything other than a hyperlink. No, it says, you cannot hover your cursor over an image. No, it isn’t possible to hover over a list item. Nope, hovering over a button does not exist.

Sure, you can define these behaviours in the html code… but that’s SOOOOO 90s! Ef off! We put these behaviours into our CSS. Right?

Yes, and that’s exactly where MSIE4, 5, 5.5, 6 and yes, even 7 go wrong.

(Edited to add the following: my latest tests show that MSIE 7 does perform hover actions on elements other than hyperlinks. Previous versions refused.)

Does the competition allow CSS-specified hover behaviours over other things than a hyperlink? Sure they do! Anything we could possibly desire and code into a web page is hoverable, according to Opera, Firefox, Safari, Camino, K-Meleon, Konqueror, Netscape, Mozilla.

Thank you, Microsoft, for refusing to implement standard behaviour.

Can we solve this stupidity?

Say, “yes Junior”! (”Yes, Junior!”)

We can add a bit of javascript to our web page, specifically for MSIE. We can hide it from decent browsers by using Conditional Comments (another MS invention, this time it cames in handy).

And here comes the second reason for my renewed hatred of MS’s poor excuse of a web browser:

Because none of the other browsers require Javascript for the hover behaviour, we want to inject it completely unobstrusively. Meaning: the decent browsers don’t get to see any of the javascript. Meaning: any behaviour that needs javascript will have to receive it… by javascript.

Can we do that? Yes, we can!

Of course, MS implements its own method. Instead of following the W3 recommendation of the DOM-2 object model for connecting events to HTML (element.addEventListener), it uses its proprietary method (element.attachEvent), and it refuses to implement the standard method. Thank you once more, MS, for making my life harder.

However, we can work with that kind of arrogance. Since the script only needs to work in MS anyway, we shouldn’t really be bothered. Annoying, yes.

First we attach our own custom initialisation to the loading of the page. Here we find hate-reason 2.1: we can’t attach it to the document, no, MSIE wants us to attach it to the bloody window. Otherwise, the initialisation simply won’t be executed. Why is this a problem? Because the window isn’t part of the page! It’s part of the browser and the page author should never be allowed to change the user’s browsing environment! So thank you, MS, for impeding on the user’s independence!

Second, we write our custom initialisation. We tell it to find the elements we wish to hover and attach the same javascript function to their hover event. There we find hate-reason 2.2: we can’t use a predefined function. Instead we have to create the function for every element. Bloody waste of memory.

Reason? Parameters. When using a predefined javascript function to hover an element, we have to pass the element itself to the function, so it can figure out which element was hovered. The Javascript language definition (a.k.a. Ecmascript) however prevents the author from supplying this information during the attachment process… which is exactly where we want to supply it!

So the hover function doesn’t know what to hover. Can we get around that? Sure we can! We just call up the window event and figure out what element was hovered! Even MSIE can do that! Right?

Kind-of.

MSIE’s implementation of the event object differs greatly from the W3 DOM2 standard. First of all, it has no target property. It does have a proprietary srcElement property however, that fills this omission. (Now the nice thing to do, MS, is to add a target property anyway, and keep the srcElement for backwards compatibility.) But what does this propery say? Does it say what element was hovered?

Kind-of.

In MSIE, the hovering doesn’t bubble up to its parent. So for very simple, flat web pages this might do. But it won’t even work when hovering a list item with a block inside of it… because it will indicate the block was hovered instead of the list item.

Well, isn’t that enough? No! We don’t want to attach this hovering behaviour to every possible element inside a list item… We want the hovering on the list item itself! Exactly the same way it works when we specify an onmouseover event on the list item. Please don’t tell me you can do the one but not the other, MSIE!

Helas.

So strike the predefined function. Instead, we use an in-line, newly created function for each list item. Great.

Thank you, Microsoft, for increasing the amount of memory used by a web page. Thank you, for forcing us to increase the complexity of our scripts. Thank you, for impeding on the user’s independence. Thank you, for assuming only hyperlinks can be hovered.

Thank you, for making decent, well-willing web authors waste 3 days trying to find ways around your crummy, short-sighted omissions.

xhtml and in-page scripts / styles

, , , ...

So you’ve decided to write XHtml instead of Html. And all of a sudden you realise: my in-page scripts and styles stopped working! (Or at least they stopped validating.)

Why, you ask?

Mostly because scripts and styles use characters that Html doesn’t really like, for instance the &. This will break validation and in some browsers it will prevent scripts and styles from being interpreted at all.

To solve this, the XHtml 1.0 recommendation describes three methods:
  1. omit any usage of html entity references inside your scripts
  2. move your scripts from in-line to a separate file
  3. escape the entire script by marking it as CDATA


The first method changes the scripts and makes them unusable.

The second method is nice and best practice, but isn’t always useful.

The third method doesn’t work.

What?

The third method doesn’t work. At least not in any current browser I’ve tested.

Why?

Let’s see how the recommendation sees this escaping:

<script type="text/javascript">
<![CDATA[
alert('hello, world!');
]]>
</script>

Guess what? Most current browsers don’t accept the code for specifying a CDATA block inside a javascript block. So they won’t recognise the script, won’t execute it, or may generate lots of errors.

Is there a solution? Yes, there is! Remember from scripts in Html, that we used to add Html comment tags to hide the scripts from unscripted browsers? We can do the same here, with the same effect!

<script type="text/javascript">
/* <![CDATA[ */
alert("hello, world!");
/* ]]> */
</script>

Easy, no?

And we can do the exact same with our style block, too:

<style type="text/css">
/* <![CDATA[ */
html { background: black; }
/* ]]> */
</style>

Now the blocks validate and will get executed.

This method was tested in:
  • Opera 9.2
  • Firefox 2.0
  • K-Meleon 1.1
  • MSIE 6
  • MSIE 7

Data URIs and MSIE

, , , ...

No match.

Bloody briljant. In 1998 some people came up with a way of enclosing a file source into an HTML or CSS file so you wouldn’t need to link to an outside file.

Where does this come in handy?

Well in all those pretty e-mails of course, sent to you by a handful of spammers and a friend or two. We can now send the pretty image we wish to show as part of the HTML itself, so we don’t need to perform dirty tricks like cross-referencing attachments or bypassing network firewalls.

Makes rich-text e-mails safe again.

Guess which browser doesn’t support Data URI’s?

Yup, the world’s most used one. Thank you, Microsoft, for refusing to improve the security of your systems since 1998.

Description: http://en.wikipedia.org/wiki/Data:_URI_scheme
Specification: http://tools.ietf.org/html/rfc2397
Download Opera, the fastest and most secure browser