Developer News


Css Tricks - Wed, 07/24/2019 - 8:04am

David DeSandro has loads of super cool JavaScript libraries he's created over the years. His latest is Zdog, a "round, flat, designer-friendly pseudo-3D engine for canvas & SVG." It's only been about a month since he dropped it (although, like any good library, it's been simmering) and it has been pretty incredible to watch it capture the imagination of loads of designers and developers.

I'm shouting out Zdog here because I think it's worth y'all checking out. There is something about the API and how easy it becomes to draw in a 3D space that is clicking with folks. It might just click with you! Having a little moment like that is what web dev is all about ;).

See the Pen
Zdog Spaceship
by Ryan Mulligan (@hexagoncircle)
on CodePen.

The Official Site

(And GitHub repo.)

See the Pen
by Jessica Paoli (@skullface)
on CodePen.

CodePen Collections

Here is a collection from Dave that gathers community-built examples:

And here's is a Collection from Dave himself of demos he created while building the library.

See the Pen
Zdog and Goo
by Chris Gannon (@chrisgannon)
on CodePen.

There is a lot of cool stuff all around the web with Zdog, like this idea of plotting data with it from Zach:

Plus a font!!

See the Pen
Zfont Advanced Demo
by James Daniel (@rakujira)
on CodePen.

CodePen Topic

We created a Topic on CodePen to help explore the library and find examples as well.

We also covered it over on the CodePen Blog when the library dropped because it was so dang exciting.

(By the way, if you have a good idea for a "Topic" on CodePen, let me know! The main thing we need is a good strong Collection of "starter" Pens to help people understand concepts and use the library, plus a Collection of strong, complete examples. I have some cool swag and stuff I could send your way if you're into the idea of helping.)

The post Zdog appeared first on CSS-Tricks.

Don’t comma-separate :focus-within if you need deep browser support

Css Tricks - Wed, 07/24/2019 - 8:04am

I really like :focus-within. It's a super useful selector that allows you to essentially select a parent element when any of its children are in focus.

Say you wanted to reveal some extra stuff when a <div> is hovered...

div:hover .extra-stuff { /* reveal it */ }

That's not particularly keyboard-friendly. But if something in .extra-stuff is tab-able anyway (meaning it can be focused), that means you could write it like this to make it a bit more accessible:

div:hover .extra-stuff, div:focus-within .extra-stuff { /* reveal it */ }

That's nice, but it causes a tricky problem.

Browsers ignore entire selectors if it doesn't understand any part of them. So, if you're dealing with a browser that doesn't support :focus-within then it would ignore the CSS example above, meaning you've also lost the :hover state.


div:hover .extra-stuff { /* reveal it */ } div:focus-within .extra-stuff { /* reveal it */ }

That is safer. But it's repetitive. If you have a preprocessor like Sass...

@mixin reveal { .extra-stuff { transform: translateY(0); } } div:hover { @include reveal; } div:focus-within { @include reveal; }

See the Pen
Mixing for :focus-within without comma-separating
by Chris Coyier (@chriscoyier)
on CodePen.

I'd say it's a pretty good use-case for having native CSS mixins.

The post Don’t comma-separate :focus-within if you need deep browser support appeared first on CSS-Tricks.

Unsuck It

Css Tricks - Tue, 07/23/2019 - 10:37am

Julia Carrie Wong and Matthew Cantor's How to speak Silicon Valley: 53 essential tech-bro terms explained was pretty hilarious. A little something in there to offend everyone.

Speaking of kinda douchey words, I'm reminded of one of my favorite sites on the internet: Unsuck It. Not only does it call out a ton of terms for being, uh, sucky, but suggests unsucky alternatives.

Bubble Up

Thank you for pointing out that issue. I’ll be sure to bubble that up.

Unsucked: Tell someone with more authority.


Oh, yes! That’s very important to me. Let’s have a powwow about this first thing tomorrow.

Unsucked: Yet more unthinking appropriation of Native American culture. Meeting.


Unsucked: Thinking.

On a somewhat related note, there's the ol' swoop and poop which is also a thing.

Direct Link to ArticlePermalink

The post Unsuck It appeared first on CSS-Tricks.

Pseudo Code

Css Tricks - Tue, 07/23/2019 - 4:39am

Yonatan Doron wrote a post on Medium not long ago called "Art of Code — Why you should write more Pseudo Code." Love that title, as a fan of pseudo code myself. That is, writing "code" that describes something you want to do or communicate, but that isn't of any particular language and doesn't use any correct APIs or anything.

Taking this time to write commented pseudo code helps organize our thoughts and our motivation and plan the desired outcome code ahead. By doing so, one moment later when we venture through to start hacking we would always have this map or skeleton of our thoughts that can help us regain focus and increase our productiveness

Jeremy Keith once likened it to writing a script:

When the user submits a form, then show a modal dialogue with an acknowledgment.” I then encouraged them to write a script …but I don’t mean a script in the JavaScript sense; I mean a script in the screenwriting or theatre sense. Line by line, write out each step that you want to accomplish. Once you’ve done that, translate each line of your English (or Portuguese) script into JavaScript.

I've seen educators use this technique time and time again. But it isn't just for teachers to use and students to learn from — it's for anyone's benefit. I find myself doing pseudo code before I write real code, sure, but I also leave it in place sometimes in code comments. Most commonly, I do it in Notion documents or in Slack conversations to get across a point.

Even simple ideas:

if stop email delivery

Anything with logic and branching or step-by-step bits benefits highly from it. Notice that code isn't valid code. It's not valid in any language I can think of. Sometimes, I'll throw in some random parenthesis or a semicolon out of muscle memory. Who cares? It's just about communicating an idea to myself or someone else.

if (grid is supported) use grid else lay out things in a basic row with flexbox

It's natural. Chances are, they won't care about the syntax either, they'll just get the idea.

on form submit validate if errors show errors; else submit to api; if api success show ui success; else show ui fail;

(After writing these out, it made me think of uilang. Check out how the plain language code blocks work there.)

Yonatan's article was missing real-world pseudo code examples, so I asked around. Check out all these great examples!

My whole notebook is a pseudo...

These transfer to comments before I start coding so I know what I’m doing & what I’ve done later

— Ruth John (@Rumyra) May 28, 2019

whiteboards are amazing for writing pseudocode as well as adding graphics to it.

— norom (@_norom_) May 28, 2019

Oh I used to make these, a long time ago....

— Ben Koppenens (@bkoppenens) May 28, 2019

All the time!

— Bryan (@iamBryanSanders) May 28, 2019

Trying to work with JavaScript and php simultaneously can get a little tricky sometimes

— frankie | webdev (@azoicx) May 29, 2019

late entry. quick map of scripts.

— Adam Styles (@thelibstyles) May 31, 2019

I'm a little surprised at how much of it is on paper! That's pretty cool, really. Just weird for me as I very rarely use paper for anything. I probably should.

The post Pseudo Code appeared first on CSS-Tricks.

Zoom, CORS, and the Web

Css Tricks - Tue, 07/23/2019 - 4:39am

It's sorta sad by funny that that big Zoom vulnerability thing was ultimately related to web technology and not really the app itself.

There is this idea of custom protocols or "URL schemes." So, like gittower:// or dropbox:// or whatever. A native app can register them, then URLs that hit them get passed to the native app. iOS has "universal links" which are coming to the web apparently. (Atishay Jain has an excellent write-up on them.) But links like that don't leave much choice — they will open in the app. If your app has both web and native components, you might want to offer the user a choice. So, you use a regular URL instead.

In order for that web page to open up a native app, apparently, the tactic used by many is to have it communicate with a server running on localhost on your own computer which uses a URL scheme to open the native app. Clever, but I've heard sentiment from folks like:

  • I had no idea this software was running a localhost server on my machine
  • It feels weird that websites out on the wild internet can communicate with my localhost server

That's the way it is though. But there are some protections in place. Namely: CORS (Cross-Origin Resource Sharing). Ugh. I feel like I deal with some kind of CORS problem every week of my life. But it's important. It prevents XHR requests from websites that aren't specifically allowed. Imagine if you visit my website, and I have your browser shoot requests over to Facebook, hoping you are logged in so I can do things on your behalf. Bad. CORS doesn't prevent that, the same-origin policy of browsers prevents that. CORS is the mechanism to control that.

If my website tries to communicate with your website, and your website's response doesn't have an Access-Control-Allow-Origin header with my domain or *, it will fail. But not everything is subject to CORS restrictions. Images, for example, are not. We can link up images from any domain and they will return data.

Chris Foster thinks CORS and a lack of understanding of CORS was at the heart of the Zoom bug.

Zoom may have needed to get this feature out and did not understand CORS. They couldn’t make the AJAX requests without the browser disallowing the attempt. Instead, they built this image hack to work around CORS. By doing this, they opened Zoom up to a big vulnerability because n/ot only can the Zoom website trigger operations in the native client and access the response, but every other website on the internet can too.

In the wake of all this, Nicolas Bailly wrote "What you should know about CORS":

This is often a source of confusion for newcomers because it's not immediately apparent what CORS is supposed to achieve. Firstly CORS is not a security measure in itself, it's actually the opposite: CORS is a way to circumvent the "Same Origin Policy" which is the security measure preventing you from making [AJAX] requests to a different domain.

The post Zoom, CORS, and the Web appeared first on CSS-Tricks.

CSS :not() with Multiple Classes

Css Tricks - Mon, 07/22/2019 - 11:39am

Say you want to select an element when it doesn't have a certain class. That's what the :not() selector is for.

body:not(.home) { }

But what if there are multiple classes you want to avoid?

There are no logical combinators with :not(), like and or or, but you can chain them, which is effectively like and.

body:not(.home):not(.away):not(.page-50) { }

The :not() selector doesn't add any specificy by itself, but what is inside does, so :not(.foo) adds the same weight as .foo does.

The post CSS :not() with Multiple Classes appeared first on CSS-Tricks.

A Beginner’s Journey to Launching a Website

Css Tricks - Mon, 07/22/2019 - 5:07am

In September 2018, I was just a few months into my journey of learning web development. As I'm sure is the case with many new developers, it was a big task for me to learn not only the basic skills required, but also keeping current with the fast-moving industry. Just as I was getting to the level where it felt as though I could build a simple website, I started to realize that it was only the first step.

Opening up a few HTML pages stored locally on my laptop felt like a million miles away from being able to say to someone, "Hey, check out my website, live on the actual internet!"

But I did it! And the best part is that it wasn't as scary, difficult or expensive as it first felt like it'd be.

It all started with me sending Chris an email, which he used to write an awesome article explaining everything in plain English.

At this point, I didn't have a fully coded website — just an idea for a basic site that I was using to teach myself as I went along. I used the ongoing progress of my site as a push to learn how to get a live website quicker. But I'm sure you could do the whole thing with an HTML document that just says "Hello, world!"

I built my site using Gatsby, a static site generator powered by React. Building a website with these tools in a modular way felt really natural to me. The concept of reusable parts is something I’m familiar with in my career as a physical product designer and mechanical design engineer. It means that you can build in stages, like Lego, brick-by-brick, until you eventually have a life-sized castle you can invite your friends to visit!

This isn't a guide. It's my personal experience in the process of getting a website from my laptop to being live on the internet. Hopefully it'll give you some hope that it's possible and achievable, even by someone who has no formal training in web development and who has only been doing it for 12 months!

Domain registrars

Before I ever bought a domain, it seemed like a pretty serious thing to do. Owning a domain means being responsible for it. People will go to that address and eventually see content that you've put there.

I don’t know if everyone has the same experience, but I spent weeks deciding on a domain name before going for it. It almost became an obsession of mine for a while, searching online for acronym generators to try and be clever, spending hours on trying to find synonyms that were cool. In the end, I settled for my name and what I do: I still smile a little when I see my name in the address bar.

Since reading Chris' article, I've actually bought two domains from two different providers: a .com and a .design. I realize that I went against Chris' advice of consolidating domain names at a single registrar, but I needed to shop around a bit to get a good deal on my .design domain. I only own two domain names — and one of them I don't actually have any plans for just yet — so keeping on top of where I bought them isn't a task. In fact, I don't remember the last time I needed to login and manage the domain I use on a daily basis!

Buying a domain name was as simple as any other online shopping transaction. Nothing really huge or scary about it. I bought my .com through Namecheap, and my .design through Google Domains, and the process was pretty similar for both. All they needed was my name, address and payment details. Pretty standard stuff!

I don't remember Google trying to sell me a load of extra packages. They seemed happy with me just buying a domain, though they did offer me free WHOIS protection which I snapped up because I didn’t want my contact details freely available for anyone who’s feeling nosey. However, as Chris warned might happen, the other registrar I went through tried really hard to sell me some extras like hosting, email, a VPN (whatever that is!) and SSL certificates.

Google Domains checkout is happy just to sell the domain name. Namecheap tries to sell you all the additional services they offer before getting to the checkout.

I didn't go for any of those extras. I already had a hosting plan, and you can use an alias through Gmail to "fake" having a email address. I honestly have no idea why I'd need a VPN, and the hosting I was going to go for gave me a free SSL certificate through Let's Encrypt. So just the domain name, please!


As Chris suggested it would be, choosing a host was a tad trickier than choosing and buying a domain name. But in the end, the web technology I used to build my site kind of guided me in a particular direction.

My site is built with Gatsby, which means it outputs straight-up static assets, basically as HTML and JavaScript files. That means that I didn't need a host that offered a server (in my most super smart authoritative voice), especially for WordPress with a MySQL database and Apache server, 6 cores @ 3.6 Ghz, 4GB RAM, 5TB bandwidth, 5 IP Addresses and 500GB SSD Storage, etc.

All that jargon goes straight over my head. All I wanted to do was upload my files to the internet and go to my domain to see them all compiled and shiny. Should be easy, right?

Well it turns out that it actually was that easy. As there's been so much hype around it recently, I thought I'd take a look at Netlify.

Netlify is recommended by Gatsby. They have really good documentation, and for my uses I felt as though I could comfortably stay within the free tier that they offer. In fact, at the moment I'm using 0.08% a month of the total bandwidth the free tier offers. Winning! Although maybe that means I’m not doing enough to get people to my site...

A quick aside about GitHub: I'm no expert at it and I don't really know any of the etiquette it entails. All I did was sign up, create a new repository and follow the instructions that they give you. After that, every time I made a change to my site, I used the buttons in my code editor (VS Code) to commit and push my changes. It works, but I have no idea if it's the correct or best practice way of doing it! I'm starting now, though, to understand how to use Git through the command line. I had no idea at all how to do it when I started, but I still muddled through it — and you can too!

Back to Netlify.

I signed up for an account (no credit card details required) and added a new site to Netlify by telling it about the GitHub repository where it was stored. When you’ve connected your repository, you can watch Netlify doing its thing deploying your site.

Part of the Netlify’s deploy process is that it shows your website going live in real time. That’s useful for debugging if something goes wrong, or just to watch and get excited like an impatient puppy waiting for a biscuit. You also get a deploy summary to quickly see what files were uploaded during deployment.

After my site was deployed to the randomly generated URL Netlify gives you, I followed their instructions for adding a domain I had registered elsewhere. They make it so easy!

I assume the instructions will be different for different hosts, but basically, Netlify gave me some server addresses which I then had to go back to my domain registrar to enter them in. These addresses are referred to as nameservers, so look out for that word!

Netlify gives you your nameserver addresses and super easy to understand documentation to set them up with your domain registrar

Once I entered my Netlify nameservers into Google Domains, Google knew where to look to send people who type my domain name into their browser’s address bar. All I had to do after that was wait for some internet magics to happen in the background. That took around three hours for me but can take anywhere from 10 minutes to 24 hours from what I hear.

After that was done, I could type my shiny new domain name into the address bar and — just like that — I'm looking at my own site, hosted live on the internet!

Content Management Systems

The world of Content Management Systems (CMS) is vast, and confusing, but it can also be completely irrelevant to you if you want it to be. I felt so liberated when I realized you don't have to worry about it. It was one less thing in my list of things to do.

My Gatsby site posts and pages (my content) was just a directory of markdown files and my CMS was my text editor. Chris and Dave talked about the idea of this in a recent episode of ShopTalk Show.

My website content is managed right in my text editor, VS Code.

Because I wanted to have a standard structure for different types of posts and pages, I eventually started using NetlifyCMS which is an open-source CMS which can be included in your site real fast. (Chris also did a video recently about NetlifyCMS for his confer-reference site... see what I did there?!) Now I can create blog posts and drafts from anywhere in the world, straight from my website, as long as I have an internet connection!

The same content managed through NetlifyCMS, which offers a great UI and GitHub integration Asset Hosting (CDNs)

A Content Delivery Network (CDN), as Chris explained in his article, is basically somewhere on the internet where you store the files you need for your website to run, HTML, CSS, images, etc. When your website needs them, it goes to the CDN and grabs the files for your site to use.

From what I've read, it's good practice to use a CDN, and because of the hosting decision I made, it's not something I have to worry about - it's included by Netlify as standard, for free!

Netlify has it's own CDN where all of the files for your website are stored. When someone goes to your website, Netlify goes to its CDN and grabs the files. It's amazingly quick, and makes your site feel so much smoother to navigate.

It's a long journey, but you can do it!

There was a point, before I set off on the journey of getting my website live, where I tried to convince myself that it's fine to just have local websites, as my career isn’t in web development. The reason for that was because the path felt like it would be difficult, long and expensive.

In fact, it was none of those things! You could get a website live on the internet for £0.99 (~$1.25 for you Americans) or less if you find a deal on a domain name. The domain name was my only expense because for the path I took for hosting, asset management and content management.

At a super basic level, the path looks like this..

Code > Buy Domain > Find/Buy Hosting > Update Nameservers > Upload Code > Live!

If you happen to use the same vendor to buy your domain name and your hosting, you can skip the nameserver step. (Netlify sells domains too!)

It's definitely possible for anyone to get their website live on the internet. There's a process that you need to follow, but if you take your time, it can be relatively straightforward. It's a really wonderful feeling, getting a thing you built in front of people, and it's honestly something that I thought I'd never be able to do. But it's certainly within everyone's reach!

Something I've come to really admire over this process (and thousands of Google searches) is the willingness of everyone in the web community to collaborate and help, accepting me and my questions as I tried to learn what I was doing. It's something that I wish was more common in my own industry.

I'd love to hear other people's experiences getting their first website live. What were your pitfalls and triumphs? Was it as scary as it first seemed?

The post A Beginner’s Journey to Launching a Website appeared first on CSS-Tricks.

CSS Animation Libraries

Css Tricks - Mon, 07/22/2019 - 5:06am

There are an awful lot of libraries that want to help you animate things on the web. These aren't really libraries that help you with the syntax or the technology of animations, but rather are grab-and-use as-is libraries. Want to apply a class like "animate-flip-up" and watch an element, uhhh, flip up? These are the kind of libraries to look at.

I wholeheartedly think you should both 1) learn how to animate things in CSS by learning the syntax yourself and 2) customize animations to tailor the feel to your site. Still, poking around libraries like this helps foster ideas, gets you started with code examples, and might form a foundation for your own projects.

Let's take a look at the landscape of them. Some libraries have different approaches: only take what you need classes, Sass mixins, light JavaScript libraries for adding/removing classes, etc. But they are all essentially "CSS animation libraries." (Some of them are kinda funny having "CSS3" in the title, which kinda dates them. People just don't say that anymore.)

While animations can both be fun and create useful interactions, it's worth remembering that not all users want them when browsing the web. See Eric Bailey's "Revisiting prefers-reduced-motion, the reduced motion media query" for information on how to accommodate users who prefer little or no motion.


You pick an animation you like and it gives you a class name you can use that calls a keyframe animation (you copy and paste both). The point is you just take what you need.

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


One of the big original classic CSS animation libraries from Dan Eden.

See the Pen
Animate.css (Part 3)
by Hudson Taylor (@Hudson_Taylor11)
on CodePen.


Tachyons itself is an atomic CSS library with a ton of utility classes for essentially designing anything by adding classes to what you need. tachyons-animate extends those by adding "Single purpose classes to help you orchestrate CSS animations." It can be used alone, but even the docs suggest it can be used in combination with other animation libraries since helper classes are generically useful.

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


These animations, like rotations and pulses, that are specifically designed to run and repeat forever.

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

Motion UI

A Sass library for creating flexible CSS transitions and animations.

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


a [?] microInteraction library built with CSS Animations and controlled by JavaScript Power

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


Vivify is sort of like Animate.css in the sense that it contains a lot of the same types of animations. It does offer plenty of its own as well.

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


A collection of CSS3 powered hover effects to be applied to links, buttons, logos, SVG, featured images and so on. Easily apply to your own elements, modify or just use for inspiration. Available in CSS, Sass, and LESS.

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


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

Magic Animations CSS3

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

It's Tuesday.

A quirky CSS Animation Library.

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


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


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


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

Motion CSS

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


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


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


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

Hexa Mimic.css

See the Pen
by Eric Treacy (@etreacy)
on CodePen.

The post CSS Animation Libraries appeared first on CSS-Tricks.

How I Created a Code Beautifier in Two Days

Css Tricks - Fri, 07/19/2019 - 10:54am

I recently drew up a wireframe for a code beautifier. The next day, I decided to turn it into a real tool. The whole project took less than two days to complete.

I'd been thinking about building a new code beautifier for a while. The idea isn't unique, but every time I use someone else's tool, I find myself reapplying the same settings and dodging advertisements every single time. &#x1f926;&#x1f3fb;‍

I wanted a simple tool that worked well without the hassle, so last week I grabbed some paper and started sketching one out. I'm a huge fan of wireframing by hand. There's just something about pencil and paper that makes the design part of my brain work better than staring at a screen.

I kicked off the design process by hand-drawing wireframes for the app.

I was immediately inspired after drawing the wireframe. The next day, I took a break from my usual routine to turn it into a something real. &#x1f468;&#x1f3fb;‍&#x1f4bb;

Check it Out

The design

I knew I wanted the code editor to be the main focus of the tool, so I created a thin menu bar at the top that controls the mode (i.e. HTML, CSS, JavaScript) and settings. I eventually added an About button too.

The editor itself takes up most of the screen, but it blends in so you don't really notice it. Instead of wasting space with instructions, I used a placeholder that disappears when you start typing.

The Dark Mode UI is based on a toggle that updates the styles.

At the bottom, I created a status bar that shows live stats about the code including the current mode, indentation settings, number of lines, number of characters, and document size in bytes. The right side of the status bar has a "Clear" and "Clean + Copy" button. The center has a logo shamelessly plugging my own service.

I don't think many developers really code on phones, but I wanted this to work on mobile devices anyway. Aside from the usual responsive techniques, I had to watch the window size and adjust the tab position when the screen becomes too narrow.

I'm using flexbox and viewport units for vertical sizing. This was actually pretty easy to do with the exception of a little iOS quirk. Here’s a pen showing the basic wireframe. Notice how the textarea stretches to fill the unused space between the header and footer.

See the Pen
Full-page text editor with header + footer
by Cory LaViska (@claviska)
on CodePen.

If you look at the JavaScript tab, you’ll see the iOS quirk and the workaround. I’m not sure how to feature detect something like this, so for now it’s just a simple device check.

Handling settings

I wanted to keep the most commonly used settings easy to access, but also expose advanced settings for each mode. To do this, I made the settings button a popover with a link to more advanced settings inside. When a setting is changed, the UI updates immediately and the settings are persisted to localStorage.

The most common settings are contained in a small panel that provides quick access to them, while advanced settings are still accessible via a link in the panel.

I took advantage of Vue.js here. Each setting gets mapped to a data property, and when one of them changes, the UI updates (if required) and I call saveSettings(). It works something like this.

function saveSettings() { const settings = {}; // settingsToStore is an array of property names that will be persisted // and "this" is referencing the current Vue model => settings[key] = this[key]); localStorage.setItem('settings', JSON.stringify(settings); }

Every setting is a data property that gets synced to localStorage. This is a rather primitive way to store state, so I might update the app to use a state management library such as Vuex later on.

To restore settings, I have a restoreSettings() function that runs when the app starts up.

function restoreSettings() { const json = localStorage.getItem('settings'); if (json) { try { const settings = JSON.parse(json); Object.keys(settings).forEach(key => { if (settingsToStore.includes(key)) { this[key] = settings[key]; } }); } catch (err) { window.alert('There was an error loading your previous settings'); } } }

The function fetches settings from localStorage, then applies them one by one ensuring only valid settings in settingsToStore get imported.

The Advanced Settings link opens a dialog with tabs for each mode. Despite having over 30 settings total, everything is organized and easy to access so users won't feel overwhelmed.

Clicking the "Advanced Settings" link opens up language-specific preferences and shortcuts. Applying themes

Dark mode is all the rage these days, so it's enabled by default. There's also a light theme for those who prefer it. The entire UI changes, except for popovers and dialogs.

I considered using prefers-color-scheme, which coincidentally landed in Firefox 67 recently, but I decided a toggle would probably be better. Browser support for the color theme preference query isn't that great yet, plus developers are weird. (For example, I use macOS with the light theme, but my text editor is dark.)

The app with Light Mode UI enabled. Defining features

Coming up with feature ideas is fairly easy. It’s limiting features for an initial release that’s hard. Here are the most relevant features I shipped right away:

  • Beautifies HTML, CSS, and JavaScript code
  • Syntax highlighting with tag/bracket matching
  • Paste or drop files to load code
  • Auto-detects indentation preference based on pasted code or dropped file
  • Light and dark themes
  • Clean and copy in one click
  • Keyboard shortcuts
  • Most JS Beautify options are configurable
  • Settings get stored indefinitely in localStorage
  • Minimal UI without ads (just an unobtrusive plug to my own service) &#x1f648;

I also threw in a few easter eggs for fun. Try refreshing the page, exploring shortcuts, and sharing it on Facebook or Twitter to find them. &#x1f609;

The tools and libraries I used

I'm a big fan of Vue.js. It's probably overkill for this project, but the Vue CLI let me start building with all the latest tooling via one simple command.

vue create beautify-code

I didn't have to waste any time scaffolding, which helped me build this out quickly. Plus, Vue came in handy for things like live stats, changing themes, toggling settings, etc. I used various Element UI components for things like buttons, form elements, popovers, and dialogs.

The editor is powered by CodeMirror using custom styles. It’s a well-supported and fantastic project that I can’t recommend enough for in-browser code editing.

The library that does all the beautifying is called JS Beautify, which handles JavaScript, HTML, and CSS. JS Beautify runs on the client-side, so there’s really no backend to this app — your browser does all the work!

JS Beautify is incredibly easy to use. Install it with npm install js-beautify and run your code through the appropriate function.

import beautify from 'js-beautify'; const code = 'Your code here'; const settings = { // Your settings here }; // HTML const html = beautify.html(code, settings) // CSS const css = beautify.css(code, settings) // JavaScript const js = beautify.js(code, settings)

Each function returns a string containing the beautified code. You can change how each language is output by passing in your own settings.

I’ve been asked a few times about Prettier, which is a comparable tool, so it’s worth mentioning that I chose JS Beautify because it’s less opinionated and more configurable. If there’s enough demand, I’ll consider adding an option to toggle between JS Beautify and Prettier.

I've used all of these libraries before, so integration was actually pretty easy. &#x1f605;

This project was made possible by my app, Surreal CMS. If you’re looking for a great CMS for static websites, check it out — it’s free for personal, educational, and non-profit websites!

Oh, and if you’re wondering what editor I used... it’s Visual Studio Code. &#x1f468;&#x1f3fb;‍&#x1f4bb;

The post How I Created a Code Beautifier in Two Days appeared first on CSS-Tricks.

What the Web Needs Now (and how ARTIFACT is here for it)

Css Tricks - Fri, 07/19/2019 - 5:09am

I recently had the pleasure of joining Dave Rupert, Chris Coyier, and Chris Ferdinandi on the Shop Talk Show to talk about the upcoming ARTIFACT Conference (Austin, TX on Sept. 30 – Oct. 1, 2019). ARTIFACT is an intimate gathering of web designers and developers where we discuss ways to build web sites that work for everyone.

This isn’t our first rodeo! I started ARTIFACT back in 2013 with Christopher Schmitt and Ari Stiles (the team behind the legendary In Control and CSS Dev conferences). At that time, the sudden avalanche of web-enabled mobile devices was throwing the web design community for a loop. How do we best leverage the recently-introduced Responsive Design techniques to adapt our designs to a spectrum of screen sizes?! What does that do to our workflows?! What happens to our beloved Photoshop comps?! How do we educate our clients and structure our billing cycles?! It was an exciting time when we needed to adjust our processes quickly to take on a radically new web viewing environment.

After four events in 2013 and 2014, ARTIFACT took a little hiatus, but we are back for a five-year reunion in 2019. We are returning to a landscape where a lot of the challenges we faced in 2013 have been figured out or, at the very least, have settled down (although there is always room for innovation and improvement).

Is our work making the web better done? Not by a long shot! Now that we’ve got a handle on the low-bar requirement of getting something readable on all those screens, we can focus our energy on higher-order challenges. How do we make our sites work easier for people of all abilities? How do we make our content, products, and services welcoming to everyone? Does our code need to be so bloated and complicated? How can we make our sites simpler and faster? How can I put new tools like CSS Grid, Progressive Web Apps, static sites, and animation to good use?

To that end, this time around ARTIFACT is expanding its focus from “designing for all the devices” to “designing for all the people.” Simply put, we want a web that doesn’t leave anyone out, and we’ve curated our program to address inclusivity, performance, and the ways that new possibilities on the web affect our workflow.

A web for everyone

Inclusive design—including accessibility, diversity, and internationalization—has been bubbling to the top of the collective consciousness of the web-crafting community. I’m incredibly encouraged to see articles, conference talks, and podcasts devoted to improving the reach of the web. At ARTIFACT, inclusivity is a major theme that winds its way throughout our program.

Photo by Jopwell from Pexels Benjamin Evans will talk about his efforts as the Inclusive Design Lead at AirBnB to create a user experience that does not alienate minority communities. Accessibility expert Elle Waters will share best practices for integrating accessibility measures into our workflows.. We’ll also hear from David Dylan Thomas on how to recognize and address cognitive bias that can affect content and the overall user experience. Even better performance Visitors may also be turned away from our sites if pages take too long to load or use too much data. We know performance matters, yet sites on the whole grow more bloated with every passing year. Tim Kadlec (who knows more about performance than just about anybody) will examine the intersection of performance and inclusion in his talk “Outside Looking In” with lots of practical code examples for how to do better. We’ll also look at performance through the lens of Progressive Web Apps (presented by Jason Grigsby of Cloud Four). In fact, improving performance is a subtext to many of our developer-oriented talks. Leveraging the modern browser In the Good News Department, another big change since the first ARTIFACT is that browsers offer a lot more features out of the box, allowing us to leverage native browser behavior and simplify our code (Viva Performance!). Chris Ferdinandi will be demonstrating exactly that in his talk “Lean Web Development,” where he’ll point out ways that taking advantage of built-in browser functionality and writing JavaScript for just the interactivity you need may make a big framework unnecessary. Better native browser features also means un-learning some of our old coping mechanisms. We’ll get to delight at all the polyfills and workarounds that have been kicked to the curb since 2012 in Dave Rupert’s tale of “The Greatest Redesign Ever Told,” and we’ll see what best practices make sense going forward. Workflow and process One thing that hasn’t changed—and likely never will—is that never-ending hamster wheel of trying to keep up with an ever-changing web development landscape. I’m guessing that if you are reading CSS-Tricks right now, you know that feeling. The methods we use to build the web are always evolving with new tools, approaches, and possibilities, which is why best practices for adapting our workflows and processes have always been a central focus at ARTIFACT. This year is no different. Jen Simmons will share her thinking process for designing a CSS grid-based layout by live-coding a site before our very eyes. Design systems, which have become a cornerstone of large-scale site production, get the treatment in talks by Kim Williams, Dan Mall, and Brad Frost. (Dan and Brad are also running their acclaimed “Designer + Developer Collaboration Workflow” workshop on October 2.) Divya Sasidharan will show off the possibilities and performance advantages of static sites in her “JAMstackin” presentation We’ll get a glimpse of the future of web animation from Sarah Drasner. (She’s bringing her popular “Design for Developers” workshop on October 2 as well).

The web can always do better to serve the people who use it. We’re proud to provide an occasion for designers and developers who care about putting their users front and center to mingle and share ideas. And yes, there will be milkshakes! The very best milkshakes.

ARTIFACT takes place in Austin, TX from September 30 to October 1, 2019 with workshops on October 2. Group discounts are available.

The post What the Web Needs Now (and how ARTIFACT is here for it) appeared first on CSS-Tricks.

Weekly Platform News: CSS ::marker pseudo-element, pre-rendering web components, adding Webmention to your site

Css Tricks - Thu, 07/18/2019 - 11:43am

Šime posts regular content for web developers on

In this week's roundup: datepickers are giving keyboard users headaches, a new web component compiler that helps fight FOUC, we finally get our hands on styling list item markers, and four steps to getting webmentions on your site.

Using plain text fields for date input

Keyboard users prefer regular text fields over complex date pickers, and voice users are frustrated by the native control (<input type="date">).

Previously, I have relied on plain text inputs as date fields with custom validation for the site, typically using the same logic on the client and the server. For known dates?—?birthdays, holidays, anniversaries, etc.?—?it has tested well.

(via Adrian Roselli)

Pre-rendering web components

Stencil is a “web component compiler” that can be used to pre-render web components (including Shadow DOM) or hide them until they are fully styled to avoid the flash of unstyled content (FOUC).

This tool also makes sure that polyfills are only loaded when needed, and its Component API includes useful decorators and hooks that make writing web components easier (e.g., the Prop decorator handles changes to attributes).

import { Component, Prop, h } from "@stencil/core"; @Component({ tag: "my-component" }) export class MyComponent { @Prop() age: number = 0; render() { return <div>I am {this.age} years old</div>; } }

(via Max Lynch)

The CSS ::marker pseudo-element

When the CSS display: list-item declaration is applied to an element, the element generates a marker box containing a marker, e.g., a list bullet (the <li> and <summary> elements have markers by default).

Markers can be styled via the ::marker pseudo-element (useful for changing the color or font of the marker), but this CSS feature is currently only supported in Firefox.

(via Rachel Andrew)

Adding Webmention to your website
  1. Sign up on; this is a service that collects webmentions on your behalf.
  2. Add <link rel="webmention"> (with the appropriate href value) to your web pages.

    There are also Webmention plugins available for all major content management systems (CMS) if you prefer building on top of your CMS.

  3. Fetch webmentions from (via Ajax) to display them on your page.
  4. Use to automate sending webmentions (when you publish content that includes links to other sites that support Webmention).

(via Daniel Aleksandersen)

The post Weekly Platform News: CSS ::marker pseudo-element, pre-rendering web components, adding Webmention to your site appeared first on CSS-Tricks.

Using GraphQL Playground with Gatsby

Css Tricks - Thu, 07/18/2019 - 5:15am

I’m assuming most of you have already heard about Gatsby, and at least loosely know that it’s basically a static site generator for React sites. It generally runs like this:

  1. Data Sources ? Pull data from anywhere.
  2. Build ? Generate your website with React and GraphQL.
  3. Deploy ? Send the site to any static site host.

What this typically means is that you can get your data from any recognizable data source — CMS, markdown, file systems and databases, to name a few — manage the data through GraphQL to build your website, and finally deploy your website to any static web host (such as Netlify or Zeit).

The Gatsby homepage illustration of the Gatsby workflow.

In this article, we are concerned with the build process, which is powered by GraphQL. This is the part where your data is managed. Unlike traditional REST APIs where you often need to send anonymous data to test your endpoints, GraphQL consolidates your APIs into a self-documenting IDE. Using this IDE, you can perform GraphQL operations such as queries, mutations, and subscriptions, as well as view your GraphQL schema, and documentation.

GraphQL has an IDE built right into it, but what if we want something a little more powerful? That’s where GraphQL Playground comes in and we’re going to walk through the steps to switch from the default over to GraphQL Playground so that it works with Gatsby.

GraphiQL and GraphQL Playground

GraphiQL is GraphQL’s default IDE for exploring GraphQL operations, but you could switch to something else, like GraphQL Playground. Both have their advantages. For example, GraphQL Playground is essentially a wrapper over GraphiQL but includes additional features such as:

  • Interactive, multi-column schema documentation
  • Automatic schema reloading
  • Support for GraphQL Subscriptions
  • Query history
  • Configuration of HTTP headers
  • Tabs
  • Extensibility (themes, etc.)

Choosing either GraphQL Playground or GraphiQL most likely depends on whether you need to use those additional features. There’s no strict rule that will make you write better GraphQL operations, or build a better website or app.

This post isn't meant to sway you toward one versus the other. We're looking at GraphQL Playground in this post specifically because it’s not the default IDE and there may be use cases where you need the additional features it provides and needs to set things up to work with Gatsby. So, let’s dig in and set up a new Gatsby project from scratch. We’ll integrate GraphQL Playground and configure it for the project.

Setting up a Gatsby Project

To set up a new Gatsby project, we first need to install the gatsby-cli. This will give us Gatsby-specific commands we can use in the Terminal.

npm install -g gatsby-cli

Now, let’s set up a new site. I’ve decided to call this example "gatsby-playground" but you can name it whatever you’d like.

gatsby new gatsby-playground

Let’s navigate to the directory where it was installed.

cd gatsby-playground

And, finally, flip on our development server.

gatsby develop

Head over to http://localhost:8000 in the browser for the opening page of the project. Your Gatsby GraphQL operations are going to be located at http://localhost:8000/___graphql.

The GraphiQL interface.

At this point, I think it’s worth calling out that there is a desktop app for GraphQL Playground. You could just access your Gatsby GraphQL operations with the URL Endpoint localhost:8000/___graphql without going any further with this article. But, we want to get our hands dirty and have some fun under the hood!

GraphQL Playground running Gatsby GraphQL Operations. Gatsby’s Environmental Variables

Still around? Cool. Moving on.

Since we’re not going to be relying on the desktop app, we’ll need to do a little bit of Environmental Variable setup.

Environmental Variables are variables used specifically to customize the behavior of a website in different environments. These environments could be when the website is in active development, or perhaps when it is live in production and available for the world to see. We can have as many environments as we want, and define different Environmental Variables for each of the environments.

Learn more about Environmental Variables in Gatsby.

Gatsby supports two environments: development and production. To set a development environmental variable, we need to have a .env.development file at the root of the project. Same sort of deal for production, but it’s .env.production.

To swap out both environments, we’ll need to set an environment variable in a cross-platform compatible way. Let’s create a .env.development file at the root of the project. Here, we set a key/value pair for our variables. The key will be GATSBY_GRAPHQL_IDE, and the value will be playground, like so:

GATSBY_GRAPHQL_IDE=playground Accessing Environment Variables in JavaScript

In Gatsby, our Environmental Variables are only available at build time, or when Node.JS is running (what we’ll call run time). Since the variables are loaded client-side at build time, we need to use them dynamically at run time. It is important that we restart our server or rebuild our website every time we modify any of these variables.

To load our environmental variables into our project, we need to install a package:

yarn add env-cmd --dev // npm install --save-dev env-cmd

With that, we will change the develop script in package.json as the final step, to this instead:

"develop": "env-cmd --file .env.development --fallback gatsby develop"

The develop script instructs the env-cmd package to load environmental variables from a custom environmental variable file (.env.development in this case), and if it can’t find it, fallback to .env (if you have one, so if you see the need to, create a .env file at the root of your project with the same content as .env.development).

And that’s it! But, hey, remember to restart the server since we change the variable.

yarn start // npm run develop

If you refresh the http://localhost:8000/___graphql in the browser, you should now see GraphQL playground. Cool? Cool!

GraphQL Playground with Gatsby. And that’s how we get GraphQL Playground to work with Gatsby!

So that’s how we get from GraphQL’s default GraphiQL IDE to GraphQL Playground. Like we covered earlier, the decision of whether or not to make the switch at all comes down to whether the additional features offered in GraphQL Playground are required for your project. Again, we’re basically working with a GraphiQL wrapper that piles on more features.


Here are some additional articles around the web to get you started with Gatsby and more familiar with GraphiQL, GraphQL Playground, and Environment Variables.

The post Using GraphQL Playground with Gatsby appeared first on CSS-Tricks.

Get Peak WordPress Performance with Jetpack

Css Tricks - Thu, 07/18/2019 - 5:09am

The irony of web performance is that the average page weight of a site continues to go up year after year, despite us being more aware of the problem and having more tools at our disposal to fight it than ever.

To paraphrase Seinfeld, "we know how to fight page weight issues; we just don't use the tools we have to fight page weight issues."

That's why Jetpack provides powerful features for all users at any plan level. They made it so that performance is integrated right into managing content on a WordPress site.

One of those things is lazy loading images. Lazy loading is an excellent technique to defer loading images until they are actually needed. So, an image never loads until the user actually scrolls to where it comes into display. That could potentially save a ton of server requests and precious bytes when waiting for a page to load. Jetpack includes lazy loading, even on free plans, so everyone has access to this performance boost.

And what's the point of lazy loading anything if you don't have somewhere to host the files? Well, Jetpack also offers unlimited static file and image hosting for every plan level. No more wondering how much storage is left on your server! You get an unlimited amount of space to store anything you need. That's pretty awesome!

It gets even more awesome. That's because the unlimited storage is part of a CDN that is designed to serve images from high-speed dedicated data centers that make downloads as fast and smooth as possible. Again, that's free to everyone!

That makes Jetpack a super resource for combatting performance issues on a WordPress site. Hey, we use Jetpack here at CSS-Tricks and it's a linchpin for so much of how this site works and operates. The performance benefits are a nice perk but it's worth checking out everything it has to offer because there's likely so much more you can leverage.

Get Jetpack

Hey it doesn't hurt there is a 20% discount right now with DISCOUNT20 until July 31st, 2019

The post Get Peak WordPress Performance with Jetpack appeared first on CSS-Tricks.

Multi-Line Truncation with Pure CSS

Css Tricks - Wed, 07/17/2019 - 11:53am

Truncating a single line of text if is fairly straightforward. Truncating multiple lines is a bit harder. Using just CSS (no JavaScript or server-side dancing) is nice for the simplicity. It's gotten a little easier lately since Firefox (since version 68) has started supporting the ultra-bizarre -webkit-line-clamp soup method, which makes browser support for that pretty OK.

There is another way though, which is very clever and something I'd call a bonafide CSS trick. We somehow failed to cover it properly in our canonical post on line clamping, so I'll cover it here then add it to that post. I first saw this trick on the now-dead Mobify blog, and more recently covered by Natalia Onischuk on HackingUI.

The trick uses line height for measuring

Here's a big part of the trick. Imagine an element has a line-height of 1.4rem and you want to make sure it only shows a maximum of three lines of text. If you set the max-height to 1.4rem * 3, you've done it!

I'm not the worlds biggest fan of united line-height, but alas, it's necessary here to do the math. I'm also not the biggest fan of setting it over and over on elements, so let's set a variable we can use later, and then use it to set a global line-height.

html { --lh: 1.4rem; line-height: var(--lh); } Set that max height

The truncation happens just like this:

.truncate-overflow { --max-lines: 3; max-height: calc(var(--lh) * var(--max-lines)); overflow: hidden; }

You actually could leave it like this. That might be good enough if you don't care about the ellipsis.

The rest of the trick comes in when you want to display that ellipsis stuff

An ellipsis ("...") signifies that text has been truncated and continues longer than what it displayed. Using it is probably a pretty good practice when truncating text so the content doesn't come to an abrupt, awkward end. (Well, the content itself might be awkward anyway, but hey, you tried.)

If you set position: relative on the element, you can absolutely position the ellipsis in the bottom-right corner.

.truncate-overflow::before { content: "..."; position: absolute; bottom: 0; right: 0; }

I was very tempted to, instead of setting the bottom, to set the top and use top: calc(var(--lh) * (var(--max-lines) - 1)). My thinking there was that you might as well place the ellipsis at the exact point you need it. If the text is too short, the hidden overflow will cut it off. The problem with that is that it doesn't deal with the "exactly max lines lines" problem. The ellipsis will show when the text matches the max lines — not only when it exceeds that space.

We'll have to get trickier!

Note that this "setting stuff in the bottom-right" thing is pretty specific to left-to-right languages. I'm going to make the demo with CSS logical properties like inset-inline-end instead of right in hopes to make it more friendly to different languages and flow scenarios.

Another limitation is that the ellipsis doesn't attach itself to the final word since it's absolutely placed. We're not going to fix that as well.

Let's cover up the ellipsis when the text is too short

This is the second part of the trick. If we position the absolute at the bottom/end of the text all the time, that's fine. But if the text is exactly equal to the --max-lines value or less, we want to hide it.

The trick there is to make a little box that is the same background as what is behind it and set it on top of the ellipsis to cover it. We can do that with the other pseudo-element:

.truncate-overflow::after { content: ""; position: absolute; right: 0; /* note: not using bottom */ width: 1rem; height: 1rem; background: white; }

Another trick we're using here is not setting a bottom (inset-block-end) property. This places the box at the bottom of the content rather than the bottom of the relative parent, which is very useful.

Let me make the boxes red so you can see them in these three different examples:

The top example has more than three lines, so we see the ellipsis. The second example only has two lines, so the red box shows that the ellipsis will be covered up (but imagine a white box instead). The last example shows that this system works even when the content is exactly the same as the value of --max-lines. Demo

See the Pen
Pure CSS multi-line truncation
by Chris Coyier (@chriscoyier)
on CodePen.

I usedwanted to use CSS logical properties here, as the browser support has gotten pretty good. If you're supporting any version of IE, you'll have to use the bottom and right.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

DesktopChromeOperaFirefoxIEEdgeSafari6962*41No7612.1Mobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox12.2-12.346*No677567

The post Multi-Line Truncation with Pure CSS appeared first on CSS-Tricks.

Improving Video Accessibility with WebVTT

Css Tricks - Wed, 07/17/2019 - 5:22am

"The power of the Web is in its universality. Access by everyone regardless of disability is an essential aspect."
- Tim Berners-Lee

Accessibility is an important element of web development, and with the ever-growing prevalence of video content, the necessity for captioned content is growing as well. WebVTT is a technology that solves helps with captioned content as a subtitle format that integrates easily with already-existing web APIs.

That’s what we’re going to look at here in this article. Sure, WebVTT is captioning at its most basic, but there are ways to implement it to make videos (and the captioned content itself) more accessible for users.

See the Pen
by Geoff Graham (@geoffgraham)
on CodePen.

Hi, meet the WebVTT format

First and foremost: WebVTT is a type of file that contains the text "WebVTT" and lines of captions with timestamps. Here’s an example:

WEBVTT 00:00:00.000 --> 00:00:03.000 - [Birds chirping] - It's a beautiful day! 00:00:04.000 --> 00:00:07.000 - [Creek trickling] - It is indeed! 00:00:08.000 --> 00:00:10.000 - Hello there!

A little weird, but makes pretty good sense, right? As you can see, the first line is "WEBVTT" and it is followed by a time range (in this case, 0 to 3 seconds) on Line 3. The time range is required. Otherwise, the WEBVTT file will not work at all and it won’t even display or log errors to let you know. Finally, each line below a time range represents captions contained in the range.

Note that you can have multiple captions in a single time range. Hyphens may be used to indicate the start of a line, though it’s not required and more stylistic than anything else.

The time range can be one of two formats: or Each part follows certain rules:

  • Hours (hh): Minimum of two digits
  • Minutes (mm): Between 00 and 59, inclusive
  • Seconds (ss): Between 00 and 59, inclusive
  • Milliseconds (tt): Between 000 and 999, inclusive

This may seem rather daunting at first. You’re probably wondering how anyone can be expected to type and tweak this all by hand. Luckily, there are tools to make this easier. For example, YouTube can automatically caption videos for you with speech recognition in addition to allowing you to download the caption as a VTT file as well! But that’s not it. WebVTT can also be used with YouTube as well by uploading your VTT file to your YouTube video.

Once we have this file created, we can then embed it into an HTML5 video element.

<!DOCTYPE HTML> <html> <body> <video controls autoplay> <source src="your_video.mp4" type="video/mp4"/> <track default kind="captions" srclang="en" label="English" src="your_caption_file.vtt"/> </video> </body> </html>

The <track> tag is sort of like a script that "plays" along with the video. We can use multiple tracks in the same video element. The default attribute indicates that a the track will be enabled automatically.

Let’s run down all the <track> attributes while we’re at it:

  • srclang indicates what language the track is in.
  • kind represents the type of track it is and there are five kinds:
    • subtitles are usually translations and descriptions of different parts of a video.
    • descriptions help unsighted users understand what is happening in a video.
    • captions provide un-hearing users an alternative to audio.
    • metadata is a track that is used by scripts and cannot be seen by users.
    • chapters assist in navigating video content.
  • label is a title for the text track that appears in the caption track
  • src is the source file for the track. It cannot come from a cross-origin source unless crossorigin is specified.

While WebVTT is designed specifically for video, you can still use it with audio by placing an audio file within a <video> element.

Digging into the structure of a WebVTT file

MDN has great documentation and outlines the body structure of a WebVTT file, which consists of up to six components. Here’s how MDN breaks it down:

  • An optional byte order mark (BOM)
  • The string "WEBVTT"
  • An optional text header to the right of WEBVTT.
    • There must be at least one space after WEBVTT.
    • You could use this to add a description to the file.
    • You may use anything in the text header except newlines or the string "-->".
  • A blank line, which is equivalent to two consecutive newlines.
  • Zero or more cues or comments.
  • Zero or more blank lines.

Note: a BOM is a unicode character that indicates the unicode encoding of the text file.

Bold, italic, and underline — oh my!

We can absolutely use some inline HTML formatting in WebVTT files! These are the ones that everyone is familiar with: <b>, <i>, and <u>. You use them exactly as you would in HTML.

WEBVTT 00:00:00.000 --> 00:00:03.000 align:start This is bold text 00:00:03.000 --> 00:00:06.000 align:middle This is italic text 00:00:06.000 --> 00:00:09.000 vertical:rl align:middle This is <u>underlined text</u> Cue settings

Cue settings are optional strings of text used to control the position of a caption. It’s sort of like positioning elements in CSS, like being able to place captions on the video.

For example, we could place captions to the right of a cue timing, control whether a caption is displayed horizontally or vertically, and define both the alignment and vertical position of the caption.

Here are the settings that are available to us.

Setting 1: Line

line controls the positioning of the caption on the y-axis. If vertical is specified (which we’ll look at next), then line will instead indicate where the caption will be displayed on the x-axis.

When specifying the line value, integers and percentages are perfectly acceptable units. In the case of using an integer, the distance per line will be equal to the height (from a horizontal perspective) of the first line. So, for example, let’s say the height of the first line of the caption is equal to 50px, the line value specified is 2, and the caption’s direction is horizontal. That means the caption will be positioned 100px (50px times 2) down from the top, up to a maximum equal to coordinates of the boundaries of the video. If we use a negative integer, it will move upward from the bottom as the value decreases (or, in the case of vertical:lr being specified, we will move from right-to-left and vice-versa). Be careful here, as it’s possible to position the captions off-screen in addition to the positioning being inconsistent across browsers. With great power comes great responsibility!

In the case of a percentage, the value must be between 0-100%, inclusive (sorry, no 200% mega values here). Higher values will move the caption from top-to-bottom, unless vertical:lr or vertical:rl is specified, in which case the caption will move along the x-axis accordingly.

As the value increases, the caption will appear further down the video boundaries. As the value decreases (including into the negatives), the caption will appear further up.

Tough picture this without examples, right? Here’s how this translates into code:

00:00:00.000 --> 00:00:03.000 line:50% This caption should be positioned horizontally in the approximate center of the screen. 00:00:03.000 --> 00:00:06.000 vertical:lr line:50% This caption should be positioned vertically in the approximate center of the screen. 00:00:06.000 --> 00:00:09.000 vertical:rl line:-1 This caption should be positioned vertically along the left side of the video. 00:00:09.000 --> 00:00:12.000 line:0 The caption should be positioned horizontally at the top of the screen. Setting 2: Vertical

vertical indicates the caption will be displayed vertically and move in the direction specified by the line setting. Some languages are not displayed left-to-right and instead need a top-to-bottom display.

00:00:00.000 --> 00:00:03.000 vertical:rl This caption should be vertical. 00:00:00.000 --> 00:00:03.000 vertical:lr This caption should be vertical. Setting 3: Position

position specifies where the caption will be displayed along the x-axis. If vertical is specified, the position will instead specify where the caption will be displayed on the y-axis. It must be an integer value between 0% and 100%, inclusive.

00:00:00.000 --> 00:00:03.000 vertical:rl position:100% This caption will be vertical and toward the bottom. 00:00:03.000 --> 00:00:06.000 vertical:rl position:0% This caption will be vertical and toward the top.

At this point, you may notice that line and position are similar to the CSS flexbox properties for align-items and justify-content, and that vertical behaves a lot like flex-direction. A trick for remembering WebVTT directions is that line specifies a position perpendicular to the flow of the text, whereas position specifies the position parallel to the flow of the text. That’s why line suddenly moves along the horizontal axis, and position moves along the vertical axis if we specify vertical.

Setting 4: Size

size specifies the width of the caption. If vertical is specified, then it will set the height of the caption instead. Like other settings, it must be an integer between 0% and 100%, inclusive.

00:00:00.000 --> 00:00:03.000 vertical:rl size:50% This caption will fill half the screen vertically. 00:00:03.000 --> 00:00:06.000 position:0% This caption will fill the entire screen horizontally. Setting 5: Align

align specifies where the text will appear horizontally. If vertical is specified, then it will control the vertical alignment instead.

The values we’ve got are: start, middle, end, left and right. Without vertical specified, the alignments are exactly what they sound like. If vertical is specified, they effectively become top, middle (vertically), and bottom. Using start and end as opposed to left and right, respectively, is a more flexible way of allowing the alignment to be based on the unicode-bidi CSS property’s plaintext value.

Note that align is not unaffected by vertical:lr or vertical:rl.

WEBVTT 00:00:00.000 --> 00:00:03.000 align:start This caption will be on the left side of the screen. 00:00:03.000 --> 00:00:06.000 align:middle This caption will be horizontally in the middle of the screen. 00:00:06.000 --> 00:00:09.000 vertical:rl align:middle This caption will be vertically in the middle of the screen. 00:00:09.000 --> 00:00:12.000 vertical:rl align:end This caption will be vertically at the bottom right of the screen regardless of vertical:lr or vertical:rl orientation. 00:00:12.000 --> 00:00:15.000 vertical:lr align:end This caption will be vertically at the bottom of the screen, regardless of the vertical:lr or vertical:rl orientation. 00:00:12.000 --> 00:00:15.000 align:left This caption will appear on the left side of the screen. 00:00:12.000 --> 00:00:15.000 align:right This caption will appear on the right side of the screen. WebVTT Comments

WebVTT comments are strings of text that are only visible when reading the source text of the file, the same way we think of comments in HTML, CSS, JavaScript and any other language. Comments may contain a new line, but not a blank line (which is essentially two new lines).

WEBVTT 00:00:00.000 --> 00:00:03.000 - [Birds chirping] - It's a beautiful day! NOTE This is a comment. It will not be visible to anyone viewing the caption. 00:00:04.000 --> 00:00:07.000 - [Creek trickling] - It is indeed! 00:00:08.000 --> 00:00:10.000 - Hello there!

When the caption file is parsed and rendered, the highlighted line above will be completely hidden from users. Comments can be multi-line as well.

There are three very important characters/strings to take note of that may not be used in comments: <, &, and -->. As an alternative, you can use escaped characters instead.

Not Allowed Alternative NOTE PB&J NOTE PB&amp;J NOTE 5 < 7 NOTE 5 &lt; 7 NOTE puppy --> dog NOTE puppy --&gt; do A few other interesting WebVTT features

We’re going to take a quick look at some really neat ways we can customize and control captions, but that are lacking consistent browser support, at least at the time of this writing.

Yes, we can style captions!

WebVTT captions can, in fact, be styled. For example, to style the background of a caption to be red, set the background property on the ::cue pseudo-element:

video::cue { background: red; }

Remember how we can use some inline HTML formatting in the WebVTT file? Well, we can select those as well. For example, to select and italic (<i>) element:

video::cue(i) { color: yellow; }

Turns out WebVTT files support a style block, a lot like the way HTML files do:

WEBVTT STYLE ::cue { color: blue; font-family: "Source Sans Pro", sans-serif; }

Elements can also be accessed via their cue identifiers. Note that cue identifiers use the same escaping mechanism as HTML.

WEBVTT STYLE ::cue(#middle\ cue\ identifier) { text-decoration: underline; } ::cue(#cue\ identifier\ \33) { font-weight: bold; color: red; } first cue identifier 00:00:00.000 --> 00:00:02.000 Hello, world! middle cue identifier 00:00:02.000 --> 00:00:04.000 This cue identifier will have an underline! cue identifier 3 00:00:04.000 --> 00:00:06.000 This one won't be affected, just like the first one! Different types of tags

Many tags can be used to format captions. There is a caveat. These tags cannot be used in a <track> element where kind attribute is chapters. Here are some formatting tags you can use.

The class tag

We can define classes in the WebVTT markup using a class tag that can be selected with CSS. Let’s say we have a class, .yellowish that makes text yellow. We can use the tag <c.yellowish> in a caption. We can control lots of styling this way, like the font, the font color, and background color.

/* Our CSS file */ .yellowish { color: yellow; } .redcolor { color: red; } WEBVTT 00:00:00.000 --> 00:00:03.000 <c.yellowish>This text should be yellow.</c> This text will be the default color. 00:00:03.000 --> 00:00:06.000 <c.redcolor>This text should be red.</c> This text will be the default color. The timestamp tag

If you want to make captions appear at specific times, then you will want to use timestamp tags. They’re like fine-tuning captions to exact moments in time. The tag’s time must be within the given time range of the caption, and each timestamp tag must be later than the previous.

WEBVTT 00:00:00.000 --> 00:00:07.000 This <00:00:01.000>text <00:00:02.000>will <00:00:03.000>appear <00:00:04.000>over <00:00:05.000>6 <00:00:06.000>seconds. The voice tag

Voice tags are neat in that they help identify who is speaking.

WEBVTT 00:00:00.000 --> 00:00:03.000 <v Alice>How was your day, Bob? 00:00:03.000 --> 00:00:06.000 <v Bob>Great, yours? The ruby tag

The ruby tag is a way to display small, annotative characters above the caption.

WEBVTT 00:00:00.000 --> 00:00:05.000 <ruby>This caption will have text above it<rt>This text will appear above the caption. Conclusion

And that about wraps it up for WebVTT! It’s an extremely useful technology and presents an opportunity to improve your site’s accessibility a great deal, particularly if you are working with video. Try some of your own captions out yourself to get a better feel for it!

The post Improving Video Accessibility with WebVTT appeared first on CSS-Tricks.

Micro Frontends

Css Tricks - Wed, 07/17/2019 - 5:20am

One random day not long ago, I started hearing joke after joke about "micro frontends" — sort of how I first learned about Toast. I didn't understand the source until asking around, which uncovered this article from Cam Jackson.

In this article we'll describe a recent trend of breaking up frontend monoliths into many smaller, more manageable pieces, and how this architecture can increase the effectiveness and efficiency of teams working on frontend code.

I'd argue it should read "front-end monoliths" and "front-end code," but I digress already.

The idea is similar to microservices, but for the front end. So, instead of one big front-end architecture (e.g. a React app), different parts of the front end are developed entirely independent of one another, have no dependencies on each other, and can be worked on and deployed independently.

It's one of those things where you can't quite tell if it's really an interesting foretelling of the future, just a niche architectural choice that happened to work for a handful of large organizations, or even just a theoretical option.

The first place my mind goes is consistency and DRY-ness. Anywhere I've worked, these things are a big deal and it seems like the industry at large has had endless front-end problems with shipping designs that start and stay consistent and cohesive without repeating itself with shovelfuls of technical debt. Independent front-ends sound like they might be a problem if Team B is being blocked by Team A for something not directly related, but then it introduces the problem of Team B's output drifting towards inconsistency with Team A's output.

The article itself talks about a browse/search landing page, a details/ordering page, and a profile page, with all three of those tackled by different independent products/teams. It sounds kinda cool and interesting to me, and it also sounds like those teams better sit right next to each other at work; otherwise this app is going the way of Frankenstein's monster in two weeks. Styling is only lightly addressed with a, "I dunno, do a good job" sort of vibe. Teams struggle with this when they are all on the same product, so I'd have huge concerns here. The first thing I'd try to solve if this is being discussed seriously would be a design system that transcends all of it and that everyone uses without fail.

And what if those micro front ends co-exist on the same page? Use <iframe>, the article says. I can't see a world where that leads to a good user experience. (iFrames are slow, especially many of them all booting up their own worlds — and what about elements that might overflow bounds like tooltips and menus?)

The other integration options... isolating them to their own bundles or even native web components sounds a bit better. But still, the idea of siloed development where a React component might be slapped on the same page as a Vuew component seems like a huge user penalty for a pretty specific organizational problem. Not to mention you're losing the benefits of a shared understanding of a codebase and the benefits of a deeper technical understanding of a smaller set of tools.

I'm probably not characterizing all of this fairly, especially because the idea is rather new to me and I've never worked like this before.

Nader Dabit has a follow up article: Building Micro Frontends with React, Vue, and Single-spa. Just so I'm not mischaracterizing that: The idea really is that you might build a React app and I build a Vue app and we'll slap 'em together on the same page. I definitely come from an era where we laughed-then-winced when we found sites that used multiple versions of jQuery on the same page, plus one thing that loaded all of MooTools and Prototype thrown on there seemingly by accident. We winced because that was a bucket full of JavaScript, mostly duplicated for no reason, causing bugs and slowing down the page. This doesn't seem all that much different.

Joel Denning points out in an AMA on the subject:

I’m pointing out that we’re in the “hate without closely examining” stage of the idea. It’s entirely possible that after legitimate, close examination that the idea still fails. But too early to tell.

Fair enough.

Sorry about piling on. &#x1f623;

— Chris Coyier (@chriscoyier) June 20, 2019

The post Micro Frontends appeared first on CSS-Tricks.

A Peek at New Methods Coming to Promises

Css Tricks - Tue, 07/16/2019 - 5:16am

Promises are one of the most celebrated features introduced to JavaScript. Having a native asynchronous artifact baked right into the language has opened up a new era, changing not only how we write code but also setting up the base for other freat APIs — like fetch!

Let's step back a moment to recap the features we gained when they were initially released and what new bells and whistles we’re getting next.

New to the concept of Promises? I highly recommend Jake Archibald’s article as a primer.

Features we have today

Let’s take a quick look at some of the things we can currently do with promises. When JavaScript introduced them, it gave us an API to execute asynchronous actions and react to their succesful return or failure, a way to create an association around some data or result which value we still don't know.

Here are the Promises features we have today.

Handling promises

Every time an async method returns a promise — like when we use fetch — we can pipe then() to execute actions when the promise is fulfilled, and catch() to respond to a promise being rejected.

fetch('//') .then(result => console.log('we got it', result.json())) .catch(error => console.error('something went wrong', error))

The classic use case is calling data from an API and either loading the data when it returns or displaying an error message if the data couldn’t be located.

In addition, in its initial release we got two methods to handle groups of Promises.

Resolving and rejecting collections of promises

A promise can be fulfilled when it was successfully resolved, rejected when it was resolved with an error, and pending while there’s no resolution. A promise is considered settled when it has been resolved, disregarding the result.

As such, there are two methods we have to help with the behavior of handling a group of promises depending on the combination of states we obtain.

Promise.all is one or those methods. It fulfills only if all promises were resolved successfully, returning an array with the result for each one. If one of the promises fails, Promise.all will go to catch returning the reason of the error.

Promise.all([ fetch('//'), fetch('//') ]) .then(results => console.log('We got an array of results', results) .catch(error => console.error('One of the promises failed', error)

In this case, Promise.all will short-circuit and go to catch as soon as one of the members of the collections throws an error, or settle when all promises are fulfilled.

Check out this short writing about promises states by Domenic Denicola for a more detailed explanation about the wording and concepts about them.

We also have Promise.race, which immediately resolves to the first promise it gets back, whether it was fulfilled or rejected. After the first promise gets resolved, the remaining ones are ignored.

Promise.race([ fetch('//'), fetch('//') ]) .then(result => console.log('The first promise was resolved', result)) .catch(reason => console.error('One of the promises failed because', reason)) The new kids on the block

OK, we’re going to turn our attention to new promise features we can look forward to.


The next proposed introduction to the family is Promise.allSettled which, as the name indicates, only moves on when the entire collection members in the array are no longer in a pending status, whether they were rejected or fulfilled.

Promise.allSettled([ fetch('//'), fetch('//'), fetch('//') ]) .then(results => { const fulfilled = results.filter(r => r.status === 'fulfilled') const rejected = results.filter(r => r.status === 'rejected') })

Notice how this is different from Promise.all in that we will never enter in the catch statement. This is really good if we are waiting for sets of data that will go to different parts of a web application but want to provide more specific messages or execute different actions for each outcome.


The next new method is Promise.any, which lets us react to any fulfilled promise in a collection, but only short-circuit when all of them failed.

Promise.any([ fetch('//'), fetch('//'), fetch('//') ]) .then(result => console.log('a batch of data has arrived', result)) .catch(() => console.error('all promises failed'))

This is sort of like Promise.race except that Promise.race short-circuits on the first resolution. So, if the first promise in the set resolves with an error, Promise.race moves ahead. Promise.any will continue waiting for the rest of the items in the array to resolve before moving forward.


Some of these are much easier to understand with a visual, so I put together a little playground that shows the differences between the new and existing methods.


Though they are still in proposal stage, there are community scripts that emulate the new methods we covered in this post. Things like Bluebird’s any and reflect are good polyfills while we wait for browser support to improve.

They also show how the community is already using these kind of asynchronous patterns, but having them built-in will open the possibilities for new patterns in data fetching and asynchronous resolution for web applications.

Besides then and catch you can pipe finally to a promise, Sarah Drasner wrote a detailed piece about it that you can check out.

If you want to know more about the upcoming Promise combinators, the V8 blog just published a short explanation with links to the official spec and proposals.

The post A Peek at New Methods Coming to Promises appeared first on CSS-Tricks.

Finally… A Post on Finally in Promises

Css Tricks - Tue, 07/16/2019 - 5:09am

“When does finally fire in a JavaScript promise?” This is a question I was asked in a recent workshop and I thought I’d write up a little post to clear up any confusion.

The answer is, to quote Snape:


The basic structure is like this:

try { // I’ll try to execute some code for you } catch(error) { // I’ll handle any errors in that process } finally { // I’ll fire either way }

Take, for instance, this example of a Chuck Norris joke generator, complete with content populated from the Chuck Norris Database API. (Aside: I found this API from Todd Motto’s very awesome list of open APIs, which is great for demos and side projects.)

See the Pen
finally! chuck norris jokes!
by Sarah Drasner (@sdras)
on CodePen.

async function getData() { try { let chuckJokes = await fetch(``) .then(res => res.json()) console.log('I got some data for you!') document.getElementById("quote").innerHTML = chuckJokes.value; } catch(error) { console.warn(`We have an error here: ${error}`) } finally { console.log('Finally will fire no matter what!') } }

In the console:

Now, let’s introduce a typo to the API and accidentally put a bunch of r's in the URL of the API. This will result in our try statement failing, which means the catch now throws an error.

async function getData() { try { // let's mess this up a bit let chuckJokes = await fetch(``) .then(res => res.json()) console.log('I got some data for you!') document.getElementById("quote").innerHTML = chuckJokes.value; } catch(error) { console.warn(`We have an error here: ${error}`) } finally { console.log('Finally will fire no matter what!') } }


One giant important piece that the example doesn’t illustrate is that the finally block will run even if in the try or catch block, a return or break statement stops the code.

When would you use this?

I’ve found it particularly useful in two different situations, though I’m sure there are others:

  • When I otherwise would duplicate code that’s need in the try and catch blocks. Here’s an example in a Vue cookbook recipe I wrote. I shut off the loading state in a finally block. This includes, like the example above, where I need to change the UI somehow in either case.
  • When there’s some cleanup to do. Oracle mentions this in their documentation. It’s Java, but the same premises apply.

Finally is not useful as often as try and catch, but worth noting for some use cases. Hope that clears it up!

The post Finally… A Post on Finally in Promises appeared first on CSS-Tricks.

So, you think you’ve got project management nailed down

Css Tricks - Tue, 07/16/2019 - 5:07am

(This is a sponsored post.)

Who needs a project manager? You're an organized person who can keep track of your own work, right?


Well, wrong if you're part of a team. The thing about being self-organized is that it's related to project management but not synonymous with it. Case in point: what happens if your project relies on someone else's involvement? Sure you're organized, but can you always say the same about your co-workers? Chances are you need something to keep everyone in sync so that a project stays on course.

That's where you should consider trying is project management, but with a human touch. Sure, there's task lists, assignments, milestones, due dates, and such like you would expect from any project management tool. That's a given. That said, takes things up a notch by stripping away the barriers that prevent team members from collaborating with one another. For example, includes real-time messaging, file sharing, reporting, and a slew of other features that bridge the gaps between people and tasks so that everyone has purview into the progress of a project. Plus, it's so pretty to look at.

There's so much more than meets the eye because goes beyond project management. There's resource management that ensures you have the right tools for a project, forecasting to affirm the prospect of a business opportunity, and even client management services. Seriously, your team and perhaps company can lean into and get a ton of use out of it.

You know what to do from here. Give a try. There's a free trial and we're sure you'll find it to be so useful that you'll want to stick with it well beyond.

Get Started

Direct Link to ArticlePermalink

The post So, you think you’ve got project management nailed down appeared first on CSS-Tricks.

Managing Multiple Backgrounds with Custom Properties

Css Tricks - Mon, 07/15/2019 - 11:17am

One cool thing about CSS custom properties is that they can be a part of a value. Let's say you're using multiple backgrounds to pull off a design. Each background will have its own color, image, repeat, position, etc. It can be verbose!

You have four images:

body { background-position: top 10px left 10px, top 10px right 10px, bottom 10px right 10px, bottom 10px left 10px; background-repeat: no-repeat; background-image: url(, url(, url(, url(; }

You want to add a fifth in a media query:

@media (min-width: 1500px) { body { /* REPEAT all existing backgrounds, then add a fifth. */ } }

That's going to be super verbose! You'll have to repeat each of those four images again, then add the fifth. Lots of duplication there.

One possibility is to create a variable for the base set, then add the fifth much more cleanly:

body { --baseBackgrounds: url(, url(, url(, url(; background-position: top 10px left 10px, top 10px right 10px, bottom 10px right 10px, bottom 10px left 10px; background-repeat: no-repeat; background-image: var(--baseBackgrounds); } @media (min-width: 1500px) { body { background-image: var(--baseBackgrounds), url(added-fifth-background.svg); } }

But, it's really up to you. It might make more sense and be easier manage if you made each background image into a variable, and then pieced them together as needed.

body { --bg1: url(; --bg2: url(; --bg3: url(; --bg4: url(; --bg5: url(; background-image: var(--bg1), var(--bg2), var(--bg3), var(--bg4); } @media (min-width: 1500px) { body { background-image: var(--bg1), var(--bg2), var(--bg3), var(--bg4), var(--bg5); } }

Here's a basic version of that, including a supports query:

See the Pen
Multiple BGs with Custom Properties
by Chris Coyier (@chriscoyier)
on CodePen.

Dynamically changing just the part of a value is a huge strength of CSS custom properties!

Note, too, that with backgrounds, it might be best to include the entire shorthand as the variable. That way, it's much easier to piece everything together at once, rather than needing something like...

--bg_1_url: url(); --bg_1_size: 100px; --bg_1_repeat: no-repeat; /* etc. */

It's easier to put all of the properties into shorthand and use as needed:

body { --bg_1: url( top 10px left 10px / 86px no-repeat; --bg_2: url( top 10px right 10px / 86px no-repeat; --bg_3: url( bottom 10px right 10px / 86px no-repeat; --bg_4: url( bottom 10px left 10px / 86px no-repeat; background: var(--bg_1), var(--bg_2),var(--bg_3),var(--bg_4); }

Like this.

The post Managing Multiple Backgrounds with Custom Properties appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.