ic

[ASAP] Hierarchical Plasmon Resonances in Fractal Structures

ACS Photonics
DOI: 10.1021/acsphotonics.0c00110




ic

[ASAP] Large Wavelength Response to Pressure Enabled in InGaN/GaN Microcrystal LEDs with 3D Architectures

ACS Photonics
DOI: 10.1021/acsphotonics.0c00251




ic

[ASAP] Quasinormal-Mode Non-Hermitian Modeling and Design in Nonlinear Nano-Optics

ACS Photonics
DOI: 10.1021/acsphotonics.0c00014




ic

[ASAP] Colloidal Quantum-Dots/Graphene/Silicon Dual-Channel Detection of Visible Light and Short-Wave Infrared

ACS Photonics
DOI: 10.1021/acsphotonics.0c00247




ic

[ASAP] Goodbye Juan José Sáenz (1960–2020): A Bright Scientific Mind, an Unusually Prolific Friend, and a Family Man

ACS Photonics
DOI: 10.1021/acsphotonics.0c00526




ic

[ASAP] Chip-Scale Reconfigurable Optical Full-Field Manipulation: Enabling a Compact Grooming Photonic Signal Processor

ACS Photonics
DOI: 10.1021/acsphotonics.0c00103




ic

[ASAP] Exciton-Polaritons with Magnetic and Electric Character in All-Dielectric Metasurfaces

ACS Photonics
DOI: 10.1021/acsphotonics.0c00063




ic

[ASAP] Colored Radiative Cooling Coatings with Nanoparticles

ACS Photonics
DOI: 10.1021/acsphotonics.0c00513




ic

[ASAP] Gain-Assisted Optomechanical Position Locking of Metal/Dielectric Nanoshells in Optical Potentials

ACS Photonics
DOI: 10.1021/acsphotonics.0c00213




ic

[ASAP] Strain-Correlated Localized Exciton Energy in Atomically Thin Semiconductors

ACS Photonics
DOI: 10.1021/acsphotonics.0c00626




ic

[ASAP] Probing the Radiative Electromagnetic Local Density of States in Nanostructures with a Scanning Tunneling Microscope

ACS Photonics
DOI: 10.1021/acsphotonics.0c00264




ic

[ASAP] Line-Scan Hyperspectral Imaging Microscopy with Linear Unmixing for Automated Two-Dimensional Crystals Identification

ACS Photonics
DOI: 10.1021/acsphotonics.0c00050




ic

[ASAP] Strong Optical Feedback Stabilized Quantum Cascade Laser

ACS Photonics
DOI: 10.1021/acsphotonics.0c00189




ic

Iconography of Security

Molly Wilson and Eileen Wagner battle the age old Christmas issues of right and wrong, good and evil, and how the messages we send through iconography design can impact the decisions users make around important issues of security. Are you icons wise men, or are they actually King Herod?


Congratulations, you’re locked out! The paradox of security visuals

Designers of technology are fortunate to have an established visual language at our fingertips. We try to use colors and symbols in a way that is consistent with people’s existing expectations. When a non-designer asks a designer to “make it intuitive,” what they’re really asking is, “please use elements people already know, even if the concept is new.”

Lots of options for security icons

We’re starting to see more consistency in the symbols that tech uses for privacy and security features, many of them built into robust, standardized icon sets and UI kits. To name a few: we collaborated with Adobe in 2018 to create the Vault UI Kit, which includes UI elements for security, like touch ID login and sending a secure copy of a file. Adobe has also released a UI kit for cookie banners.

Activity log from the Vault Secure UI Kit, by Adobe and Simply Secure.
Cookie banner, from the Cookie Banner UI Kit, by Adobe.

Even UI kits that aren’t specialized in security and privacy include icons that can be used to communicate security concepts, like InVision’s Smart Home UI Kit. And, of course, nearly every icon set has security-related symbols, from Material Design to Iconic.

Key, lock, unlock, shield, and warning icons from Iconic.
A selection of security-related icons from Material Design.
Security shields from a selection of Chinese apps, 2014. From a longer essay by Dan Grover.

Many of these icons allude to physical analogies for the states and actions we’re trying to communicate. Locks and keys; shields for protection; warning signs and stop signs; happy faces and sad faces. Using these analogies helps build a bridge from the familiar, concrete world of door locks and keyrings to the unfamiliar, abstract realm of public- and private-key encryption.

flickr/Jim Pennucci
GPG Keychain, an open-source application for managing encryption keys. Image: tutsplus.com

When concepts don’t match up

Many of the concepts we’re working with are pairs of opposites. Locked or unlocked. Private or public. Trusted or untrusted. Blocked or allowed. Encouraged or discouraged. Good or evil. When those concept pairs appear simultaneously, however, we quickly run into UX problems.

Take the following example. Security is good, right? When something is locked, that means you’re being responsible and careful, and nobody else can access it. It’s protected. That’s cause for celebration. Being locked and protected is a good state.

“Congratulations, you’re locked out!”

Whoops.

If the user didn’t mean to lock something, or if the locked state is going to cause them any inconvenience, then extra security is definitely not good news.

Another case in point: Trust is good, right? Something trusted is welcome in people’s lives. It’s allowed to enter, not blocked, and it’s there because people wanted it there. So trusting and allowing something is good.

“Good job, you’ve downloaded malware!”

Nope. Doesn’t work at all. What if we try the opposite colors and iconography?

That’s even worse. Even though we, the designers, were trying both times to keep the user from downloading malware, the user’s actual behavior makes our design completely nonsensical.

Researchers from Google and UC Berkeley identified this problem in a 2016 USENIX paper analyzing connection security indicators. They pointed out that, when somebody clicks through a warning to an “insecure” website, the browser will show a “neutral or positive indicator” in the URL bar – leading them to think that the website is now safe. Unlike our example above, this may not look like nonsense from the user point of view, but from a security standpoint, suddenly showing “safe/good” without any actual change in safety is a pretty dangerous move.

The deeper issue

Now, one could file these phenomena under “mismatching iconography,” but we think there is a deeper issue here that concerns security UI in particular. Security interface design pretty much always has at least a whiff of “right vs. wrong.” How did this moralizing creep into an ostensibly technical realm?

Well, we usually have a pretty good idea what we’d like people to do with regards to security. Generally speaking, we’d like them to be more cautious than they are (at least, so long as we’re not trying to sneak around behind their backs with confusing consent forms and extracurricular data use). Our well-intentioned educational enthusiasm leads us to use little design nudges that foster better security practices, and that makes us reach into the realm of social and psychological signals. But these nudges can easily backfire and turn into total nonsense.

Another example: NoScript

“No UX designer would be dense enough to make these mistakes,” you might be thinking.

Well, we recently did a redesign of the open-source content-blocking browser extension NoScript, and we can tell you from experience: finding the right visual language for pairs of opposites was a struggle.

NoScript is a browser extension that helps you block potential malware from the websites you’re visiting. It needs to communicate a lot of states and actions to users. A single script can be blocked or allowed. A source of scripts can be trusted or untrusted. NoScript is a tool for the truly paranoid, so in general, wants to encourage blocking and not trusting. But:

“An icon with a crossed-out item is usually BAD, and a sign without anything is usually GOOD. But of course, here blocking something is actually GOOD, while blocking nothing is actually BAD. So whichever indicators NoScript chooses, they should either aim to indicate system state [allow/block] or recommendation [good/bad], but not both. And in any case, NoScript should probably stay away from standard colors and icons.”

So we ended up using hardly any of the many common security icons available. No shields, no alert! signs, no locked locks, no unlocked locks. And we completely avoided the red/green palette to keep from taking on unintended meaning.

Navigating the paradox

Security recommendations appear in most digital services are built nowadays. As we move into 2020, we expect to see a lot more conscious choice around colors, icons, and words related to security. For a start, Firefox already made a step in the right direction by streamlining indicators for SSL encryption as well as content blocking. (Spoilers: they avoided adding multiple dimensions of indicators, too!)

The most important thing to keep in mind, as you’re choosing language around security and privacy features, is: don’t conflate social and technical concepts. Trusting your partner is good. Trusting a website? Well, could be good, could be bad. Locking your bike? Good idea. Locking a file? That depends.

Think about the technical facts you’re trying to communicate. Then, and only then, consider if there’s also a behavioral nudge you want to send, and if you are, try to poke holes in your reasoning. Is there ever a case where your nudge could be dangerous? Colors, icons, and words give you a lot of control over how exactly people experience security and privacy features. Using them in a clear and consistent way will help people understand their choices and make more conscious decisions around security.


About the author

Molly Wilson is a designer by training and a teacher at heart: her passion is leveraging human-centered design to help make technology clear and understandable. She has been designing and leading programs in design thinking and innovation processes since 2010, first at the Stanford d.school in Palo Alto, CA and later at the Hasso-Plattner-Institut School of Design Thinking in Potsdam, Germany. Her work as an interaction designer has focused on complex products in finance, health, and education. Outside of work, talk to her about cross-cultural communication, feminism, DIY projects, and visual note-taking.

Molly holds a master’s degree in Learning, Design, and Technology from Stanford University, and a bachelor’s degree magna cum laude in History of Science from Harvard University. See more about her work and projects at http://molly.is.

Eileen Wagner is Simply Secure’s in-house logician. She advises teams and organizations on UX design, supports research and user testing, and produces open resources for the community. Her focus is on information architecture, content strategy, and interaction design. Sometimes she puts on her admin hat and makes sure her team has the required infrastructure to excel.

She previously campaigned for open data and civic tech at the Open Knowledge Foundation Germany. There she helped establish the first public funding program for open source projects in Germany, the Prototype Fund. Her background is in analytic philosophy (BA Cambridge) and mathematical logic (MSc Amsterdam), and she won’t stop talking about barbershop music.

More articles by Molly Wilson & Eileen




ic

Microbrowsers are Everywhere

Colin Bendell gets into the minutia of microbrowsers - the small previews of your site that are pervasive all around the web and through social media apps and search engines whenever an item of content on your site is referenced.


You’ve seen it everywhere - that little thumbnail preview of a website mentioned in a tweet, the expanded description in a Slack channel, or in WhatsApp group chat.

Figure 1: The preview shown in a group chat provides a hint of what the real webpage looks like

These link previews are so commonplace that we hardly pay any attention to how our site design might be impacting the generated preview. Yet, these previews can be the most influential part for attracting new audiences and increasing engagement - possibly more than SEO. Even more alarming is that most web analytics are blind to this traffic and can’t show you how these Microbrowsers are interacting with your site.

As we close out the year, here are five essential questions and ideas that every web dev should know about Microbrowsers.

1. What are Microbrowsers? How are they different from “normal” browser?

We are all very familiar with the main browsers like Firefox, Safari, Chrome, Edge and Internet Explorer. Not to mention the many new browsers that use Chromium as the rendering engine but offer unique user experiences like Samsung Internet or Brave.

In contrast, Microbrowsers are a class of User-Agents that also visit website links, parse HTML and generate a user experience. But unlike those traditional browsers, the HTML parsing is limited and the rendering engine is singularly focused. The experience is not intended to be interactive. Rather the experience is intended to be representational - to give the user a hint of what exists on the other side of the URL.

Creating link previews is not new. Facebook and Twitter have been adding these link previews in posts for nearly a decade. That used to be the primary use case. Marketing teams created backlog items to adopt different microdata - from Twitter Cards and Open Graph annotations for Facebook. LinkedIn likewise embraced both Open Graph and OEmbed tags to help generate the previews

<meta name="description" content="seo description long">
<meta name="keywords" content="seo keyword list">

<link rel="shortcut icon" href="favicon.ico" 
                          type="image/x-icon">
<link rel="icon" href="favicon_32.png" sizes="32x32">
<link rel="icon" href="favicon_48.png" sizes="48x48">
<link rel="icon" href="favicon_96.png" sizes="96x96">
<link rel="icon" href="favicon_144.png" sizes="144x144">

<meta property="og:title" content="Short title here" />
<meta property="og:description" content="shortish description" />
<meta name="twitter:title" content="Short title here">
<meta name="twitter:description" content="shortish description">

<meta property="og:image"
      content="https://res.cloudinary.com/.../hero-img.png" />

<meta name="twitter:image:src"
      content="https://res.cloudinary.com/.../hero-img.png">

As group chats and other collaboration tools have become more prevalent, we have seen many features from the big social media platforms emerge. Particularly in recent years we’ve seen the adoption of the link unfurling behaviour in these chat platforms. Rather than reinventing the wheel, each platform looks for pre-existing microdata to generate the preview.

But which data should be used? How should this be arranged? As it turns out, each platform behaves slightly differently; presenting information in slightly different ways.

Figure 2: The same amazon link shared in iMessage (left), Hangouts and WhatsApp (right)

2. If Microbrowsers are everywhere, why don’t I see them in my analytics reports?

It’s easy to miss the traffic from Microbrowsers. This is for a number of reasons:

First, page requests from Microbrowsers don’t run JavaScript and they don’t accept cookies. The Google Analytics <script> block won’t be run or executed. And all cookie will be ignored by the rendering agent.

Second, if you were to do a log analysis based on HTTP logs from your CDN or web stack, you would see a relatively small volume of traffic. That is assuming you can identify the User-Agent strings. Some of these Microbrowsers impersonate real browsers and others impersonate Facebook or twitter. For example, iMessage uses the same User-Agent string for all these requests and it hasn’t changed since iOS 9.

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) 
             AppleWebKit/601.2.4 (KHTML, like Gecko) 
             Version/9.0.1 Safari/601.2.4 
             facebookexternalhit/1.1  
             Facebot Twitterbot/1.0

Finally, many platforms - particularly Facebook Messenger and Hangouts use centralized services to request the preview layout. This, in contrast to WhatsApp and iMessage where you will see one request per user. In the centralized consumer approach your web servers will only see one request, but this one request might represent thousands of eyeballs.

3. Microbrowser are probably more important than google bot

We all know the importance of having our web sites crawled by search engines like googlebot. These bots are the lifeblood for lead generation and for discovering new users.

However, the real gold for marketers is from word-of-mouth discussions. Those conversations with your friends when you recommend a TV show, a brand of clothing, or share a news report. This is the most valuable kind of marketing.

Last year when assembling the data for Cloudinary’s State of the Visual Media report, I discovered that there was a very prominent usage pattern over the USA holiday season. During thanksgiving, all the way to Black Friday, the rate of link sharing skyrocketed as group chats shared deals and insights.

Zooming out (and normalizing for time-of-day), we can see that there is a daily cadence of link sharing and word of mouth referrals. It probably isn’t a shock to see that we predominantly share links in Slack between Monday and Friday, while WhatsApp is used all week long. Likewise, WhatsApp is most often used during our ‘break’ times like lunch or in the evening after we put the kids to bed.

While the link preview is increasingly common, there are two user behaviours to balance:

  • Users can be skeptical of links sent via SMS and other chats. We don’t want to be fooled into clicking a phishing links and so we look for other queues to offer validation. This is why most platforms use the preview while also emphasize the website url host name.

  • Skimming. I’m sure you’ve had the experience coming out of a meeting or grocery store to find a group chat with 100 messages. As you scroll to catch up on the conversation, links can easily be skipped. In this way, users expect the preview to act as a summary to tell them how important it is to visit the link.

Figure 4: Nielsen Norman Group summarizes the research in a dynamic image preview

Figure 5: A mockup of how an ecommerce product could create compelling previews showcasing colors, stock and price in the preview

4. Microbrowsers are not real browsers (they just play one on TV)

As I previously mentioned, Microbrowsers pretend to be a browser in that they send the right HTTP headers and often send impersonating User-Agent strings. Yet, there are several characteristics that a web dev should be aware of.

First, Microbrowsers try to protect the User’s privacy. The user hasn’t decided to visit your site yet, and more importantly, the user is having a private conversation. The fact that your brand or website is mentioned should just make your ears burn, but you shouldn’t be able to listen in to the conversation.

For this reason, all Microbrowsers:

  • don’t execute JavaScript - so your react application won’t work
  • ignore all cookies - so your A/B or red/green cookies will be ignored
  • some will follow redirects, but will quickly time out after a few seconds and give up trying to expand the link.
  • there won’t be a referer: HTTP header when the user clicks the link for the full browser. In fact, a new user will appear as ‘direct’ traffic - as though they typed in the url.

Second, Microbrowsers have a very small brain and very likely don’t use an advanced network algorithm. Most browsers will use a tokenizer to parse the HTML markup and send requests to the network stack asynchronously. Better yet, browsers will do some analysis of the resources needed before sending the async request to the network.

Based on observational experimentation, most platforms simply use a glorified for loop when parsing the HTML and often request the resources synchronously. This might be ok for fast wifi experiences, but it can cause inconsistent experiences on flaky wifi.

For example, iMessage will discover and load all <link rel="icon" > favicon, all <meta property="og:image" images, and all <meta name="twitter:image:src" before deciding what to render. Many sites still advertise 5 or more favicon sizes. This means that iMessage will download all favicons regardless of size and then not use them if it decides to instead render the image.

For this reason the meta markup that is included is important. The lighter the content, the more likely it will be to be rendered.

5. Markup Matters

Since Microbrowsers are simple-brained browsers, it is all the more important to produce good markup. Here are a few good strategies:

  • It’s almost 2020, you only need one favicon size. Remove all the other <link rel="shortcut icon" and <link rel="icon" references.
  • Based on observational experimentation, the most commonly recognized microdata tags for preview are the Open-Graph tags. When the OG and twitter card tags are missing, the default SEO <meta name="description" is used. However, since the description is often nonsensical SEO optimized phrases, users’ eyes will likely glaze over.

  • On that note, use good descriptive text
  • Provide up to three <meta property="og:image" images. Most platforms will only load the first one, while others (notably iMessage) attempts to create a collage.

Figure 6: Amazon uses User-Agent detection which results in many link previews using the description meta tag.

  • Use <meta property="og:video* with progressive (not streaming) video experiences.
<meta property="og:type" content="video.other">
<meta property="og:video:url" 
               content="https://shoesbycolin.com/blue.mp4">
<meta property="og:video:secure_url" 
               content="https://shoesbycolin.com/blue.mp4">
<meta property="og:video:type" content="video/mp4">
<meta property="og:video:width" content="1280">
<meta property="og:video:height" content="720">
  • Don’t use UA sniffing to hide the <meta> tags. Sites like Amazon do this to try and show only Facebook/Twitter the microdata annotated website. But this can cause problems for some Microbrowsers that don’t use the same impersonation convention. The result is a simple link without a preview.
  • Use the opportunity to tell your product story or summarize your ideas.

Summary

As more of our conversations happen in group chats and slack channels, link previews are an important way for you to engage users before they start the journey on your site. Unfortunately, not all websites present good or compelling previews. (And now that you know what to look for, you won’t be able to unsee bad examples - I’m sorry). To help users take the leap and visit your site, we need to make sure that all our pages are annotated with microdata. Better yet, we can use these previews to create compelling visual summaries.


About the author

Colin is part of the CTO Office at Cloudinary and co-author of the O’Reilly book High Performance Images. He spends much of his time at the intersection of high volume data, media, browsers and standards. He recently helped the community effort writing chapters in the Web Almanac on Media and CDNs. You can find him on tweeting @colinbendell and at blogging at https://bendell.ca

More articles by Colin




ic

Building a Dictaphone Using Media Recorder and getUserMedia

Chris Mills brushes up his shorthand and shows how the MediaStream Recording API in modern browsers can be used to capture audio directly from the user’s device. Inching ever closer to the capabilities of native software, it truly is an exciting time to be a web developer.


The MediaStream Recording API makes it easy to record audio and/or video streams. When used with MediaDevices.getUserMedia(), it provides an easy way to record media from the user’s input devices and instantly use the result in web apps. This article shows how to use these technologies to create a fun dictaphone app.

A sample application: Web Dictaphone

To demonstrate basic usage of the MediaRecorder API, we have built a web-based dictaphone. It allows you to record snippets of audio and then play them back. It even gives you a visualisation of your device’s sound input, using the Web Audio API. We’ll just concentrate on the recording and playback functionality in this article, for brevity’s sake.

You can see this demo running live, or grab the source code on GitHub. This has pretty good support on modern desktop browsers, but pretty patchy support on mobile browsers currently.

Basic app setup

To grab the media stream we want to capture, we use getUserMedia(). We then use the MediaRecorder API to record the stream, and output each recorded snippet into the source of a generated <audio> element so it can be played back.

We’ll first declare some variables for the record and stop buttons, and the <article> that will contain the generated audio players:

const record = document.querySelector('.record');
const stop = document.querySelector('.stop');
const soundClips = document.querySelector('.sound-clips');

Next, we set up the basic getUserMedia structure:

if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
   console.log('getUserMedia supported.');
   navigator.mediaDevices.getUserMedia (
      // constraints - only audio needed for this app
      {
         audio: true
      })

      // Success callback
      .then(function(stream) {

      })

      // Error callback
      .catch(function(err) {
         console.log('The following `getUserMedia` error occured: ' + err);
      }
   );
} else {
   console.log('getUserMedia not supported on your browser!');
}

The whole thing is wrapped in a test that checks whether getUserMedia is supported before running anything else. Next, we call getUserMedia() and inside it define:

  • The constraints: Only audio is to be captured for our dictaphone.
  • The success callback: This code is run once the getUserMedia call has been completed successfully.
  • The error/failure callback: The code is run if the getUserMedia call fails for whatever reason.

Note: All of the code below is found inside the getUserMedia success callback in the finished version.

Capturing the media stream

Once getUserMedia has created a media stream successfully, you create a new Media Recorder instance with the MediaRecorder() constructor and pass it the stream directly. This is your entry point into using the MediaRecorder API — the stream is now ready to be captured into a <Blob>, in the default encoding format of your browser.

const mediaRecorder = new MediaRecorder(stream);

There are a series of methods available in the MediaRecorder interface that allow you to control recording of the media stream; in Web Dictaphone we just make use of two, and listen to some events. First of all, MediaRecorder.start() is used to start recording the stream once the record button is pressed:

record.onclick = function() {
  mediaRecorder.start();
  console.log(mediaRecorder.state);
  console.log("recorder started");
  record.style.background = "red";
  record.style.color = "black";
}

When the MediaRecorder is recording, the MediaRecorder.state property will return a value of “recording”.

As recording progresses, we need to collect the audio data. We register an event handler to do this using mediaRecorder.ondataavailable:

let chunks = [];

mediaRecorder.ondataavailable = function(e) {
  chunks.push(e.data);
}

Last, we use the MediaRecorder.stop() method to stop the recording when the stop button is pressed, and finalize the Blob ready for use somewhere else in our application.

stop.onclick = function() {
  mediaRecorder.stop();
  console.log(mediaRecorder.state);
  console.log("recorder stopped");
  record.style.background = "";
  record.style.color = "";
}

Note that the recording may also stop naturally if the media stream ends (e.g. if you were grabbing a song track and the track ended, or the user stopped sharing their microphone).

Grabbing and using the blob

When recording has stopped, the state property returns a value of “inactive”, and a stop event is fired. We register an event handler for this using mediaRecorder.onstop, and construct our blob there from all the chunks we have received:

mediaRecorder.onstop = function(e) {
  console.log("recorder stopped");

  const clipName = prompt('Enter a name for your sound clip');

  const clipContainer = document.createElement('article');
  const clipLabel = document.createElement('p');
  const audio = document.createElement('audio');
  const deleteButton = document.createElement('button');

  clipContainer.classList.add('clip');
  audio.setAttribute('controls', '');
  deleteButton.innerHTML = "Delete";
  clipLabel.innerHTML = clipName;

  clipContainer.appendChild(audio);
  clipContainer.appendChild(clipLabel);
  clipContainer.appendChild(deleteButton);
  soundClips.appendChild(clipContainer);

  const blob = new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' });
  chunks = [];
  const audioURL = window.URL.createObjectURL(blob);
  audio.src = audioURL;

  deleteButton.onclick = function(e) {
    let evtTgt = e.target;
    evtTgt.parentNode.parentNode.removeChild(evtTgt.parentNode);
  }
}

Let’s go through the above code and look at what’s happening.

First, we display a prompt asking the user to name their clip.

Next, we create an HTML structure like the following, inserting it into our clip container, which is an <article> element.

<article class="clip">
  <audio controls></audio>
  <p>_your clip name_</p>
  <button>Delete</button>
</article>

After that, we create a combined Blob out of the recorded audio chunks, and create an object URL pointing to it, using window.URL.createObjectURL(blob). We then set the value of the <audio> element’s src attribute to the object URL, so that when the play button is pressed on the audio player, it will play the Blob.

Finally, we set an onclick handler on the delete button to be a function that deletes the whole clip HTML structure.

So that’s basically it — we have a rough and ready dictaphone. Have fun recording those Christmas jingles! As a reminder, you can find the source code, and see it running live, on the MDN GitHub.


This article is based on Using the MediaStream Recording API by Mozilla Contributors, and is licensed under CC-BY-SA 2.5.


About the author

Chris Mills manages the MDN web docs writers’ team at Mozilla, which involves spreadsheets, meetings, writing docs and demos about open web technologies, and occasional tech talks at conferences and universities. He used to work for Opera and W3C, and enjoys playing heavy metal drums and drinking good beer.

More articles by Chris




ic

A Modern Typographic Scale

Rob Weychert reaches for the top notes to sing us a song of typographic scale. A little attention to scale and to the mathematics will help you to hit a high note with your designs this Christmas and beyond.


I’ve been studying music theory this year. While some of its core concepts were already familiar to me, much of their specifics were not. Or so I thought. A funny thing happened when I was learning the major scales.

While playing through a song I had written some years before, I started picking it apart to see how it correlated with the theory I was learning. I had composed the melody without any thought to what the specific notes were, but as I started to transcribe them, a pattern quickly emerged: all the B’s and E’s were flat and the rest of the notes were natural. Lo and behold, long before my music theory studies began, I had written a song in B♭ major. My ears already knew how the major scales worked even if my brain didn’t. (If you know how “do re mi fa so la ti do” is supposed to sound tonally, then your ears know, too.)

When music is composed to a scale, it sounds “right” to us. And just as our ears appreciate harmony and melody with a rational basis, our eyes can appreciate the same concepts applied to spatial relationships.

Have you ever struggled with sizing type in a design project, especially when you need more than just one or two sizes? Have you ever despaired at the number of ad-hoc type sizes on your site spiraling out of control over time? It could be that you’ve been composing the typographic equivalent of a cacophonous symphony. And the first thing any composer will tell you to do is to get that thing on a scale.

Meet the typographic scale

You don’t need to know music theory to work with a typographic scale. You only need to know that a scale is a range of values with an established mathematic relationship. For a typographic scale, that relationship is frequently a steady interval between type sizes. Depending on what you need your type to do, the interval might be fixed (e.g. each size is two pixels bigger than the size before it) or it might be proportional (e.g. each size is twice as big as the size before it). I personally rarely find fixed intervals useful, so I’ll be focusing on proportional intervals.

The most important thing to understand about proportional intervals is thankfully not complicated: The bigger the intervals are, the more drastic the size differences will be in your scale. If your layout calls for contrast, a bigger interval might be the way to go. If you’re aiming for something more nuanced, go smaller. But keep these things in mind:

  • There is such a thing as too much nuance: if a size on your scale is virtually indistinguishable from the sizes adjacent to it, it defeats the purpose of using a scale.
  • On the flip side, too much contrast renders the sizes’ proportional relationship moot. At a certain point, massive display type is arguably more graphic than textual.
  • More is less. The more sizes you use, the less they’ll mean.
A small interval (left, 1.1) offers a smoother range of sizes; a large interval (right, 1.8) offers more contrast.

Setting up the scale variables

The quickest way to get a scale up and running when working on the web is to drop its values into some CSS variables. The naming convention I typically use begins with --scale0, which is the body text size. The size below it is --scale-1 (as in “scale minus one”), the size above it is --scale1, and so on. Keeping the names relative to each other like this helps me move around the scale intuitively as I use it. If, say, --scale4 isn’t big enough for my h1, I can move up to --scale5 or --scale6, and I always know exactly how many steps away from the body text I am. Here’s a first pass at a simple set of scale variables using an interval of 1.5:

:root {
  --scale-2: 7.1px;  /* 10.7 ÷ 1.5 */
  --scale-1: 10.7px; /* 16 ÷ 1.5   */
  --scale0: 16px;    /* body text  */
  --scale1: 24px;    /* 16 × 1.5   */
  --scale2: 36px;    /* 24 × 1.5   */
}

I can use these variables with any CSS property that accepts a numeric value, like so:

p { font-size: var(--scale0); }

Rooting around in rems

I’m off to a good start. However, those px values are a little too absolute for my liking. If I convert them to rems, it’ll give my scale more flexibility. rem stands for “root em.” 1rem is equivalent to the html element’s text size, which in most browsers defaults to 16px. Crucially, though, users can adjust that size in their browser settings, and using rems in my CSS will respect those preferences.

:root {
  --scale-2: 0.4rem;  /* 0.7rem ÷ 1.5 */
  --scale-1: 0.7rem;  /* 1rem ÷ 1.5   */
  --scale0: 1rem;     /* body text    */
  --scale1: 1.5rem;   /* 1rem × 1.5   */
  --scale2: 2.25rem;  /* 1.5rem × 1.5 */
}

Another benefit of the relative nature of rems: I tend to use larger text sizes on large viewports and smaller text sizes on small viewports. Rather than adjusting dozens or hundreds of typographic CSS declarations per breakpoint, I can shift the whole scale up or down merely by adjusting the font-size on the html element:

html { font-size: 100%; }     /* 1rem = 16px */

@media screen and (min-width: 25em) {
  html { font-size: 112.5%; } /* 1rem = 18px */
}

Calculating with calc()

My scale is coming along. Its variables’ intuitive names make it easy for me to use, and its rem values respect the user’s browser preferences and allow me to easily shift the size of the entire scale at different viewport sizes. But my setup still isn’t optimized for one very important adjustment: the interval, which is currently 1.5. If 1.5 isn’t quite working for me and I want to see how an increase or decrease will affect the scale, I need to do the math all over again for every step in the scale every time I adjust the interval. The bigger the scale, the more time that will take. It’s time to put down the abacus and get calc() involved.

:root {
  --int: 1.5;
  --scale0: 1rem;
  --scale-1: calc(var(--scale0) / var(--int));
  --scale-2: calc(var(--scale-1) / var(--int));
  --scale1: calc(var(--scale0) * var(--int));
  --scale2: calc(var(--scale1) * var(--int));
}

My interval now has its very own variable, called --int. calc() determines each scale size by multiplying the preceding size by --int. Now that every size is ultimately dependent on --scale0’s value, --scale0 must appear first in the list. Since the sizes smaller than --scale0 are going down rather than up, their values require division rather than multiplication.

Scaling the scale

I can now quickly and easily tweak my scale’s interval by adjusting --int until the proportions are just right, but if I want to add more sizes to the scale, I need to add more variables and calc() values. This isn’t too big of a deal, but if I want to double or triple the number of sizes, it’s kind of a headache. Luckily, this is the sort of thing Sass is really good at. In the following code, adjusting the first four Sass variables at the top of :root will quickly spin up a set of CSS variables like the scale above, with any interval (proportional or fixed) and any number of scale sizes:

:root {
  $interval: 1.5;    // Unitless for proportional, unit for fixed
  $body-text: 1rem;  // Must have a unit
  $scale-min: -2;    // Unitless negative integer
  $scale-max: 2;     // Unitless positive integer

  --int: #{$interval};
  --scale0: #{$body-text};

  @if $scale-min < 0 {
  // Generate scale variables smaller than the base text size
    @for $i from -1 through $scale-min {
      @if type-of($interval) == number {
        @if unitless($interval) {
          --scale#{$i}: calc(var(--scale#{$i + 1}) / var(--int));
        } @else {
          --scale#{$i}: calc(var(--scale#{$i + 1}) - var(--int));
        }
      }
    }
  }
  @if $scale-max > 0 {
    // Generate scale variables larger than the base text size
    @for $i from 1 through $scale-max {
      @if type-of($interval) == number {
        @if unitless($interval) {
          --scale#{$i}: calc(var(--scale#{$i - 1}) * var(--int));
        } @else {
          --scale#{$i}: calc(var(--scale#{$i - 1}) + var(--int));
        }
      }
    }
  }
}

Go forth and scale

Typographic scales have been an indispensable part of my work for many years, and CSS variables and calc() make setup, adjustments, and experimentation easier than ever. I hope you find these techniques as useful as I do!


About the author

Rob Weychert is a Brooklyn-based designer. He helps shape the reading experience at ProPublica and has previously helped make books at A Book Apart, games at Harmonix, and websites at Happy Cog. In his free time, he obsesses over music and film. Despite all this, he is probably best known as a competitive air guitarist.

More articles by Rob




ic

Addiction debates : hot topics from policy to practice / Catherine Comiskey.

Thousand Oaks : SAGE Publishing, 2019




ic

Cigarette taxes and smoking among sexual minority adults [electronic resource] / Christopher Carpenter, Dario Sansone

Cambridge, Mass. : National Bureau of Economic Research, 2020




ic

The effects of e-cigarette taxes on e-cigarette prices and tobacco product sales [electronic resource] : evidence from retail panel data / Chad D. Cotti, Charles J. Courtemanche, Johanna Catherine Maclean, Erik T. Nesson, Michael F. Pesko, Nathan Tefft

Cambridge, Mass. : National Bureau of Economic Research, 2020




ic

Effect of prescription opioids and prescription opioid control policies on infant health [electronic resource] / Engy Ziedan, Robert Kaestner

Cambridge, Mass. : National Bureau of Economic Research, 2020




ic

Cigarette taxes and teen marijuana use [electronic resource] / D. Mark Anderson, Kyutaro Matsuzawa, Joseph J. Sabia

Cambridge, Mass. : National Bureau of Economic Research, 2020




ic

Suburban Xanadu [electronic resource] : the Casino Resort on the Las Vegas Strip and Beyond

Hoboken : Taylor & Francis, 2003.




ic

Vicious games [electronic resource] : capitalism and gambling / Rebecca Cassidy.

London : Pluto Press, 2020.




ic

Drug courts [electronic resource] : a new approach to treatment and rehabilitation / James E. Lessenger, Glade F. Roper, editors

New York : Springer, [2007]




ic

The moccasin game [electronic resource] / produced by the National Film Board of Canada. --

Montreal : National Film Board of Canada, 1983.




ic

The evolving consequences of OxyContin reforumulation on drug overdoses [electronic resource] / David Powell, Rosalie Liccardo Pacula

Cambridge, Mass. : National Bureau of Economic Research, 2020




ic

AMERICAN LEGION, ET AL. v. AMERICAN HUMANIST ASSN., ET AL.. Decided 06/20/2019




ic

KNICK, ROSE MARY v. SCOTT, PA, ET AL.. Decided 06/21/2019




ic

UNITED STATES v. DAVIS, MAURICE L., ET AL.. Decided 06/24/2019




ic

Leadership decapitation: strategic targeting of terrorist organizations / Jenna Jordan

Dewey Library - HV6431.J674 2019




ic

Power to the people: how open technological innovation is arming tomorrow's terrorists / Audrey Kurth Cronin

Dewey Library - U39.C76 2020




ic

Also serving time: Canada's provincial and territorial correctional officers / Rosemary Ricciardelli

Dewey Library - HV9506.R53 2019




ic

The modern Republican Party in Florida / Peter Dunbar and Mike Haridopolos

Dewey Library - JK2358.F5 D86 2019




ic

The Queen: the forgotten life behind an American myth / Josh Levin

Dewey Library - HV6692.T39 L48 2019




ic

Human rights in twentieth-century Australia / Jon Piccini

Dewey Library - JC599.A8 P53 2019




ic

No visible bruises: what we don't know about domestic violence can kill us / Rachel Louise Snyder

Dewey Library - HV6626.2.S59 2019




ic

Shadows of doubt: stereotypes, crime, and the pursuit of justice / Brendan O'Flaherty, Rajiv Sethi

Online Resource




ic

Prisoners of politics: breaking the cycle of mass incarceration / Rachel Elise Barkow

Online Resource




ic

Homeland security and public safety: research, applications and standards / editors, Philip J. Mattson and Jennifer L. Marshall

Barker Library - UA23.H538 2019




ic

The sovereignty game: Neo-Colonialism and the Westphalian System / Will Hickey

Online Resource




ic

Insurgency prewar preparation and intrastate conflict: Latin America and beyond / Joel J. Blaxland

Online Resource




ic

Japan rearmed: the politics of military power / Sheila A. Smith

Online Resource




ic

Arendt on the political / David Arndt, Saint Maryʹs College, California

Dewey Library - JC251.A74 A83 2019




ic

Extreme reactions: radical right mobilization in Eastern Europe / Lenka Bustikova, Arizona State University

Dewey Library - JC573.2.E852 B88 2020




ic

Territorial sovereignty: a philosophical exploration / Anna Stilz

Dewey Library - JC327.S79 2019




ic

Assessment of the in-house laboratory independent research at the Army's Research, Development, and Engineering Centers / Army Research Program Review and Analysis Committee, Division on Engineering and Physical Sciences

Online Resource




ic

The suspect: an Olympic bombing, the FBI, the media, and Richard Jewell, the man caught in the middle / Kent Alexander & Kevin Salwen

Dewey Library - HV8079.B62 A44 2019




ic

Reclaiming Liberalism David F. Hardwick, Leslie Marsh, editors

Online Resource




ic

Socialist Practice: Histories and Theories / Victor Wallis

Online Resource