Before jQuery, JavaScript was something you tolerated. You wrote it because you had to - form validation, dropdown menus, Ajax requests - but every feature required writing browser detection code, maintaining two or three parallel implementations for IE/Firefox/Safari, and debugging differences that had no sane explanation.
John Resig had been working on a CSS-selector-based DOM manipulation library since January 2006. He presented it at BarCamp NYC in August. The name was jQuery. The version was 1.0. The compressed size was 19KB.
I started using it the week it launched. Within two months I had removed every custom DOM utility function I had written over the previous four years. jQuery did all of it, better, in less code, and it worked in IE 6.
What jQuery Actually Solved
The core problem jQuery addressed: querying and manipulating the DOM required different code in every browser.
// Without jQuery - DOM manipulation in 2005
// Adding a class to all <li> elements inside a specific <ul>
// IE only:
var items = document.all['menu'].children;
for (var i = 0; i < items.length; i++) {
if (items[i].tagName === 'LI') {
items[i].className += ' active';
}
}
// Firefox/Mozilla only:
var menu = document.getElementById('menu');
var items = menu.getElementsByTagName('li');
for (var i = 0; i < items.length; i++) {
items[i].setAttribute('class',
items[i].getAttribute('class') + ' active'
);
}
// Events: IE vs W3C
function addEvent(element, type, fn) {
if (element.addEventListener) {
element.addEventListener(type, fn, false); // W3C
} else if (element.attachEvent) {
element.attachEvent('on' + type, fn); // IE
}
}
With jQuery 1.0:
// The same operations in jQuery
// One line. Works in IE 6, Firefox 1.5, Safari 2.
$('#menu li').addClass('active');
// Events - one API
$('#menu li').click(function() {
$(this).toggleClass('active');
});
jQuery's Selector Engine
The feature that defined jQuery's API was CSS selectors as the query language for the DOM. In 2006, document.querySelector() did not exist in any browser (it came in 2008). To find elements, you used getElementById, getElementsByTagName, or painful tree walking.
jQuery implemented CSS selectors in pure JavaScript:
// What jQuery made possible in 2006 - none of this existed natively
// Find all odd table rows in tables with class "data-table"
$('table.data-table tr:odd').css('background-color', '#f5f5f5');
// Find inputs inside forms that are required but empty
$('form input[required]').filter(function() {
return $(this).val() === '';
}).addClass('error');
// Find paragraphs that contain the word "error"
$('p:contains("error")').css('color', 'red');
// Find checked checkboxes in a specific form
$('#myform input[type="checkbox"]:checked').each(function() {
console.log($(this).val() + ' is checked');
});
// These all worked. In IE 6.
// The internal implementation was a custom CSS parser -
// Sizzle, which jQuery open-sourced in 2009.
Ajax with jQuery
Pre-jQuery Ajax meant 15 lines of boilerplate (cross-browser XHR creation, headers, onreadystatechange). jQuery's Ajax API:
// jQuery 1.0 Ajax - 2006
// Fetch and display user data without page reload
$('#load-user-btn').click(function() {
var userId = $(this).data('user-id') || $(this).attr('rel');
$.ajax({
url: '/api/user.php',
type: 'GET',
data: { id: userId },
dataType: 'html', // expecting HTML fragment back
beforeSend: function() {
$('#user-panel').html('<p class="loading">Loading...</p>');
},
success: function(html) {
$('#user-panel').html(html);
},
error: function(xhr, status) {
$('#user-panel').html('<p class="error">Failed to load user.</p>');
}
});
});
// Even shorter for simple cases:
$('#user-panel').load('/api/user.php?id=' + userId);
// JSON request:
$.getJSON('/api/stats.php', function(data) {
$('#visits').text(data.visits);
$('#signups').text(data.signups);
});
Animations: The Thing Everyone Wanted
In 2005-2006, every client asked for "smooth animations" on their website. Implementing them by hand with setInterval and manual pixel calculations was tedious. jQuery's animation API:
// Before jQuery: smooth accordion - hand-written
function toggleSection(id) {
var el = document.getElementById(id);
var height = el.offsetHeight;
var targetHeight = (el.style.display === 'none') ? 200 : 0;
var step = (targetHeight - height) / 10;
var timer = setInterval(function() {
height += step;
el.style.height = height + 'px';
if (Math.abs(height - targetHeight) < 2) {
clearInterval(timer);
el.style.height = targetHeight + 'px';
if (targetHeight === 0) el.style.display = 'none';
}
}, 30);
}
// With jQuery 1.0:
$('.section-header').click(function() {
$(this).next('.section-body').slideToggle(300);
});
// Fade effects:
$('#notification').fadeIn(200).delay(3000).fadeOut(500);
// Custom animations:
$('#sidebar').animate({
width: '0px',
opacity: 0
}, 400, function() {
$(this).hide();
});
// Chaining - everything returned $(this):
$('#submit-btn')
.css('background', '#ccc')
.attr('disabled', true)
.text('Submitting...');
The IE 6 Problem and How jQuery Solved It
Internet Explorer 6 had 80%+ market share in 2006. Abandoning IE6 compatibility was not an option. IE6's JavaScript quirks were extensive:
- No
addEventListener- onlyattachEvent - Event object was
window.event, not passed as argument opacitywasfilter: alpha(opacity=50), notopacity: 0.5- PNG alpha transparency broken
- Various CSS layout bugs affecting JavaScript-calculated positions
offsetWidth/offsetHeightinconsistencies
jQuery 1.0 absorbed all of these. The CSS method transparently handled opacity:
// jQuery handled IE opacity internally:
$(el).css('opacity', 0.5);
// IE got: el.style.filter = 'alpha(opacity=50)'
// Others: el.style.opacity = '0.5'
// The developer wrote one line.
// Event normalization:
$('a').click(function(e) {
e.preventDefault(); // worked in IE via e.returnValue = false internally
e.stopPropagation(); // worked in IE via e.cancelBubble = true internally
// One API. Both browsers.
});
This normalization layer was jQuery's most important technical contribution. Not the selector engine, not the Ajax wrapper - the fact that every event handler got a normalized event object, every style operation worked across browsers, every DOM method behaved consistently.
The 2006 Ecosystem
jQuery launched alongside other JavaScript libraries competing for the same problem:
- Prototype.js (2005, Rails-bundled) - extended native objects (
Array.prototype,String.prototype), causing conflicts with other code - MooTools - similar to jQuery but class-based OOP focus
- Dojo - large, enterprise-focused, everything including a build system
- YUI (Yahoo) - comprehensive but verbose
jQuery won the broad adoption race because: no dependency, small file size, non-invasive (didn't extend native prototypes), and the selector-based API that was intuitive for developers who already knew CSS.
By 2009, jQuery was included on more websites than any other JavaScript library. By 2012, it was on over 50% of all websites. It remained the dominant JavaScript library until React began displacing it for complex applications circa 2016 - and it still ships on the majority of web pages today.
The JavaScript landscape before and after August 2006 are fundamentally different. Before: browser JavaScript was a pain you minimized. After: it was a first-class tool you actually wanted to use.
Aunimeda builds modern web frontends - from single-page applications to complex multi-locale sites.
Contact us to discuss your frontend project. See also: Web Development, Corporate Website Development