Upping Your Type Game
The ultimate primer on web type for web developers by Jessica Hische.
Direct Link to Article — Permalink
jQuery Conference Portland 2013 has a limited number of regular tickets still available. Two days. Two tracks. Fresh speakers. Jun 13-14. $50 off for members of the jQuery Foundation. Join today and get your first year of fan dues paid for with purchase of both a training and conference ticket. Training provided by Bocoup on Jun 12. Use coupon code CSSTricks25off for $25 off.
Upping Your Type Game is a post from CSS-Tricks
Just One of Those Weird Things About CSS: Background on <body>
So you want to make the background of your website red eh? You'll probably put this in your CSS:
body { background: red; }Done!
Check out this Pen!You're going about your business and then all the sudden one day this happens:
Check out this Pen!What in the heck? Why is the red cut off like that? I put red as the background color on the body?
You did, but the fact that that red color floods the background is just a strange anomaly of CSS. The body element isn't actually as tall as the browser window. It's only as tall as the content inside it, just like a div or anything else.
See:
In the absence of a background on the html element, the body background will cover the page. If there is a background on the html element, the body background behaves just like any other element.
Somewhere along the line, a background-color got set on the html element.
Perhaps you're using normalize.css 2.1.1, which included setting the background to white on the html element to "Prevent system color scheme's background color being used in Firefox, IE, and Opera." This has since been reverted, presumably because it caused this issue too widely.
To "fix" it, just remove the background on the html element, or move whatever you want to "flood" always to the html element as its behavior is consistant.
jQuery Conference Portland 2013 has a limited number of regular tickets still available. Two days. Two tracks. Fresh speakers. Jun 13-14. $50 off for members of the jQuery Foundation. Join today and get your first year of fan dues paid for with purchase of both a training and conference ticket. Training provided by Bocoup on Jun 12. Use coupon code CSSTricks25off for $25 off.
Just One of Those Weird Things About CSS: Background on <body> is a post from CSS-Tricks
This Website Brought To You By…
I always wanted to write something on all the technologies that a website relies on in order to have been created and work. My attempts have so far failed because it spirals out of control so quickly. Kevin Kelly sums it up:
A web page relies on perhaps a hundred thousand other inventions, all needed for its birth and continued existence. There is no web page anywhere without the inventions of HTML code, without computer programming, without LEDs or cathode ray tubes, without solid state computer chips, without telephone lines, without long-distance signal repeaters, without electrical generators, without high-speed turbines, without stainless steel, iron smelters, and control of fire. None of these concrete inventions would exist without the elemental inventions of writing, of an alphabet, of hypertext links, of indexes, catalogs, archives, libraries and the scientific method itself. To recapitulate a web page you have to re-create all these other functions. You might as well remake modern society.
The article isn't about the web hardly at all, it's about the interconnectivity of tools and how far we'll be set back if that is disrupted. I enjoyed the term "upcreation tool." So many of the tools we use as web workers are tools in which to make more complex tools.
Direct Link to Article — Permalink
jQuery Conference Portland 2013 has a limited number of regular tickets still available. Two days. Two tracks. Fresh speakers. Jun 13-14. $50 off for members of the jQuery Foundation. Join today and get your first year of fan dues paid for with purchase of both a training and conference ticket. Training provided by Bocoup on Jun 12. Use coupon code CSSTricks25off for $25 off.
This Website Brought To You By… is a post from CSS-Tricks
Logic in Media Queries
Just in case you have brain farts about this constantly like I do.
IfThat's what media queries are: logical if statements. "If" these things are true about the browser, use the CSS inside.
AndThe keyword and.
@media (min-width: 600px) and (max-width: 800px) { html { background: red; } } OrComma separate.
@media (max-width: 600px), (min-width: 800px) { html { background: red; } }Technically these are treated like to separate media queries, but that is effectively and or.
NotReverse the logic with the keyword not.
@media not all and (max-width: 600px) { html { background: red; } }Just doing not (max-width: 600px) doesn't seem to work for me, hence the slightly funky syntax above. Perhaps someone can explain that to me. Note that not only works for the current media query, so if you comma separate, it only affects the media query it is within. Also note that not reverses the logic for the entire media query as a whole, not individual parts of it. not x and y = not (x and y) ≠ (not x) and y
ExclusiveTo ensure that only one media query is in effect at time, make the numbers (or whatever) such that that is possible. It may be easier to mentally manage them this way.
@media (max-width: 400px) { html { background: red; } } @media (min-width: 401px) and (max-width: 800px) { html { background: green; } } @media (min-width: 801px) { html { background: blue; } }Logically this is a bit like a switch statement, only without a simple way to do "if none of these match do this" like default.
OverridingThere is nothing preventing more than one media query from being true at the same time. It may be more efficient to use this in some cases rather than making them all exclusive.
@media (min-width: 400px) { html { background: red; } } @media (min-width: 600px) { html { background: green; } } @media (min-width: 800px) { html { background: blue; } }Media queries add no specificity to the selectors they contain, but source order still matters. The above will work because they are ordered correctly. Swap that order and at browser window widths above 800px the background would be red, perhaps unintuitively.
Mobile FirstYour small screen styles are in your regular screen CSS and then as the screen gets larger you override what you need to. So, min-width media queries in general.
html { background: red; } @media (min-width: 600px) { html { background: green; } } Desktop FirstYour large screen styles are in your regular screen CSS and then as the screen gets smaller you override what you need to. So, max-width media queries in general.
html { background: red; } @media (max-width: 600px) { html { background: green; } } Gettin WackyYou can be as complex as you want with this.
@media only screen and (min-width: 100px), not all and (min-width: 100px), not print and (min-height: 100px), (color), (min-height: 100px) and (max-height: 1000px), handheld and (orientation: landscape) { html { background: red; } }Note the only keyword was intended to prevent non-media-query supporting browsers to not load the stylesheet or use the styles. Not sure how useful that ever was / still is.
jQuery Conference Portland 2013 has a limited number of regular tickets still available. Two days. Two tracks. Fresh speakers. Jun 13-14. $50 off for members of the jQuery Foundation. Join today and get your first year of fan dues paid for with purchase of both a training and conference ticket. Training provided by Bocoup on Jun 12. Use coupon code CSSTricks25off for $25 off.
Logic in Media Queries is a post from CSS-Tricks
CSS-Tricks Chronicle XIII
I'll be speaking at the upcoming Front End Design Conference in Florida. If you have tickets, see you there! If not, sorry, this one is sold out.
I recently spoke at TXJS, and they recorded the talks, so mine and a bunch of others are available on their Vimeo channel.
Next week I head out for Graves Mountain, as I do every year. So this week I'm planning for that, both getting ready for it as well as getting ready to be unplugged for the week.
ShopTalk is going strong! We have lots of great guests lined up. We've recorded a show in advance to air while I'm away at Graves. I'm sure we'll have a show every week for a very long time to come.
Recent shows include Ben Frain, Pam Selle, and Ben Schwarz.
CodePen is going strong as well. The team has made the huge leap of taking it full time. It's been a touch slow, but it's because both Tim and I moved across the country (me to Milwaukee, WI) and we've been settling in a bit. We're also working on big new features. There will be little new stuff coming here and there, but a lot of time has been sunk into big stuff that'll take a bit to get out.
The Patten Rodeo is back as well, in Season Two.
There are also CodePen PENS now, as well as stickers, and get get both if you order a T-Shirt.
Kern and Burn have a book called Conversations With Design Entrepreneurs and there is a bit of an interview with me in there. I got the book and it is super nice. One of the nicest feeling and reading books I have.
I have a few new articles on The Pastry Box Project. One is a story of a person opening a mustard packet and... well just take of that one what you will. The other is the only bit of life advice I have to offer.
I have some ideas burning for new stuff for The Lodge so I'll be launching into that the next few months. Nothing to share yet, but I'll let you know. I also have a nice list cooking for CSS-Tricks v11. It probably won't be a huge redesign, but more re-align-y focusing on enhanced functionality.
jQuery Conference Portland 2013 has a limited number of regular tickets still available. Two days. Two tracks. Fresh speakers. Jun 13-14. $50 off for members of the jQuery Foundation. Join today and get your first year of fan dues paid for with purchase of both a training and conference ticket. Training provided by Bocoup on Jun 12. Use coupon code CSSTricks25off for $25 off.
CSS-Tricks Chronicle XIII is a post from CSS-Tricks
The Design of Code: Organizing JavaScript
Great design is a product of care and attention applied to areas that matter, resulting in a useful, understandable, and hopefully beautiful user interface. But don’t be fooled into thinking that design is left only for designers.
There is a lot of design in code, and I don’t mean code that builds the user interface—I mean the design of code.
Well-designed code is much easier to maintain, optimize, and extend, making for more efficient developers. That means more focus and energy can be spent on building great things, which makes everyone happy—users, developers, and stakeholders.
There are three high-level, language-agnostic aspects to code design that are particularly important.
- System architecture—The basic layout of the codebase. Rules that govern how various components, such as models, views, and controllers, interact with each other.
- Maintainability—How well can the code be improved and extended?
- Reusability—How reusable are the application’s components? How easily can each implementation of a component be customized?
In looser languages, specifically JavaScript, it takes a bit of discipline to write well-designed code. The JavaScript environment is so forgiving that it’s easy to throw bits and pieces everywhere and still have things work. Establishing system architecture early (and sticking to it!) provides constraints to your codebase, ensuring consistency throughout.
One approach I’m fond of consists of a tried-and-true software design pattern, the module pattern, whose extensible structure lends itself to a solid system architecture and a maintainable codebase. I like building modules within a jQuery plugin, which makes for beautiful reusability, provides robust options, and exposes a well-crafted API.
Below, I’ll walk through how to craft your code into well-organized components that can be reused in projects to come.
The module patternThere are a lot of design patterns out there, and equally as many resources on them. Addy Osmani wrote an amazing (free!) book on design patterns in JavaScript, which I highly recommend to developers of all levels.
The module pattern is a simple structural foundation that can help keep your code clean and organized. A “module” is just a standard object literal containing methods and properties, and that simplicity is the best thing about this pattern: even someone unfamiliar with traditional software design patterns would be able to look at the code and instantly understand how it works.
In applications that use this pattern, each component gets its own distinct module. For example, to build autocomplete functionality, you’d create a module for the textfield and a module for the results list. These two modules would work together, but the textfield code wouldn’t touch the results list code, and vice versa.
That decoupling of components is why the module pattern is great for building solid system architecture. Relationships within the application are well-defined; anything related to the textfield is managed by the textfield module, not strewn throughout the codebase—resulting in clear code.
Another benefit of module-based organization is that it is inherently maintainable. Modules can be improved and optimized independently without affecting any other part of the application.
I used the module pattern for the basic structure of jPanelMenu, the jQuery plugin I built for off-canvas menu systems. I’ll use that as an example to illustrate the process of building a module.
Building a moduleTo begin, I define three methods and a property that are used to manage the interactions of the menu system.
var jpm = { animated: true, openMenu: function( ) { … this.setMenuStyle( ); }, closeMenu: function( ) { … this.setMenuStyle( ); }, setMenuStyle: function( ) { … } };The idea is to break down code into the smallest, most reusable bits possible. I could have written just one toggleMenu( ) method, but creating distinct openMenu( ) and closeMenu( ) methods provides more control and reusability within the module.
Notice that calls to module methods and properties from within the module itself (such as the calls to setMenuStyle( )) are prefixed with the this keyword—that’s how modules access their own members.
That’s the basic structure of a module. You can continue to add methods and properties as needed, but it doesn’t get any more complex than that. After the structural foundations are in place, the reusability layer—options and an exposed API—can be built on top.
jQuery pluginsThe third aspect of well-designed code is probably the most crucial: reusability. This section comes with a caveat. While there are obviously ways to build and implement reusable components in raw JavaScript (we’re about 90 percent of the way there with our module above), I prefer to build jQuery plugins for more complex things, for a few reasons.
Most importantly, it’s a form of unobtrusive communication. If you used jQuery to build a component, you should make that obvious to those implementing it. Building the component as a jQuery plugin is a great way to say that jQuery is required.
In addition, the implementation code will be consistent with the rest of the jQuery-based project code. That’s good for aesthetic reasons, but it also means (to an extent) that developers can predict how to interact with the plugin without too much research. Just one more way to build a better developer interface.
Before you begin building a jQuery plugin, ensure that the plugin does not conflict with other JavaScript libraries using the $ notation. That’s a lot simpler than it sounds—just wrap your plugin code like so:
(function($) { // jQuery plugin code here })(jQuery);Next, we set up our plugin and drop our previously built module code inside. A plugin is just a method defined on the jQuery ($) object.
(function($) { $.jPanelMenu = function( ) { var jpm = { animated: true, openMenu: function( ) { … this.setMenuStyle( ); }, closeMenu: function( ) { … this.setMenuStyle( ); }, setMenuStyle: function( ) { … } }; }; })(jQuery);All it takes to use the plugin is a call to the function you just created.
var jpm = $.jPanelMenu( ); OptionsOptions are essential to any truly reusable plugin because they allow for customizations to each implementation. Every project brings with it a slew of design styles, interaction types, and content structures. Customizable options help ensure that you can adapt the plugin to fit within those project constraints.
It’s best practice to provide good default values for your options. The easiest way to do that is to use jQuery’s $.extend( ) method, which accepts (at least) two arguments.
As the first argument of $.extend( ), define an object with all available options and their default values. As the second argument, pass through the passed-in options. This will merge the two objects, overriding the defaults with any passed-in options.
(function($) { $.jPanelMenu = function(options) { var jpm = { options: $.extend({ 'animated': true, 'duration': 500, 'direction': 'left' }, options), openMenu: function( ) { … this.setMenuStyle( ); }, closeMenu: function( ) { … this.setMenuStyle( ); }, setMenuStyle: function( ) { … } }; }; })(jQuery);Beyond providing good defaults, options become almost self-documenting—someone can look at the code and see all of the available options immediately.
Expose as many options as is feasible. The customization will help in future implementations, and flexibility never hurts.
APIOptions are terrific ways to customize how a plugin works. An API, on the other hand, enables extensions to the plugin’s functionality by exposing methods and properties for the implementation code to take advantage of.
While it’s great to expose as much as possible through an API, the outside world shouldn’t have access to all internal methods and properties. Ideally, you should expose only the elements that will be used.
In our example, the exposed API should include calls to open and close the menu, but nothing else. The internal setMenuStyle( ) method runs when the menu opens and closes, but the public doesn’t need access to it.
To expose an API, return an object with any desired methods and properties at the end of the plugin code. You can even map returned methods and properties to those within the module code—this is where the beautiful organization of the module pattern really shines.
(function($) { $.jPanelMenu = function(options) { var jpm = { options: $.extend({ 'animated': true, 'duration': 500, 'direction': 'left' }, options), openMenu: function( ) { … this.setMenuStyle( ); }, closeMenu: function( ) { … this.setMenuStyle( ); }, setMenuStyle: function( ) { … } }; return { open: jpm.openMenu, close: jpm.closeMenu, someComplexMethod: function( ) { … } }; }; })(jQuery);API methods and properties will be available through the object returned from the plugin initialization.
var jpm = $.jPanelMenu({ duration: 1000, … }); jpm.open( ); Polishing developer interfacesWith just a few simple constructs and guidelines, we’ve built ourselves a reusable, extensible plugin that will help make our lives easier. Like any part of what we do, experiment with this structure to see if it works for you, your team, and your workflow.
Whenever I find myself building something with a potential for reuse, I break it out into a module-based jQuery plugin. The best part about this approach is that it forces you to use—and test—the code you write. By using something as you build it, you’ll quickly identify strengths, discover shortcomings, and plan changes.
This process leads to battle-tested code ready for open-source contributions, or to be sold and distributed. I’ve released my (mostly) polished plugins as open-source projects on GitHub.
Even if you aren’t building something to be released in the wild, it’s still important to think about the design of your code. Your future self will thank you.
Writing Testable JavaScript
We’ve all been there: that bit of JavaScript functionality that started out as just a handful of lines grows to a dozen, then two dozen, then more. Along the way, a function picks up a few more arguments; a conditional picks up a few more conditions. And then one day, the bug report comes in: something’s broken, and it’s up to us to untangle the mess.
As we ask our client-side code to take on more and more responsibilities—indeed, whole applications are living largely in the browser these days—two things are becoming clear. One, we can’t just point and click our way through testing that things are working as we expect; automated tests are key to having confidence in our code. Two, we’re probably going to have to change how we write our code in order to make it possible to write tests.
Really, we need to change how we code? Yes—because even if we know that automated tests are a good thing, most of us are probably only able to write integration tests right now. Integration tests are valuable because they focus on how the pieces of an application work together, but what they don’t do is tell us whether individual units of functionality are behaving as expected.
That’s where unit testing comes in. And we’ll have a very hard time writing unit tests until we start writing testable JavaScript.
Unit vs. integration: what’s the difference?Writing integration tests is usually fairly straightforward: we simply write code that describes how a user interacts with our app, and what the user should expect to see as she does. Selenium is a popular tool for automating browsers. Capybara for Ruby makes it easy to talk to Selenium, and there are plenty of tools for other languages, too.
Here’s an integration test for a portion of a search app:
def test_search fill_in('q', :with => 'cat') find('.btn').click assert( find('#results li').has_content?('cat'), 'Search results are shown' ) assert( page.has_no_selector?('#results li.no-results'), 'No results is not shown' ) endWhereas an integration test is interested in a user’s interaction with an app, a unit test is narrowly focused on a small piece of code:
When I call a function with a certain input, do I receive the expected output?Apps that are written in a traditional procedural style can be very difficult to unit test—and difficult to maintain, debug, and extend, too. But if we write our code with our future unit testing needs in mind, we will not only find that writing the tests becomes more straightforward than we might have expected, but also that we’ll simply write better code, too.
To see what I’m talking about, let’s take a look at a simple search app:

When a user enters a search term, the app sends an XHR to the server for the corresponding data. When the server responds with the data, formatted as JSON, the app takes that data and displays it on the page, using client-side templating. A user can click on a search result to indicate that he “likes” it; when this happens, the name of the person he liked is added to the “Liked” list on the right-hand side.
A “traditional” JavaScript implementation of this app might look like this:
var tmplCache = {}; function loadTemplate (name) { if (!tmplCache[name]) { tmplCache[name] = $.get('/templates/' + name); } return tmplCache[name]; } $(function () { var resultsList = $('#results'); var liked = $('#liked'); var pending = false; $('#searchForm').on('submit', function (e) { e.preventDefault(); if (pending) { return; } var form = $(this); var query = $.trim( form.find('input[name="q"]').val() ); if (!query) { return; } pending = true; $.ajax('/data/search.json', { data : { q: query }, dataType : 'json', success : function (data) { loadTemplate('people-detailed.tmpl').then(function (t) { var tmpl = _.template(t); resultsList.html( tmpl({ people : data.results }) ); pending = false; }); } }); $('<li>', { 'class' : 'pending', html : 'Searching …' }).appendTo( resultsList.empty() ); }); resultsList.on('click', '.like', function (e) { e.preventDefault(); var name = $(this).closest('li').find('h2').text(); liked.find('.no-results').remove(); $('<li>', { text: name }).appendTo(liked); }); });My friend Adam Sontag calls this Choose Your Own Adventure code—on any given line, we might be dealing with presentation, or data, or user interaction, or application state. Who knows! It’s easy enough to write integration tests for this kind of code, but it’s hard to test individual units of functionality.
What makes it hard? Four things:
- A general lack of structure; almost everything happens in a $(document).ready() callback, and then in anonymous functions that can’t be tested because they aren’t exposed.
- Complex functions; if a function is more than 10 lines, like the submit handler, it’s highly likely that it’s doing too much.
- Hidden or shared state; for example, since pending is in a closure, there’s no way to test whether the pending state is set correctly.
- Tight coupling; for example, a $.ajax success handler shouldn’t need direct access to the DOM.
The first step toward solving this is to take a less tangled approach to our code, breaking it up into a few different areas of responsibility:
- Presentation and interaction
- Data management and persistence
- Overall application state
- Setup and glue code to make the pieces work together
In the “traditional” implementation shown above, these four categories are intermingled—on one line we’re dealing with presentation, and two lines later we might be communicating with the server.

While we can absolutely write integration tests for this code—and we should!—writing unit tests for it is pretty difficult. In our functional tests, we can make assertions such as “when a user searches for something, she should see the appropriate results,” but we can’t get much more specific. If something goes wrong, we’ll have to track down exactly where it went wrong, and our functional tests won’t help much with that.
If we rethink how we write our code, though, we can write unit tests that will give us better insight into where things went wrong, and also help us end up with code that’s easier to reuse, maintain, and extend.
Our new code will follow a few guiding principles:
- Represent each distinct piece of behavior as a separate object that falls into one of the four areas of responsibility and doesn’t need to know about other objects. This will help us avoid creating tangled code.
- Support configurability, rather than hard-coding things. This will prevent us from replicating our entire HTML environment in order to write our tests.
- Keep our objects’ methods simple and brief. This will help us keep our tests simple and our code easy to read.
- Use constructor functions to create instances of objects. This will make it possible to create “clean” copies of each piece of code for the sake of testing.
To start with, we need to figure out how we’ll break our application into different pieces. We’ll have three pieces dedicated to presentation and interaction: the Search Form, the Search Results, and the Likes Box.

We’ll also have a piece dedicated to fetching data from the server and a piece dedicated to gluing everything together.
Let’s start by looking at one of the simplest pieces of our application: the Likes Box. In the original version of the app, this code was responsible for updating the Likes Box:
var liked = $('#liked'); var resultsList = $('#results'); // ... resultsList.on('click', '.like', function (e) { e.preventDefault(); var name = $(this).closest('li').find('h2').text(); liked.find( '.no-results' ).remove(); $('<li>', { text: name }).appendTo(liked); });The Search Results piece is completely intertwined with the Likes Box piece and needs to know a lot about its markup. A much better and more testable approach would be to create a Likes Box object that’s responsible for manipulating the DOM related to the Likes Box:
var Likes = function (el) { this.el = $(el); return this; }; Likes.prototype.add = function (name) { this.el.find('.no-results').remove(); $('<li>', { text: name }).appendTo(this.el); };This code provides a constructor function that creates a new instance of a Likes Box. The instance that’s created has an .add() method, which we can use to add new results. We can write a couple of tests to prove that it works:
var ul; setup(function(){ ul = $('<ul><li class="no-results"></li></ul>'); }); test('constructor', function () { var l = new Likes(ul); assert(l); }); test('adding a name', function () { var l = new Likes(ul); l.add('Brendan Eich'); assert.equal(ul.find('li').length, 1); assert.equal(ul.find('li').first().html(), 'Brendan Eich'); assert.equal(ul.find('li.no-results').length, 0); });Not so hard, is it? Here we’re using Mocha as the test framework, and Chai as the assertion library. Mocha provides the test and setup functions; Chai provides assert. There are plenty of other test frameworks and assertion libraries to choose from, but for the sake of an introduction, I find these two work well. You should find the one that works best for you and your project—aside from Mocha, QUnit is popular, and Intern is a new framework that shows a lot of promise.
Our test code starts out by creating an element that we’ll use as the container for our Likes Box. Then, it runs two tests: one is a sanity check to make sure we can make a Likes Box; the other is a test to ensure that our .add() method has the desired effect. With these tests in place, we can safely refactor the code for our Likes Box, and be confident that we’ll know if we break anything.
Our new application code can now look like this:
var liked = new Likes('#liked'); var resultsList = $('#results'); // ... resultsList.on('click', '.like', function (e) { e.preventDefault(); var name = $(this).closest('li').find('h2').text(); liked.add(name); });The Search Results piece is more complex than the Likes Box, but let’s take a stab at refactoring that, too. Just as we created an .add() method on the Likes Box, we also want to create methods for interacting with the Search Results. We’ll want a way to add new results, as well as a way to “broadcast” to the rest of the app when things happen within the Search Results—for example, when someone likes a result.
var SearchResults = function (el) { this.el = $(el); this.el.on( 'click', '.btn.like', _.bind(this._handleClick, this) ); }; SearchResults.prototype.setResults = function (results) { var templateRequest = $.get('people-detailed.tmpl'); templateRequest.then( _.bind(this._populate, this, results) ); }; SearchResults.prototype._handleClick = function (evt) { var name = $(evt.target).closest('li.result').attr('data-name'); $(document).trigger('like', [ name ]); }; SearchResults.prototype._populate = function (results, tmpl) { var html = _.template(tmpl, { people: results }); this.el.html(html); };Now, our old app code for managing the interaction between Search Results and the Likes Box could look like this:
var liked = new Likes('#liked'); var resultsList = new SearchResults('#results'); // ... $(document).on('like', function (evt, name) { liked.add(name); })It’s much simpler and less entangled, because we’re using the document as a global message bus, and passing messages through it so individual components don’t need to know about each other. (Note that in a real app, we’d use something like Backbone or the RSVP library to manage events. We’re just triggering on document to keep things simple here.) We’re also hiding all the dirty work—such as finding the name of the person who was liked—inside the Search Results object, rather than having it muddy up our application code. The best part: we can now write tests to prove that our Search Results object works as we expect:
var ul; var data = [ /* fake data here */ ]; setup(function () { ul = $('<ul><li class="no-results"></li></ul>'); }); test('constructor', function () { var sr = new SearchResults(ul); assert(sr); }); test('display received results', function () { var sr = new SearchResults(ul); sr.setResults(data); assert.equal(ul.find('.no-results').length, 0); assert.equal(ul.find('li.result').length, data.length); assert.equal( ul.find('li.result').first().attr('data-name'), data[0].name ); }); test('announce likes', function() { var sr = new SearchResults(ul); var flag; var spy = function () { flag = [].slice.call(arguments); }; sr.setResults(data); $(document).on('like', spy); ul.find('li').first().find('.like.btn').click(); assert(flag, 'event handler called'); assert.equal(flag[1], data[0].name, 'event handler receives data' ); });The interaction with the server is another interesting piece to consider. The original code included a direct $.ajax() request, and the callback interacted directly with the DOM:
$.ajax('/data/search.json', { data : { q: query }, dataType : 'json', success : function( data ) { loadTemplate('people-detailed.tmpl').then(function(t) { var tmpl = _.template( t ); resultsList.html( tmpl({ people : data.results }) ); pending = false; }); } });Again, this is difficult to write a unit test for, because so many different things are happening in just a few lines of code. We can restructure the data portion of our application as an object of its own:
var SearchData = function () { }; SearchData.prototype.fetch = function (query) { var dfd; if (!query) { dfd = $.Deferred(); dfd.resolve([]); return dfd.promise(); } return $.ajax( '/data/search.json', { data : { q: query }, dataType : 'json' }).pipe(function( resp ) { return resp.results; }); };Now, we can change our code for getting the results onto the page:
var resultsList = new SearchResults('#results'); var searchData = new SearchData(); // ... searchData.fetch(query).then(resultsList.setResults);Again, we’ve dramatically simplified our application code, and isolated the complexity within the Search Data object, rather than having it live in our main application code. We’ve also made our search interface testable, though there are a couple caveats to bear in mind when testing code that interacts with the server.
The first is that we don’t want to actually interact with the server—to do so would be to reenter the world of integration tests, and because we’re responsible developers, we already have tests that ensure the server does the right thing, right? Instead, we want to “mock” the interaction with the server, which we can do using the Sinon library. The second caveat is that we should also test non-ideal paths, such as an empty query.
test('constructor', function () { var sd = new SearchData(); assert(sd); }); suite('fetch', function () { var xhr, requests; setup(function () { requests = []; xhr = sinon.useFakeXMLHttpRequest(); xhr.onCreate = function (req) { requests.push(req); }; }); teardown(function () { xhr.restore(); }); test('fetches from correct URL', function () { var sd = new SearchData(); sd.fetch('cat'); assert.equal(requests[0].url, '/data/search.json?q=cat'); }); test('returns a promise', function () { var sd = new SearchData(); var req = sd.fetch('cat'); assert.isFunction(req.then); }); test('no request if no query', function () { var sd = new SearchData(); var req = sd.fetch(); assert.equal(requests.length, 0); }); test('return a promise even if no query', function () { var sd = new SearchData(); var req = sd.fetch(); assert.isFunction( req.then ); }); test('no query promise resolves with empty array', function () { var sd = new SearchData(); var req = sd.fetch(); var spy = sinon.spy(); req.then(spy); assert.deepEqual(spy.args[0][0], []); }); test('returns contents of results property of the response', function () { var sd = new SearchData(); var req = sd.fetch('cat'); var spy = sinon.spy(); requests[0].respond( 200, { 'Content-type': 'text/json' }, JSON.stringify({ results: [ 1, 2, 3 ] }) ); req.then(spy); assert.deepEqual(spy.args[0][0], [ 1, 2, 3 ]); }); });For the sake of brevity, I’ve left out the refactoring of the Search Form, and also simplified some of the other refactorings and tests, but you can see a finished version of the app here if you’re interested.
When we’re done rewriting our application using testable JavaScript patterns, we end up with something much cleaner than what we started with:
$(function() { var pending = false; var searchForm = new SearchForm('#searchForm'); var searchResults = new SearchResults('#results'); var likes = new Likes('#liked'); var searchData = new SearchData(); $(document).on('search', function (event, query) { if (pending) { return; } pending = true; searchData.fetch(query).then(function (results) { searchResults.setResults(results); pending = false; }); searchResults.pending(); }); $(document).on('like', function (evt, name) { likes.add(name); }); });Even more important than our much cleaner application code, though, is the fact that we end up with a codebase that is thoroughly tested. That means we can safely refactor it and add to it without the fear of breaking things. We can even write new tests as we find new issues, and then write the code that makes those tests pass.
Testing makes life easier in the long runIt’s easy to look at all of this and say, “Wait, you want me to write more code to do the same job?”
The thing is, there are a few inescapable facts of life about Making Things On The Internet. You will spend time designing an approach to a problem. You will test your solution, whether by clicking around in a browser, writing automated tests, or—shudder—letting your users do your testing for you in production. You will make changes to your code, and other people will use your code. Finally: there will be bugs, no matter how many tests you write.
The thing about testing is that while it might require a bit more time at the outset, it really does save time in the long run. You’ll be patting yourself on the back the first time a test you wrote catches a bug before it finds its way into production. You’ll be grateful, too, when you have a system in place that can prove that your bug fix really does fix a bug that slips through.
Additional resourcesThis article just scratches the surface of JavaScript testing, but if you’d like to learn more, check out:
- My presentation from the 2012 Full Frontal conference in Brighton, UK.
- Grunt, a tool that helps automate the testing process and lots of other things.
- Test-Driven JavaScript Development by Christian Johansen, the creator of the Sinon library. It is a dense but informative examination of the practice of testing JavaScript.
This week's sponsor: Igloo Software
If SharePoint and Facebook had a baby, it would look a lot like Igloo (without the recessive balding or oversharing tendencies). Hosted, managed and with a major release every 90 days, Igloo is a whitelabel content platform built for today’s needs. We also have Sandwich Video.
Prepros
Is an open-source app modeled after CodeKit. Prepros runs on Windows where CodeKit is Mac only. From people who have tried it, it seems good.
Direct Link to Article — Permalink
jQuery Conference Portland 2013 has a limited number of regular tickets still available. Two days. Two tracks. Fresh speakers. Jun 13-14. $50 off for members of the jQuery Foundation. Join today and get your first year of fan dues paid for with purchase of both a training and conference ticket. Training provided by Bocoup on Jun 12. Use coupon code CSSTricks25off for $25 off.
Prepros is a post from CSS-Tricks
Chrome’s requestAutocomplete()
Auto-filling forms is nice because it saves time and is less prone to user error. Even better is not even needing to see a form in the first place.
Direct Link to Article — Permalink
jQuery Conference Portland 2013 has a limited number of regular tickets still available. Two days. Two tracks. Fresh speakers. Jun 13-14. $50 off for members of the jQuery Foundation. Join today and get your first year of fan dues paid for with purchase of both a training and conference ticket. Training provided by Bocoup on Jun 12. Use coupon code CSSTricks25off for $25 off.
Chrome’s requestAutocomplete() is a post from CSS-Tricks
Replace the Image in an <img> with CSS
The following is a guest post by Marcel Shields. Marcel in a difficult place where he needed to change the image on a page but didn't have access to the HTML. Rare, but I'm sure we've all be in weird situations like this. He explains how he managed to replace that image without needing to access the HTML or JavaScript. Also turns out to be a pretty good way to replace anything with an image.
I just wanted to share something I found really cool about using CSS box-sizing. Chris wrote a really good introduction a few years back if you're not familiar with the property. It makes things a lot more sane when thinking about layout. People love it so much, they put it on everything like hot sauce. I wanted to share how I found it useful as (yet) another image replacement technique.
A few days ago at work, I was asked to replace an <img> on our site with another image hosted elsewhere. Simple right? But the catch was I would not be able to replace the markup as it was already deployed to production, but could inject CSS or JS through our CMS. For whichever technology I chose, it would be inserted on all site pages. I only needed on one specific page, and the attributes of parent containers were non-specific to the desired page.
<head> <title>Really Cool Page</title> </head> <body> <!-- .header would be across site on other pages with different children, so no background image adding --> <div class="header"> <img class="banner" src="http://notrealdomain1.com/banner.png"> </div> </body>This is simple to do with JavaScript, but I wanted to see if there was another, even simpler, way. After a few iterations in Chrome Dev Tools, I thought to use the box-sizing property to keep dimensions strict, add the new image as a background image, and just push the inline image out of the way with padding and see what happened.
/* All in one selector */ .banner { display: block; -moz-box-sizing: border-box; box-sizing: border-box; background: url(http://notrealdomain2.com/newbanner.png) no-repeat; width: 180px; /* Width of new image */ height: 236px; /* Height of new image */ padding-left: 180px; /* Equal to width of new image */ }It worked beautifully. Here's what's cool:
- It works on just about any element, even empty ones like <img> or <hr>
- Browser support is excellent (Chrome, Firefox, Opera, Safari, IE8+) http://caniuse.com/#feat=css3-boxsizing
- Refrains from using SEO unfriendly display: none or other properties
That last point seemed important, as it works really well for text replacement too without any adjustment. Check it out!
Check out this Pen!
jQuery Conference Portland 2013 has a limited number of regular tickets still available. Two days. Two tracks. Fresh speakers. Jun 13-14. $50 off for members of the jQuery Foundation. Join today and get your first year of fan dues paid for with purchase of both a training and conference ticket. Training provided by Bocoup on Jun 12. Use coupon code CSSTricks25off for $25 off.
Replace the Image in an <img> with CSS is a post from CSS-Tricks
Matt Mullenweg on Yahoo-Tumblr
“We’re at the cusp of understanding the ultimate value of web publishing platforms, particularly ones that work cross-domain.”–Matt Mullenweg of WordPress.
Slider with Sliding Backgrounds
Among the many super nice design features of the Yahoo! Weather app for iOS is the transition between city screens. The background image doesn't just move away as the screen moves from one screen to the next, the background image itself slides. It appears to be hiding some of the "old" screen and revealing more of the "new" screen those closer you have it to being in full view.
Let's try and pull it off on the web.
The HTMLLike any slider, there are three main components:
- The container that holds everything into shape
- A sliding container that is as wide as all the slides in a row
- Each individual side container
We won't bother too much with content inside the slide. I'll just add the temperature to show each slide can indeed hold content on top.
<div class="slider" id="slider"> <div class="holder"> <div class="slide" id="slide-0"><span class="temp">74°</span></div> <div class="slide" id="slide-1"><span class="temp">64°</span></div> <div class="slide" id="slide-2"><span class="temp">82°</span></div> </div> </div>The container might be a <section>, slides might be <article>. It really depends. I'll let you make the semantic choices for your own needs.
The layout plan is like this:
The CSS
The "slider" (visual container) and the slides need to have explicity the same size. We'll use pixels here but you could make it work with anything.
.slider { width: 300px; height: 500px; overflow-x: scroll; } .slide { float: left; width: 300px; height: 500px; }Floating those slides to the left isn't going to make them line up in a row, because the parent element of the slides isn't wide enough to let them do that. That's one of the reasons we need the holder element. It will be 300% wide (Num. of slides × 100%) which will fit three slides exactly.
.holder { width: 300%; }Each one of our slides has a unique ID. This is useful because, if we choose, we can create anchor links that link to those ID's and the slider will "jump" to those slides. We'll add JavaScript to do some actual "sliding", but our slider will work even without that. ID's make that possible, so let's use them here to drop in some lovely background images.
#slide-0 { background-image: url(http://farm8.staticflickr.com/7347/8731666710_34d07e709e_z.jpg); } #slide-1 { background-image: url(http://farm8.staticflickr.com/7384/8730654121_05bca33388_z.jpg); } #slide-2 { background-image: url(http://farm8.staticflickr.com/7382/8732044638_9337082fc6_z.jpg); }With all this in place, our layout comes into shape:
The CSS (black fading)
Just as a small detail, the temperature set in white may be in danger of not being visible depending on the photo behind it. To ensure that it is, we can make the photo subtly fade to black toward the bottom. A pseudo element will do nicely.
.slide:before { content: ""; position: absolute; bottom: 0; left: 0; width: 100%; height: 40%; background: linear-gradient(transparent, black); }A picture explanation is in order here:
The JavaScript (background sliding)
We're going to use jQuery here because we love life. Our goal is the adjust the background-position of the slides as we scroll. We can set background-position in percentages in CSS, but that alone doesn't do the cool hide/reveal more effect we're looking for. Based the amount scrolled (which we can measure in JavaScript), we'll adjust the background-position. Alone, that would look something like this:
$("#slider").on("scroll", function() { $(".slides").css({ "background-position": $(this).scrollLeft()/6-100+ "px 0" }); });The "6" and "-100" in there are magic numbers. Not CSS magic numbers that are prone to frailty, but traditional magic numbers. Just some numbers that happen to make the effect work. A bummer, perhaps, but not that big of a deal. Design-y things are sometimes like that. Perhaps best to leave a comment in the code to that effect. These particular numbers are based on the images I used and their size and what looked good.
The effect here is the background shifting we're after:
Notice the less of the yellow streetcar is visible when the slide is almost out of view.
The JavaScript (imparting structure)
That little snippet of JavaScript looks lonely up there without any structure behind it. A slider is a great excuse to look at a simple way to structure JavaScript.
We can make everything slider-related one object.
var slider = { };Then we'll group up the related elements into one area, bind our events together, and write little functions that do very specific things.
var slider = { el: { slider: $("#slider"), allSlides: $(".slide") }, init: function() { // manual scrolling this.el.slider.on("scroll", function(event) { slider.moveSlidePosition(event); }); }, moveSlidePosition: function(event) { // Magic Numbers this.el.allSlides.css({ "background-position": $(event.target).scrollLeft()/6-100+ "px 0" }); } }; slider.init(); The HTML (adding navigation)Adding swipe stuff would be super (super) sweet (hint). But for now let's add little press-able links to change slides, rather than relying on the scrollbar. You might even remove the scrollbar in real life (straight up overflow: hidden; on the container). What we need is anchor links that link to the ID's of the individual slides.
<nav class="slider-nav"> <a href="#slide-0" class="active">Slide 0</a> <a href="#slide-1">Slide 1</a> <a href="#slide-2">Slide 2</a> </nav>Style those as you will. For the demo, I make them little tiny gray circles with the text hidden.
The JavaScript (adding navigation)Our structure is more useful now. We simply add a few more elements we're dealing with, add a new event we're watching for (clicks on nav), and write a little function to deal with that event.
We know how far to animate the scroll position when a nav link is clicked from the ID on the link itself. The link might be href="#slide-1", which we can get "1" from easily. Then the position we need to scroll to is (1 × width of slide), so 300 in our case. We'll store that 300 value right in the JavaScript.
var slider = { el: { slider: $("#slider"), allSlides: $(".slide"), sliderNav: $(".slider-nav"), allNavButtons: $(".slider-nav > a") }, timing: 800, slideWidth: 300, // could measure this init: function() { // You can either manually scroll... this.el.slider.on("scroll", function(event) { slider.moveSlidePosition(event); }); // ... or click a thing this.el.sliderNav.on("click", "a", function(event) { slider.handleNavClick(event, this); }); }, moveSlidePosition: function(event) { // Magic Numbers this.el.allSlides.css({ "background-position": $(event.target).scrollLeft()/6-100+ "px 0" }); }, handleNavClick: function(event, el) { // Don't change URL to a hash, remove if you want that event.preventDefault(); // Get "1" from "#slide-1", for example var position = $(el).attr("href").split("-").pop(); this.el.slider.animate({ scrollLeft: position * this.slideWidth }, this.timing); this.changeActiveNav(el); }, changeActiveNav: function(el) { // Remove active from all links this.el.allNavButtons.removeClass("active"); // Add back to the one that was pressed $(el).addClass("active"); } }; slider.init();We have an "active" class on the nav links just to use in CSS to visually indicate which slide is active. We handle that by removing "active" from all links and then adding it back to the one that was clicked.
Demo! Check out this Pen!
jQuery Conference Portland 2013 has a limited number of regular tickets still available. Two days. Two tracks. Fresh speakers. Jun 13-14. $50 off for members of the jQuery Foundation. Join today and get your first year of fan dues paid for with purchase of both a training and conference ticket. Training provided by Bocoup on Jun 12. Use coupon code CSSTricks25off for $25 off.
Slider with Sliding Backgrounds is a post from CSS-Tricks
Photo Swivel
The following is a guest post by Alex Young (@the_alexyoung). Alex has created a simple technique to "rotate" the subject of a photo simply by hiding and showing multiple stacked photographs taken at different angles. Enjoy!
Web designers and developers have always fascinated us with fun and engaging ways we interact with their websites. I love discovering new techniques that these designers/developers have come up with. One technique in particular that sparked my interest is something that I saw on Warby Parker’s website. They were able to create a cool effect where model follows the user’s mouse, showing off the different angles of the frames.
I’ve seen this technique mainly used for showing off sunglasses, but I’m interested to see what you guys can come up with for other real-world applications.
Before we begin, you will need a few things. Well, seven things to be exact. You are going to need seven photos of something taken at seven different angles.
HTML SetupWhat we are setting up is a container called “faces”, then have created an area that we are going to use to display the photos – “face-area”. We also have a div to hold each of the seven individual images.
<div id="faces"> <div id="face-area"> <div id="image-1" style="display: none;"> <img src="http://cdn.css-tricks.com/images/look-left-3.jpg"> </div> <div id="image-2" style="display: none;"> <img src="http://cdn.css-tricks.com/images/look-left-2.jpg"> </div> <div id="image-3" style="display: none;"> <img src="http://cdn.css-tricks.com/images/look-left-1.jpg"> </div> <div id="image-4" style="display: none;"> <img src="http://cdn.css-tricks.com/images/look-center.jpg"> </div> <div id="image-5" style="display: none;"> <img src="http://cdn.css-tricks.com/images/look-right-1.jpg"> </div> <div id="image-6" style="display: none;"> <img src="http://cdn.css-tricks.com/images/look-right-2.jpg"> </div> <div id="image-7" style="display: none;"> <img src="http://cdn.css-tricks.com/images/look-right-3.jpg"> </div>Now we'll create a div that is going to do exactly what the name implies. It is going to lay on top of the other div. We can divide this div into 7 small columns and divide them equally across it. These 7 columns will be used to listen for when the mouse is hovering over that specific one. Adding “data-number” to each div will allow us to refer to each in jQuery later on.
<div id="the_faces_overlay"> <div class="the_faces" data-number="1"></div> <div class="the_faces" data-number="2"> </div> <div class="the_faces" data-number="3"></div> <div class="the_faces" data-number="4"></div> <div class="the_faces" data-number="5"></div> <div class="the_faces" data-number="6"></div> <div class="the_faces" data-number="7"></div> </div> </div><!-- END #face-area --> </div> <!-- END #faces --> CSS SetupMost of the CSS is pretty self-explanatory. There is one thing I need to mention that is important, make sure that the 7 columns fit perfectly together across the span of the div.
body { background: #333 } #faces { height: 333px; width: 500px; margin: 0 auto; border: 8px solid white; } #face-area { height: 500px; width: 333px; position: relative; } #the_faces_overlay { position: absolute; width: 500px; top: 0; left: 0; } #faces .the_faces { height: 333px; width: 14.2857143%; float: left; margin: 0; padding: 0; } jQuery SetupWe need to listen for when each of the columns are hovered over. This is where those “data-numbers” come in handy. If we wanted to add more columns down the road we wouldn't have to add any more JavaScript.
// Reveal the "center" image var centerImage = $("#image-4").show(); // Bind hovers to each column $(".the_faces").each(function() { $(this).on("mouseover", function() { $("#image-" + $(this).attr("data-number")).show(); }).on("mouseout",function() { $("#image-" + $(this).attr("data-number")).hide(); }); }); // Reset center image $("#face-area").on("mouseleave", function() { centerImage.show(); }).on("mouseenter", function() { centerImage.hide(); }); Tada! Check out this Pen!There you have it! Now you have your very own, head turning model. Use it to show off your very own products. There are tons of uses for this out there. Let me know what you come up with.
Editor's note: this would be a fun demo to work on adding touch support, wouldn't it? Follows a swipe or something.
jQuery Conference Portland 2013 has a limited number of regular tickets still available. Two days. Two tracks. Fresh speakers. Jun 13-14. $50 off for members of the jQuery Foundation. Join today and get your first year of fan dues paid for with purchase of both a training and conference ticket. Training provided by Bocoup on Jun 12. Use coupon code CSSTricks25off for $25 off.
Photo Swivel is a post from CSS-Tricks
Replacing images when printing
It isn’t all that uncommon that, after you’ve polished your print stylesheet to make a site look well on paper as well as on screen, you realise that the logo really doesn’t look its best. It may look blurry or pixelated on paper due to having a pixel density intended for screen viewing, of course. But even worse, its edges may look ugly or it may actually be invisible because whatever is behind it when viewed on screen isn’t printed.
Applying a background colour to the logo image or its containing element in the print CSS isn’t going to help either since most browsers by default do not print backgrounds at all. If you can’t change the image used for screen so that it will look good in print as well, you need to somehow make browsers use a different image when printing. One way of doing that is by using CSS generated content.
Posted in CSS.
Copyright © Roger Johansson
Media Query Change Detection in JavaScript Through CSS Animations
The following is a guest post by Alessandro Vendruscolo. Media queries are relevant to both CSS and JS. The need and desire to manage those in one place is real. There have been some clever ways to do this, like Jeremy Keith's Conditional CSS. But in that case, the onus is on you to test after window state changes. You can get a true listener with MediaQueryList, but then you're maintaining the media queries in both places again. Ah well, I'll let Alessandro explain.
Media queries were first introduced more than twelve years ago (yes, the first draft dates back to 4 April 2001!) and were introduced to limit the scope of a style sheet:
A media query consists of a media type and one or more expressions to limit the scope of a certain style sheet. […] By using media queries, content presentations can be tailored to a range of devices without changing the content itself.
With media queries in CSS we can selectively use styles depending on, for example, the width of browser screen:
@media screen and (min-width: 960px) { body { padding: 50px; } }In the example above, if your browser screen is wider than or equal to 960px, the body will have 50px of padding.
DOM events triggered from CSS animationsA simple click event:
document.querySelector('a.button').addEventListener('click', function(event) { // do something });Nothing fancy here, just standard DOM programming. The click event, among many other events, are generated when the user interacts with the page: clicks, moves the cursor, scrolls the page and so on.
All of these events are related to the DOM, and generates as a consequence of user's interactions. There are also some events which are specifically related to CSS animations: animationStart, animationEnd (and their transition cousins, transitionStart, transitionEnd).
If we insert a new element onto the page and it has an animation, we know that CSS animation will start as soon as it is inserted. So if we watch for the animationstart event of that animation, we can know when it was inserted.
@keyframes nodeInserted { from { clip: rect(1px, auto, auto, auto); } to { clip: rect(0px, auto, auto, auto); } } .an-element { animation-duration: 0.001s; animation-name: nodeInserted; } document.addEventListener("animationstart", function (event) { if (event.animationName == "nodeInserted") { // an element with class an-element has been inserted in the DOM } }, false);Thanks to David Walsh, Daniel Buchner, and Omar Ismail for blogging about this around a year ago.
Putting together media queries and animationsPerhaps you can see where this is going. If we trigger the animation when a media query changes (rather than on node insertion), we can also detect when that media query change happened in our JavaScript.
body { animation-duration: 0.001s; } @media screen and (min-width: 1000px) { body { animation-name: min-width-1000px; } } @media screen and (min-width: 700px) { body { animation-name: min-width-700px; } } @keyframes min-width-700px { from { clip: rect(1px, auto, auto, auto); } to { clip: rect(0px, auto, auto, auto); } } @keyframes min-width-1000px { from { clip: rect(1px, auto, auto, auto); } to { clip: rect(0px, auto, auto, auto); } } document.addEventListener(animationEnd, dispatchEvent, false); // check the animation name and operate accordingly function dispatchEvent(event) { if (event.animationName === 'min-width-700px') { document.body.innerHTML = 'Min width is 700px'; } else if (event.animationName === 'min-width-1000px') { document.body.innerHTML = 'Min width is 1000px'; } }Editor's note: choose your names wisely.
We have the same simple animation that doesn't actually do anything, but this time, the animation is inside an @media block.
If the window becomes wider than 700px, the min-width-700px animation will trigger, and our dispatchEvent will get this information. Think of it like a callback. We can then adapt our page by showing new widgets, destroying others, or whatever else you need to do to adapt to the new screen size.
The cool thing is that we don't need to use the window resize event, which can be slow and fire too many times (throttling is normally needed). The animationstart event will trigger as soon as the Media query matches, even if we didn't resize the window. If we then resize the window, the event will fire just when the media query matches.
The right way to do these thingsNow we've talked about how to get JavaScript callbacks of window width changes, without relying the resize event.
But I wouldn't suggest you to put this in production code. It works, but the right way to do this should be to use the matchMedia method, which returns a MediaQueryList. MediaQueryList objects can have listeners, and thus we can use the addListener method to get notified when a Media query matches or not.
Enquire.js has recently reached version 2, and wraps the matchMedia method, which gives us a clean and robust wrapper.
jQuery Conference Portland 2013 has a limited number of regular tickets still available. Two days. Two tracks. Fresh speakers. Jun 13-14. $50 off for members of the jQuery Foundation. Join today and get your first year of fan dues paid for with purchase of both a training and conference ticket. Training provided by Bocoup on Jun 12. Use coupon code CSSTricks25off for $25 off.
Media Query Change Detection in JavaScript Through CSS Animations is a post from CSS-Tricks
MapBox Develops an Open Source Vector Format for Maps
MapBox's new vector-based map tiles are more stable, more scalable, and customizable to an amazing degree.
This week's sponsor: Typekit
Typekit is the easiest way to use real fonts on the web. Add a line of code to your pages and choose from hundreds of web fonts. Simple, bulletproof, standards compliant, accessible, and totally legal. Learn more at http://typekit.com
Paul Irish on Chrome Moving to Blink
I know you’ve been asked this plenty of times already, but: no new vendor prefixes, right? Right?
Nope, none! They’re great in theory but turns out they fail in practice, so we’re joining Mozilla and the W3C CSS WG and moving away them. There’s a few parts to this.
Firstly, we won’t be migrating the existing -webkit- prefixed properties to a -chrome- or -blink- prefix, that’d just make extra work for everyone. Secondly, we inherited some existing properties that are prefixed. Some, like -webkit-transform, are standards track and we work with the CSS WG to move ahead those standards while we fix any remaining issues in our implementation and we’ll unprefix them when they’re ready. Others, like -webkit-box-reflect are not standards track and we’ll bring them to standards bodies or responsibly deprecate these on a case-by-case basis. Lastly, we’re not introducing any new CSS properties behind a prefix.
Pinky swear?
Totes. New stuff will be available to experiment with behind a flag you can turn on in about:flags called “Experimental Web Platform Features”. When the feature is ready, it’ll graduate to Canary, and then follow its ~12 week path down through Dev Channel, Beta to all users at Stable.
The Blink prefix policy is documented and, in fact, WebKit just nailed down their prefix policy going forward. If you’re really into prefix drama (and who isn’t!) Chris Wilson and I discussed this a lot more on the Web Ahead podcast [37:20].
How long before we can try Blink out in Chrome?
Blink’s been in Chrome Canary as of the day we announced it. The codebase was 99.9% the same when Blink launched, so no need to rush out and check everything. All your sites should be pretty much the same.
Chrome 27 has the Blink engine, and that’s available on the beta channel for Win, Mac, Linux, ChromeOS and Android. (See the full beta/stable/dev/canary view).
While the internals are apt to be fairly different, will there be any radical changes to the rendering side of things in the near future?
Nothing too alarming, layout and CSS stuff is all staying the same. Grid layout is still in development, though, and our Windows text rendering has been getting a new backend that we can hook up soon, greatly boosting the quality of webfont rendering there.
We’re also interested in better taking advantage of multiple cores on machines, so the more we can move painting, layout (aka reflow), and style recalculation to a separate thread, but the faster everyone’s sites will render. We’re already doing multi-threaded painting on ChromeOS and Android, and looking into doing it on Mac & Windows. If you’re interested in these experimental efforts or watching new feature proposals, take a look at the blink-dev mailing list. A recent proposed experiment is called Oilpan, where we’ll look into the advantages of moving the implementation of Chrome’s DOM into JavaScript.
Will features added to Blink be contributed back to the WebKit project? Short term; long term?
Since Blink launched there’s been a few patches that have been landed in both Blink and WebKit, though this is expected to decline in the long-term, as the code bases will diverge.
When are we likely to start seeing Blink-powered versions of Chrome on Android? Is it even possible on iOS, or is iOS Chrome still stuck with a Safari webview due to Apple’s policies?
Blink is now in the Chrome Beta for Android. Chrome for iOS, due to platform limitations, is based on the WebKit-based WebView that’s provided by iOS.
Part of this move seems to be giving Google the freedom to remove old or disused features that have been collecting dust in WebKit for ages. There must be a few things high on that list—what are some of those things, and how can we be certain their removal won’t lead to the occasional broken website?
A few old ’n crusty things that we’re looking at removing: the isindex attribute, RangeException, and XMLHttpRequestException. Old things that have little use in the wild and just haven’t gotten a spring cleaning from the web platform for ages.
Now, we don’t want to break the web, and that’s something that web browser engineers have always been kept very aware of. We carefully gauge real-world usage of things like CSS and DOM features before deprecating anything. At Google we have a copy of the web that we run queries against, so we have a pretty OK idea of what CSS and JavaScript out there is using.
Blink also has over 32,000 tests in its test suite, and manual confirmation that over 100 sites work great before every release ships. And we’re working closely with the W3C and Adobe to share tests and testing infrastructure across browsers, with the goals of reducing maintenance burden, improving interoperability, and increasing test coverage. Eventually we’d like all new features to ship with shared conformance tests, ensuring interoperability even as we add cutting-edge stuff.
Still, any deprecation has to be done responsibly. There’s now a draft Blink process for deprecating features which includes:
- Anonymous metrics to understand how much any specific feature is used “in the wild”
- ”Intent to deprecate” emails that hit blink-dev months before anything is removed
- Warnings that you’ll find in your DevTools console if you’re using anything deprecated
- Mentions on the Chromium blog like this Chrome 27 wrap-up.
Did part of the decision to branch away from WebKit involve resistance to adding a Dart VM? WebKit’s goals explicitly mention JavaScript, and Apple representatives have been fairly vocal about not seeing a need.
Nope, not at all. The decision was made by the core web platform engineers. Introducing a new VM to a browser introduces considerable maintenance cost (we saw this with V8 and JavaScriptCore both in WebKit) and right now Dart isn’t yet ready to be considered for an integration with Blink. (more on that in a sec). Blink’s got strong principles around compatibility risk and this guides a lot of the decisions around our commitments to potential features as they are proposed. You can hear a more complete answer here from Darin Fisher, one of the Chrome web platform leads.
Have any non-WebKit browsers recently expressed an interest in Dart? A scripting language that only stands to work in one browser sounds a little VBScript-y.
Not yet, but since Dart compiles to JavaScript and runs across the modern web, it’s not gated by other browsers integrating the VM. But it’s still early days, Dart has not yet reached a stable 1.0 milestone and that there are still technical challenges with the Dart VM around performance and memory management. Still, It’s important to point out that Dart is an open source project, with a bunch of external contributors and committers.
Let me take a moment to provide my own perspective on Dart. :) Now, as you know, I’m a JavaScript guy, so early on, I took a side and and considered Dart an enemy. JavaScript should win; Dart is bad! But then I came to realize the Dart guys aren’t just setting out to improve the authoring and scalability of web application development. They also really want the web to win. Now I’ve recently spoke about how The Mobile Web Is In Trouble, and clarified that my priorities are seeing it provide a fantastic user experience to everyone. For me, seeing the mobile web be successful trumps language wars and certainly quibbling over syntax. So I’m happy to see developers embrace the authoring advantages of Coffeescript, the smart subset of JavaScript strict mode, the legendary Emscripten & asm.js combo, the compiler feedback of TypeScript and the performance ambitions of Dart. It’s worth trying out technologies that can leapfrog the current expectations of the user experience that we can deliver. Our web is worth it.
Will Opera be using the Chromium version of Blink wholesale, as far as you know? Are we likely to see some divergence between Opera and Chrome?
As I understand it, Opera Mobile, Opera Desktop, and Opera Mini will all be based on Chromium. This means that they’ll not only share the exact version of Blink that Chrome uses, but also the same graphics stack, JavaScript engine, and networking stack. Already, Opera has contributed some great things to Blink and we’re excited about what’s next.
Why the name “Blink,” anyway?
Haha. Well… it’s a two parter. First, Blink evokes a certain feeling of speed and simplicity—two core principles of Chrome. Then, Chrome has a little tradition of slightly ironic names. Chrome itself is all about minimizing the browser chrome, and the Chromebook Pixel is all about not seeing any pixels at all. So naturally, it fits that Blink will never support the infamous <blink> tag. ;)
<3z
W3C to Publish Encrypted Media Extensions Specification
The W3C announced today that it intends to publish the controversial Encrypted Media Extensions extension specification despite highly outspoken resistance, paving the way for native web DRM.
