The Web Bare Necessities
Today I had yet another conversation on Web Development and Frameworks, with someone that is not even into Web Development but is trying to catch up through common feeds such Hacker News or similar channels.
The funny part of nowadays Web Development is that people believe you need a Framework to create something Web related, or you are out.
Once again, Frameworks are a very good option when they solve your problem, but these might also be the reason you have a problem in the first place.
As example, in this recent post of mine, the task was simple, but developers decided regardless to use a Framework in order to compare performance, and without even considering a Web standards code-base competitor.
Accordingly, this one is my take on questions such: “how do I usually do Web Development?“
The Web is already a Framework
Concepts like Separation of Concerns, Decoupling, Model View Controller, and many other words you might have heard about Web Development, are actually available by default.
For instance, this is the most basic, fully cross platform, View we could have on the web:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Most basic View</title>
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1.0"
>
</head>
<body></body>
</html>
Such view could be enriched through some Style Sheet, improving the visualization of the page we are going to deliver.
And such style could be included either via link
<head>
<!-- ... previous <head> content, plus ... -->
<link rel="styleSheet" href="css/main.css">
</head>
or even inline, as some performance related technique might suggest these days
<head>
<!-- ... previous <head> content, plus ... -->
<style>
/* an inline style example */
html {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
</style>
</head>
We could already put manually some model
related data, writing some text directly on the body
tag, truth is that we probably would like to deliver some modern fancy page and not just a static one.
Fair enough, and here it comes as standard!
A modern DOM in a bounce of bytes
If you have been using jQuery for the last 5+ years you probably didn’t notice that this library influenced, and surely in a good way, few modern Web standards.
My 2.4KB CDN based DOM4 polyfill, as example, is capable of normalizing so many new standard features it would be lame to use a library in order to obtain what native can do already, and most of the time even faster.
Add the most basic and unobtrusive $
dollar based utility you can think of, and you might realize things can be already very simple to do, without adding superfluous, but precious, bytes to download for our delivered page.
$('body').on('click', function (e) {
console.log('the user clicked somewhere');
});
So far, with a total amount of 3.6KB minified and gzipped from a CDN, which means these will be irrelevant once used in different sites from the very same CDN, we can do already amazing things like adding, removing, or dispatching a listener with ease!
// can we pass events around?
// CustomEvent is there to help!
$('body').dispatch('click');
// simplified through the $ utility
Giving for granted we can extend the API with anything we need, what else are we missing?
Adding Graceful Enhancement
The most important goal of the Web is backward compatibility, and this is also a double bladed sword ‘cause sometimes it’s just not easy, or possible at all, to polyfill older browsers.
However, whenever it’s very cheap and simple, or widely adopted as solution, it’s always convenient to have handy snippets capable of fixing most known issues on the modern Web.
For instance, while Internet Explorer removed conditional HTML comments from its parser, good old IE9 and lower will understand them, giving us the ability to fix most common APIs like HTML5 Timers, by default capable of accepting extra arguments at declaration time, plus most of the entire DOM Level 3 specification for IE8 only.
<head>
<!-- before any other script on the page -->
<!--[if lte IE 9]>
<script>(function(f){window.setTimeout=f(window.setTimeout);window.setInterval=f(window.setInterval)})(function(f){return function(c,t){var a=[].slice.call(arguments,2);return f(function(){c.apply(this,a)},t)}});</script>
<![endif]-->
<!--[if IE 8]><script src="//cdnjs.cloudflare.com/ajax/libs/ie8/0.2.5/ie8.js"></script><![endif]-->
The purpose of these conditional comments is pretty simple:
- every browser on this planet will simply ignore them, no concrete payload added to our pages
- normalized DOM including
addEventListener
,Event
constructor, and other commonly used method on native browser world for IE8 - extra arguments to Standard Timers in IE9 or lower, the only incompatible old browsers
// what's cool about extra arguments?
function logIt(i) {
console.log(i);
}
// for instance, you don't need
// a closure per each iteration
for (var i = 0; i < 5; i++) {
setTimeout(logIt, i * 1000, i);
}
You would rarely find books talking about timers as standard, which is the reason even big names creating JavaScript engines might have hard time implementing them the right way at their first attempt.
I guess sometimes one really needs to read just standard specifications, instead of trusting blindly some opinionated blog post or book, what do you think?
Bringing in ES5
I have been working on Mobile Web for long time, and the amount of inconsistencies between not so modern browsers has been both a nightmare and a revelation.
What I have learned in my experience is that most of the modern JavaScript features you’d like to have today, are available by default in every browser or engine that introduced Function.prototype.bind
natively.
No kidding, the most basic feature detection test you can make, in order to have a 99% fully capable ES5 modern environment, is to check for this method in the native prototype:
<script>
Function.bind||(function(s){document.write([
'<script src="'+s+'es5-shim.min.js" defer><',
'<script src="'+s+'es5-sham.min.js" defer><',''
].join('/script>'))}(
'//cdnjs.cloudflare.com/ajax/libs/es5-shim/4.1.7/'
));
</script>
Above little piece of code in your header, will ensure only older browsers will bring in most needed ES5 methods polyfills in your page.
Just be sure this script is added early enough in your stack, and please feel free to remove defer
from those scripts, but definitively don’t use async
instead, since it’s full of surprises.
Only one missing bit!
Web standards introduced a while ago the DOMContentLoaded event type, an event that made old style Web pages instantly responsive and reactive because scripts were executed before the user could even see the page!
That feature got lost recently when they introduced the script async
attribute, something that could be parsed and interpreted at any time in a page life cycle, even after the DOM content has been loaded, making the listener DOMContentLoaded
completely unreliable.
In few words, for one non-blocking script achievement unlocked, a commonly used entry point to initialize components and page logic has been lost!
So this is the way we could solve the issue:
<script>
!function(r,e,a,d,y){
function $(f){d?f():r.push(f)}e.ready=$;e.addEventListener(a,
y=function(){d=!e.removeEventListener(a,y,d);while(y=r.shift())y()},d
)}([],document,'DOMContentLoaded',!1);</script>
Used as inline script on top of the page, eventually after conditional old IE comments, we can be definitively sure whatever we pass to document.ready(fn)
will be executed ASAP.
It’s some sort of hidden, but well known dependency, we could simply trust on our project or Website, and without compromising required bandwidth at all.
Moreover, if you are familiar with jQuery, think document.ready(fn)
as its equivalent. Many developers have been writing plugins and logic starting from $(document).ready(fn)
, you just need to drop the wrapper and use above snippet inline to have exact same feature ;-)
Normalized CSS
In order to be sure that all elements will consistently render as expected, we might want to add as very first style the following one:
<head>
<!-- before any other style -->
<link
rel="styleSheet"
href="//cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css"
>
</head>
The normalize.css library is battle-tested and also used in famous frameworks such bootstrap.
As Summary
What I didn’t mention at the beginning, is that I would have described this Website layout.
All mentioned techniques, polyfills, and practices in this post are exactly what you are surfing now indeed:
- a responsive page that works mobile first and on Desktop too
- a page compatible down to IE8 and even terminal based browsers such lynx, granting max reachability with minimal effort
- a simple hamburger menu logic on the top right corner, mostly based on CSS classes, handled through normalized DOM4
classList
methods - a basic, most effective, inline fallback for old browsers incapable of rendering SVG
- a scroller helper for heading sections and simplified browser history
- a little “catch the nyan cat“ game on top that won’t burn your device battery if not focused or visualized
And all of above points in a tiny Web site, probably one of the smallest you can surf on these days.
Accordingly, are you still sure you need “that Framework“ to deliver your next project?
Please feel free to leave some comment in the Disqus area, and thank you for reading!