6 posts on HTML5

Introducing Multirange: A tiny polyfill for HTML5.1 two-handle sliders

1 min read 0 comments Report broken page

multirangeAs part of my preparation for my talk at CSSDay HTML Special, I was perusing the most recent HTML specs (WHATWG Living Standard, W3C HTML 5.1) to see what undiscovered gems lay there. It turns out that HTML sliders have a lot of cool features specced that aren’t very well implemented:

  • Ticks that snap via the list attribute and the <datalist> element. This is fairly decently implemented, except labelled ticks, which is not supported anywhere.
  • Vertical sliders when height > width, implemented nowhere (instead, browsers employ proprietary ways for making sliders vertical: An orient=vertical attribute in Gecko, -webkit-appearance: slider-vertical; in WebKit/Blink and writing-mode: bt-lr; in IE/Edge). Good ol’ rotate transforms work too, but have the usual problems, such as layout not being affected by the transform.
  • Two-handle sliders for ranges, via the multiple attribute.

I made a quick testcase for all three, and to my disappointment (but not to my surprise), support was extremely poor. I was most excited about the last one, since I’ve been wanting range sliders in HTML for a long time. Sadly, there are no implementations. But hey, what if I could create a polyfill by cleverly overlaying two sliders? Would it be possible? I started experimenting in JSBin last night, just for the lolz, then soon realized this could actually work and started a GitHub repo. Since CSS variables are now supported almost everywhere, I’ve had a lot of fun using them. Sure, I could get broader support without them, but the code is much simpler, more elegant and customizable now. I also originally started with a Bliss dependency, but realized it wasn’t worth it for such a tiny script.

So, enjoy, and contribute!

Multirange


A better tool for cubic-bezier() easing

2 min read 0 comments Report broken page

A few days ago, I had a talk at a conference in Zurich (I’m going to write more about it in another post). The talk was about “10 things you might not know about CSS3”. The first of those things was how you can do bouncing transitions with cubic-bezier() instead of an easing keyword. As usual, my slides included a few live demos of the functionality, in which I edited the cubic-bezier() parameters and the audience could see the transition produced.

However, in the case of cubic-bezier() that’s not enough. No matter how much you see someone changing the parameters, if you don’t picture it in a 2D plane, it’s very hard to understand how it works. So, the night before, I searched for a tool I could use to show them how bezier curves are formed. I found plenty, but all of them restricted the the coordinates to the 0-1 range. I’m not sure if the cause is ignorance about the spec changes or that Webkit hasn’t caught up with those changes yet (but it will, soon). The only one that supported values out of range was this one from the Opera Dragonfly developers, but I found it kinda impossible to adapt.

For my talk, I tried to adapt one of them but it was late so I gave up after a while and ended up just showing them a screenshot. And the day after the talk, I started adapting this to my needs (ever tried coding at a conference? It’s awesome, you get to ask questions from very knowledgeable people and ger replies straight away). And then I started cleaning up the code, changing how it worked, adding features. At this point, I think the only thing that’s left from that tool is …the HTML5 doctype. After 3-4 days, I finished it, and got it its own domain, cubic-bezier.com (I was surprised it was still free).

So, in a nutshell, what makes this better?

Lots of things:

  • It supports y values out of range, as per the latest version of the spec (and shows a warning for Webkit)
  • It’s fully accessible from the keyboard
  • You can move the handles not only by dragging but also by clicking on the plane or using the keyboard arrow keys
  • You can mouse over the plane and see the progression and time percentages that correspond to every point
  • You can save curves you like in your “Library” (uses localStorage to persist them)
  • You can import and export curves to/from your library to share them with others
  • You can share a permalink to every curve. For example, here’s a bouncing transition (FF & Opera only)
  • You can compare the current curve with any in your library, setting the duration yourself
  • Custom favicon that reflects the current curve

Cool stuff used

Given that this tool is not only for developers, but for badass developers that care about stuff like cubic-bezier(), I think I can safely assume they’re using a top notch browser. So, I went crazy with using cool modern stuff:

  • HTML5: Canvas, localStorage, History API, range inputs, oninput event, output, classList, data- attributes
  • ES5: Accessors, Array#map, Array#forEach
  • Selectors API
  • JSON
  • CSS3: Transitions, gradients, media queries, border-radius, shadows, :in-range pseudoclass, box-sizing, transforms, text-overflow

I also used my tiny chaining framework, Chainvas throughout this project.

Browser support

So far, I’ve tested it in modern versions of Chrome, Firefox, Opera and Safari and it seems to work. I haven’t tested it in IE10 (too lazy to open vm), although I want it to work there too, so if it doesn’t let me know. :)

Enjoy! cubic-bezier.com


Chainvas: Make APIs chainable, enhance the canvas API

1 min read 0 comments Report broken page

It’s definitely not the first time someone writes a script to make the canvas API chainable, as a quick Google search will confirm.

However, I think my attempt has merit, because it’s not really focused in chaining canvas methods, but just about every API you use it on and because it’s super small, only 1KB!

You can find it here: chainvas

Enjoy!


CSS.coloratum: Convert and share CSS colors

2 min read 0 comments Report broken page

Whenever I wanted to convert a CSS named color to RGB, I used to open the CSS3 colors spec in a new tab, search in the page and copied the values. Every time it felt even more tedious. I didn’t want to search in long tables, I wanted to type the color somewhere and get the values back, in an easy to copy format. So, after yet another color lookup earlier today, I decided to scratch my own itch and do it myself.

Of course, I didn’t plan to include a whole database of CSS colors in the website. My idea was much simpler: Use the named color to draw a rectangle in a <canvas> and then read the R,G,B values through ctx.getImageData().

I got the core functionality done in under 10 minutes, so I started adding stuff. I added a hex and HSL representation, I used canvas.toDataURL() to get a data URI of the rectangle and use it as a dynamic favicon*, I made the colors sharable and bookmarkable by using an old-fashioned hash. Also, I realized it actually supports any CSS supported color represenation by design, not just named colors.

Regarding the color conversions themselves, I took extra care to avoid redundancy. So values < 1 don’t have leading zeroes (.5 instead of 0.5) and when the hex color is in the format #xxyyzz it gets converted to #xyz. When it’s an RGBA color, it still converts it to hex, since those values will be supported in CSS4.

Since it’s for developers, I didn’t bother at all with fallbacks.

Cool stuff used:

  • HTML5: canvas, autofocus, output, oninput event, hashchange event
  • CSS3: gradients, media queries, box-sizing, background-clip, border-radius, shadows, RGBA
  • ES5: Array#map()
  • Selectors API

The reason the input’s border appears weird on Webkit is this long standing Webkit bug. Also, for some reason my nice dynamic favicons don’t display on Firefox, although they display fine in Webkit and Opera.

Enjoy: CSS.coloratum

Happy color sharing! Let me know of any problems or suggestions you may have.

PS: In case you’re wondering about the domain, I’ve had it for ages for another project and I thought it was quite fitting.

*Thanks to @milo for giving me the idea of using a dynamic favicon


A polyfill for HTML5 progress element, the obsessive perfectionist way

6 min read 0 comments Report broken page

Yesterday, for some reason I don’t remember, I was looking once more at Paul Irish’s excellent list of polyfills on Github. I was really surprised to see that there are none for the <progress> element. It seemed really simple: Easy to fake with CSS and only 4 IDL attributes (value, max, position and labels). “Hey, it sounds fun and easy, I’ll do it!”, I thought. I have no idea how in only 1 day this turned into “OMG, my brain is going to explode”. I’ve documented below all the pitfalls I faced. And don’t worry, it has a happy ending: I did finish it. And published it. So, if you’re not interested in long geeky stories, just jump straight to its page.

First things first: Controlling the width of the value bar

Most progress bars out there use 2 elements: One for the container and one for the value bar. I was pretty stubborn about not using an extra element. I wanted to use pseudo-elements instead and keep the DOM tree as clean as I found it. And there it was, the first problem: How to set the width?

CSS3 attr() and calc() are hardly supported and attr() is not even allowed in calc(), so I quickly realized that a pure CSS solution was out of the question. However, if I used JavaScript, how would I set a different width for every progress::before? You can’t set that in an inline style, and assigning every <progress> element an ID and adding separate rules seems a bit too intrusive to me. Think about it for a second, what would you do?

I realized I had to control the width of the pseudo-element through CSS properties of the parent container somehow. And then it dawned on me: If the pseudoelement has display:block, it will automatically get the parent width, minus the padding and borders. There it was, this was my solution. I just had to set padding-right accordingly, so that the value bar gets the width it needs to be! And I had already given it box-sizing: border-box, as it was in Webkit’s UA stylesheet, so I didn’t have to worry about padding changing the width of the element. The first problem was solved.

Becoming dynamic

The static part was quite easy indeed. Selecting all <progress> elements and using their attributes to set an appropriate padding-right was pretty much run of the mill. But that wasn’t enough. What happens if you set the properties through script? What happens if you set the attributes? The progress bar should update accordingly, it had to be dynamic. A static progress bar is not much of a fallback. It might be acceptable for <meter>, since in most interfaces it’s used in a static way. But a progress bar needs to change in order to show um, progress.

First step was adding the properties that are in its DOM Interface. “Easy, I’ll add them to the prototype” thought my naïve self. So, I needed to find which prototype, I didn’t want to add them in every HTML element of course. So I eagerly typed Object.prototype.toString.call(document.createElement('progress')) in Firebug’s console and it slapped me in the face with an '[object HTMLUnknownElement]'. D’oh! I had forgotten that unknown elements share a common prototype named like that. So, I had to add them to each one individually. I hated that, but since it was the only way, I did it and moved on.

Of course, I didn’t just assign a static value to them, otherwise they wouldn’t solve much: The progress bar would still be static. I assigned getters and setters that used the value and max attributes to return what they should. Assigning getters and setters to a property is a whole new problem by itself, as some browsers use __defineGetter__/__defineSetter__ and some others the ES5 standard Object.defineProperty. But I had solved that one before, so it didn’t slow me down.

The getters and setters solved the issue one-way only: If you set the properties, the progress bar and its attributes would be updated. That would be enough for most authors using the polyfill, but no, I wanted it to be perfect. “If you change the attributes, the progress bar and its properties should too!” my annoyingly pedantic inner self insisted. “And what if you dynamically add more <progress> elements?”.

There are two ways to do stuff when attributes change and elements get added: Polling and mutation events. The advantage of polling is its perfect browser support, which comes at a big cost: It’s horrible performance-wise. Also, polling introduces a delay that could be unacceptable in some cases, especially considering how short the duration of some progress bar use cases is. So, I went with mutation events, even though they are deprecated (seriously W3C? deprecating something, without providing a solid alternative??) and don’t have perfect browser support. After all, it was the only way (I don’t consider polling a real option in this case).

Styling

After messing around a little, it seemed to work great in Opera 10.63 and Firefox 5, which I had open for my tests. It was time to write some unit tests and check it out in more browsers. Instead, I opted to style it, as a desperate attempt to delay my confrontation with IE8 a bit longer (and for good reason, as it turned out later). Given that CSS is kinda my specialization, I expected styling to be a piece of cake and even relaxing. Instead, it came with it’s fair share of trouble and hard dilemmas.

If you notice the native progress bars in OSX, you will see that they use gradients. I mocked up something similar with CSS gradients, which wasn’t easy, as I wanted to keep the hue/saturation information in the background-color only, for easy modifications and Webkit uses a regular gradient with color stops that have different hues and saturations. And then I realised that this was not going to show up at all in IE8-IE9, which were 2 major browsers that my polyfill would target. No gradient may be acceptable in determinate progress bars, but it’s not an option in indeterminate ones: Scrolling diagonal stripes is the convention and there’s no other way to communicate this status to the average user.

So I decided to go with the old way of using raster images for gradients (through a data URI). Another painful slap in the face was when I realized that those moving stripes need to be semi-transparent. To do that, my options were:

  • CSS3 animations - no good in my case, as it’s crucial to show up and their browser support isn’t that good
  • SVG with SMIL - Much better browser support than CSS3 animations, but still no go in IE
  • APNG - Only supported by Firefox and Opera, even after all these years

I happened to be chatting with Tab Atkins at the moment, and he suggested I go with plain ol’ GIFs. I was originally negative, but after thinking about it I realized that antialiasing is not that crucial in 45deg stripes, especially when they’re moving. I tried it, I liked the result, so I kept it. Phew, that one was easy.

The IE8 nightmare

After spending a few hours tweaking the gradients and the CSS (yes, hours. I said I’m an obsessive perfectionist, didn’t I?) I finally wrote some unit tests and fired up Virtualbox to test with IE8. I prepared myself for the worst, and secretly hoped I’d be pleasantly surprised. Instead, I faced a developer’s worst nightmare. Two words: Stack overflow.

The culprit was a classic IE bug with DOM properties and HTML attrtibutes that I had blissfully forgotten: IE thinks they’re the same. I had added getters and setters (or etters, as I like to call both) to the max and value properties which used the max and value attributes, resulting in infinite recursion in IE8.

This was the hardest of all problems, and I never completely solved it: A few unit tests still fail in IE8 because of it, although there’s no infinite recursion any more. Luckily, this bug was fixed in IE9, so the polyfill works flawlessly there.

My first idea was the obvious one: to duplicate the values somewhere. In a lookup table, in another property, somewhere. I didn’t quite like the idea, so I kept brainstorming. And then it dawned on me. They’re already duplicated somewhere, and not only it’s not redundant, but actually encouraged: in the WAI-ARIA attributes!

To clarify, when progress elements are natively supported, they already have built-in ARIA roles and attributes. However, when they’re not, you should add them yourself, if you want the control to be accessible. From my research, there was a progressbar role, and it required the attributes aria-valuemin, aria-valuemax, aria-valuenow and aria-labelledby. I implemented all but the latter, as it proved too much of a hassle for very few edge cases (how many people put IDs in their labels without using aria-labelledby themselves?). So, aria-valuemax was already duplicating max and aria-valuenow was duplicating value. I changed everything to use those instead.

After lots of head-scratching, IE-cursing and feeling that my brain was going to explode all over my laptop, I managed to kinda have it working. I knew in advance that some unit tests would fail, as it doesn’t support mutation events. I eventually gave up when I realized that the last unit test in the “static” category failed because getAttribute('max') returned null, since IE had completely removed the attribute from the DOM tree. It was the last straw and made me say “That’s it, I’m done with this piece of shit”.

Safari 5 craziness

After IE, it was Safari’s turn. I knew that I could only target Safari 5, as Safari 4 doesn’t support etters on DOM elements and Safari 5.1 will probably support progress elements natively, since they’ve been in Webkit for ages. I launched Safari without fear. “How can it possibly not work in Safari? It will probably be fine, maybe just need a one or two little tweaks in the worst case”, I reassured myself thinking.

The progress bars were not even showing. At all. My first guess was that it was a one time rendering error. When it persisted after a few reloads, I opened the dev tools to see what the hell happened. I saw a series of errors like this:

<progress> is not allowed inside <label>. Content ignored. Unmatched encountered. Ignoring tag.

At first, I thought the problem was the label. So I made all labels external. And then still got the same errors for the <li>s. And every other element I tried. Even when I put them directly into the <body>, Safari complained that they are not allowed to be inside it! It turned out that this was a bug in a build of Webkit, and coincidentally, this build was the one Safari 5 uses.

There wasn’t much to think about in this one: They’re not in the DOM, so I can’t do anything about them. It’s mission impossible.

Happy(?) end

After IE8’s and Safari5’s cruel rejection, I was quite dispirited. IE8 had already caused me to make my code uglier and more verbose, and now Safari 5 flat out refuses to accept any treatment. It worked flawlessly in Firefox 3.5, but that didn’t cheer me up much. I decided that this has already taken up too much of my time. It’s now the community’s turn. Have any ideas about how further improvement? Maybe some more unit tests? I’ll be waiting for your pull requests! :) Github repo

Appendix: Why do some unit tests fail in browsers that natively support <progress>?

While developing this, I discovered 2 browser bugs: One in Webkit’s implementation and in for Opera’s. I plan to report these soon.


Change URL hash without page jump

1 min read 0 comments Report broken page

In modern complex layouts, sometimes the point where a hash will transport you to will be entirely different than the one you actually wanted. If you prevent the default event, you will save yourself from the page jump, but the hash won’t change either. You can accept the regular behavior and change scrollTop after the jump, but the user will still see a distracting flicker. Chris Coyier found a great workaround last year but it’s not meant for every case.

A different solution

Turns out we can take advantage of the History API to do that quite easily. It’s just one line of code:

history.pushState(null, null, ‘#myhash’);

and we can combine it with the old method of setting location.hash to cater for older browsers as well:

if(history.pushState) { history.pushState(null, null, ‘#myhash’); } else { location.hash = ‘#myhash’; }

Browser support?

The History API is supported by:

  • Firefox 4+
  • Safari 5+
  • Chrome 8+
  • Coming soon in Opera

Enjoy :)