Being prompted on the Google home page to “Install Google Chrome” for “A faster way to browse the web” while I am already using Google Chrome for Mac: epic browser detection fail.
Anyway, Chrome definitely is a faster way to browse the Web. It’s amazing!
In a current project at Shepherd Interactive, certain page elements were designed with
background gradients.
Given the desire to minimize
the need for externally-loaded background images wherever possible, I thought this would be a great opportunity to play around with WebKit's
proposed CSS Gradients, which are natively supported
by Safari, Chrome, and other WebKit-based browsers. In being a WebKit proposal, however, CSS Gradients are not (yet) natively supported in
other rendering engines as used by Firefox, Opera, and Internet Explorer.
CSS Gradients via Canvas provides a subset of WebKit's CSS Gradients proposal
for browsers that implement the HTML5 canvas element.
To use, just include css-gradients-via-canvas.js (12KB) anywhere on the page (see examples below).
Unlike WebKit, this implementation does not currently allow gradients to be used for border images, list bullets, or generated content.
The script employs document.querySelectorAll()—it has no external dependencies
if this function is implemented; otherwise, it looks for the presence of jQuery, Prototype, or Sizzle to provide selector-querying functionality.
The implementation works in Firefox 2/3+ and Opera 9.64 (at least). Safari and Chrome have native support for CSS Gradients since they use WebKit, as already mentioned.
Beginning with version 3.6, CSS Gradients are also natively supported by Firefox and this implementation
will defer in such case; note that you will need to specify two separate background CSS properties, one with -webkit-gradient and another with -moz-linear/radial-gradient which has a different syntax).
This implementation does not work in Internet Explorer since IE does not support Canvas, although IE8 does support the data: URI scheme, which is a prerequisite
(see support detection method).
When/if Gears's Canvas API fully implements the HTML5 canvas specification, then this implementation
should be tweakable to work in IE8. In the mean time, rudimentary gradients may be achieved in IE by means of its non-standard
gradient filter.
CSS Gradients via Canvas works by parsing all stylesheets upon page load (DOMContentLoaded), and searches for all instances of CSS gradients being
used as background images. The source code for the external stylesheets is loaded via XMLHttpRequest—ensure that they are
cached by serving them with a far-future Expires header to avoid extra HTTP traffic.
The CSS selector associated with the gradient background image property is used to query all elements on the page; for each of the selected elements,
a canvas is created of the same size as the element's dimensions, and the specified gradients are drawn onto that canvas. Thereafter, the gradient image is
retrieved via canvas.toDataURL() and this data is supplied as the background-image for the element.
A few notes regarding interactivity with this implementation: CSS gradients will not be applied to elements dynamically added after DOMContentLoaded.
Additionally, each element that has a CSS gradient applied to it gets assigned
a method called refreshCSSGradient(); at any time, this method may be invoked to redraw the gradient on a given element.
This is especially useful (and necessary) when an element's size dynamically changes, for example as the result of some user interaction. Likewise, it is important
to note that it will not work to rely on event handlers to invoke refreshCSSGradient() on elements whose style is changed by CSS rules with pseudo-selectors like
:hover and :active; this is because event handlers are fired before the rule's style changes are applied to the element.
Toggling an element's class name by scripting is how you can assure that its style will be changed before calling refreshCSSGradient(). The
last example below demonstrates this.
Changelog
1.3 ():
Detecting native support in Firefox 3.6; it had only been detecting support for 3.6 alpha, which
had significantly different syntax. I ported the linear gradient examples over to use the new native Firefox
syntax, but am still working on the radial gradients; the syntax has changed a lot!
1.2 ():
Phong Nguyen raised an excellent point
in that stylesheets which don't contain any CSS Gradients should be ignored in order
to improve performance (in his case, for example, the jQuery UI
stylesheets are large and don't need to be parsed).
Now you can add class="no-css-gradients" to any
style or link element and that will prevent
this script from looking for CSS Gradients to apply with canvas.
1.1 ():
Now if cssGradientsViaCanvas.useCache is set to
true, the CSS rules containing gradients are cached in
sessionStorage instead of having to be re-parsed out of
the stylesheets each time a page loads. For this to work, there
must be implementations of JSON.stringify() and
JSON.parse() available (e.g. json2.js).
Ability to use
data: URIs for images is not explicitly detected since
testing for the presence of canvas.toDataURI() is
sufficient.
1.0.3 ():
Detecting support for native support for CSS Gradients in Firefox 3.6
1.0.2 ():
Now requiring that gradient(…) only be used with the
background-image property instead of with the
background shorthand properties since the
additional background-* properties are not parsed out.
Examples
The following two boxes are from WebKit's Background
Gradients Example (a couple browser-specific background properties are disabled in the first one):
It appears that your browser doesn't support CSS Gradients, neither natively nor via Canvas.
The gradients you see below are regular externally-loaded PNG images that demonstrate the CSS gradient effects; the gradients were generated from
this Canvas implementation of CSS Gradients (see browser support above).
Note I am currently in the process of porting the following WebKit radial gradients example over to the Firefox equivalents, which are significantly different!
Here is a bonus diagonal rainbow…but wait, there's more! Clicking on the element causes its width to increase and when it does, its gradient is adjusted (see notes above).
(Clicking will not have the desired effect because, again, it appears your browser is not supported.)
A couple years ago I learned of the University of Washington’s Computational Linguistics Master’s program and I was really interested. But since I had moved to Portland, it wasn’t feasible for me to attend classes—this is especially true now since I am employed here and got married a year ago.
For my birthday this year, my dad gave me one of the best presents ever: John McWhorter’s audio course “The Story of Human Language“; LaVonne and I couldn’t get enough of his lectures. I’m sad to say I’ve finished them, but listening to them re-peaked my interest in the academic study of Linguistics; so I meandered over to UW’s Computational Linguistics website and, to my shock, I found that the entire program can now be completed via online correspondence! I was so excited! I was already a couple months past the admission application deadline, but I contacted the department and got approval to apply. Now, a few weeks later, I have just received news that I have been accepted into the program! This is one of my dreams come true!
For some more background and the reasons why I’m excited about this program, I’ve included below the statement of purpose I wrote for the application. If everything works out, I will begin studying part-time this Fall while still being employed full-time at Shepherd Interactive. (Note: when talking about Open Scriptures below, I don’t mention the others who are working so hard alongside me—it’s true I started it, but now it’s “my project” only in the sense that I am but a part of it.)
Statement of Purpose for Application to UW Computational Linguistics Program
Using the computer to solve linguistic problems has been a core interest of mine for the past decade. As I studied and entered the workforce as a web application developer, I have studied linguistics and languages on the side. When I started my undergraduate studies at Seattle Pacific University, I was intending to create a self-designed major in computational linguistics, but I was disappointed to find that the faculty weren’t experienced enough in this area to advise me. So I made do by majoring in computer science and minoring in both linguistics and Spanish. I thoroughly enjoyed taking CS and linguistics courses in parallel, taking concepts in one and applying them in another, for example studying the Chomsky hierarchy in my syntax course for linguistics but then applying his concepts in my compiler design CS course. Furthermore, I used my web application development skills to create relevant applications along the way, like a syntax tree drawer and a popular IPA chart keyboard tool, and I also completed various linguistics assignments by publishing them on the Web.
Although I learned much from taking computer science and linguistics in parallel, I have missed out on the focused intersection of the two in the sub-field of natural language processing. It is my desire to satisfy my initial undergraduate computational linguistic aspirations in the Master’s program at the University of Washington.
With regard to applying what I would learn in the program, I am the founder of the Open Scriptures project, an initiative which seeks to interlink the various scriptural corpora and derivative datasets to create a Linked Data infrastructure for scripture, and on top of this foundation provide a platform that allows developers to build innovative applications on top of the data available. One of the key problem areas in this endeavor is the alignment of translated texts with their source manuscripts. I had been thinking to utilize collective intelligence to power the semantic interlinking of the texts, but I have come to realize that NLP will be necessary to achieve the desired results. The concepts and techniques I learn in the Master’s program would be directly applicable to my project.
I am an advanced Spanish speaker, and I have also taken one term each of French and Koiné Greek, and two terms of Biblical Hebrew. I am especially interested in Semitic languages and corpus linguistics of the Hebrew Tanakh and the Arabic Qur’an. I am studying Arabic on my own, and have attained a novice familiarity with the language. I desire that this Master’s program in computational linguistics would be a stepping stone to further graduate studies in the field.
To make multiple borders appear around an element, the traditional
approach has been to nest multiple elements and apply a different border to
each. For example, to put a rainbow border on an element:
I have rainbow borders!
This approach uses seven div elements. However, there is an
alternative that avoids the need for so many superfluous elements: the
new CSS3 box-shadow
property. A key feature of this property is that it allows for multiple shadows to be supplied at once:
box-shadow: none | <shadow> [ , <shadow> ]*
When multiple shadows are supplied, they can be positioned on top of each
other to create a multiple-border effect. Using the box-shadow
property in this way requires support for the "spread radius" value, and this
is not currently supported by WebKit (includes Safari and Chrome). However,
Firefox 3.5 (now available
as a preview release) does support
the box-shadow spread radius, and if
using that browser, the following example should look identical to the example
above:
I have rainbow borders!
Using box-shadow for multiple borders not only eliminates the need for extra markup,
it also allows the multiple borders to be easily rounded on corners simply by adding the
border-radius
property (see screenshot from Firefox 3.5):
I have rainbow borders with rounded corners!
To accomplish the above with multiple nested elements, you would have to
tediously increase the border-radius for each wrapped
element in order to get the corner arcs to fit together properly.
I suppose using box-shadow to implement borders is a kind of hack
(the technique requires setting margins because the shadows don't effect page flow),
but we're celebrating the compeltion of Firefox 3.5 by
showcasing hacks like these!
It would be great if multiple borders could simply be specified on a
border property just as is possible with box-shadow.
Each subsequent border defined could wrap around the previously defined borders.
The property could be defined:
border: none | <border> [ , <border> ]*
In any case, the box-shadow property still has a benefit of
allowing the borders to blend together by specifying the box-shadow's
blur radius (see screenshot from Firefox 3.5):
I have blended rainbow borders!
It's exciting to see how Mozilla is implementing bleeding-edge CSS features in Firefox
as we have become accustomed to from the WebKit team. Great work everyone!
Updates: Added note at end to respond to V1’s comment, and fixed the “awkward CSS syntax” which was actually a big typo (thanks Harmen).
The data: URI scheme is now supported by the most current version of every major browser, including Internet Explorer. Because of this I wanted to use CSS background images encoded with data: URIs in a current project at Shepherd Interactive. Why? The first rule of High Performance Websites is to Minimize HTTP Requests. By storing background images directly in the stylesheet only one HTTP request is then necessary to fetch the stylesheet and the images all at once. Furthermore, by giving that stylesheet a far-future cache expiration date the browser will never need to request it again.
However, while every browser vendor’s current version supports data: URIs, older browsers like MSIE 7 do not. Therefore it is necessary to also have fallback CSS rules to serve externally-referenced background images. I came up a way of doing this by utilizing the following script which I place as an inline script in the document head:
var data = new Image();
data.onload = data.onerror = function(){
if(this.width != 1 || this.height != 1)
document.documentElement.className += " no-data-uri";
}
data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
This script attempts to load a 1×1 pixel via a data: URI. If the onload callback fires and it detects that the image’s width and height are each a single pixel, then the browser supports data: URIs. Otherwise the browser does not support such URIs and a class name is added to the document root so that fallback CSS rules can be written, for example:
In this way, CSS rules can define background images that utilize data: URIs only for browsers that support them, while at the same time older browsers still render the content properly due to the fallback rules. Note that for browsers that support data: URIs, the fallback CSS rule above will never be applied and thus its externally-referenced background image will never be downloaded. However, if the browser does not support data: URIs, then the resources will essentially be downloaded twice, but that’s the price you pay for using an old browser. In any case, when the images are tiny (<1KB) then the overhead is minimal for non-supporting browsers, and your development process is greatly eased since you don’t have to hassle with creating image sprites (which are sometimes impossible anyway); those who use current browser versions will be rewarded as will the generations of Internet users to come.