Showing posts with label css. Show all posts
Showing posts with label css. Show all posts

Saturday, February 11, 2012

On CSS vendor prefixes and applying pressure where it is making most sense

If you are a web developer chances are pretty good that you have read quite o lot of tweets and blog posts on vendor prefixes lately. It all started when Daniel Glazman issued an urgent call for action. Various people have chipped in including Bruce Lawson and the Web Standards Project.

This is an expanded version from a comment I wrote on Daniel Glazman's blog.

My background

Please bear with me as I explain my background. It is important for the thoughts I have at the end.

I am an educator. I teach web development for a living and has done so for more than a decade. As a consultant for Skolverket, Sweden's national agency of education I have in fact succeeded in making standards, accessibility and best practices mandatory requirements for all teaching in the country at the secondary level (approx. senior high school in the USA/A-levels in UK).

I am participating in the Web Standards Project Education Task Force, am co-author of InterACT with Web Standards and have written material for the InterACT curriculum project. I also participated in OWEA and now the Web Education Community Group at the W3C. (Of course nothing on this blog is the official position of any such entity.)

I thoroughly believe in education!

Nevertheless I do not see how education alone can solve the problem at hand. Too much misinformation, too much marketing, too much Apple- and Google-centric journalism. Education can only alleviate the problem, never solve it.

There is a solution available that will make the problem disappear

There is in fact a solution available. One that would do more good than anything else.

Webkit must drop support of prefixed properties when there has been a standards compliant solution implemented, after a reasonable grace period. Say 6 months.

This is after all what all other browser vendors are doing right now.

This is how prefixes are supposed to work. This is the right thing! Anything else is a violation of the principle.

And yes, this will break sites, which is the exact point of this solution!!!

This is the only way to create the necessary urgency that will reach into web development sweat shops in India and China, as well as into the corporate management level in the larger companies.

There are educated web developers that simply do not have the time or the mandate to fix problems like these, because upper management do not care. They think about their own product here and now, not what's good for the web as a whole 10 or 15 years into the future.

Let's apply pressure on Apple

This is primarily not about blame, but applying pressure where it is most useful.

Let's create and uproar in the web development world strong enough to create bad will for Apple, forcing upper management to do the right thing!

Apple (and to a lesser extent Google) are sitting on the solution. Not Microsoft, not Mozilla, not Opera.

If they are getting away with acting badly it is because we are letting them, letting love for the products they make get in the way of the higher goals, letting them behave in ways that perhaps was OK when the iPhone was launched and Webkit had 0 % market share on mobile, but not changing their way according to the present situation.

Apple initially supported SOPA and PIPA – which speaks volumes about the default mind set within the company – but back peddled. So even if they have claimed that they will never remove the support for prefixes, let's create enough pressure on Apple that they will benefit from back peddling again!

Right now the pressure is applied to Mozilla, Opera and Microsoft to do the right thing, even if it will hurt their market share – and by extension their ability to fight for a free and open web in the long run. We are asking those companies to sacrifice themselves for the common good and for higher ideals.

But Apple is either loved too much for anyone to act against them – or seen as a lost cause, an unfixable problem, the IT equivalent of North Korea.

As long as the web development community is stuck in that love/hate relationship with Apple, we can never act sensibly.

Who can afford it?

Apple has just had a another record quarter and even may surpass IBM and HP in a few years.

  • Still they won't hire evangelists like Opera, Google and Mozilla that teach best practices.
  • Still they won't hire full time spec writers to get their proprietary extensions through the standardization process.

The takeaway from every Apple keynote I've heard the last years is "concentrate on the iPhone and iPad".

This message need to change!

The other main stakeholder in Webkit is Google. And their business is not shabby either. In fact it is Android and Chrome that has made Webkit the most popular browsing engine in the world.

But Google embraces open more than Apple. Google may very well be quite easily persuaded to stop supporting prefixed properties for mature technologies, in my opinion.

It is Apple that primarily needs to be pressured.

What's at stake?

Since Mozilla not only develops their browser openly, but has an open process for just about anything I stumbled upon their internal discussion about supporting -webkit- prefixes already a few months ago. First of it is quite clear that nobody within that organizations likes the idea of supporting -webkit- prefixes. Even those that support the idea do so with the utmost distress.

But except for some Gnu/Linux distros Gecko is not the default rendering engine anywhere. Opera is in a similar position. For the majority of users their is but one incentive to switch: A better user experience.

That is the bottom line.

Not ideology, but my experience as a user today, is what makes people switch.

However, since Mozilla and Opera to a high degree are value driven organizations it is easy to think that it is "their job" to keep the web open. But if right decisions comes at the cost of minuscule market shares they won't have much power to wield anyway.

And please remember that Opera and Mozilla did go down the path of ideology concerning video codecs. Would that have been possible today when their market share is falling?

It's time for Apple to pay back

Apple has never been a true champion of the open web or indeed anything open. Despite the fact that open technologies saved Apple from ruin. That, and two important gifts from Microsoft: Cash in return for stock that gave no voting power and a commitment not to stop developing Office for Mac OS.

Back in the 90's Apple struggled to develop a modern and technologically sound operating system. Copland failed. Taligent failed. And so did a bunch of other efforts.

The number one option was to buy BeOS and that deal almost came through. (Imagine the world if it had! Steve Jobs return would probably not have happened...)

However, what Apple could not develop in house they found in open source:

But also this might not have been. KHTML developers came very close to throwing in the towel and switching to Gecko.

Once again, what if they had? What if they had not persisted thanks to ideology, not business considerations?

Projects driven by ideology provided Apple with the core technologies from which they have built Mac OS X, iOS and the Safari browser.

And Apple also benefited from Firefox. It was Firefox that wrestled the web away from Microsoft. It was Firefox embracing standards that provided the opportunity to develop a browser like Safari. Remove Firefox from the equation and there would never have been a superior browsing experience on the iPhone. Those experiences were made possible from developers embracing standards thus eliminating the Microsoft monoculture.

So why should Apple help the world? Because the world first helped Apple!

Once again, we should apply pressure where pressure is due.

Unconditional love or unconditional hate bestowed upon Apple will both just make the company worse. And as for the latter (hate), did you notice that Apple actually pack peddled concerning SOPA and PIPA? Given enough pressure the company actually can abandon bad ideas.

If the web development community keeps praising Apple as if the company does nothing wrong – or at least nothing wrong that can't be excused – or if we treat Apple like a lost cause, a closed brainwashed sect incapable of change, then by all means, put all pressure on Mozilla, Opera and Microsoft.

But please acknowledge that in so doing we are forfeiting our best chance to keep the web open. Remember, this is not so much an issue of who is to blame, as it is an issue of how it could be fixed.

Thursday, July 15, 2010

Rotating table headers now in 4 of the top 5 browsers

Update May 3, 2012. Demo link fixed. + Firefox 14+ (Aurora, Nightly) no longer skews text. Apparently the CSS Working Group have recently decided that Webkit behavior was better and Mozilla has fixed their code. I think this was a bad decision, but that is how things stand. Other stuff seem to be happening in the CSS WG with regards to skew and I have unfortunately been unable to keep track of this. Note that skewX does not seem to be in jeopardy, though.

A little more than a year ago I wrote about a technique I have developed to rotate table column headers. (If you have not, you had better read that article to understand this one correctly.) Back in May 2009, this could be done in Firefox 3.5 and Safari 4. Now browsers have evolved and it's doable in all major browsers, except Internet Explorer. So, with Firefox, Chrome, Safari and Opera all supporting this, has the time arrived to use this on production sites?

The sad answer is no, there are still a few issues to that needs to be sorted out in my opinion. First of all, one really can not ignore Internet Explorer, and even if we can rotate content using -ms-filter, that is not an optimal solution. I have also seen reports that these filters will not work in IE9 in its strictest standards mode. Removing them, while not adding CSS transformation, gradients and a few more things, will make it near impossible to achieve true cross platform effects. I hope that won't be the case, though. (More thoughts on this in my conclusion.)

Updates to my code

The full demo is at keryx.se/lab/rotating-th/rotate-th-2.html

Today I revisted my code. The first thing I did was simply to slam on -o- prefixed rules, identical to all -moz- rules. The result looked like this. Click the image to see it in full size.

Screenshot of Opera, firefox and Chrome, showing bad alignment

Not nice. Firefox, Opera and Chrome (the 3 browsers I could test on my Linux driven Thinkpad) all got the horizontal position differently. Admittedly, Chrome got a slightly different rule, thanks to a Webkit CSS filter. But this worked as intended in my tests one year ago. My code was largely experimental and not really calculated anyway, so I was not surprised that it broke. It was intended as a proof of concept, not as production ready code.

Before I started to investigate the differences in earnest, I tweeted, and soon Faruk Ateş chipped in and had some helpful thoughts. First we removed my line "top: 1em" for all browsers. Note, that it must be removed. Manually setting it to 0, will still mess things up in Firefox. I suppose that's a bug, since the calculated value is 0 with that line removed…

The line that was removed:

th > span > span {
    …
    top: 1em;
    …
}

Stability issues

Next problem, subpixels. I had used the em unit to set heights and widths. But 1.3em is not the same in all browsers. In my code it's 23.4 pixels in Firefox, but only 23 in Opera and Chrome. The latter two does not translate ems into subpixels. At least not on Linux and Windows. So I made some changes to the code, to use pixels almost everywhere.

th > span > span {
    …
    padding: 9px;
    height: 23px;
    width: 120px;
    …
}
td {
    padding: 5px;
    text-align: right;
    width: 36px;
}

All values above were set in ems in my original version. Now I was getting close to a working version. There was one thing that bugged my designer eye – and I am really not a designer. The line in between table columns did not align perfectly with the column header lines in Firefox. Once again, this was a sub-pixel problem. So I added this rule, explained in the comments:

th > span > span {
    …
    position: absolute;
    left: -0.5px; 
        /* 
          So far only Firefox does subpixel positioning = 
            ignored by Opera, Chrome and Safari.
          But they got this right (visually) in the first place.
          This rule puts the rotated span exactly in place for Ffox
          (tested on Linux and Windows July 2010)
        */
    …
}

Should Opera and/or Webkit add support for subpixel positioning, it is my hope that it will affect their rendering just like it does in Firefox. But this is a fragile hope!

Webkit text skew (not a) bug

Update May 3, 2012. Firefox 14+ now treats text the same way as Webkit.

To make the text as legible as possible it is skewed back to being non-skewed. Let me explain. There are three spans. The outermost is simply an anchor for the middle one, where the real magic happens. That span is rotated and skewed. That leaves the text a bit… skewy(?) To remedy that, I use a third span, only used to skew the text back again.

th > span > span {
    …
    -moz-transform: rotate(-65deg) skewX(25deg);
    -o-transform: rotate(-65deg) skewX(25deg);
    -webkit-transform: rotate(-65deg) skewX(25deg);
    -moz-transform-origin: 0% 0%;
    -o-transform-origin: 0% 0%;
    -webkit-transform-origin: 0% 0%;
    …
}
th > span > span > span {
    /* Rotate the text back, so it will be easier to read */
    -moz-transform: skewX(-25deg);
    -o-transform: skewX(-25deg);
    -webkit-transform: skewX(-25deg);
    /*
      Safari and Chrome won't skew back, so the above
      line is actually redundant right now
      (checked July 2010 on Linux and Windows)
    */
}

I suppose this is a Webkit bug, that needs to be filed. This image illustrates the problem. The red line shows the actual angle of the stroke in the letter "l" (small "L"). The green line shows what angle it was supposed to be.

Text is still skewed in Safari

Screenshot of my table from Safari on a Mac, graciously provided by Matthew Irish. This problem affects all Webkit based browsers, on Windows, Linux and Mac.

Opera text blurriness and zoom bug

Opera gets the skewiness right. (Being a non native English speaker, I love the word skew and will jump at every opportunity to skew it!) However, Opera looses the smoothness of the text, once it has been rotated. It will look blurry. The following image compares Opera to Firefox. The text is not perfect in Firefox either, though.

An even bigger problem with Opera is that it really will mess the text up when zooming the page, to the point where it becomes totally illegible. The image below is zoomed to 300 % and one can not read the text at all, since the bottom (=left) margin has widened and pushed the letters on top of each other.

Messed up text in Opera when zoomed

Gaps between cells in Firefox

The image above illustrates another problem in Firefox, perhaps also caused by subpixel positioning. At some zoom levels small gaps appear between the cells. Note that we are not drawing lines on the actual table cells but a box around the edges of a span. We are just visually emulating rotated table headers.

From previous testing I also found these gaps also when not zooming the page. One has to be really precise in the measurements to fix this. Right now I basically get the visuals right by having the line from one cell on top of the line from the previous cell.

If I'd fine tuned my technique, I think these gaps could be avoided. Not drawing both lines both left and right (= top and bottom in CSS) and extending the top (= right) line a bit might do the trick.

On subpixels

A small aside: It might seem like subpixel positioning is all bad. I believe it generally is a feature, not a bug. I wish all browsers could agree on Firefox' behavior. But in this context it seem to be problematic. I will ping a few people at Mozilla and see what their take on this is.

Conclusions and some thoughts about the future

Please see the top note about things being unstable in CSS WG, when it comes to skew.

I really think there should be a CSS-rule that would make this super easy. Rotating column headers is a really common technique in spreadsheet programs like Excel and LibreOffice Calc. I use it all the time. It would be a great feature for Google and Zoho Docs and similar on-line products. So far, however, the CSS Working Group and browser vendors have shown very little interest.

All browsers display an issue of some kind with my current technique:

  • Killing: Bad rendering of the text in Opera, especially when zooming.
  • Bad: Gaps in Firefox between the cells, when zooming.
  • Slightly annoying: Skewed text in Safari and Chrome (and probably Firefox 14+).

Internet Explorer 9 is a big question mark. My current idea is to capability detect for CSS transforms and replicate this behavior in SVG, if available, or using -ms-filter as a third option. That should cover all bases = MSIE 6-9, Firefox 3.5+, Opera 10.51+, Safari 4+ and Chrome (always at the latest version, at least until it comes to the corporate environment – a subject worthy of a blog post by itself).

Having to limit oneself to pixels as a unit and fixed width for the columns is a major obstacle. For this reason, as well as the Internet Explorer problems, I think that the only sane way of doing this at the moment and the foreseeable is using JavaScript. Perhaps this could be my first official JQuery plug-in. (Please feel free to beat me to it!)

Friday, April 23, 2010

Why declarative animation should be in the DOM and not in CSS

Note: This blog post did reflect my opinion at the time of writing. Since then technology has evolved and now this has become less of an issue. I will leave the post online, but if you came to learn about how to do animation today, reading will be a waste of your time.

A little more than a year ago Safari introduced experimental support for CSS based animations, to compliment transformations and transitions. I have no gripe with transitions and transformations, but I think animations belong in the DOM and not in CSS. My main argument is that animations will most of the time be triggered by DOM-events, and during at least the next five years most CSS-based animations will be duplicated using classic DOM-methods anyway. The purported separation of animation (for designers) who are supposedly scared away from scripting is not a valid argument, since they are going to use libraries anyway. (And, frankly, the CSS animation syntax in itself looks quite scary to most people!)

Originally, this started out mostly as a gut feeling, and the arguments that I've made on the W3C mailing list are varied and admittedly a bit confused. I was thinking out loud more than I was presenting a coherent argument. Hopefully this blog post will come across as more reasonable!

I also believe that this discussion needs to be known outside of the CSS working group and the participants on the www-style mailing list. Specifically, it needs the input of developers of JavaScript libraries and normal web developers. These are the people who will be affected the most by any decision. (I am providing an abundance of links to the discussion on the mailing list for context.)

CSS animation – the good parts

A few aspects of the CSS animation proposal are brilliant and not of dispute:

  • Declarative syntax. Designers specify what effect they want, not how the browser should achieve it.
  • Hardware acceleration. Animations get smoother, faster and less CPU-draining. The GPU is optimized for this and can perform the calculations using only a fraction of the power and time a CPU would take to do the same number crunching.

When I am asking the CSS working group to reconsider CSS animations I am not in any way trying to take away these two strong points. I am firmly pro having GPU-accelerated, declarative animations in the browser. I just think the DOM is a better fit for them.

What will be animated?

CSS has no events, it has states. Basically it knows the focused and unfocused state on links and widgets and if a pointer is hovering, clicking ("active") or not hovering over an element. While exeperimenting with the CSS animation syntax, the working is producing examples using these states. Ironically mobile devices are one of the main reasons why CSS animations were originally thought up, and they rarely have a pointer, and CSS is not really equipped to handle touch events.

It can safely be assumed that 99 % of all real world use cases for animation will be the result of user or server interaction on some part of the document that is not being animated. The user clicks a button and a div will slide into view. The user presses a key on his keyboard and text will wiggle and bounce. Data is sent back from an AJAX request, and the received data will appear through an attention grabbing sliding effect.

Currently the only way to achieve these real world use cases is by adding or removing class attribute values. Thus we have scripts that will trigger animation in the DOM and the actual design of the animated effects in CSS. Conceptually this is nice. Separation of logic is a good thing™. However, in real world practice this will not be so neat.

Events confusion

Even though there are no events in CSS, there is discussion about having animations running upon entering a state, while being in a state and when leaving a state. These are not events in a technical sense, but outside of the W3C working group, most developers will be really confused about the difference. Such precise knowledge is not found in abundance! If a specific application need to differentiate between these, it is by far easier for developers to use the more familiar DOM events.

Having some animations run because they are affected directly, e.g. on hover, some animations run because they are triggered by a scripted change of className, and in both cases also have animations that may run entering, during and leaving states looks like a recipe for unmaintainable and confusing development. It is way much better to trigger all events from one place only, and that place can only be the DOM.

How to implement animations in a library

OK, you are building a little library to animate stuff. What do you do? I suppose the following:

  1. First you capability detect support for declarative animation. That in itself would be easier if it was in the DOM, but it is at least doable now. But not in a neat fashion. Score one against having animations in CSS.
  2. If CSS-animation is indeed supported, you will wrap your animate function around className switches. Doable, but not neat.
  3. If CSS-animation is unsupported, you fall back to old school timed manipulation of the style attribute.
    • However, using the animation parameters from the CSS-file is a huge impracticality. You must find a way to read all CSS-files, parse them and interpret the cascade, the specificitivity of all animation rules and convert that information into timed logic. This is impractical, slow and CPU-draining and fragile.
    • The CSS Object Model (CSSOM) will not alleviate this problem. Browsers that need to parse the animation rules are the ones that neither implement animations, nor the corresponding CSSOM.

Alternatively, the author is required to re-specify the animation once again, now using a syntax for the fallback. We thus get code duplication, with all the error proneness and maintenance problems that follows from that approach. But it is the only approach currently available with reasonable results.

It can safely be said, that CSS-animations are not backwards compatible in any reasonable way. And we are going to need backwards compatible solutions for almost another decade or so.

What about progressive enhancement?

Using progressive enhancement we can deliver CSS-based animation to browser that support it, and non-animated but still usable content to the rest. Problem solved, is it not?

I like progressive enhancement. I teach it and I practice it. However, there will be a great number of real world customers that will insist upon having animations in both the brand new cutting edge browsers and the legacy ones. As least as long as more than 10 % of their visitors use them. We can preach all we want. This scenario will face the real world developer way too often.

Animations will be used to convey information as well as for eye candy. Not having a scripted fall back will not be an option for such use cases either. In real world web development, progressive enhancement can not be called upon to be a panacea, how appealing that thought ever may be.

What else will be hard to do using a CSS approach?

In real world use cases developers are also going to want to manipulate animation and keyframe properties, as well as programmatically create animations from scratch. Using the CSSOM this can probably be done in browser that support animation but once again the fallback for legacy browsers will be very hard to achieve.

What is my counter proposal

I have barely begun thinking about this issue, so any propsal I have at the moment should not be regarded as a final suggestion. In order to keep the separation of concern between designers and developers – for those situations where one has the luxury to keep them separate – animations must be easy to define with a CSS-like syntax. JSON fits that requirement quite well. The method to start an animation could be called runAnimation. It might return a value that I can store in a variable in order to manipulate or cancel the running animation. Another way to manipulate it would be by altering the animation properties. For convenience, there should also be a method to stop all running animations on an element.

Here is an example, recreating the effect from Surfin' Safari's announcement:


// Keep the JSON objects in a separate file for designers to fiddle with

var bounce = {
    "from" : {
        "left" : "0px"
   }
   "to" : {
       "left" : "200px"
    }
}

var myAnimation = {
 "animation-name" : "bounce",
 "animation-duration" : "4s",
 "animation-iteration-count" : "10",
 "animation-direction": "alternate"
}

// Keep these lines in another file for the JavaScript guy/girl to fiddle with

document.getElementById("foo1").onclick = function() {
    document.getElementById("bar").runAnimation(myAnimation);
}

document.getElementById("foo2").onclick = function() {
    document.getElementById("bar").stopAllAnimations();
}

// Example 2
// Keep the JSON objects in a separate file for designers to fiddle with

var pulse = {
    "0%" : {
        "background-color" : "red",
        "opacity" : "1.0",
        "transform": "scale(1.0) rotate(0deg)"
    }
    "33%" : {
        "background-color": "blue",
        "opacity" : "0.75",
        "transform" : "scale(1.1) rotate(-5deg)"
    }
    "67%" : {
        "background-color": "green",
        "opacity": "0.5",
        "transform": "scale(1.1) rotate(5deg)"
    }
    "100%" : {
        "background-color": red,
        "opacity": "1.0",
        "transform" : "scale(1.0) rotate(0deg)"
    }
}

var pulsedbox {
    "animation-name": "pulse",
    "animation-duration": "4s",
    "animation-direction" : "alternate",
    "animation-timing-function" : "ease-in-out"
}

// And here comes the DOM-parts, this time using JQuery for easy iteration

$(".pulsedbox").each(function() {
    this.runAnimation(pulsedbox);
});

As stated above, my counter proposal is not a finished product in any way. It merely is intended to serve as an illustration to an alternative approach. The technical merits or defeciencies of that proposal is in itself not really something that should guide the general discussion about how to implement declarative animation. The principles on which I draw the conclusion that the DOM is a better fit is the true talking point here.

Now I am especially interested in hearing the opinions from the DOM-scripting community!

Monday, March 22, 2010

PPK is wrong, vendor prefixes are a necessary evil.

Yet another considered harmful essay has hit the web. This time it is PPK, a well known JavaScript guru and very influential author that has written it. And I get to disagree with another one of my heroes. (Just recently I have disagreed with Rasmus Leerdorf on the naming of the next major PHP version...)

Basically PPK is like many others fed up with writing the same rule 2, 3 or even 4 times. You know the drill:


-moz-border-radius: npx;
-webkit-border-radius: npx;
border-radius: npx;
Add in a few (-ms-)filter as well and it's a nightmare. And the CSS-validator is not configured to ignore these, even though they are not errors per se. It is sure easy to echo PPK's sentiment. But I believe he is wrong, and fortunately I am not the only one.

Proposals do change

Case in point is border-radius and gradients. Mozilla could not just drop -moz- from border radius, since their 6 year old implementation is not aligned with standards. Webkit can not drop the prefix from their gradients rules, since the standard probably - please note that word, probably - will look like Mozillas implementation.

I also note that he has put the non-prefixed version of a rule before the prefixed ones, which is not optimal for the very same reason. A problem I have dealt with in an earlier blog post.

Experimental versions are needed for things to move along. Without them very few people will be able to experiment and improve the proposal. This is a real need, this is a real problem.

Contrary to what PPK says, vendors do not simply copy each other. They often start that way, end then they run into questions like what about... and they will have to discuss and test and decide and make changes. Both to the implementation and the spec. Such discussions take place on the W3C mailing lists all the time.

Standards must be standards

PPK dislikes vendor prefixes because they seem to be the opposite of standards: Vendor specific rules, code forks, similar to browser sniffing in JavaScript.

But what he is proposing is effectually doing away with the entire W3C process. Yes, it is slow and burdened by politics. But if we drop vendor prefixes that will mean that as soon as a browser puts out a new technology it, by virtue of being first, has decided unilaterally what the syntax should look like and how it should work in every browser. This is not a standards process, this is in fact the opposite. First to market rules and everyone else be damned!

Experimental versions of future standards are a good thing, since they allow for real discussion and much more thorough standardization. One of the reasons standards are moving slowly is that today they are much more detailed, much more tested and therefore much more reliable.

This is not unique to web standards. Consider IEEE802.11n and the fact that we for a couple of years had draft version equipment on the market. Good or bad? It made the final implementation better, so yes it was good. And a necessary evil as well.

There must be room for errors

Webkit has not copied Mozilla's implementation of border-radius and Mozilla has not copied Webkit's gradients. Having discussed the proposals changes have been made, lessons have been learned and this has happened in real life.

If a vendor must not use prefixes it would take forever to get to a place where they would be confident enough to put out a new technology. Opera and Microsoft may skip the prefix for border radius, since thanks to Mozilla that 6 years ago put out an experimental implementation and thanks to Webkit, that 3 years ago put a out a slightly different experimental implementation, the standard has now reached Candidate Recommendation status and web authors demand the technology, because we have been able to experiment with it!

If it had not been for prefixes, only a very few people would actually have bothered to download experimental browsers and try this out. That is our only other option. The word would not have spread and demand had not been built up.

Is summary. PPK, I love your work and have tons of respect four you. But in this case you are wrong. I will not shout long live the prefixes, since I wish that every prefixed CSS rule should have short life. But I want that short life to be productive.

Sunday, June 28, 2009

Do not put experimental features last in your CSS

Today's blog post will be short one. I have lately seen code like this on more than one occasion:

#foo { 
border-radius : 10px; 
-moz-border-radius : 10px; /* Mozilla */
-webkit-border-radius : 10px; /* Webkit */
}

What is the problem?

Right now only one line will have an effect. In Gecko-based browsers, like Firefox, the one starting with -moz-, in recent Webkit based browsers, like Safari and Chrome, the one starting with -webkit-, as indicated in the comments. These are the two current experimental implementations of the coming CSS 3 border radius property.

Hopefully in the near future the specification will thanks to these two implementations reach a level of maturity, where browsers may start to implement it in a non-experimental version. If so one thing is to be expected. The non-experimental implementation will most likely differ (somewhat) from the experimental one! And as a developer you will most probably want the final version to be the one that browsers actually use. And when two rules affect the same property like this (equal specificity, equally placed in the cascade), the last one will override the first one. Therefore you should put things in this order:

#foo { 
-moz-border-radius : 10px; /* Mozilla */
-webkit-border-radius : 10px; /* Webkit */
border-radius : 10px; 
}

Why is this better?

During a transition phase, lasting at least a few years, Webkit and Gecko can be expected to support both implementations. There are sites that use the experimental versions only and in order to give them a grace period, dropping support as soon as the final version is implemented is not an option. Historically Mozilla has let such grace periods last for 2-4 versions of Firefox.

So this is the bottom line. Put experimental features first, standard features last. That will ensure a better forward compatibility.

Monday, May 4, 2009

Rotating column headers using CSS only

Note: This article now has a follow-up from July 2010, explaining how to get this working in more browsers and in a more reliable way.

For a while I have wanted a solution that would rotate table column headers on web pages. In Excel or Open Office Calc, this is a breeze. However, the only way to do it in todays browsers is using images, or perhaps SVG or even the Canvas element from the HTML 5 spec. However, this is a pure design issue, and therefore falls into the domain of CSS. And I think that I've come up with a solution, or at least an idea for a solution.

Screenshot of Firefox 3.5b4pre and Safari 4.0 beta showing column rotated headers

The image above should give you an idea about what I mean. The benefits of this design is that one can keep all columns relatively narrow, while at the same time use long words to describe them in their headers. If you use Firefox 3.5 or Safari 4.0 or another browser that supports -moz-transform or -webkit-transform you can also look at my experimental page. View its source to get the full picture of what I have done.

The technique

One can not simply rotate the th-elements. It will look like this: Screenshot of failed solution. Only text rotated.

There is a number of problems:

  • The rotation is applied after the browser has allocated width for the columns. Our intention was to save horizontal space. We need to remove the text content out of the normal flow, using absolute positioning.
  • Any borders and background color will not be rotated. The text will extend out on top.

My solution is to wrap the text in three spans. Yes that's an awful lot, but they each serve a purpose. The first span is the holding area, relative to which the second span will be absolutely positioned. Its CSS is as follows:

    th > span {
      position: relative;
    }

The second span is rotated as well as skewed. Rotation is counter clockwise, hence it's set to a negative degree. The skewX is set so that the border originally to the left, now to the bottom, is completely horizontal. Mathematically the formula is abs(rotationdegree) + skewdegree = 90.

In order for all headers to be of equal height, we set a width. Remember that the visible height is the un-rotated width. For some yet un-investigated reason Firefox will put the span a bit further up than Safari, so I'll add a CSS filter to fix that. Border and color is added, as well as some padding, just for the appearance.

th > span > span {
  /* Must remove span from normal flow in order to keep columns from widening */
  position: absolute;
  white-space: nowrap;
  top: 1em; /* Firefox 3.5. Safari is reset below */
  -moz-transform: rotate(-65deg) skewX(25deg);
  -webkit-transform: rotate(-65deg) skewX(25deg);
  -moz-transform-origin: 0% 0%;
  -webkit-transform-origin: 0% 0%;
  border: 1px solid;
  padding: 0.5em;
  height: 1.3em;
  width: 120px;
  /* Illustrate where it's at with color */
  background-color: yellow;
  /* If one wants centered text, this is the place to reset it */
  /* From a design point of view it might not be desirable */
  text-align: center;
}
/* CSS filter for Safari */
@media screen and (-webkit-min-device-pixel-ratio: 0){
  th > span > span {
    top: 0;
  }
}

The text will be a bit hard to read. I therefore un-skew it in a third span. This does not work, however in Safari 4.0 beta:

th > span > span > span {
  /* Rotate the text back, so it will be easier to read */
  -moz-transform: skewX(-25deg);
  /* Safari 4.0 beta won't skew back, so the next line is actually redundant right now */
  -webkit-transform: skewX(-25deg);
}

For the full HTML and CSS, look at my experimental page and view source.

Problems

  1. This solution is quite fragile. Widths and heights, margins and paddings might mess things up. Columns must not be of a flexible width.
  2. For pixel perfection, there is a slight nuance, where Firefox positions the spans 1 pixel further to the right, than Safari.
  3. As I said, there is an awful lot of spans...
  4. And worst of all. So far I have not developed a fall back for browser that do not support CSS transformations. In those the table will just look awful and the table headers will be unreadable.

Anyway, I think this solution has some potential. Until the CSS WG and browser vendors gives us an even better solution, this is my best effort. Is there a better solution somewhere, please let me know!