HTML has a special input type for dates, like this: <input type="date">. In supporting browsers (pretty good), users will get UI for selecting a date. Super useful stuff, especially since it falls back to a usable text input. But how do you set it to a particular day?
To set a particular day, you’ll need to set the value to a YYYY-MM-DD format, like this:
<input type="date" value="1980-08-26">
Minor note: placeholder won’t do anything in a browser that supports date inputs. Date inputs can have min and max, so only a date between a particular range can be selected. Those take the same format. Just for fun we’ve used a step value here to make only Tuesday selectable:
How about defaulting the input to the value of today? Unfortunately, there is no HTML-only solution for that, but it’s possible with JavaScript.
<input id="today" type="date">
let today = new Date().toISOString().substr(0, 10);
document.querySelector("#today").value = today;
// or...
document.querySelector("#today").valueAsDate = new Date();
It’s also possible to select a specific week or month. Prefilling those is like this:
I received a really wonderful question from Bryan Braun the other day during a workshop I was giving at Sparkbox. He asked if, over the years, if there were opinions about web design and development I strongly held that I don’t anymore.
I really didn’t have a great answer at the time, even though surely if I could rewind my brain there would be some embarrassing ones in there.
At the risk of some heavy self-back-patting, this is exactly the reason I try and be pretty open-minded. If you aren’t, you end up eating crow. And for what? When you crap on an idea, you sound like a jerk at the time, and likely cause more harm than good. If you end up right, you were still a jerk. If you end up wrong, you were a jerk and a fool.
I like the sentiment the web is a big place. It’s a quick way of saying there are no hard and fast right answers in a playground this big with loose rules, diversity of everything, and economic overlords.
I don’t want to completely punt on this question though.
I’ve heard Trent Walton say a number of times that, despite him being all-in on Responsive Web Design now, at first it seemed like a very bad idea to him.
I remember feeling very late to the CSS preprocessing world, because I spent years rolling my eyes at it. I thought it the result of back end nerds sticking their noses into something and bringing programming somewhere that didn’t need it. Looking back, it was mostly me being afraid to learn the tools needed to bring it into a workflow.
It’s not to find industry-wide holy wars these days, where strongly held opinions duke it over time, and probably end up giving ground to each other in the end.
But what of those internal personal battles? I’d be very interested to hear people’s answers on this…
What strongly-help opinion did you used to have about web design and development, but not anymore?
You know those those „introduction” emails? Someone thinks you should meet someone else, and emails happen about it. Or it’s you doing the introducing, either by request or because you think it’s a good idea. Cutting to the chase here, those emails could be done better. Eight years ago, Fred Wilson coined the term „double opt-in intro”.
This is how it can work.
You’re doing the vetting
Since you’re writing the emails here, it’s your reputation at stake here. If you do an introduction that is obnoxious for either side, they’ll remember. Make sure you’re introducing people that you really do think should know each other. Like a bizdev cupid.
You’re gonna do two (or three) times writing
The bad way to do an intro is to email both people at once. Even if this introduction has passed your vetting, you have no idea how it’s going to turn out. There is a decent chance either of them or both aren’t particularly interested in this, which makes you look like a dolt. It doesn’t respect either of their time, puts your reputation at risk, and immediately puts everyone into an awkward position (if they ignore it they look like an asshole).
Instead, you’re going to write two emails, one to each person you’re trying to introduce. And you’re not going to reveal who the other person is, except with non-identifying relevant details and your endorsement.
They do the opt-ing in
If either of the folks are interested in this introduction, they can email you back. Give them an easy out though, I’d say something like „if for any reason you aren’t into it, just tell me so or ignore this, I promise I understand”. If you don’t make it easy to blow you off, it’s your just transferring the awkward situation to yourself.
If either of them isn’t into it, it doesn’t matter. They don’t know who the other is and there is no awkwardness or burnt bridge.
If both are into it, great, now it’s time for the third email actually introducing them. Get out of the way quickly.
It’s about more than awkwardness and reputation, it’s about saftey
See:
It's also why double opt-in intros are *a must*. Please please please don't go intro'ing people to each other without asking first.
Just because you have someone’s email address in your book doesn’t mean you should be giving it out to anyone that asks. Better to just assume any contact info you have for someone else is extremely private and only to be shared with their permission.
You know those the little notification windows that pop up in the top right (Mac) or bottom right (Windows) corner when, for example, a new article on our favorite blog or a new video on YouTube was uploaded? Those are push notifications.
Part of the magic of these notifications is that they can appear even when we’re not currently on that website to give us that information (after you’ve approved it). On mobile devices, where supported, you can even close the browser and still get them.
Article Series:
Setting Up & Firebase (You are here!)
The Back End (Coming soon!)
Push notification on a Mac in Chrome
A notification consists of the browser logo so the user knows from which software it comes from, a title, the website URL it was sent from, a short description, and a custom icon.
We are going to explore how to implement push notifications. Since it relies on Service Workers, check out these starting points if you are not familiar with it or the general functionality of the Push API:
You are free to choose the back-end system which suits you best. I went with Firebase since it offers a special API which makes implementing a push notification service relatively easy.
In this part, we’ll only focus on the front end, including the Service Worker and manifest, but to use Firebase, you will also need to register and create a new project.
Implementing Subscription Logic
HTML
We have a button to subscribe which gets enabled if 'serviceWorker' in navigator. Below that, a simple form and a list of posts:
Now we can initialize Firebase using the credentials given under Project Settings → General. The sender ID can be found under Project Settings → Cloud Messaging. The settings are hidden behind the cog icon in the top left corner.
Firebase offers its own service worker setup by creating a file called `firebase-messaging-sw.js` which holds all the functionality to handle push notifications. But usually, you need your Service Worker to do more than just that. So with the useServiceWorker method we can tell Firebase to use our own `service-worker.js` file as well.
Now we can create a userToken and a isSubscribed variable which will be used later on.
Notice the function initializePush() after the Service Worker registration. It checks if the current user is already subscribed by looking up a token in localStorage. If there is a token, it changes the button text and saves the token in a variable.
Here we also handle the click event on the subscription button. We disable the button on click to avoid multiple triggers of it.
Update the Subscription Button
To reflect the current subscription state, we need to adjust the button’s text and style. We can also check if the user did not allow push notifications when prompted.
Let’s say the user visits us for the first time in a modern browser, so he is not yet subscribed. Plus, Service Workers and Push API are supported. When he clicks the button, the subscribeUser() function is fired.
Here we ask permission to send push notifications to the user by writing messaging.requestPermission().
The browser asking permission to send push notifications.
If the user blocks this request, the button is adjusted the way we implemented it in the updateBtn() function. If the user allows this request, a new token is generated, saved in a variable as well as in localStorage. The token is being saved in our database by updateSubscriptionOnServer().
Save Subscription in our Database
If the user was already subscribed, we target the right database reference where we saved the tokens (in this case device_ids), look for the token the user already has provided before, and remove it.
Otherwise, we want to save the token. With .once('value'), we receive the key values and can check if the token is already there. This serves as second protection to the lookup in localStorage in initializePush() since the token might get deleted from there due to various reasons. We don’t want the user to receive multiple notifications with the same content.
function updateSubscriptionOnServer(token) {
if (isSubscribed) {
return database.ref('device_ids')
.equalTo(token)
.on('child_added', snapshot => snapshot.ref.remove())
}
database.ref('device_ids').once('value')
.then(snapshots => {
let deviceExists = false
snapshots.forEach(childSnapshot => {
if (childSnapshot.val() === token) {
deviceExists = true
return console.log('Device already registered.');
}
})
if (!deviceExists) {
console.log('Device subscribed');
return database.ref('device_ids').push(token)
}
})
}
Unsubscribe User
If the user clicks the button after subscribing again, their token gets deleted. We reset our userToken and isSubscribed variables as well as remove the token from localStorage and update our button again.
Below that we add all events around handling the notification window. In this example, we close the notification and open a website after clicking on it.
Another example would be synchronizing data in the background. Read Google’s article about that.
Show Messages when on Site
When we are subscribed to notifications of new posts but are already visiting the blog at the same moment a new post is published, we don’t receive a notification.
A way to solve this is by showing a different kind of message on the site itself like a little snackbar at the bottom.
To intercept the payload of the message, we call the onMessage method on Firebase Messaging.
The last step for this part of the series is adding the Google Cloud Messaging Sender ID to the `manifest.json` file. This ID makes sure Firebase is allowed to send messages to our app. If you don’t already have a manifest, create one and add the following. Do not change the value.
{
"gcm_sender_id": "103953800507"
}
Now we are all set up on the front end. What’s left is creating our actual database and the functions to watch database changes in the next article.
Say you want to attach a click handler to a <button>. You almost surely are, as outside of a <form>, buttons don’t do anything without JavaScript. So you do that with something like this:
var button = document.querySelector("button");
button.addEventListener("click", function(e) {
// button was clicked
});
But that doesn’t use event delegation at all.
Event delegation is where you bind the click handler not directly to the element itself, but to an element higher up the DOM tree. The idea being that you can rip out and plop in new DOM stuff inside of there and not worry about events being destroyed and needing to re-bind them.
This is where it gets tricky. In this example, even if the user clicks right on the button somewhere, depending on exactly where they click, e.target could be:
The button element
The svg element
The use element
So if you were hoping to be able to do something like this:
document.documentElement.addEventListener("click", function(e) {
if (e.target.tagName === "BUTTON") {
// may not work, because might be svg or use
}
});
Unfortunately, it’s not going to be that easy. It doesn’t matter if you check for classname or ID or whatever else, the element itself that you are expecting might just be wrong.
There is a pretty decent CSS fix for this… If we make sure nothing within the button has pointer-events, clicks inside the button will always be for the button itself:
button > * {
pointer-events: none;
}
This also prevents a situation where other JavaScript has prevented the event from bubbling up to the button itself (or higher).
document.querySelector("button > svg").addEventListener("click", function(e) {
e.stopPropagation();
e.preventDefault();
});
document.querySelector("button").addEventListener("click", function() {
// If the user clicked right on the SVG,
// this will never fire
});
ES2017 was finalized in June, and with it came wide support for my new favorite JavaScript feature: async functions! If you’ve ever struggled with reasoning about asynchronous JavaScript, this is for you. If you haven’t, then, well, you’re probably a super-genius.
Async functions more or less let you write sequenced JavaScript code, without wrapping all your logic in callbacks, generators, or promises. Consider this:
function logger() {
let data = fetch('http://sampleapi.com/posts')
console.log(data)
}
logger()
This code doesn’t do what you expect. If you’ve built anything in JS, you probably know why.
But this code does do what you’d expect.
async function logger() {
let data = await fetch('http:sampleapi.com/posts')
console.log(data)
}
logger()
That intuitive (and pretty) code works, and its only two additional words!
Async JavaScript before ES6
Before we dive into async and await, it’s important that you understand promises. And to appreciate promises, we need go back one more step to just plain ol’ callbacks.
Promises were introduced in ES6, and made great improvements to writing asynchronous code in JavaScript. No more „callback hell”, as it is sometimes affectionately referred to.
A callback is a function that can be passed into a function and called within that function as a response to any event. It’s fundamental to JS.
function readFile('file.txt', (data) => {
// This is inside the callback function
console.log(data)
}
That function is simply logging the data from a file, which isn’t possible until the file is finished being read. It seems simple, but what if you wanted to read and log five different files in sequence?
Before promises, in order to execute sequential tasks, you would need to nest callbacks, like so:
// This is officially callback hell
function combineFiles(file1, file2, file3, printFileCallBack) {
let newFileText = ''
readFile(string1, (text) => {
newFileText += text
readFile(string2, (text) => {
newFileText += text
readFile(string3, (text) => {
newFileText += text
printFileCallBack(newFileText)
}
}
}
}
It hard to reason about and difficult to follow. This doesn’t even include error handling for the entirely possible scenario that one of the files doesn’t exist.
I Promise it gets better (get it?!)
This is where a Promise can help. A Promise is a way to reason about data that doesn’t yet exist, but you know it will. Kyle Simpson, author of You Don’t Know JS series, is well known for giving async JavaScript talks. His explanation of promises from this talk is spot on: It’s like ordering food a fast-food restaurant.
Order your food.
Pay for your food and receive a ticket with an order number.
Wait for your food.
When your food is ready, they call your ticket number.
Receive the food.
As he points out, you may not be able to eat your food while you’re waiting for it, but you can think about it, and you can prepare for it. You can proceed with your day knowing that food is going to come, even if you don’t have it yet, because the food has been „promised” to you. That’s all a Promise is. An object that represents data that will eventually exist.
readFile(file1)
.then((file1-data) => { /* do something */ })
.then((previous-promise-data) => { /* do the next thing */ })
.catch( /* handle errors */ )
That’s the promise syntax. Its main benefit is that it allows an intuitive way to chain together sequential events. This basic example is alright, but you can see that we’re still using callbacks. Promises are just thin wrappers on callbacks that make it a bit more intuitive.
The (new) Best Way: Async / Await
A couple years ago, async functions made their way into the JavaScript ecosystem. As of last month, its an official feature of the language and widely supported.
The async and await keywords are a thin wrapper built on promises and generators. Essentially, it allows us to „pause” our function anywhere we want, using the await keyword.
async function logger() {
// pause until fetch returns
let data = await fetch('http://sampleapi.com/posts')
console.log(data)
}
This code runs and does what you’d want. It logs the data from the API call. If your brain didn’t just explode, I don’t know how to please you.
The benefit to this is that it’s intuitive. You write code the way your brain thinks about it, telling the script to pause where it needs to.
The other advantages are that you can use try and catch in a way that we couldn’t with promises:
async function logger () {
try {
let user_id = await fetch('/api/users/username')
let posts = await fetch('/api/`${user_id}`')
let object = JSON.parse(user.posts.toString())
console.log(posts)
} catch (error) {
console.error('Error:', error)
}
}
This is a contrived example, but it proves a point: catch will catch the error that occurs in any step during the process. There are at least 3 places that the try block could fail, making this by far the cleanest way to handle errors in async code.
We can also use async functions with loops and conditionals without much of a headache:
async function count() {
let counter = 1
for (let i = 0; i < 100; i++) {
counter += 1
console.log(counter)
await sleep(1000)
}
}
This is a silly example, but that will run how you’d expect and it’s easy to read. If you run this in the console, you’ll see that the code will pause on the sleep call, and the next loop iteration won’t start for one second.
The Nitty Gritty
Now that you’re convinced of the beauty of async and await, lets dive into the details:
async and await are built on promises. A function that uses async will always itself return a promise. This is important to keep in mind, and probably the biggest „gotcha” you’ll run into.
When we await, it pauses the function, not the entire code.
async and await are non-blocking.
You can still use Promise helpers such as Promise.all(). Here’s our earlier example:
async function logPosts () {
try {
let user_id = await fetch('/api/users/username')
let post_ids = await fetch('/api/posts/<code>${user_id}')
let promises = post_ids.map(post_id => {
return fetch('/api/posts/${post_id}')
}
let posts = await Promise.all(promises)
console.log(posts)
} catch (error) {
console.error('Error:', error)
}
}
Await can only be used in functions that have been declared Async.
Therefore, you can’t use await in the global scope.
// throws an error
function logger (callBack) {
console.log(await callBack)
}
// works!
async function logger () {
console.log(await callBack)
}
Available now!
The async and await keywords are available in almost every browser as of June 2017. Even better, to ensure your code works everywhere, use Babel to preprocess your JavaScript into and older syntax that older browsers do support.
A podcast (turns out to be a 2-parter) from Reply All in which Alex Goldman gets a scam phone call about his iCloud account being compromised. He goes pretty far into investigating it, speaking regularly with the people who run these scams.
I was asked (by this fella on Twitter) a question about design patterns. It has an interesting twist though, related to hiring, which I hope makes for a good poll.
Note: There is a poll embedded within this post, please visit the site to participate in this post’s poll.
I’ll let this run for a week or two. Then (probably) instead of writing a new post with the results, I’ll update this one with the results. Feel free to comment with the reasoning for your vote.
Imgix has been a long-time display ad sponsor here on CSS-Tricks. This post is not technically sponsored, I just noticed that they released a tool for analyzing image performance at any given URL that is pretty interesting.
We know web performance is a big deal. We know that images are perhaps the largest offender in ballooning page weights across the web. We know we have tools for looking at page performance as a whole. It seems fairly new to me to have tools for specifically analyzing and demonstrating how we could have done better with images specifically. That’s what this Page Weight tool is.
Clearly this is a marketing tool for them. You put in a URL, and it tells you how you could have done better, and specifically how imgix can help do that. I’m generally a fan of that. Tools with businesses behind them have the resources and motivation to stick around and get better. But as ever, something to be aware of.
As we can see checking out the homepage for Page Weight, you drop in a URL, it analyzes all the images and gives you some information about how much more performant they could have been. What’s going on behind the scenes there?
We run each image on the page through imgix, resizing to fit the image container as best we can tell, and also transform file formats, color palettes, and quality breakpoints to determine which combination provides the best size savings. Then we display that version for each image.
I see it suggests fitting the image to the container, but that only makes sense for 1x displays right? Images need to be larger than their display pixel size for visual crispness on high-density display.
Definitely. The Page Weight tool does not currently address high-DPR display differences, but our service does. We offer automated high-DPR support via Client Hints, and manually via our dpr parameter, which allows developers to set the desired value directly (useful on its own or as a fallback for Client Hint support in browsers that don’t yet support that functionality). Our imgix.js front-end library also generates a comprehensive srcset (based on the defined sizes) to address whatever size/DPR the device requires.
I think most developers here are smart enough to realize this is really smart marketing for imgix. But also smart enough to realize the images are a huge deal in web performance and want to do better. What can imgix do that a developer on their own can’t do? Or that is fairly impractical for a developer to do on their own?
First, it is important to note that resizing is not the only thing that imgix does, although it is a very common use case. We provide over 100 different processing parameters that enable developers to do everything from context-aware cropping to color space handling to image compositing. So adopting imgix gives a developer access to a lot of image handling flexibility without a lot of hassle, even if they’re primarily using it to support responsive design.
That said, it is not impossible to get a very simple resizing solution running on your own, and many developers start out there. Usually, this takes the form of some kind of batch script based on ImageMagick or Pillow or some other image manipulation library that creates derivative images for the different breakpoints.
For a while, that’s often sufficient. But once your image library gets beyond a few hundred images, batch-based systems begin to break down in various ways. Visibility, error handling, image catalog cleaning, and adding support for new formats and devices are all things that get much harder at scale. Very large sites and sites where content changes constantly will often end up spending significant dev time on these kinds of maintenance tasks.
So really, „could you build this?” is a less useful question than „should you build this?” In other words, is image processing central enough to the value proposition of what you’re building that you’re willing to spend time and effort maintaining your own system to handle it? Usually, the answer is no. Most developers would rather focus on the what’s important and leave images to something like imgix — a robust, scaleable system that just works.
Does the tool look at responsive images syntax in HTML? As in, which image was actually downloaded according to the srcset/sizes or picture element rules?
Not yet. That’s a feature we’re hoping to implement in the next version of the tool.
Can you share implementations of imgix that are particularly impressive or creative?
An interesting use we see more and more is image processing for social media. These days, many sites see the majority of their traffic coming in through social, which makes it more important than ever to make content look good in the feed. Setting OpenGraph tags is a start, but every social network has a different container size. This creates a similar problem to the one posed by mobile fragmentation, and we can help by dynamically generating social images for each network. This provides a polished presentation without adding a ton of overhead for the person maintaining the site.
Other customers are pushing even further by combining several images to create a custom presentation for social. HomeChef, a meal delivery service, does this to dynamically create polished, branded images for Pinterest from their ingredient photos.
We actually created an open source tool called Motif (GitHub Repo) to make it easier for developers to get started with dynamically generating social images through imgix.
Nicky Case’s games are a damn treasure in this world. Most importantly, they are fun and compelling to play. They also make gameplay the vehicle for education on tricky, intricate, and important issues. Issues that would be much harder to learn about by just reading. They are also a masterclass in design: clear calls to action, clear onboarding, meaningful interactions and animations, and good copy.