Today’s Readings

Kids, I can remember when the new image on the block was PNG. Now we’re talking about AVIF and WebP! Addy Osmani gives a fantastic breakdown of which format performs best, including not only browser support, but also browser decoding speeds (once downloaded to the browser, how fast the downloaded image can be seen by the user), image format capabilities (alpha? animation? color range? depth map?), how to determine which format is best for your needs (warning: the optimal image format could change with each and every image), and how to progressively implement the various formats to make sure your users get the best quality image as fast as possible (spoiler: use picture)!

Will be pretty helpful @when @when hits browsers! ;-P Interesting that nearly all comments are about the curfuffle between @if and @when. I guess it’s a good thing if that is all we have to complain about…

Similar trail (and a wee bit of foreshadowing!), is this incredibly creative use of max and min to create conditional value in CSS.

Speaking of mins and maxs, here is a quick run-through of min-content, max-content, and fit-content, including real-world use-cases! Like the figure/caption one…

And what good is all that well-fitting text if people cannot read it? Here is a really nice intro for picking the right (static) font-sizes for the various parts of your content.

And finally, some times being a little “dirty” can be really fun! Like using an HTML table to represent an image… pure, dirty, genius.

Happy reading,
Atg

Today’s Readings

Wow, this is some exciting stuff! And also so much worse than the old-school browser wars… :-) PWAs are already able to do so much that makes all the forked-coding, uploading, updating and managing app stores completely unnecessary, but the toughest hurdle remains, and has nothing to do with any of that: How can we get users to understand and accept that apps do not have live in the app stores?

I have been banging on about CSS container queries for what seems like an eternity. So long, in fact, that I gave up on them, assuming it will probably never happen! But low-and-behold, now container queries are doing the banging, on your favorite browser’s door!

Hopping on the web performance train for a hot second:

accent-color is a very simple progressive enhancement for adding branding to form elements. (Also love the bit about how browsers automatically adjust checkboxes and radio buttons for accessibility contrast!)

I must say, unless I am walking down a dark alley, I usually do not think much about shadows… But apparently my old-school box-shadow is pretty weak

Got a fixed header on your site? Ever use deep-links? Then you know the frustration of the deep-link text appearing under your fixed header… Most sites give extra top-padding to push it past the header, but scroll-margin-top is a way better way to make your sections headers appear below your fixed header!

Like music? Wish we could time travel? Well Radiooooo, by RADIOOOOO, let’s you at least time travel through music, from all around the world

And finally, speaking of time travel, I really enjoyed this nostalgic stroll through the history of web development, from the days before CSS, through the browser wars, past DHTML and Web 2.0, beyond the death of IE and into the future… Hope you enjoy it, too!

Happy reading,
Atg

Replacing jQuery with Vanilla ES6

Following a discussion with a colleague about how “necessary” jQuery is now-days, considering how far ES6 has come, I decided to conduct a small experiment: I would clone a live, functioning JS module and replace as much jQuery as possible (ideally all) with vanilla ES6.

Initially, I thought this would take the better part of an afternoon, including testing. Day two, still going…

While working my way through the cloned module, there have definitely been moments where I had to stop and hunt for the vanilla JS equivalent (jQuery sure can make one lazy!), as well as situations where I had to conduct small function tests to see if this would work to replace that.

Along the way, I am realizing that pretty much all jQuery functionality can fairly easily be replaced by vanilla ES6 (jQuery is, after all, just JS), but what I can see myself missing is the jQuery convenience

No matter how comfy you get typing .querySelector, it will never be as easy as typing $… Not to mention having to know whether you need .querySelector or .querySelectorAll, and the fact that .querySelectorAll returns a NodeList instead of an array… And don’t get me started on the loss of function-chaining!

So, while jQuery certainly can be replaced, what remains to be seen is whether it should be… Yes, it is 30kb (minified), but is removing that additional weight and latency enough to warrant the additional coding time and code weight? No matter how frugal your code is, vanilla JS does take more code to write, which takes longer to type, and in the end makes your code base larger…

As of now, I am still enjoying the experiment, but more than once have I found myself thinking “You know, I should create a micro library to alleviate some of these pain-points, like creating my own $ selector, etc.” Then I immediately start to wonder how long it would take for that micro library to start approaching 30kb… :-)

Anyhow, below are a few of the work-arounds that I have found, documented mostly so that I can remember how to switch things later, but maybe some of you will find them useful, too!

  • Select something

    // jQuery:
    $( '.something' );
    // ES6:
    document.querySelector( '.something' ); // single
    document.querySelectorAll( '.something' ); // multiple
  • Select something within a parent

    // jQuery:
    parent.find( '.something' );
    // ES6:
    parent.querySelector( '.something' ); // single
    parent.querySelectorAll( '.something' ); // multiple
  • Add CSS class

    // jQuery:
    elem.addClass( 'className' );
    // ES6:
    elem.classList.add( 'className' );
  • Remove CSS class

    // jQuery:
    elem.removeClass( 'className' );
    // ES6:
    elem.classList.remove( 'className' );
  • Set attribute

    // jQuery:
    elem.attr( 'attributeName', 'newValue' );
    // ES6:
    elem.setAttribute( 'attributeName', 'newValue' );
  • Get attribute

    // jQuery:
    elem.attr( 'attributeName' );
    // ES6:
    elem.getAttribute( 'attributeName' ); // 'newValue'
  • Set data attribute

    // jQuery:
    elem.data( 'attributeName', 'newValue' );
    // ES6:
    elem.dataset.attributeName = 'newValue';
    elem.setAttribute( 'data-attributeName', 'newValue' );
  • Get data attribute

    // jQuery:
    elem.data( 'attributeName' );
    // ES6:
    elem.dataset; // { attributeName: 'newValue' }
    elem.dataset.attributeName; // 'newValue'
    elem.getAttribute( 'data-attributeName' ); // 'newValue'
  • Insert text string

    // jQuery:
    elem.text( 'Something' );
    // ES6:
    elem.innerText = 'Something';
  • Insert HTML string

    // jQuery:
    elem.html( '<h1>Something</h1>' );
    // ES6:
    elem.innerHTML = '<h1>Something</h1>';
  • Append HTML element

    // jQuery:
    parent.append( '<a class="btn btn-success" href="' +url+ '">Sign up</a>' );
    // ES6:
    let elem = document.createElement( 'a' );
    elem.setAttribute( 'className', 'btn btn-success' );
    elem.setAttribute( 'href', url );
    elem.innerText = 'Sign up';
    parent.appendChild( elem );
  • Append HTML string

    // jQuery:
    parent.append( '<a class="btn btn-success" href="' +url+ '">Sign up</a>' );
    // ES6:
    parent.insertAdjacentHTML( 'beforeend', `<a class="btn btn-success" href="${url}">Sign up</a>` );
  • Loop through Array

    // jQuery:
    arr.each( (item), function{...} );
    // ES6:
    arr.forEach( item => { ... } );
  • Loop through Object

    // jQuery:
    obj.each( (key, value), function{...} );
    // ES6:
    for ( const [key, value] of Object.entries(obj) ) {
        console.log(key, value);
    }
    for ( const key in obj) {
        console.log(key, obj[key]);
    }
  • Add Event Listener

    // jQuery:
    elem.on( 'click', function(e) {...} );
    // ES6:
    elem.addEventListener( 'click', (e) => {...} );
  • Add Delegate Event Listener

    // jQuery:
    elem.on( 'click', 'div.className', function(e){...} );
    // ES6:
    elem.addEventListener( 'click', (e) => {
       if ( e.target.nodeName === 'DIV' && e.target.classList.contains('className') ) {
          ...
       }
    });
  • Ajax request

    // jQuery:
    $.ajax({
        url: 'https://example.com',
        method: 'post',
        dataType: 'json',
        contentType: 'application/json',
        data: JSON.stringify(data),
        success: function( response ){
            ...
        },
        error: function( error ){
            ...
        }
    });
    // ES6:
    fetch( 'https://example.com', {
        method: 'post',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(data)
    })
    .then( response => {
        ...
    })
    .catch( error => {
        ...
    });

Additional Resources

I found a few other similar resources, of course, some of which contained stuff I didn’t include, so I will link to them here; feel free to share your favorites too!

Happy coding,
Atg

Today’s Readings

Let’s start off with some fun, simple, but powerful layout bits:

500+ CSS Icons, Customizable & Retina-Ready, entirely built in CSS, Embed, NPM & API

About says it all!

How do you hide things in a browser? Know your options, and the pros & cons for each.

Intended to solve problems, <input type="number"> might create more than it solves

Then there’s this list from … Oy.

But to bring us back to “happy”, make your way through these HTML attributes that will make your users’ day way better!

For you copy/paste fiends out there (like me), this playground code-generator is going to make your day!

Nice little JS library to add pan & zoom functionality to any HTML element. Especially nice for mobile users!

I have been dreaming of Scroll to Text Fragment for a very long time. Although the documentation status says “shipping to stable channel in Chrome M80”, not working for me… Anyone?

Learn how to ship Smaller HTML Payloads with Service Workers. Note that while this article outlines how to do this for a static site, it could work just as easily for a dynamic site, by building a separate “content only” template.

Keeping with that topic, give your site a performance boost using IndexedDB to cache content.

has long been a proponent of preaching performance, but as we all know that is some times a hard pitch to both clients and upper management. But he offers a nice idea in his latest post on the topic.

Have you tested your favicons lately? Gonna guess no. This site does a thorough test of your current favicons, shows you errors for an incredibly large list of devices (including all various mobile device options and sizes), then let’s you upload an image to create all the various favicon images you need, and provides the HTML to put them all into action…

And finally, a complete history of the Millennium Falcon. Because… yeah, there is no reason for this…

Happy reading,
Atg

“Switching to night-mode” (sort of)

A long time ago in a post far, far away, a commenter made a random suggestion:

I’m reading this awesome article at 3 pm and for future readers who want night theme.
Add body
filter: invert(100%);
and change
background-color: #212121;

When I read this, it really stuck in my bonnet; it sounded like an incredibly simple and practical solution, and yet more than 3 years later, I have still done nothing about it…

So, while trying to build up this new head of steam, I decided to tackle this relatively simple project.

Then I was reminded why the tech world is so fun/frustrating: seldom are things as simple as one might expect…

First of all, with the required CSS seemingly in hand, I had to decide how I was going to activate “night mode”…

A toggle seemed obvious, but where to put it? This site’s layout changes quite a bit across various screen sizes, which means I would need to visit all, plan, think, design… I’m tired already… Plus, a toggle would also mean that a reader would have to be momentarily blinded while trying to find the toggle, before switching it.

So then I remembered hearing about the Ambient Light Sensor API, and thought that sounded really cool: the reader would automatically get the proper day/night mode!
Then I checked CanIUse.com for this API… So, I guess “Bravo Firefox 68 for Android and all those users!”

Then I found @media (prefers-color-scheme: dark) {...}, which has considerably better support, and gets triggered because the reader at some point implied they prefer a dark mode! I’m not sure how many people are actually doing this (aside from me, I mean), but I figured, well, at least those readers could get the cool “night mode”…

So I dug in and gave it a go.

Then I was reminded once again that I work in tech, when I realized that filter is like opacity, in that it cascades down and affects all child elements, including img and video elements… And while some readers might really dig the far-out spin on things, I’m not sure it was the right look for this blog… :-/
Have a look-see (click again to go back to normal-mode)

Any day of coding
Unnecessary image, only here for effect…

Which means, in order to offer this “simple” feature, I would basically have to create completely new CSS for this entire site… So, maybe later?

For anyone else that is interested in trying something like this on your site (maybe you have no images or videos, or have a lot more time/patience than I have right now?), here are a few good articles to help you get started…

And so, happy night-moding,
Atg