Building a RSS Viewer With Vue: Part 2

Welcome to Part 2 of this mini-series on building a RSS viewer with Vue. In the last post, I walked through how I built my demo using Vue.js and Vuetify on the front end and Webtask on the back end. When I built that initial version, I knew it was exactly thatmdash;an “initial” version. I took some time to work on a few updates, and while I won’t dare call this a “perfect” version, I do think I’ve made some improvements and I’d like to share them with you.

Article Series:

  1. Setup and first iteration
  2. Refinements and final version (This Post)

Before I get started, here are links to the completed demo and source code.

View Demo View Code

Feel free to fork, file PRs, and report bugs to your heart’s content!

The Plan

When I shared the initial version in Part 1, I outlined some ideas to improve the RSS reader, including:

  • Moving to Vuex.
  • Starting to switch to components in the layout. (Well, I was already using Vuetify components, but I meant custom components for my application.)
  • Using IndexedDB to store feed items for quicker access and offline support.

That was the plan, and like most plans, I wasn’t necessarily able to hit everything in this update (and I’ll explain why at the end). But hopefully you’ll see the improvements as a general “moving in the right direction” for the application. With that out of the way, let’s get started!

Implementing Vuex

I’ll start off discussing the biggest change to the application, the addition of Vuex. As I said in the previous post, Vuex describes itself as a “state management pattern + library” on their “What is Vuex” page. No offense to their documentation, but I had a difficult time wrapping my head around exactly what this meant, from a practical sense.

After having using it in a few small projects now, I’m coming to appreciate what it provides. To me, the core benefit is providing a central interface to your data. If I’ve got a basic Vue app working with an array of values, I may have multiple different methods that modify it. What happens when I begin to have certain rules that must be applied before the data changes? As a simple example, imagine an array of RSS feeds. Before I add a new one, I want to ensure it doesn’t already exist in the list. If I have one method that adds to the feed list, that isn’t a problem, but if I have more, it may become cumbersome to keep that logic in sync across the different methods. I could simply build a utility to do this, but what happens when I have other components in play as well?

While it is absolutely not a one-to-one comparison, I feel like Vuex reminds me of how Providers or Services work in Angular. If I ever want to do work with any data, I’ll ensure I use a central provider to handle all access to that data. That’s how I look at Vuex.

So the big change in this application was to migrate all the data related items to a store. I began by adding the library to my HTML:

<script src="https://unpkg.com/vuex"></script>

Woot! Half-way done! (OK maybe not.)

I then created an instance of my store in my JavaScript file:

const feedStore = new Vuex.Store({ // lots of stuff here
});

and included it in my Vue app:

let app = new Vue({ el: '#app', store:feedStore, // lots of stuff here too...
});

Now comes the interesting part. Any time my Vue application needs data, which primarily consists of the list of feeds and the items from those feeds, it’s going to ask the store for them. So, for example, my feeds value is now computed:

feeds() { return feedStore.state.feeds;
},

This is now defined in the state portion of my store:

state: { allItems: [], feeds: [], selectedFeed: null
},

Notice that feeds defaults to an empty array. I had previously used the created event of my Vue app to read in the data from localStorage. Now, I ask the store to do that:

created() { feedStore.dispatch('restoreFeeds');
},

Back in the store, the logic is pretty much the same:

restoreFeeds(context) { let feedsRaw = window.localStorage.getItem('feeds'); if(feedsRaw) { try { let feeds = JSON.parse(feedsRaw); context.state.feeds = feeds; context.state.feeds.forEach(f => { context.dispatch('loadFeed', f); }); } catch(e) { console.error('Error restoring feed json'+e); // bad json or other issue, nuke it window.localStorage.removeItem('feeds'); } }
},

I say “pretty much the same” except now I’m doing a bit of error-checking on the value read in from localStorage. But here’s the crucial bit. I already said I failed in terms of switching to IndexedDB, but in theory, I could build a third version of this application with an updated store and my Vue app won’t know the difference. And that’s where I started to get really excited. The more I worked, the more “dumb” my Vue app became and the less tied it was to any particular implementation of storage. Let’s look at the complete Vue app now:

let app = new Vue({ el: '#app', store:feedStore, data() { return { drawer:true, addFeedDialog:false, addURL:'', urlError:false, urlRules:[], selectedFeed:null } }, computed: { showIntro() { return this.feeds.length == 0; }, feeds() { return feedStore.state.feeds; }, items() { return feedStore.getters.items; } }, created() { feedStore.dispatch('restoreFeeds'); }, methods:{ addFeed() { this.addFeedDialog = true; }, allFeeds() { feedStore.dispatch('filterFeed', null); }, addFeedAction() { this.urlError = false; this.urlRules = []; feedStore.dispatch('addFeed', {url:this.addURL}) .then(res => { this.addURL = ''; this.addFeedDialog = false; }) .catch(e =>{ console.log('err to add', e); this.urlError = true; this.urlRules = ["URL already exists."]; }); }, deleteFeed(feed) { feedStore.dispatch('deleteFeed', feed); }, filterFeed(feed) { feedStore.dispatch('filterFeed', feed); } }
})

What you’ll notice is that pretty much all of the actual logic is now gone and all I’m really doing here is here, although I apologize for lumping everything together in one file.

Adding a Component

One of the other changes I mentioned was beginning to “component-ize” the view layer. I ended up only making one component, feed-item. This reduced the total number of lines in the HTML a bit:

<v-flex xs12 v-for="item in items" :key="item.link"> <feed-item :title="item.title" :content="item.content" :link="item.link" :feedtitle="item.feedTitle" :color="item.feedColor" :posted="item.pubDate"></feed-item>
</v-flex>

It isn’t a huge change by any means, but it did make it bit easier for me when I started working on the feed display. As I’m not using a fancy builder yet, I defined my component straight in JavaScript like so:

Vue.component('feed-item', { props:[ 'color','title','content','link','feedtitle', 'posted' ], template: ` <v-card :color="color"> <v-card-title primary-title> <div class="headline">{{title}} ({{posted | dtFormat}})</div> </v-card-title> <v-card-text> {{content | maxText }} </v-card-text> <v-card-actions> <v-btn flat target="_new" :href="link">Read on {{feedtitle}}</v-btn> </v-card-actions> </v-card> `
});

I’m not doing anything at all fancy in heremdash;there’s no dynamic logic or events or anything like that, but I could certainly add that later where it makes sense. I did finally get around to adding the date and time of posting. If you’re curious about how I built the formatter used for it, read my article Build A i18n Filter Using Vue.js & Native Web Specs.”

The Power of Delete!

Oh, and I finally added a way to delete feeds:

Trash can icon, FTW!

This just fires off a method on the Vue object that, in turn, fires off a call to the store that takes care of removing the feed and items from the UI and then persisting it. A small thing, but, wow, did I wish I had that in the first version when testing. And here is a final shot of everything:

The awesome app in all it’s awesomeness

Next Steps… and What Happened to IndexedDB?

As I said in the beginning, this version is still not perfect but I definitely feel better about it. I highly encourage you to share tips, suggestions, and bug reports in the comments below or on the GitHub repo.

So what happened to IndexedDB support? The issue I ran into was how to properly initialize the database. Vuex stores don’t have a concept of a created process. I could have done something like this:

// dummy code for getting feeds
dispatch('getDB')
.then(() => // do stuff
);

Where the getDB action returns a promise and handles doing a one-time IndexedDB opening and storing the value in the state. I may give this a shot later, and again, what I love about Vuex is that I know I can safely do that without interfering with the rest of the application.


Article Series:

  1. Setup and first iteration
  2. Refinements and final version (This Post)

The post Building a RSS Viewer With Vue: Part 2 appeared first on CSS-Tricks.

Here’s the thing about “unused CSS” tools

There are a lot of tools that aim to help you remove “unused CSS” from your project. Never a week goes by that I don’t see a tool for this being shared or promoted. It must strike some kind of perfect chord for some developers. I care about performance, and I know that reducing file sizes is good for performance. Indeed, it is. I bet we have CSS that is unused in our stylesheets, if we removed that, that’s a performance win. Yep, it would be. We should automate that. Ehhhhhh, I’m not so sure.

There are major performance tooling players that play up this idea, like Lighthouse and how it gives you CSS and JS “Coverage”, which will surely tell you that you’re shipping code you don’t need to be.

The tools that claim to help you with unused CSS have to perform analysis to be able to tell you what is unused and what isn’t.

Here’s one way to do that analysis. Render a page of your site and get the complete DOM. Then get the complete CSSOM as well, which can give you an array of all the selectors in your CSS. Loop over those selectors and do a querySelector in the DOM and see if it matches anything. If it doesn’t, that CSS selector is unused.

Clever, right?!

I think so. But that analysis paints a rather limited picture.

Say that analysis runs two seconds after the page is complete, but there is some JavaScript that runs and injects a modal after five seconds (ughghk, I know). The analysis would have missed the HTML in that modal, which likely has styles, and thus would have incorrectly reported those styles as unused.

So, timing is one factor. Hopefully, this analysis tool has some way to configure multiple timings.

We’re also only looking at one page so far. Of course, a site might have tens, hundreds, or thousands of pages. To be entirely sure about unused styles, looking at all of them is the most sure-fire bet.

Multiple pages is another factor. Hopefully, an analysis tool has a way to look at as many pages as you tell it to. Perhaps it can look at a sitemap?

Remember the timing thing? We might think of timing as one generic form of state. There are countless other things that could be state related. Is the user logged in or not? What plan are they on? Is their credit card expired thus showing some kind of special message? Do situational things like time/date/geolocation change state? What about real-time data? Stuff from an API?

Application-level state is clearly a big factor. Hopefully, this analysis tool can trigger/set all possible combinations of state.

There is interactive state as well. What about modals that come up because something is clicked? What is the active tab? Is this menu open or closed? What scroll position are they at? There are infinite permutations of this. Imagine a warning bar that shows up seven seconds after the user logs in to warn user about their expired credit card which contains a custom styled select menu which can be in an open or closed state, but only on the user settings page.

It seems unlikely that this analysis tool can handle all those possibilities. Even with loads of configuration, mock state, and integration testing, it couldn’t cover the near-infinite possible permutations of all this.

And yet, I don’t think these tools are useless — they are just…tools. Their use can actually be a positive step toward better code. Their use says OK, I admit it, I’m a little afraid our CSS. You could use this tool to get a broad picture of what your unused CSS might be, then combine that with your own knowledge of your CSS code base to make more informed decisions. Or take another technological step and do something like add a background image to those unused selectors and check server logs to see if they get hit.

It should be said that this whole idea of unused CSS is a part of the CSS-in-JS saga that our industry is going through. If all your styles are written as part of components, there kinda is no unused CSS. Either the component gets used and the styles come with it, or it doesn’t. If you’re particularly sensitive about the danger of unused CSS, that alone might sway you toward a CSS-in-JS tool.

It also should be said that this DOM and CSSOM analysis technique is only one possible way of checking for unused styles. If you had some kind of fancy tooling that could analyze all of your templates, styles, and scripts, presumably that could determine unused styles as well. We talk about that in the recent ShopTalk Show episode with Chris Eppstein.

The post Here’s the thing about “unused CSS” tools appeared first on CSS-Tricks.

Building a RSS Viewer With Vue: Part 1

As I explore, learn, and most importantly, play with Vue.js, I’ve been building different types of apps as a way to get practice with and improve my use of it. A few weeks ago, I was reading about the shut down of Digg’s RSS Reader and while great alternatives exist, I thought it would be fun to build my own with Vue. In this article, I’m going to explain how I put it together and also what’s wrong with it. I knew getting into this that I was going to make some compromises, so the plan is to follow up this version with a nicer one in a follow-up post.

Article Series:

  1. Setup and first iteration (This Post)
  2. Refinements and final version

Let’s start by looking at the app and explaining the various components.

View Demowebpack for this application — just a simple script include with no build process.

The Vuetify, a very nice material design framework that is easy to use. I’m still learning it, so you can be sure that my design could be better, though I’m really happy with how it looks now.

Persistence is done via localStorage. I store the feed metadata retrieved from the RSS feed. This typically includes things like the name of the site, the main URL, and a description. I do not store feed items which means every time you load the site, I re-fetch items. The next version will keep items locally using IndexedDB.

So, how do I load feed information? I could just make a network request to the URL, but most RSS feeds aren’t making use of CORS which means the browser would be blocked from loading it. To get around this, I wrote a quick serverless function with Webtask. It handles both creating a CORS-friendly endpoint as well as parsing the feeds’ XML into friendly JSON.

Now that I’ve covered the various parts of the application, let’s start looking at the code!

The Layout

Let’s start with the layout. As I said, I’m using Vuetify for the UI. I started off using the dark sample layout. This is what creates the header, footer, and left column used for the menu.

Application template

I used the card component for individual feed items. I’m not quite happy with the layout here. For example, I don’t have publication dates rendered yet because I had trouble finding a nice way to render it. I decided to simply punt and wait till the next version, which we’ll **see in Part 2 of this series.

Instead of dumping the entire source code on you at once, let’s look at the individual parts. First, here’s the introductory/help text before any feeds have been added:

<div v-if="showIntro"> <p> Welcome to the RSS Reader, a simple way to manage RSS feeds and read content. To begin using the RSS Reader, add your first feed by clicking the button below. </p> <p> <v-btn color="primary" large @click="addFeed"> <v-icon>add</v-icon> Add Feed </v-btn> </p>
</div>

When you do have feeds, items are displayed as a list of cards:

<v-container fluid grid-list-lg> <v-layout row wrap> <v-flex xs12 v-for="item in items"> <v-card :color="item.feedColor"> <v-card-title primary-title> <div class="headline">{{item.title}}</div> </v-card-title> <v-card-text> {{item.content | maxText }} </v-card-text> <v-card-actions> <v-btn flat target="_new" :href="item.link">Read on {{item.feedTitle}}</v-btn> </v-card-actions> </v-card> </v-flex> </v-layout>
</v-container>

Note the button for reading a feed item uses a target to open it up in a new tab.

To display feeds, I use a list component:

<v-list dense> <v-list-tile @click="allFeeds"> <v-list-tile-action> <v-icon>dashboard</v-icon> </v-list-tile-action> <v-list-tile-content> <v-list-tile-title>All Feeds</v-list-tile-title> </v-list-tile-content> </v-list-tile> <v-list-tile @click="filterFeed(feed)" v-for="feed in feeds" :value="feed == selectedFeed"> <v-list-tile-action> <v-icon :color="feed.color">bookmark</v-icon> </v-list-tile-action> <v-list-tile-content> <v-list-tile-title>{{ feed.title }} </v-list-tile-title> </v-list-tile-content> </v-list-tile> <v-list-tile @click="addFeed"> <v-list-tile-action> <v-icon>add</v-icon> </v-list-tile-action> <v-list-tile-content> <v-list-tile-title>Add Feed</v-list-tile-title> </v-list-tile-content> </v-list-tile>
</v-list>

Finally, here is the modal layout:

<v-dialog v-model="addFeedDialog" max-width="500px"> <v-card> <v-card-title>Add Feed</v-card-title> <v-card-text> Add the RSS URL for a feed below, or the URL for the site and I'll try to auto-discover the RSS feed. <v-text-field v-model="addURL" label="URL" :error="urlError" :rules="urlRules"></v-text-field> </v-card-text> <v-card-actions> <v-btn color="primary" @click.stop="addFeedAction">Add</v-btn> <v-btn color="primary" flat @click.stop="addFeedDialog=false">Close</v-btn> </v-card-actions> </v-card>
</v-dialog>

The Logic

Now for the fun part — JavaScript! As before, I’m not going to dump the entire file on you. Instead, let’s tackle it bit by bit.

On start up, I load any existing feeds that may have defined and then display the introduction text, if needed:

created() { this.restoreFeeds(); if (this.feeds.length === 0) this.showIntro = true;
},

The restoreFeeds method handles checking LocalStorage for existing feeds.

restoreFeeds() { let feeds = localStorage.getItem('feeds'); if (feeds) { this.feeds = JSON.parse(feeds); this.feeds.forEach((feed,idx) => { feed.color = colors[idx % (colors.length-1)]; this.loadFeed(feed); }); }
},

Note that this method handles assigning a color (which is a simple array) and then loading feed data.

Speaking of that, how do I handle loading RSS information? Currently there are two times where this happens. First is when you initially add the feed and second when you reload the application and the feed was already defined. In both cases, I call one URL — the serverless task defined with Webtask. This task will return everything — the metadata about the feed and the items itself. I only care about the metadata on the *first* call and, in theory, I could have made the code a bit quicker by removing the metadata at the server side and strip that out but it didn’t seem like it was worth the effort.

That serverless function is rather simple:

'use strict'; const Parser = require('rss-parser');
const parser = new Parser(); module.exports = function(context, cb) { let url = ''; if(context.body && context.body.url) url = context.body.url; if(context.query && context.query.url) url = context.query.url; if(url === '') cb(new Error('URL parameter not passed.')); console.log('gonna parse '+url); parser.parseURL(url) .then(feed => { console.log(feed); cb(null, {feed:feed}); }) .catch(e => { cb(e); }); }

All I’m doing here is wrapping the npm package rss-parser and that handles all the converting for me. The if statements you see in the beginning handle looking for the url parameter. When calling my webtask, I can either pass a query string variable or send it as part of a HTTP body. Either way, I simply use the rss-parser module and return the result.

The endpoint for this function is:

https://wt-c2bde7d7dfc8623f121b0eb5a7102930-0.sandbox.auth0-extend.com/getRss

You’re welcome to try it out yourself. You can see this being used in the method handling adding a feed:

addFeedAction() { this.urlError = false; this.urlRules = []; //first, see if new if(this.feeds.findIndex((feed) => { return (feed.rsslink === this.addURL); }) >= 0) { this.urlError = true; this.urlRules = ["URL already exists."]; return; } else { fetch(rssAPI+encodeURIComponent(this.addURL)) .then(res => res.json()) .then(res => { // ok for now, assume no error, cuz awesome this.addURL = ''; //assign a color first res.feed.color = colors[this.feeds.length % (colors.length-1)]; // ok, add the items (but we append the url as a fk so we can filter later) res.feed.items.forEach(item => { item.feedPk = this.addURL; item.feedColor = res.feed.color; this.allItems.push(item); }); // delete items delete res.feed.items; // add the original rss link res.feed.rsslink = this.addURL; this.feeds.push(res.feed); this.addFeedDialog = false; //always hide intro this.showIntro = false; //persist the feed, but not the items this.storeFeeds(); }); } },

This method first checks if a feed already exists and, if it doesn’t, it hits the serverless endpoint to get the details. I’ve got a bit of data duplication going on when I store items. I didn’t want to store items “under” a feed object and instead use a global Vue data value, allItems. Therefore, I copy the feed identifier and color into each item. The idea was to make it easier to do item display and filtering later. This feels “wrong” to me, but again, this is my first draft. I’m using a computed property for items and you can see that logic here:

items:function() { if(this.allItems.length === 0) return []; // filter let items = []; if(this.selectedFeed) { console.log('filtered'); items = this.allItems.filter(item => { return item.feedPk == this.selectedFeed.rsslink; }); } else { items = this.allItems; } items = items.sort((a, b) => { return new Date(b.isoDate) - new Date(a.isoDate); }); return items;
}

Looking at it now, I could gather my items from each feed instead of storing one global array, though I could address this later, if I want. I love that Vue gives me options for how to solve things like this.

Where Next?

When I started this article, I explicitly thought *this* *is* a first draft. I’ve pointed out things here and there that I like and don’t like, but what exactly do I plan for the next version?

  • I want to move all the data access into Vuex. Vuex is described as a “state management pattern + library” for Vue. If that doesn’t make much sense to you, don’t worry. I had no idea what it meant at first either. To me, Vuex provides a way to handle more complex data in an encapsulated manner. This becomes even more important as you start building more components that need to share data.
  • Speaking of components, I should consider making “item” a proper Vue component. That’s an easy win.
  • I want to start storing feed items in IndexedDB so you’ll get content the second you open the application. This will make the application much more performant and provide basic offline support. Of course, you can’t read the full entries if you’re offline, but at least *something* could be provided.
  • …and anything you suggest! Take a look at the code and feel free to make suggestions and point out mistakes!

Stay tuned for the second post!

The post Building a RSS Viewer With Vue: Part 1 appeared first on CSS-Tricks.

Creating your own meme generator

Almost every time a new meme pops up in my Twitter feed, I think of a witty version to create. I’m not alone in this. Memes are often a way to acknowledge a shared experience or idea. In a variation of the “Is this a pigeon” meme that has been making the rounds online, a designer Daryl Ginn joked about the elementary nature of most applications that say they use artificial intelligence.

Several people replied to his tweet saying something along the lines of “replace this with this.” Daryl’s version got them thinking about other possible variations. Platforms like imgFlip exist to make meme generations fast and easy. However, there is only so much customization they can allow. For many memes, creating new versions can only be done by people with Photoshop knowledge. But it doesn’t have to be so! For some memes that require more than Impact for the font text on an image, a meme generator can be created using the HTML Canvas API. In this tutorial, we’re going to make a generator for the #saltbae meme.

But first…

Let’s look at some fun interactive meme examples!

The website pablo.life allows you to create your own Kanye West TLOP album cover by changing the text and image.

This is one of my favorites:

The digital agency R/GA created the Straight Outta Somewhere campaign where users “show the world where they’re from by uploading their own photo and filling in the blank after ‘Straight Outta ____.'” Users can download and share the meme.

Developer Isaac Hepworth created the Trump Executive Order Generator.

Spotify collaborated with Migos to create a range of downloadable Valentine’s Day cards that can be customized by changing names.

Let’s build our own meme generator!

Now, the tutorial. In a popular version of the #saltbae meme, instead of salt, Salt Bae (whose name is Nusret Gökçe) sprinkles something other than salt.

Loading an image

The first thing we have to do is load the original image onto the canvas. You can load an image one of two ways: from a URL or from one that exists in the DOM using the <img> tag but is hidden.

Here’s how we do it with a hidden image tag:

<canvas id="canvas" width="1024" height="1024"> Canvas requires a browser that supports HTML5.
</canvas>
<img crossOrigin="Anonymous" id="salt-bae" src="http://res.cloudinary.com/dlwnmz6lr/image/upload/v1520011253/170203-salt-bae-mn-1530_060e5898cdcf7b58f97126d3cfbfdf71.nbcnews-ux-2880-1000_kllh1d.jpg"/>

I’m hosting the image on Cloudinary and added the crossOrigin attribute so we don’t run into any CORS issues.

function drawImage(text) { const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); const img = document.getElementById('salt-bae'); ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
} window.onload = function() { drawImage();
}

We’re using the canvas drawImage function to draw the image to the canvas. It can be used to draw videos or parts of an image as well. The method provides different ways to do this. We’re drawing the image by indicating the position and the width and height of the image.

ctx.drawImage(img, x, y, width, height);

Alternatively, we could load the image from a URL:

function loadAndDrawImage(src) { // Create an image object. (Not part of the dom) const image = new Image(); // After the image has loaded, draw it to the canvas image.onload = () => { // draw image }; // Then set the source of the image that we want to load image.src = src;
}

Now we load in an image to replace the sprinkles Salt Bae is throwing. First, we load the image using one of the techniques I mentioned earlier, then we draw it to the screen like we did with the Salt Bae base image.

function getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive
} function drawBackgroundImage(canvas, ctx) { ctx.clearRect(0, 0, canvas.width, canvas.height); const img = document.getElementById('salt-bae'); ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
} function getRandomImageSize(min, max, width, height) { const ratio = width / height; // Used for aspect ratio width = getRandomInt(min, max); height = width / ratio; return { width, height };
} function drawSalt(src, canvas, ctx) { // Create an image object. (Not part of the dom) const image = new Image(); image.src = src; // After the image has loaded, draw it to the canvas image.onload = function() { for (let i = 0; i < 8; i++) { const randomX = getRandomInt(10, canvas.width/2); const randomY = getRandomInt(canvas.height-300, canvas.height); const dimensions = getRandomImageSize(20, 100, image.width, image.height); ctx.drawImage(image, randomX, randomY, dimensions.width, dimensions.height); } } return image;
} onload = function() { const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); drawBackgroundImage(canvas, ctx); const saltImage = drawSalt('http://res.cloudinary.com/dlwnmz6lr/image/upload/v1526005050/chadwick-boseman-inspired-workout-program-wide_phczey.webp', canvas, ctx);
};

Now we can let users sprinkle something other than sprinkles.

Uploading an image

We’re going to add a button that triggers an image upload and includes an event listener to listen for a change.

<input type="file" class="upload-image">`
function updateImage(file, img){ img.src = URL.createObjectURL(file);
} onload = function() { const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); drawBackgroundImage(canvas, ctx); const saltImage = drawSalt('http://res.cloudinary.com/dlwnmz6lr/image/upload/v1526005050/chadwick-boseman-inspired-workout-program-wide_phczey.webp', canvas, ctx); const input = document.querySelector("input[type='file']"); /* * Add event listener to the input to listen for changes to its selected * value, i.e when files are selected */ input.addEventListener('change', function() { drawBackgroundImage(canvas, ctx); // clear canvas and re-draw updateImage(this.files[0], saltImage); });
};

URL.createObjectURL() creates a DOMString containing a URL representing the object given in the parameter which, in this case, is the uploaded file.

We can even up the game a little bit, like providing some default options. I’ve added a few emojis you can play around with as a starting point.

Downloading the final image

Once the new meme has been generated, we want users to be able to download and share it. The typical way of doing this is by opening the canvas in a new tab using the toDataURL method but the user would have to right click to save the image from that tab and that’s not very convenient.

So, instead, we can take advantage of the download attribute added to links in HTML5. We create a link that, on click, sets the download attribute to the result of canvas.toDataURL. The toDataURL() method “returns a data URI containing a representation of the image in the format specified.”

function addLink() { var link = document.createElement('a'); link.innerHTML = 'Download!'; link.addEventListener('click', function(e) { link.href = canvas.toDataURL(); link.download = "salt-bae.png"; }, false); link.className = "instruction"; document.querySelectorAll('section')[1].appendChild(link);
}

Well that’s it! Our meme generator is done.

Some cool links

  • Darius Kazemi has been making a bunch of twitter bots that generate memes.
  • Vox Media has a meme generator called meme that’s open source.

Meme away!

The post Creating your own meme generator appeared first on CSS-Tricks.

More Unicode Patterns

Creating is the most intense excitement one can come to know.

—Anni Albers, On Designing

I recently wrote a post — that was shared here on CSS-Tricks — where I looked at ways to use Unicode characters to create interesting (and random) patterns. Since then, I’ve continued to seek new characters to build new patterns. I even borrowed a book about Unicode from a local library.

(That’s a really thick book, by the way.)

It’s all up to your imagination to see the possible patterns a Unicode character can make. Although not all characters are good as patterns, the process is a good exercise for me.

And, aside from Unicode itself, the methods to build the patterns may not be so obvious. It usually takes a lot of inspiration and trial and error to come up with new ones.

More tiling

There are actually many ways to do tiling. Here’s one of my favorite tile patterns, which can be easily achieved using CSS grid:

A series of squares that vary in size from small to large and are arranged in a masonry pattern.
.grid { /* using `dense` to fill gaps automatically. */ grid-auto-flow: dense;
} .cell { /* using `span` to change cell size */ grid-column-end: span <num>; grid-row-end: span <num>;
}

Grid Invaders by Miriam Suzanne is a good example of this technique.

Now, what I’m trying to do is put some Unicode characters into this grid. And most importantly, update the font-size value according to the span of its cell.

A series of red and orange Chinese Unicode characters arranged in the grid pattern of the previous image.
Pattern using characters \2f3c through \2f9f

I only tested with Chrome on Mac. Some of the examples may look awful on other browsers/platforms.

.cell { /* ... */ --n: <random-span>; grid-column-end: span var(--n); grid-row-end: span var(--n);
} .cell:after { /* ... */ font-size: calc(var(--n) * 2vmin);
}

It’s a bit like the Tag Cloud effect, but with CSS. Lots of patterns can be made this way.

A series of orange and red \2686 and \2689 Unicode characters arranged in the same grid pattern as the other examples.
Pattern using characters \2686 through \2689
Unicode characters \21b0, \21b1, \21b2 and \21b4 arranged in the same grid pattern as the other examples. The effect is like a series of arrows pointed in different directions.
Pattern using charaters \21b0, \21b1, \21b2 and \21b4

The span of the columns and rows don’t always have to be the same value. We can make small modifications by changing how many rows each cell spans:

The grid layout with taller columns now that each cell spans more rows.
.cell { /* only change the row span */ grid-row-end: span <num>;
}

Since the font-size property scales up/down in both directions (vertically and horizontally), the scaleY() in the transform property will be used instead.

Red and blue diamond-shaped Unicode characters squeezed into the taller, thinner columns of the grid layout.
Pattern using characters \25c6 through \25c8
:after { /* ... */ transform: scaleY(calc(var(--span) * 1.4));
}

And here’s another one, made by rotating the inner container of the grid to some degree.

Red and blue triangles pointed diagonally in the grid layout.

The triangles also can be drawn with clip-path and will be more responsive, but it’s nice to do something in a different way.

More modifications to the layout:

The grid layout with skewed cells so that they form repeating parallelograms instead of rectangles.
.column-odd { transform: skewY(40deg);
} .column-even { transform: skewY(-40deg);
}

Now follow these transformations for each column.

Plus sign Unicode characters in green, red, yellow and gray that follow the parallelogram pattern of the updated grid, forming a crochet-like effect.
Pattern using characters \1690 through \1694

Composition

Many Unicode pairs share some kind of shape with different angles. For example, parentheses, brackets, and arrows with different that go in different directions. We can use this concept to combine the shapes and generate repeatable patterns.

This pattern uses less-than and greater-than signs for the base:

Wavy pattern using <code><</code> and <code>></code>” /></figure>
<pre rel=:nth-child(odd):after { content: '<'; } :nth-child(even):after { content: '>'; }

Here we go with parentheses:

A wavy pattern using ( and )
:nth-child(odd):after { content: '(';
} :nth-child(even):after { content: ')';
}

These are characters we use everyday. However, they give us a fresh look and feeling when they are arranged in a new way.

There’s another pair of characters, , and . Placing them in the grid and scaling to a proper value connect them together into a seamless pattern:

It’s like weaving with characters! We can even take it up a notch by rotating things:

Pattern using \169b and \169c

Rings

Last week, I joined a CodePen Challenge that challenged the group to make a design out of the sub and sup elements. As I experimented with them, I noticed that the two tags scaled down automatically when nested.

So, I tried to put them around a circle:

.first-level { /* Slice the circle into many segments. */ transform: rotate( calc(360deg / var(--slice) * var(--n)) );
}

Suddenly, I realized this method can be used to generate background patterns, too. The results are pretty nice.

The Unicode characters for less-than and greater-than signs repeated in a circle that starts large around the edge and narrows in, like the characters are flushing down a drain.
Pattern using \003e
sub:after, sup:after { content: '\003e';
}

The interesting thing is that changing a single character can end up with very different results.

Adding the Unicode character \002e creates the same circular pattern, but with arrows and dots.
Combining \002e and \003e together to form a pattern
Combining \25c9 and \2234 creates a different effect in the same circular layout

Wrapping up

That’s all for now! The color palettes used in this article are from Color Hunt and Coolors.co.

The examples are generated with css-doodle, except for Ring examples in the last section. Everything here can be found in this CodePen collection.

Hope you like them and thanks for reading!

The post More Unicode Patterns appeared first on CSS-Tricks.

​Truly understand your site visitors’ behavior

(This is a sponsored post.)

Hotjar is a quick and easy way to truly understand your visitors and identify opportunities for improvement and growth.

Try the all-in-one analytics and feedback tool for free.

Direct Link to Article — Permalink

The post ​Truly understand your site visitors’ behavior appeared first on CSS-Tricks.

Understanding the Almighty Reducer

I was recently mentoring someone who had trouble with the .reduce() method in JavaScript. Namely, how you get from this:

const nums = [1, 2, 3]
let value = 0 for (let i = 0; i < nums.length; i++) { value += nums[i]
}

…to this:

const nums = [1, 2, 3]
const value = nums.reduce((ac, next) => ac + next, 0)

They are functionally equivalent and they both sum up all the numbers in the array, but there is a bit of paradigm shift between them. Let’s explore reducers for a moment because they’re powerful, and important to have in your programming toolbox. There are literally hundreds of other articles on reducers out there, and I’ll link up some of my favorites at the end.

What is a reducer?

The first and most important thing to understand about a reducer is that it will always only return one value. The job of a reducer is to reduce. That one value can be a number, a string, an array or an object, but it will always only be one. Reducers are really great for a lot of things, but they’re especially useful for applying a bit of logic to a group of values and ending up with another single result.

That’s the other thing to mention: reducers will not, by their nature, mutate your initial value; rather they return something else. Let’s walk over that first example so you can see what’s happening here. The video below explains:

It might be helpful to watch the video to see how the progression occurs, but here’s the code we’re looking at:

const nums = [1, 2, 3]
let value = 0 for (let i = 0; i < nums.length; i++) { value += nums[i]
}

We have our array (1, 2, 3) and the first value each number in the array will be added to (0). We walk through the amount of the array and add them to the initial value.

Let’s try this a little differently:

const nums = [1, 2, 3]
const initialValue = 0 const reducer = function (acc, item) { return acc + item
} const total = nums.reduce(reducer, initialValue)

Now we have the same array, but this time we’re not mutating that first value. Instead, we have an initialValue that will only be used at the start. Next, we can make a function that takes an accumulator 
and an item. The accumulator is the collected value
 returned in the last invocation that informs the function what the next value will be added to. In this case of addition, you can think of it as a snowball rolling down a mountain that eats up each value in its path as it grows in size by every eaten value.

snowball accumulating values

We’ll use .reduce() to apply the function and start from that initial value. This can be shortened with an arrow function:

const nums = [1, 2, 3]
const initialValue = 0 const reducer = (acc, item) => { return acc + item
} const total = nums.reduce(reducer, initialValue)

And then shortened some more! Implicit returns for the win!

const nums = [1, 2, 3]
const initialValue = 0 const reducer = (acc, item) => acc + item const total = nums.reduce(reducer, initialValue)

Now we can apply the function right where we called it, and we can also plop that initial value directly in there!

const nums = [1, 2, 3] const total = nums.reduce((acc, item) => acc + item,

An accumulator can be an intimidating term, so you can think of it like the current state of the array as we’re applying the logic on the callback’s invocations.

The Call Stack

In case it’s not clear what’s happening, let’s log out what’s going on for each iteration. The reduce is using a callback function that will run for each item in the array. IThe following demo will help to make this more clear. I’ve also used a different array ([1, 3, 6]) because having the numbers be the same as the index could be confusing.

See the Pen showing acc, item, return by Sarah Drasner (@sdras) on CodePen.

When we run this, we’ll see this output in the console:

"Acc: 0, Item: 1, Return value: 1" "Acc: 1, Item: 3, Return value: 4" "Acc: 4, Item: 6, Return value: 10"

Here’s a more visual breakdown:

  1. It shows that the accumulator is starting at our initial value, 0
  2. Then we have the first item, which is 1, so our return value is 1 (0 + 1 = 1)
  3. 1 becomes the accumulator on the next invocation
  4. Now we have 1 as the accumulator and 3 is the item aince it is next in the array.
  5. The returned value becomes 4 (1 + 3 = 4)
  6. That, in turn, becomes the accumulator and the next item at invocation is 6
  7. That results in 10 (4 + 6 = 10) and is our final value since 6 is the last number in the array

Simple Examples

Now that we’ve got that under our belt, let’s look at some common and useful things reducers can do.

How many of X do we have?

Let’s say you have an array of numbers and you want to return an object that reports the number of times those numbers occur in the array. Note that this could just as easily apply to strings.

const nums = [3, 5, 6, 82, 1, 4, 3, 5, 82] const result = nums.reduce((tally, amt) => { tally[amt] ? tally[amt]++ : tally[amt] = 1 return tally
}, {}) console.log(result)

See the Pen simplified reduce by Sarah Drasner (@sdras) on CodePen.

Wait, what did we just do?

Initially, we have an array and the object we’re going to put its contents into. In our reducer, we ask: does this item exist? If so, let’s increment it. If not, add it and set it to 1. At the end, please return the tally count of each item. Then, we run the reduce function, passing in both the reducer and the initial value.

Take an array and turn it into an object that shows some conditions

Let’s say we have an array and we want to create an object based on a set of conditions. Reduce can be great for this! Here, we want to create an object out of any instance of a number contained in the array and show both an odd and even version of this number. If the number is already even or odd, then that’s what we’ll have in the object.

const nums = [3, 5, 6, 82, 1, 4, 3, 5, 82] // we're going to make an object from an even and odd
// version of each instance of a number
const result = nums.reduce((acc, item) => { acc[item] = { odd: item % 2 ? item : item - 1, even: item % 2 ? item + 1 : item } return acc
}, {}) console.log(result)

See the Pen simplified reduce by Sarah Drasner (@sdras) on CodePen.

This will shoot out the following output in the console:

1:{odd: 1, even: 2}
3:{odd: 3, even: 4}
4:{odd: 3, even: 4}
5:{odd: 5, even: 6}
6:{odd: 5, even: 6}
82:{odd: 81, even: 82}

OK, so what’s happening?

As we’re going through every item in the array, we create a property for even and odd, and based on an inline condition with a modulus operator, we’ll either store the number or increment it by 1. The modulus operator is really good for this because it can quickly check for even or odd — if it’s divisible by two, it’s even, if not, it’s odd.

Other resources

At the top, I mentioned other posts out there that are handy resources to get more familiar with the role of reducers. Here are a few of my favorites:

  • The MDN documentation is wonderful for this. Seriously, it’s one of their best posts, IMO. They also describe in a bit more detail what happens if you don’t provide an initial value, which we didn’t cover in this post.
  • Daniel Shiffman is always amazing at explaining things on Coding Train.
  • A Drip of JavaScript does a good job, too.

The post Understanding the Almighty Reducer appeared first on CSS-Tricks.

Your Brain on Front-End Development

Part of the job of being a front-end developer is applying different techniques and technologies to pull off the desired lovely Dribbble shot for a Food Recipe Website from Riko Sapto Dimo.

It’s a very appealing design, and there is loads in there to think about from a front-end web design and development standpoint.

We’re going to mostly be talking about design pattern choices and HTML/CSS tech choices. There is much more to the job of front-end development. Accessibility! Performance! Semantics! Design systems! All important stuff as well.

Multi-line padded text

Ah yes, that look where text has a background that follows the length of the lines of text. We’ve called that Multi-Line Padded Text in the past and looked at a number of ways to do it. The easiest and most modern way to handle it is with box-decoration-break.

See the Pen Multiline Padding with box-decoration-break by Chris Coyier (@chriscoyier) on CodePen.

Flexbox header

That header area is just begging for flexbox. It’s a single-direction layout with elements of different sizes and different space between them. Expressing that in flexbox is going to be easier than any other method and not require any fixed sizing or magic numbers — not to mention flexible!

Grid layout

The overall page layout here could be expressed nicely with CSS grid. Remember that flexbox and grid are not at odds. An element placed in a grid cell can be flexbox! Like the header above, that makes perfect sense. The main content area and footer, as grid cells, could probably go either way.

Vertical writing

Not the most obvious thing to pull off! Your best bet is using writing modes. Jen Simmons has written about this, and here’s a demo:

See the Pen Writing Mode Demo — Headline by Jen Simmons (@jensimmons) on CodePen.

Line clamping

Looks like we have some truncation going on here. General performance-wise, we’d probably be wanting the data being sent only be a few lines long. But the front end can help with this too, if it has to. Three lines of text are shown here with ellipsis at the end. Perhaps the design really needs the copy to always be a maximum of three lines. That’s called line clamping.

See the Pen Line Clampin’ by Chris Coyier (@chriscoyier) on CodePen.

Custom fonts

Like most sites these days, this design is coated in custom web fonts. With a design this striking, I’d be very careful about my font loading technique. My gut tells me I’d be more into FOIT than FOUT here, and ideally I’d cache that font file as hard as I could so that we’d have neither as often as possible.

Text over images

That text “Dinner Menu” is squarely over some busy photographic imagery below. It’s still readable though, largely because of the bright white of the text over a darkened image. We’ve covered thinking this through in the past in detail. White text over a darkened image is generally the way to go, and darkened enough such that just about any image will be OK. There are other options though, like gradients and blurring (which is also in use here in the footer)

See the Pen ByKwaq by Chris Coyier (@chriscoyier) on CodePen.

SVG icons / Star ratings

There are a number of simple, vector icons scattered around the design. Those are a sure-bet for an SVG icon system. This is my current recommendation for approaching an SVG icon system. Inline the SVG. Simple and powerful.

Those star ratings are probably SVG territory as well. Here’s a good collection of options. Progressively enhancing from radio buttons always seems like a smart way to go:

See the Pen CSS: Radio Input Stars by Jake Albaugh (@jakealbaugh) on CodePen.

Hamburgers

It might seem a little superfluous on a large screen design like this, especially as there is navigation already visible. But hey, it’s hard to avoid these days and there is something to be said about training users where site navigation can happen regardless of where you’re looking at the site.

Here’s a collection of those type of menus.

See the Pen Hamburger menu flip with text change by Eric Grucza (@egrucza) on CodePen.


Anything else in the design I didn’t mention that your mind goes to right away?

The post Your Brain on Front-End Development appeared first on CSS-Tricks.

Creating a VS Code Theme

Everyone has special and perhaps, particular, tastes when it comes to their code editor. There are literally thousands of themes out there, and for good reason: a thing of beauty and enhancement to productivity for one can be a hindrance to another.

It’s been an item on my bucket list to create my own theme. I was coding very late the one night, well into the small hours of the morning. Everyone in my house was sleeping and so, as usual, the only light was the glow of my screen. I know it’s not necessarily healthy to code like this, but it’s literally the time I’m most productive: there are minimal distractions, I’m not dealing with work stuff, family stuff, friend stuff, or puppy stuff. I can focus.

I had some preferences set for the theme I had been using and, though they all worked well for daytime or plane rides, I always felt like something was missing for late night coding sessions. I decided it was time to craft my own theme.

We’ll talk first about the general process for creating a theme in case you’d like to create one of your own, and then we’ll dive into some of the research and testing that went into mine in particular to peek into the process.

Fire It Up

Before you do anything, you’re going to install instructions to do so are here. I know it looks like a lot, but it takes anywhere from 5-10 minutes, and then you’ll never have to do it again, for any extension you create.

Now that you’ve got that under your belt, here are the steps you need to start work.

First, you need to run:

npm install -g yo generator-code

This makes the generator globally available on your machine (meaning you can now create a theme in any directory). You can then execute this command to kick off your theme:

yo code

You will be prompted by a screen that looks like this:

yeoman code generator welcome in terminal

Note that I’ve used the arrows here to navigate to the “New Color Theme” option. Note also that this is how you’d want to make any other extension.

When selecting this, it asks if this is a new theme or if we want to import from an existing one. We want to create a new one.

beginning prompt in terminal

Next, you’ll have to answer a few other questions, including:

  • What’s the extension’s name?
  • What is the the identifier? (I just went with the name, that’s probably typical.)
  • What is the the description? (I just put something silly in initially. Don’t worry, you can update this in your package.json in the future.)
  • What’s the publisher’s name? (See earlier instructions.)
  • What name should be shown to the user? (I used the same as the extension name.)
  • Is this theme dark, light, or high contrast?

It will set you up with a base theme to start skinning your color preferences. The full scoop and all the details are here. More details about themes in general are here.

Test Drive

We have our base theme and we have some concepts for the palette. So, how do we test it out? When you open the directory with your theme, you can press fn + f5 on Mac (or just f5 on Windows) and a new window immediately pops open where you can test your theme! You’ll see in the original theme window that you now have a little control panel where you can reload, pause, and stop. Don’t forget to save before you do!

controls for editor

OK, now that you have the other window open, hit Command + Shift + P to get the command explorer. In there type, “Developer: Inspect TM Scopes” and you’ll see a prompt come up that allows you to look through all the tags and attributes: it will tell you their color, their font styles, and how you need to target it.

what it looks like to inspect scopes in the new window

There is one problem, though. There are a lot of things in the editor you can’t target because VS Code will interpret that as you trying to drive the rest of the editor (i.e. the file viewer, the terminal, and the search boxes). Here are the two ways I found to figure out the rest of the scopes:

  • This page is extremely helpful in understanding some of the base things you need to configure. In fact, you might want to start with some of these.
  • There are DevTools! You can open them the same way you do with Chrome: Command + Option + I. What I did was look for the color in the computed styles and look them up in the text editor to target them. You’ll notice that the default in the DevTools is RGBA, so you will have to Shift + click on the color to change it’s format until you get to the equivalent hex values. I could then scan through the matching colors in my theme json until I found the matching value and change it.

Another Small Tip!

When I first started to develop the theme, I thought I would try forking someone else’s theme as a starting point. I tried out Wes Bos’ Cobalt Two. Though I didn’t end up using it, one thing he had that I found valuable was a demos directory with examples of all of a whole slew of different languages. I started by moving his over, but realized quickly that the files weren’t long enough for my testing needs. So I created my own. In the course of correcting issues people filed, I also created a React stateless functional component example, a Ruby example, and of course I created a .vue single file component 😀 This is also helpful in maintenance because if people are seeing an issue on a file type I previously didn’t test on, they can PR the file into the demos directory, and I can target what they’re seeing. It makes duplication and testing really simple.

Research

Research for a code theme? Isn’t that over the top? Probably! But I was genuinely curious: what would work best for legibility for the vast majority of people, while still being something I liked?

Color and contrast

The first step was considering accessibility. I always liked how solarized themes made legibility a central theme to their palettes. I read about color retention and accessibility, and it turns out that men have a really high incidence of colorblindness (around 8% for men, 1% for women). The majority of programmers are men, so even though I am not colorblind, it was a no-brainer to craft the theme at least partially around including those with colorblindness. The most typical is red/green deficiency so I found a few good ways to test with my favorite being, funnily enough, a bit manual.

I originally started by testing random images to see if I could discern a pattern that I could match. One thing I noticed while testing was that complementary colors seemed to perform the best across all tests. However, if three colors needed to be tested at once, a triad color composition also produced good results.

If you’re unfamiliar with color relationships, Adobe Color CC (previously Kuler) makes it easier to visualize and you can even create a color palette directly in the editor.

complimentary color palette
triad color palette
analagous color palette

It’s extremely important to know that a color is only a color in reference to another color. This is part of what makes crafting a color theme so difficult. Color isn’t static, it’s all about relationships. You’re probably a little familiar with this in terms of accessibility. A light green on a black may be accessible, but when you change it to a white background it no longer is.

Accessibility in color can be measured with a number of tools. Here are some of my favorites:

  • Colorable
  • Text on a background image a11y check
  • Contrast-A
  • Accessible Colors

It’s also really nice to set up your palette for accessibility from the start. Color Safe is a great tool that helps with that.

I cover more details about color and perception in this post: A Nerd’s Guide to Color on the Web.

Colors and Reading Comprehension

Another piece of this was learning which colors, if any, had an effect on reading comprehension. In some studies, it’s been shown that black text on white background, such as used in some light themes, can be difficult for comprehension. The theory is that the use of overlays to change the text color has improved cognitive awareness for many, especially those with dyslexia and autism. However, these studies are controversial and it’s inconclusive whether the overlays are effective in comprehension or a preference.

There is a syndrome called Irlen, or Scotopic Sensitivity Syndrome (SSS) that is known to interfere with the ability to discern letters and words. It is a visual perception disability on the magnocellular level — the visual pathway that can help with scanning and comprehension. This has been thought to be connected to — reading with impairment under certain types of light, and some think it can affect up to 50% of people (again, this figure is controversial and inconclusive).

We’re still learning about SSS, but there are some studies that color overlays can help focus attention to the text and reduce eyestrain. The colors found to increase readability and contrast so far for those with SSS have been beige, goldenrod, green, pink and blue. Blue has shown thus far to have the strongest link for people with Reading Disability and Attention Deficit/Hyperactivity Disorder.

Despite the fact that these studies haven’t reached statistical signifigance from what I can gather, I couldn’t find evidence that there was any harm in following them, and it seemed safest to keep them in mind while developing the theme. I chose a dark theme with blue as the primary color and used the other colors that tested well in supportive and contrasting roles throughout the theme.

Other Theme Inspiration

There were a few palettes I looked at for inspiration. For example, I did an exploratory study into what kind of tone I wanted.

  • Palenight Material: the reds and purples in my theme started with this one, and I adjusted the purples values.
  • Dracula: this theme’s base was a bit darker and provided contrast to the pastels I wanted in my theme.
  • Panda: I borrowed the turquoise color and adjusted it a bit.

I also looked at the work of Maggie Appleton quite a bit. I especially like her work on Egghead.io, which is amazing on every level.

css tailwinds illustration
webasm illustration

Those greens and oranges are where I started with my palette. I made adjustments while working on accessibility. The blackest blue-black that’s in the lower right of the image became the base of my main background.

Decisions, Decisions

There were a lot of decisions to make at this point. Thankfully, my research was done. Remember, I wanted pastels, like the ones used in the Material Palenight, Panda and Dracula Dark themes. Specifically, I wanted to use beige, goldenrod, green, pink and blue based on what I had read in the research phase. But the most important part to me was contrast across the color spectrum. That’s what I felt some of the other themes lacked, even if they nailed the colors.

I went to work, creating blue and a golden color as the base standard for working across the color spectrum.

I used purple for keywords that are informative but I didn’t want to call out as strongly — if you’re trying to create contrast, you also need to consider what colors to make subtle so that it gives attention to what’s most important. If everything is important, nothing is. I also wanted to offset the fact that the purple had a shallow contrast by making it different in some other way. I did this with the use of italics. Some people like that, some hate it. I decided to buy a font called Dank Mono, similar to Operator Mono, or Fira Code (the latter being the free open source version), partially because I enjoyed the presentation of the italic glyphs. They also have font ligatures, which can be quite stylish. You set them in your user preferences with "editor.fontLigatures": true. Some people aren’t super into the italics, though, so I created a no italic version that people could switch to if it bothered them.

I wanted to call out state/data strongly because it tends to be important for me when when scanning code. I started with red because I had seen that in many other themes, but I couldn’t get away from the fact that my eyes would only go there and the fact that red is often associated with error states. So, instead, I used the strongest color against the background I had chosen, white, and italicized it to offset it even more. It also has the benefit of being a midpoint between blue and gold. I saved the red/orange distinction for React components, which needed to have some separation from the standard HTML elements.

Contrast is a zero-sum game: if everything is important, nothing is. I tried my best to be sure things that were conceptually similar or could fall back, did so that strong contrast was intentional and everything didn’t turn into a rainbow, because that hurts your ability to scan the document.

One such decision was to keep the sidebar contrast low in order to keep the focus on the editor. I found that if I tried to bring the contrast up in other parts of my editor, my eyes actually began to hurt. This can be a challenging thing about some accessibility- because not all humans are the same, things like color and font can become a spectrum rather than a hard rule.

After running a lot of tests, the compromise I decided on was to keep the theme to what I myself could use without strain, and update the readme with the preferences I would recommend for someone who was different from me and needed the contrast levels to be higher. If you go into your user settings in VS Code (Code > Preferences > Settings), in the righthand pane, you can add your own customizations. With the help of some people in the community who filed issues because they wanted this feature, we arrived at these possible color preference updates for those who need the contrast:

"workbench.colorCustomizations": { "activityBar.background": "#000C1D", "activityBar.border": "#102a44", "sideBar.background": "#001122", "sideBar.border": "#102a44", "sideBar.foreground": "#8BADC1"
},

You can actually drop any colors in here, this was just a suggestion for a starting point based on the existing theme colors. These workbench color customizations are really handy, they allow people to use a theme, and then make small tweaks as they feel they need them. If you’re using a theme and it’s allllmost perfect but not quite, you can always make small changes this way.

There were hundreds of other small decisions I made over the course of creating it (and am still making now that I’m maintaining it), but after I had made a good amount of tweaks, I would check my work against the colorblind simulator. It wasn’t terribly easy getting it to work right in every language for every setting, but I did my best. This is where that demo folder came in really handy. Now that it’s launched, if someone needs particular language support, I can encourage them to PR the folder so that I can support it.

Here’s an example Angular file:

beginning angular file

…and here are some of the tests I ran to determine if there was enough contrast. Remember, what I was looking for was contrast across the color spectrum for meaningful distinctions, and slight contrast for things that require less attention:

angular file testing

It took a good amount of tests to get something that didn’t become monochrome, especially across languages. The amount of color combinations possible are a bit endless, and it’s pretty difficult to make something that works perfectly in every scenario. That’s why I spent a lot of time crafting the demo folder and making small tweaks to try to cover as much ground as possible.

Bugfixes

I launched it! Everyone party! 🎉

The most helpful thing to me were the contributions of people using the theme and letting me know their pain points by logging issues in the GitHub repo. It’s hard to see every failure scenario across a theme, and have so far had 16 subsequent releases to fix over 50 bugs so far, some with help from the community. The more people who let me know what they’re seeing, the better the theme gets. Not everything gets in of course — there are times when people want things that conflict with other requests, so I have to make a judgement call in some cases. Still, this this is rare and the majority of feedback so far have been very clean-cut and actionable.

That’s it! If you’d like to check out the theme, it’s available here for free. I hope you found this useful, either for background into the theme and the decisions that were made, or for a process in creating your own.

The post Creating a VS Code Theme appeared first on CSS-Tricks.

World wide wrist

After all the hubbub with WWDC over the past couple of days, Ethan Marcotte is excited about the news that the Apple Watch will be able to view web content.

He writes:

If I had to guess, I’d imagine some sort of “reader mode” is coming to the Watch: in other words, when you open a link on your Watch, this minified version of WebKit wouldn’t act like a full browser. Instead of rendering all your scripts, styles, and layout, mini-WebKit would present a stripped-down version of your web page. If that’s the case, then Jen Simmons’s suggestion is spot-on: it just got a lot more important to design from a sensible, small screen-friendly document structure built atop semantic HTML.

But who knows! I could be wrong! Maybe it’s a more capable browser than I’m assuming, and we’ll start talking about best practices for layout, typography, and design on watches.

I had this inkling for a long while that there wouldn’t ever be a browser in the Watch due to its constraints, but instead I hoped that there might be a surge of methods to read web content aloud via some sort of voice interface. “Siri, read me the latest post from James’ blog,” is probably nightmare fuel for most people but I was sort of holding out for devices like this to access the web via audio.

Another interesting aside is that both Safari OSX and iOS have had a reader mode for a long time now, but have it as an option enabled by the user while viewing the content. Bypassing the user-enabled option would be the difference on watchOS and where our structured, semantic chops are put to task.

Direct Link to Article — Permalink

The post World wide wrist appeared first on CSS-Tricks.