Web Standards

Fitting Text to a Container

Css Tricks - Fri, 06/29/2018 - 4:44am

There are a number of ways to go about putting some text in a container and having it size itself to fill that container. There are different technologies we can use and different considerations to think about. Let us count the ways.

Magic Number it with viewport units

If you set type with vw (viewport width) units, you can find an exact number where the text pretty closely fits the container and doesn't break as you resize. I'd call this a magic number.

In this case, font-size: 25.5vw; works down to a 320px viewport, but still will break much lower than that.

See the Pen Fitted Text with Viewport Units by Chris Coyier (@chriscoyier) on CodePen.

This is kind of a less exotic version of fluid typography, which involves more of a sprinkling of viewport units and min/max sizes.

FitText

Dave Rupert's FitText is up for the job. You still need a bit of a magic number to get the sizing just right for any particular job:

See the Pen Fitted Text with FitText by Chris Coyier (@chriscoyier) on CodePen.

FitText without jQuery

If you aren't using jQuery, there are options. Listed from the repo:

Example of the first:

See the Pen Fitted Text with FitText (no jQuery) by Chris Coyier (@chriscoyier) on CodePen.

textFit

Swap the words in FitText around and you got yourself textFit! It's another JavaScript library that adjusts font sizes to fit text into a container. Big caveat here though: textFit is designed for two-dimensions. So you need a width and height on the element for it to do it's thing.

See the Pen Fitted Text with textFit by Chris Coyier (@chriscoyier) on CodePen.

fitty

fitty is more like FitText in that it resizes type to maximize just horizontally, but actually seems to require no magic numbers.

See the Pen Fitted Text with fitty by Chris Coyier (@chriscoyier) on CodePen.

TextFill

TextFill is jQuery-based and requires a width, height, and a configured maximum font size to work. Here's the basic demo we've been working from:

See the Pen Fitted Text with TextFill by Chris Coyier (@chriscoyier) on CodePen.

FlowType

FlowType is kind of designed to work on a whole document of text, resizing it all fluidly at once, with minimum and maxium viewport sizes. But you can scope it however you want. You also apply a magic number to get things how you want them.

See the Pen Fitted Text with FlowType by Chris Coyier (@chriscoyier) on CodePen.

Just use SVG

With width: 100% and a viewBox, SVG will be a fullsize box that resizes with an aspect ratio. Pretty neat trick! To set the type, you'll need some magic numbers to get that viewBox just right and push the text into the right spot — but it's doable with zero dependencies, just like the viewport units demo.

See the Pen Fitted Text with SVG by Chris Coyier (@chriscoyier) on CodePen.

The post Fitting Text to a Container appeared first on CSS-Tricks.

How to create a logo that responds to its own aspect ratio

Css Tricks - Thu, 06/28/2018 - 11:16am

One of the cool things about <svg> is that it's literally its own document, so @media queries in CSS inside the SVG are based on its viewport rather than the HTML document that likely contains it.

This unique feature has let people play around for years. Tim Kadlec experimented with SVG formats and which ones respect the media queries most reliably. Sara Soueidan experimented with that a bunch more. Jake Archibald embedded a canvas inside and tested cross-browser compatibility that way. Estelle Weyl used that ability to do responsive images before responsive images.

Another thing that has really tripped people's triggers is using that local media query stuff to make responsive logos. Most famously Joe Harrison's site, but Tyler Sticka, Jeremy Frank, and Chris Austin all had a go as well.

Nils Binder has the latest take. Nils take is especially clever in how it uses <symbol>s referencing other <symbol>s for extra efficiency and min-aspect-ratio media queries rather than magic number widths.

For the record, we still very much need container queries for HTML elements. I get that it's hard, but the difficulty of implementation and usefulness are different things. I much prefer interesting modern solutions over trying to be talked out of it.

Direct Link to ArticlePermalink

The post How to create a logo that responds to its own aspect ratio appeared first on CSS-Tricks.

Empower Through Web Development

Css Tricks - Thu, 06/28/2018 - 4:56am

As a person with a disability, I appreciate the web and modern-day computing for their many affordances. The web is a great place to work and share and connect. You can make a living, build your dream, and speak your mind.

It’s not easy, though. Beginners struggling with the box model often take to Google in search of guidance (and end up at this very website). More seasoned developers find themselves hopping from framework to framework trying to keep up. We experience plenty of late nights, console logs, and rage quits.

It’s in times like these that I like to remember why I’m doing this thing. And that’s because of the magic of creating. Making websites is empowering because it allows you to shape the world—in ways big and small, public and personal. It’s especially powerful for people with disabilities, who gain influence on the tech that they rely on. And, hey, you can do web stuff for fun and profit.

The magic of craft

I knew I wanted to be a person who makes websites the first time I ever wrote HTML, hit reload, and saw my changes. I felt the power coursing through my veins as I FTP-ed my site to my shiny new web server under my very own domain name. My mind jumped into the future, imagining my vast web empire.

I never got around to making an empire, but I had something most of my friends didn’t—a personal homepage. I don’t care how ugly or weird they might be, I think everyone should have a homepage they made for themselves. I love going to personal web homes—you know, just to check out what they’ve done with the place.

I love that the web can be this artisanal craft. My disability (spinal muscular atrophy) precludes me from practicing many crafts one might pick up. And yet as a child, I watched as my grandfather would take to his workshop and emerge with all sorts of wooden inventions—mostly toys for me, of course. I came to appreciate the focus and dedication he put into it. Regardless of what terrible things were going on in life, he could escape into this wonderful world of creation, systems, and problem-solving. I wanted that too. Years later, I found my craft. What with its quirky boxes, holy wars, and documentation.

But I loved it. I couldn’t get enough. And finally I realized… this can be my life’s work. I can get paid to make things on the internet.

But first, some not great facts about employment

Employment levels of people with disabilities are low, and those who are employed tend to be in low-paying occupations.

— U.S. Department of Labor

The U.S. Department of Labor (DOL) keeps statistics on employment levels for people with disabilities and, let me tell you, they kind of suck. The DOL goes on to say that only a third of working-age people with disabilities were employed, on average, in the 2010-2012 period. In contrast, over two-thirds of people without disabilities were employed in the same period.

This problem affected me personally as I struggled to get a job after college. Fortunately, the web is a great tool for breaking down barriers. With its vast learning resources, free and open source software, and plethora of ways to connect and share, the web makes possible all sorts of employment opportunities. I'm now a designer/developer at Mad Genius and loving it.

I urge anyone—disabled or not—who finds themselves with limited access to more conventional jobs to consider working on the web. Whether you draw, write, design, or code, there’s something here for you. This big web we’re building for everyone should be built by everyone.

We need that thing that you’re going to build

Last fall, I launched A Fine Start, a web service and browser extension for turning your new tab page into a minimal list of links. Some people saw it when Chris mentioned it in an article and it picked up quite a few new users. But what those users don’t know is that A Fine Start began life as an assistive technology.

Because of my extremely weak muscles, I type using a highly customized on-screen keyboard. It’s doable, but tedious, so I use the mouse method of getting things done wherever possible. I could open a new tab and start typing, but I would rather click. As a result, I made Start, a one-file tool that allowed me to save lists of links and get at them quickly when set as my new tab page—no keyboard necessary.

It was fantastic and I realized I needed Start on every computer I used, but I had no way of getting my bookmarks on another device without sticking them in a text file in Dropbox. So, last year, I wrote a backend service, polished the design, made a Chrome extension, and threw my baby out of the nest to see if it would fly. We’ll see.

The point is, there’s something the world needs, waiting to be built. And you are the only one who can build it. The recipe is mediocre ideas, showing up, and persistence. The web needs your perspective. Load up on your caffeinated beverage of choice, roll up your sleeves, and practice your craft. You’ve got the power. Now use it.

The post Empower Through Web Development appeared first on CSS-Tricks.

Free E-book: ?Modernize for Mobile Apps

Css Tricks - Thu, 06/28/2018 - 4:54am

(This is a sponsored post.)

No sign up required to read the free e-book.

Building modern apps (mobile, PWAs or Single Page Apps) that connect to legacy or enterprise systems is a pain. We put together an e-book that discusses the various options for how to make it all work. Here are some of the chapter contents:

  • The Challenges of Migrating to a Modern Mobile Architecture
  • Strategies for Migrating to Mobile
  • Strategies for Migrating to the Cloud
  • Data & Mobile Applications
  • Future-Proofing Your Modernization Efforts

Check out our Mobile Modernization: Architect Playbook

Direct Link to ArticlePermalink

The post Free E-book: ?Modernize for Mobile Apps appeared first on CSS-Tricks.

The Best UX Tools For User Research And User Testing [2018 Edition]

Usability Geek - Wed, 06/27/2018 - 2:26pm
There are a lot of UX tools out there. A LOT. It is nice to have multiple options, but it can also be a pain when it comes to choosing. Just as an app user can be overwhelmed by too many features, UX...
Categories: Web Standards

Vue + TypeScript: A Match Made in Your Code Editor

Css Tricks - Wed, 06/27/2018 - 3:57am

Vue is so hot right now and I’ve been thinking of doing a serious project with it since quite a while, so when the opportunity popped up, I hopped in. But there was a little problem — one of the requirements of the project was to write it in TypeScript. At first, I was super stressed about how I was going to ever get started on this combo, but vue-cli made it so easy.

I’d be lying if I said this ride was super smooth. There were frustrations, hours of staring at the screen and some fistbumps with my table but after working with Vue + TypeScript for over a month now, I can say it was worth it — and if I had to code another app with Vue, I wouldn’t do it without TypeScript.

Prerequisites

This article is about pairing Vue and TypeScript and assumes some basic knowledge of both. If you haven’t had a chance to play with them yet and are curious, Vue has a great guide, and the TypeScript docs are a great place to start.

We need to have vue-cli installed globally, so we can quickly spin up Vue project. Install vue-cli by running the following command in your terminal:

npm install -g @vue/cli

Once we have that installed, we’re good to go. If you don’t have TypeScript installed, we don’t need to do that beforehand, as vue-cli takes care of that when you start a new project and choose TypeScript there.

Getting Started

Now that we have vue-cli installed, all we need to do to get a project with Vue + TypeScript started is to run vue create. While creating a new project, choose TypeScript and we’re good to go.

vue create <app-name>

Here’s the result once our project spins up:

vue-cli also provides us the ability to choose Babel along with TypeScript for polyfills, CSS preprocessors, linter, unit testing libraries (I picked Jest, go Jest!) along with other config. You can even save your choices in a preset, to use it later, for another project.

Here’s a rundown of the handy questions you’ll get asked to configure the project:

One thing I’d like to mention is that vue-cli 3.0 comes with a user interface which makes it even more easy to create a new project. Run vue ui in terminal and vue-cli opens a UI where you can set up a new project.

What’s in the Box

After vue-cli is done, we get a nice directory structure of our app with all the setup already done.

  • tsconfig.json: This is all set up and we can edit it to suit our requirements.
  • shims-vue.d.ts: These shims are already set up to help TypeScript understand .vue files (Single File Components) when they are imported.
  • vue-property-decorator: If you choose to use class-style components, vue-cli adds this plugin so we can use all sorts of decorators. This comes quite handy and make the code more readable.
  • Class components: If you choose to use them, vue-cli sets the stage for you. Bear in mind that you would still need to register router hooks so class components can resolve them.
Sass Setup

One thing that I needed to set up and I wish was included out of the box was shared Sass partials. To avoid importing my Sass variables and mixins in every component, I had to load them in vue.config.js. shared.scss is the file exporting all variables and mixins that are used within the app.

Here’s where I landed with my Sass configuration:

chainWebpack: (config) => { config .module .rule('vue') .uses .get('vue-loader') .tap(({ loaders, loaders: { scss }, ...options }) => ({ ...options, loaders: { ...loaders, scss: [ ...scss, { loader: 'sass-resources-loader', options: { resources: [ './src/styles/shared.scss', ], }, }, ], }, })); Vue Property Decorator

The vue-property-decorator package exposes Vue properties and makes them available to use as decorators. In my application, I ended up using only @Component, @Prop, @Watch but there are others such as @Emit, @Inject and @Model, that make your code much more verbose when used extensively.

Vuex

Vuex has typings...nuff said! Vuex supports TypeScript to boot and, at first, I didn’t even know it. I started to look for proper ways to combine Vuex with TypeScript and stumbled upon Alex Jover Morales’ egghead.io course on Vue.js State Management with Vuex and TypeScript. It helped me understand the correct way of managing Vuex state when using TypeScript.

For example:

// actions.ts import { ActionTree } from 'vuex'; import { RootState, ModuleState } from '@/types'; const actions: ActionTree<ModuleState, RootState> = { // all your actions go here }; Vuex-class

This is yet another thing that I didn’t know existed when I first started but know wish I had found it sooner. I was creating getters for almost everything, but that didn’t feel right. I started looking for better ways to do this and found an interesting article by Francesco Vitullo which cleared up a few things for me. That’s where I found out about vuex-class which provides decorators for all vuex mappers.

So, now instead of writing a new getter for simply accessing a property in state, I could do this:

import { State, } from 'vuex-class' @Component export class MyComp extends Vue { @State(state => state.bar) stateBar } Development Experience With VS Code

With TypeScript, the coding experience on VS Code is so much better. There is no going back and forth to check what mutation types I declared in mutation-types.ts because VS Code can recognize them and suggest correct ones as I type.

The same goes for modifying state in mutations — with TypeScript, the editor knew what my state structure looks like and suggests correct properties.

If you’re using VS Code, I strongly recommend using the Vetur plugin because it provides Vue tooling and comes with other bells and whistles like syntax highlighting (this works great with Vue single file components) and linting right out of the box.

Final Thoughts

Just like everything else in the JavaScript ecosystem, Vue + TypeScript still has a long way to go. For example, I could not use vuelidate because it doesn’t have typings. But thankfully vee-validate provided a workaround, so I didn’t have to go down the difficult road of writing those myself.

In conclusion, I found the development experience to be much smoother and VS Code is a totally different beast when you work with TypeScript. I don’t really need to sing the praises of Vue — it is very easy to pick up and start building and saves days trying to wrap your head around the inner workings of a framework.

The post Vue + TypeScript: A Match Made in Your Code Editor appeared first on CSS-Tricks.

Better rendering for variable fonts

Css Tricks - Tue, 06/26/2018 - 8:46am

I was messing around with a variable font the other day and noticed this weird rendering issue in the latest version of Chrome where certain parts of letterforms were clipping into each other in a really weird way. Thankfully, though, Stephen Nixon has come to the rescue with a temporary hack to fix the issue which using a text-shadow on the text that’s using the variable font:

.variable-font { text-shadow: 0 0 0 #000; /* text color goes last here */ }

Once you do that, you shouldn’t be able to see those weird clip marks in the letterforms anymore. Yeah, it feels pretty hacky but I’m sure this rendering bug will be fixed relatively soon. It doesn’t look like it affects other browsers, as far as I can tell.

Direct Link to ArticlePermalink

The post Better rendering for variable fonts appeared first on CSS-Tricks.

Handling Errors with Error Boundary

Css Tricks - Tue, 06/26/2018 - 4:14am

Thinking and building in React involves approaching application design in chunks, or components. Each part of your application that performs an action can and should be treated as a component. In fact, React is component-based and, as Tomas Eglinkas recently wrote, we should leverage that concept and err on the side of splitting any large chunking into smaller components.

Splitting inevitably introduces component hierarchies, which are good because they bloated components and architecture. However, things can begin to get complicated when an error occurs in a child component. What happens when the whole application crashes?! Seriously, React, why do the parent and sibling components have to pay for the sins of another component? Why?

Error Boundaries

React 16 came with a lot of goodies, one of which is error boundaries. Let's consult the documentation and break down what it says about this gem because we can use it to spot errors where they occur and resolve them faster and with less headache!

Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.

That’s a lot of jargon but, like components, we can break it down into less complex chunks.

Error boundaries are React Components

This makes a lot of sense and useful because it's a concept we have using all along. The difference is that juice was sprayed on it to make it different from a normal component. Still, don't forget the basic idea that error boundaries are themselves React Components!

Error boundaries catch JavaScript errors anywhere in their child component tree

In case you have forgotten how children component tree work, here is an example:

<ParentComponent> <FirstChild> <FirstChildDaughter> </FirstChildDaughter> </FirstChild> <SecondChild> </SecondChild> </ParentComponent>

We have two parent and three child components. According to what we have learned so far about error boundaries, we can replicate the above tree to:

<ErrorBoundaryComponent> <ParentComponent> <FirstChild> <FirstChildDaughter> </FirstChildDaughter> </FirstChild> <SecondChild> </SecondChild> </ParentComponent> </ErrorBoundaryComponent>

By wrapping the whole tree up in an ErrorBoundaryComponent, we can catch any JavaScript errors that occur in its child components. Cool, right?

Error boundaries log those errors

When errors are caught, we want boundaries errors to do something with them, preferably something to tell us about the. Developers often make use of error logging platforms to monitor errors that occur on their software. With error boundaries, we can do the same.

Error boundaries display a fallback UI

Instead of displaying the whole annoying combo of reds in different shades, you can choose a customized user interface to display when an error occurs. That can come in super handy because it allows you to tailor errors in a style that makes it easier for you to read and scan. Super cool, right?

Like me, you'll think that this means error boundaries will catch all JavaScript errors. Sadly, that's not true. Here are errors that they will gracefully ignore:

  • Event handlers
  • Asynchronous code (e.g. setTimeout or requestAnimationFrame callbacks)
  • Server-side rendering
  • Errors thrown in the error boundary itself (rather than its children)
componentDidCatch()

The extra juice that makes a component an error boundary is componentDidCatch() — this is a lifecycle method that works like the JavaScript catch{} block, but for components. When an error is found in a child component, the error is handled by the closest error boundary. Only class components can be error boundaries.

componentDidCatch() accepts two parameters:

  • error: This is the error that was thrown
  • info: An object which contains a trace of where the error occurred
Error Boundary In Action

Say we are working on a feature that lists locations where conferences can be held. Something like this:

See the Pen error boundary 0 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

The application lists locations from the Location component and the individual locations are output as Location Cards. We take a little extra care to ensure the name of each location is rendered in uppercase for consistency. For this tutorial purpose, we will add an empty object to the list of locations.

class Location extends React.Component { state = { locations: [ { "name": "Ojo", "zone": "Lagos State", "region": "South West" }, { "name": "Ahiazu Mbaise", "zone": "Imo State", "region": "South East" }, { "name": "Akoko-Edo", "zone": "Edo State", "region": "South South" }, { "name": "Anka", "zone": "Zamfara State", "region": "North West" }, { "name": "Akwanga", "zone": "Nasarawa State", "region": "North Central" }, { } ] } render() { return ( <div> <div> <div> <h2>Locations</h2> </div> </div> <div> {this.state.locations .map(location => <LocationCard key={location.id} {...location} /> )} </div> </div> ) } } const LocationCard = (props) => { return ( <div> <hr /> <p><b>Name:</b> {props.name.toUpperCase()}</p> <p><b>Zone:</b> {props.zone}</p> <p><b>Region:</b> {props.region}</p> <hr /> </div> ) } const App = () => ( <div> <Location /> </div> ) ReactDOM.render(<App />, document.getElementById("root"));

If you run this in the browser, you will see an error similar to this screenshot:

That’s not totally helpful, so let's apply an error boundary to handle help us out. First, we'll create an ErrorBoundary component:

class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false, error: null, info: null }; } componentDidCatch(error, info) { this.setState({ hasError: true, error: error, info: info }); } render() { if (this.state.hasError) { return ( <div> <h1>Oops, something went wrong :(</h1> <p>The error: {this.state.error.toString()}</p> <p>Where it occured: {this.state.info.componentStack}</p> </div> ); } return this.props.children; } }

An initial state for hasError, error, and info is created. Then, the componentDidCatch() lifecycle method is added. If an error occurs in the constructor, render or lifecycle method of any of its children components, the hasError state will be changed to true. When this happens, the ErrorBoundary component renders and displays the error. But if there are no errors, the children of the ErrorBoundary component are rendered instead as we’d expect.

Next, we need to add both the ErrorBoundary and Location components to our main App component:

const App = () => ( <div> <ErrorBoundary> <Location /> </ErrorBoundary> </div> )

See the Pen error boundary 2 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

We don't see that annoying TypeError UI anymore! Things are working!

There's one little thing we can do to improve the app. If you check the code in the demo, you'll see an empty object we added at the end. Is it possible to have the other credible locations render? Most definitely! Inside the Location component, we can wrap the LocationCard component with the ErrorBoundary component to scope error logging directly to the cards:

class Location extends React.Component { state = { locations: [ { "name": "Ojo", "zone": "Lagos State", "region": "South West" }, { "name": "Ahiazu Mbaise", "zone": "Imo State", "region": "South East" }, { "name": "Akoko-Edo", "zone": "Edo State", "region": "South South" }, { "name": "Anka", "zone": "Zamfara State", "region": "North West" }, { "name": "Akwanga", "zone": "Nasarawa State", "region": "North Central" }, { // Empty! } ] } render() { return ( <div> <div> <div> <h2>Locations</h2> </div> </div> <div> {this.state.locations .map(location => <ErrorBoundary> // Should render all locations, but the empty instance <LocationCard key={location.id} {...location} /> </ErrorBoundary> )} </div> </div> ) } }

This time, the credible locations show, except the one that is empty. You can choose to wrap the whole component tree with an error boundary component once, or you can wrap different components at strategic places. The decision is up to you.

Wrapping Up

I encourage you to start making use of error boundaries in your applications. Similarly, it’s worth digging in a little deeper. For that, here are some issues in the React repo on Error Boundaries and event handles, go through them so you can see the current state of where things are at:

The post Handling Errors with Error Boundary appeared first on CSS-Tricks.

?Add real-time comments to a Gatsby blog

Css Tricks - Tue, 06/26/2018 - 4:11am

(This is a sponsored post.)

This tutorial will show you how to add realtime comments to a Gatsby blog. You will use Node and Express to create a simple backend, allowing users to add and view comments instantly.

Direct Link to ArticlePermalink

The post ?Add real-time comments to a Gatsby blog appeared first on CSS-Tricks.

UX As Tech’s Tranquiliser

Usability Geek - Mon, 06/25/2018 - 10:58am
In 2005, a restaurant owner became so frustrated when using his laptop that he threw it into a deep fat fryer. In 2007, police investigated a late-night ruckus caused by an aggravated gentleman...
Categories: Web Standards

Resilient, Declarative, Contextual

Css Tricks - Mon, 06/25/2018 - 7:34am

Keith J. Grant:

I want to look at three key characteristics of CSS that set it apart from conventional programming languages: it’s resilient; it’s declarative; and it’s contextual. Understanding these aspects of the language, I think, is key to becoming proficient in CSS.

  1. Like HTML, unknown or slightly broken CSS doesn't stop a site in its tracks.
  2. You write something you want to happen in CSS, it happens, and a bunch of related things may happen to. I like Keith's example with font-size. Increase it, and the container will also grow in height without you having to tell it to.
  3. You can't understand what CSS is going to do without understanding the DOM structure it is paired with and the other styles at play.

And it’s my suspicion that developers who embrace these things, and have fully internalized them, tend to be far more proficient in CSS.

Easy to learn, a lifetime to master, as they say.

Direct Link to ArticlePermalink

The post Resilient, Declarative, Contextual appeared first on CSS-Tricks.

Drawing Images with CSS Gradients

Css Tricks - Mon, 06/25/2018 - 4:10am

What I mean by "CSS images" is images that are created using only HTML elements and CSS. They look as if they were SVGs drawn in Adobe Illustrator but they were made right in the browser. Some techniques I’ve seen used are tinkering with border radii, box shadows, and sometimes clip-path. You can find a lot of great examples if you search daily css images" on CodePen. I drew some myself, including this Infinity Gauntlet, but in one element with only backgrounds and minimal use of other properties.

Let’s take a look at how you can create CSS images that way yourself.

The Method

Understanding the shorthand background syntax as well as how CSS gradients work is practically all you need to draw anything in one element. As a review, the arguments are as follows:

background: <'background-color'> || <image> || <position> [ / <size> ]? || <repeat> || <attachment> || <origin> || <clip>;

They can occur in any order except that there must be a / between the position and size. We must keep those two arguments in that order as well, or else we’ll get unexpected results. Not all of these need to be included, and for this purpose we won’t be using the color, repeat, attachment, origin, or clip arguments. This leaves us with image, size, and position. Since backgrounds repeat by default, however, we must place background-repeat: no-repeat; right under everything in background (if certain backgrounds ought to be repeat, we can use repeating-linear-gradient() and repeating-radial-gradient()). In that case, the skeleton CSS will be this:

.image { background: <image> <position> / <size>; background-repeat: no-repeat; }

We can even use multiple sets of background arguments! Therefore, we can stack and separate them with commas like this:

.image { background: <image> <position> / <size>, <image> <position> / <size>, <image> <position> / <size>; background-repeat: no-repeat; }

The structure above is the basis of how we’ll draw images—one line per shape. Keep in mind that the rendering order is the opposite of how absolutely- or fixed-position elements are ordered. The first one will show up on top instead of at the bottom. In other words, the circles (radial gradients) below would be rendered from bottom to top (blue on bottom, red on top).

.circles { background: radial-gradient(7em 7em at 35% 35%, red 50%, transparent 50%), radial-gradient(7em 7em at 50% 50%, gold 50%, transparent 50%), radial-gradient(7em 7em at 65% 65%, blue 50%, transparent 50%); background-repeat: no-repeat; width: 240px; height: 240px; } Drawing

We’ll use Sass (SCSS) to draw these images so we can make use of variables for a color palette. That will make the code shorter, easier to read and change darkened or lighter variants of colors. We could use variables in normal CSS instead and forget Sass, but due to Internet Explorer’s lack of support, let’s stick with Sass. To explain how this works, we’ll experiment with shapes using both linear and radial gradients.

Setting Up a Color Palette

Our palette will consist of RGB or HSL colors. I’ll explain later why to keep the colors in either of those formats. For this example, we’ll use RGB.

$r: rgb(255,0,0); // hsl(0,100%,50%) $o: rgb(255,128,0); // hsl(32,100%,50%)

What I like to do to keep code short and easy to read is use a minimum of one letter to represent each color (e.g. $r for red). If using darker or lighter shades of one color, I add a d before the base letter or letters for dark or an l for light. I’d use $dr for dark red and $lr for light red. If there’s a need for more than two other shades, then I add a number at the end to indicate the shade level. For instance, $dr1 for dark red, $dr2 for a darker red, and $lr1 for light red, $lr2 for a lighter red. Such a palette would look like this (with dark first, normal next, and light last):

$dr1: rgb(224,0,0); $dr2: rgb(192,0,0); $r: rgb(255,0,0); $lr1: rgb(255,48,48); $lr2: rgb(255,92,92); Setting the Scale and Canvas

We’ll use em units for the image dimensions so that the image can easily be resized proportionally. Since 1em is equal to the element’s font size, each unit of the image will be adjusted accordingly if changed. Let’s set a font size of 10px and set both the width and height to 24em. Units of 10px is the easiest to think in because if you mentally do the math, you instantly get 240 × 240px. Then just to see where the edges of the canvas are, we’ll use a 1px gray outline.

$r: rgb(255,0,0); // hsl(0,100%,50%) $o: rgb(255,128,0); // hsl(32,100%,50%) .image { background-repeat: no-repeat; font-size: 10px; outline: 1px solid #aaa; width: 24em; height: 24em; }

Be mindful about using smaller font sizes, however; browsers have a minimum font size setting (for accessiblity reasons). If you set a font size of 4px and the minimum is 6px, it’ll be forced at 6px.

Furthermore, you can enable responsiveness just by using calc() and viewport units. Perhaps we can use something like calc(10px + 2vmin) if desired, but let’s stick with 10px for now.

Drawing Shapes

The fun part begins here. To draw a square that is 8 × 8em in the center, we use a linear-gradient() with two same-colored stops.

.image { background: linear-gradient($r, $r) 50% 50% / 8em 8em; ... }

To mold it into something more like a trapezoid, set an angle of 60deg. At the same time, let’s add $T for transparent to our palette and then place both the stops for $r and $T at 63% (right before the bottom-right corner gets cut off).

$T: transparent; .image { background: linear-gradient(60deg,$r 63%, $T 63%) 50% 50% / 8em 8em; ... }

Setting both stops at the same value makes the slanted side as crisp as the others. If you look at it more closely though, it appears to be pixelated:

To correct this, we slightly adjust one of the stops (by 1% or roughly so) so that the edge is smooth enough. So, let’s change $r’s 63% to 62%.

This will be an issue with round edges as well while working with radial gradients, which we’ll see later. If you’re viewing this in a browser other than Safari, everything looks great even if transitioning to a non-transparent color instead (say orange). The problem with transitioning to transparent in Safari is that you’ll notice a bit of black lining at the slanted side.

This is because the transparent keyword in Safari is always black transparency, and we see some black as a result. I really wish Apple would fix this, but they never will. For the time being, let’s add a new $redT variable for red transparency under $r. Scrap the $T we used for transparent as we’ll no longer use it.

$rT: rgba(255,0,0,0); // hsla(0,100%,50%,0)

Then let’s replace transparent with $redT. This takes care of our Safari problem!

.image { background: linear-gradient(60deg,$r 62%, $rT 63%) 50% 50% / 8em 8em; ... }

If you’ve been wondering why we weren’t using hex colors, Internet Explorer and Edge don’t support the #rgba and #rrggbbaa notations (yep, hex has had an alpha channel since late 2016 if you never knew), and we want this to work as cross-browser as possible. We also want to stay consistent with our choice of color format.

Now let’s move the shape vertically to 20% and draw an orange circle of the same dimensions. Also, add another variable for its transparent version. For the smooth edge, insert a 1% gap between the solid and transparent oranges.

$oT: rgba(255,128,0,0); // hsla(32,100%,50%,0) .image { background: linear-gradient(60deg,$r 62%, $rT 63%) 50% 20% / 8em 8em, radial-gradient(8em 8em at 50% 80%, $o 49%, $oT 50%); ... }

To maintain consistency with our sizing, the second color stop should be at 50% instead of 100%.

Positioning Shapes

The way gradients are positioned is based on whether the unit is fixed or a percentage. Suppose we turn both of the gradients into squares and try to place them all the way across the div horizontally.

.image { background: linear-gradient($r, $r) 24em 20% / 8em 8em, linear-gradient($o, $o) 100% 80% / 8em 8em; ... }

The red square ends up completely off canvas (outlined), and the right side of the orange square touches the other side. Using fixed units is like placing absolutely positioned elements or drawing shapes in HTML5 canvas. It’s true in that sense that the point of origin is at the top left. When using percent and a set background size, the div gets "fake padding" of half the background size. At the same time, the background’s point of origin is centered (not to be confused with background-origin, which regards box corners).

Now, if we turned these gradients into radial gradients as circles and applied the same x-positions 24em and 100%, both end up at the other side cut in half. This is because the point of origin is always in the center if we write the background like so:

.image { background: radial-gradient(8em 8em at 24em 20%, $r 49%, $rT 50%), radial-gradient(8em 8em at 100% 80%, $o 49%, $oT 50%); ... }

If we rewrote the background so that the position and size are after the gradient and used 100% 100% at center, they’ll be positioned like the linear gradients. The red one ends up outside, and the orange one touches the right edge. The "fake padding" occurs once again with the orange.

.image { background: radial-gradient(100% 100% at center, $r 49%, $rT 50%) 24em 20% / 8em 8em, radial-gradient(100% 100% at center, $o 49%, $oT 50%) 100% 80% / 8em 8em; ... }

There’s no single proper way to position shapes, but to place it like an absolutely or fixed positioned HTML element, use fixed units. If in need of a quick way to place a shape (using the position / size parameters) in the dead center, 50% is the best option as the shape’s origin will be its center. Use 100% if it should touch the very right side.

Sizing Shapes

Sizing in CSS backgrounds works as we’d expect, but it’s still influenced by the kind of unit used for position—fixed or percent. If we take our squares again and change their width to 10em, the red one expands to the right, and the orange one expands sideways.

.image { background: linear-gradient($r, $r) 12em 20% / 10em 8em, linear-gradient($o, $o) 50% 80% / 10em 8em; ... }

If we used em units for the y-position, the shape will grow downwards or shrink upwards after changing height. If we use a percentage, then it will expand both vertical directions.

A moment ago, we looked at two ways to draw circles with radial gradients. The first way is to specify the width and height between the ( and at and then the position after that:

.image { background: radial-gradient(8em 8em at 50% 50%, $r 49%, $rT 50%); ... }

The second way is to use 100% 100% in the center and then give the position and size:

.image { background: radial-gradient(100% 100% at 50% 50%, $r 49%, $rT 50%) 50% 50% / 8em 8em; ... }

These methods both draw circles but will result in different outputs because:

  1. The first way occupies the whole div since there was no real background position or size.
  2. Giving a real position and size to the second sets it a bounding box. Consequently, it’ll behave just like a linear gradient shape.

Suppose we replaced $rT with $o. You’ll see that the orange will cover what was white or shapes under it (if we added any) for the first way. Using the second way, you’ll easily notice the bounding box revealed by the orange.

Additionally, the purpose of 100% 100% instead of using circle or ellipse is to allow the circle to occupy whole bounding box. It even gives us complete control over its dimensions. That way, it’ll remain the same if you change the 50% 50% position to something else. If using one of the two keywords, the edge of the circle stops only about 71% of the way when centered and becomes more distorted if its position is adjusted. For example, here’s what happens when we change the x-position to 0 for circle and ellipse:

In the long run, you can reimagine the syntax as radial-gradient(width height at x y) or radial-gradient(100% 100% at x-in-bounding-box y-in-bounding-box) x y / width height. If you are drawing just a circle or oval, you can simplify the code with the first way. If drawing part of a circle or part of a ring, then the second way comes into play. There will be many applications of that in the examples we’ll create next.

Examples

Ready to draw something for real now? We’ll walk through three examples step by step. The first two will be static—one with lots of half-circles and the other dealing with some rounded rectangles. The last example will be smaller but focused on animation.

Static Image

This parasol will be our first static image:

We’ll use a palette with red ($r and $rT), white ($w and $wT), orange ($o and $oT), and dark orange ($do and $doT).

$r: rgb(255,40,40); $rT: rgba(255,40,40,0); $w: rgb(240,240,240); $wT: rgba(240,240,240,0); $o: rgb(255,180,70); $oT: rgba(255,180,70,0); $do: rgb(232,144,0); $doT: rgba(232,144,0,0);

Let’s set up our drawing area of 30 × 29em.

.parasol { // background to go here background-repeat: no-repeat; font-size: 10px; outline: 1px solid #aaa; width: 30em; height: 29em; }

Above the background-repeat, we’ll begin drawing the parts of the parasol. First, add the gradients that make up the pole (since neither overlap one another, the bottom-to-top order doesn’t matter at this point):

.parasol { background: // 1 radial-gradient(200% 200% at 100% 100%, $do 49%, $doT 50%) 14em 0 / 1em 1em, radial-gradient(200% 200% at 0% 100%, $o 49%, $oT 50%) 15em 0 / 1em 1em, // 2 linear-gradient(90deg, $do 50%, $o 50%) 14em 1em / 2em 25em, // 3 radial-gradient(100% 200% at 50% 0, $oT 0.95em, $o 1em, $o 1.95em, $do 2em, $do 2.95em, $doT 3em) 14em 26em / 6em 3em, // 4 radial-gradient(200% 200% at 100% 100%, $o 49%, $oT 50%) 18em 25em / 1em 1em, radial-gradient(200% 200% at 0% 100%, $do 49%, $doT 50%) 19em 25em / 1em 1em; ... }
  1. To draw each side of the top of the pole, we used quarters of a circle that are 1 × 1em. To make them occupy their bounding boxes, we used circles that are twice the size (200% 200%) positioned at the bottom right and at the bottom left. We could also use keyword pairs like right bottom or left bottom, but it’s shorter to use the percent equivalents. Notice the 1% gaps between the stops to ensure smoothness.
  2. For the long part, we used a long rectangle with an abrupt dark orange-to-orange. There’s no need for a fractional tiny gap since we’re not working with a curve or slant.
  3. This part of the pole is a bit trickier to draw than the others because we have to maintain the 2em diameter. To draw this arc, we use a box of 6 × 3em so that there is a 2em space between the ends that are also 2em. Then we use a radial gradient at the center top where each stop occurs 1em each (and spread by 0.05em for smoothness).
  4. The last two are just like the first except they are positioned at the right end of the arc so that they seamlessly fit. Also, the colors swap places.

Then above the previous gradients, add the following from bottom to top to draw the top of the umbrella without the pointy ends:

.parasol { background: radial-gradient(100% 200% at 50% 100%, $r 50%, $rT 50.25%) 50% 1.5em / 9em 12em, radial-gradient(100% 200% at 50% 100%, $w 50%, $wT 50.25%) 50% 1.5em / 21em 12em, radial-gradient(100% 200% at 50% 100%, $r 50%, $rT 50.25%) 50% 1.5em / 30em 12em, ... }

To draw the half circles that make up this part, we used a gradient size of 100% 200%, which makes each diameter fit into its background width but have twice the height and centered at the bottom. By ordering them bottom to top so that the largest is on bottom and smallest on top, we get the curves we want.

As our stack of gradients grows taller, it’ll become difficult after a while to identify which background or group of backgrounds corresponds to what part of the image. So to make it easier to pin them down, we can split them into groups lead by a comment describing what each group is for. Right now, we have split the stack to groups for the top of the parasol and the pole.

.parasol { background: /* top */ radial-gradient(100% 200% at 50% 100%, $r 50%, $rT 50.25%) 50% 1.5em / 9em 12em, radial-gradient(100% 200% at 50% 100%, $w 50%, $wT 50.25%) 50% 1.5em / 21em 12em, radial-gradient(100% 200% at 50% 100%, $r 50%, $rT 50.25%) 50% 1.5em / 30em 12em, /* pole */ radial-gradient(200% 200% at 100% 100%, $do 49%, $doT 50%) 14em 0 / 1em 1em, radial-gradient(200% 200% at 0% 100%, $o 49%, $oT 50%) 15em 0 / 1em 1em, linear-gradient(90deg, $do 50%, $o 50%) 14em 1em / 2em 25em, radial-gradient(100% 200% at 50% 0, $oT 0.95em, $o 1em, $o 1.95em, $do 2em, $do 2.95em, $doT 3em) 14em 26em / 6em 3em, radial-gradient(200% 200% at 100% 100%, $o 49%, $oT 50%) 18em 25em / 1em 1em, radial-gradient(200% 200% at 0% 100%, $do 49%, $doT 50%) 19em 25em / 1em 1em; ... }

Then, in between the top and the pole, we’ll add the next chunk of backgrounds to render the pointy ends. To determine the widths of each segment, we must get the distance between each point where red and white meet. They all must add up to 30em.

Starting with the white and narrowest red half circles, we subtract the red’s width of 9em from the white’s width of 21em and divide the result by 2 to get the width of the two white segments (point "b" in the figure). So, the result would be 6em ( b = (21 - 9) / 2 = 6 ). Then the middle red segment would be 9em (21 - (6 + 6) = 9). What we have left now are the outer red segments (point "a" in the figure). Subtract the sum of what we have now from the width of the larger red half circle and divide that result by 2. That would be make the value of point a: (30em - (6 + 6 + 9)) / 2 = 4.5em.

.parasol { background: ... /* pointy ends */ radial-gradient() 0 13.5em / 4.5em 3em, radial-gradient() 4.5em 13.5em / 6em 3em, radial-gradient() 50% 13.5em / 9em 3em, radial-gradient() 19.5em 13.5em / 6em 3em, radial-gradient() 25.5em 13.5em / 4.5em 3em, ... }

To draw the half circles similar to how we drew the top part, we start with the transparent counterpart of the color for each shape so that they resemble arc bridges. We’ll also add an extra 5% to each gradient width (not the background box width) so that each point formed by adjacent backgrounds won’t overly sharp and thin.

.parasol { background: ... /* pointy ends */ radial-gradient(105% 200% at 50% 100%, $rT 49%, $r 50%) 0 13.5em / 4.5em 3em, radial-gradient(105% 200% at 50% 100%, $wT 49%, $w 50%) 4.5em 13.5em / 6em 3em, radial-gradient(105% 200% at 50% 100%, $rT 49%, $r 50%) 50% 13.5em / 9em 3em, radial-gradient(105% 200% at 50% 100%, $wT 49%, $w 50%) 19.5em 13.5em / 6em 3em, radial-gradient(105% 200% at 50% 100%, $rT 49%, $r 50%) 25.5em 13.5em / 4.5em 3em, ... }

Finally, you’ll no longer need that 1px solid #aaa outline. Our parasol is complete!

See the Pen Parasol by Jon Kantner (@jkantner) on CodePen.

Something With Rounded Rectangles

This next example will be an old iPhone model in which there are more details than the newer models. The thing about this one is the two rounded rectangles, which are the outside and middle of the home button.

The palette will consist of black ($bk and $bkT) for the home button edge, dark gray ($dg and$dgT) for the body, gray ($g and $gT) for the camera and speaker, light gray ($lg and $lgT) for the outside border, blue ($bl and $blT) for the camera lens, and a very dark purple ($p and $pT) for the screen.

$bk: rgb(10,10,10); $bkT: rgba(10,10,10,0); $dg: rgb(50,50,50); $dgT: rgba(50,50,50,0); $g: rgb(70,70,70); $gT: rgba(70,70,70,0); $lg: rgb(120,120,120); $lgT: rgba(120,120,120,0); $bl: rgb(20,20,120); $blT: rgba(20,20,120,0); $p: rgb(25,20,25); $pT: rgba(25,20,25,0);

Let’s set up our canvas at 20 × 40em and use the same font size we used for the parasol, 10px:

.iphone { // background goes here background-repeat: no-repeat; font-size: 10px; outline: 1px solid #aaa; width: 20em; height: 40em; }

Before we begin drawing our first rounded rectangle, we need to think about our border radius, which will be 2em. Also, we want to leave some space at the left for the lock switch and volume buttons, which will be 0.25em. For this reason, the rectangle will be 19.75 × 40em. Considering the 2em border radius, we’ll need two linear gradients intersecting each other. One must have a width of 15.75em (19.75em - 2 × 2), and the other must have a height of 36em (40em - 2 × 2). Position the first 2.25em from the left and then the second 0.25em from the left and 2em from the top.

.iphone { background: /* body */ linear-gradient() 2.25em 0 / 15.75em 40em, linear-gradient() 0.25em 2em / 19.75em 36em; ... }

Since the light gray border will be 0.5em thick, let’s make each gradient stop immediately switch from light gray ($lg) to dark gray ($dg) and vice versa at 0.5em and 0.5em before the end (40em - 0.5 = 39.5em for the first gradient, 19.75em - 0.5 = 19.25em for the second). Set an angle of 90deg for the second to make it go horizontal.

.iphone { background: /* body */ linear-gradient($lg 0.5em, $dg 0.5em, $dg 39.5em, $lg 39.5em) 2.25em 0 / 15.75em 40em, linear-gradient(90deg, $lg 0.5em, $dg 0.5em, $dg 19.25em, $lg 19.25em) 0.25em 2em / 19.75em 36em; ... }

In each square corner, as indicated by the orange box in the figure, we’ll place the rounded edges. To create those shapes, we use radial gradients that are twice the size of their bounding boxes and located in each corner. Insert them above the body backgrounds.

.iphone { background: /* corners */ radial-gradient(200% 200% at 100% 100%, $dg 1.45em, $lg 1.5em, $lg 50%, $lgT 51%) 0.25em 0 / 2em 2em, radial-gradient(200% 200% at 0% 100%, $dg 1.45em, $lg 1.5em, $lg 50%, $lgT 51%) 18em 0 / 2em 2em, radial-gradient(200% 200% at 100% 0%, $dg 1.45em, $lg 1.5em, $lg 50%, $lgT 51%) 0.25em 38em / 2em 2em, radial-gradient(200% 200% at 0% 0%, $dg 1.45em, $lg 1.5em, $lg 50%, $lgT 51%) 18em 38em / 2em 2em, ... }

To get the 0.5em-thick light gray ends, think about where the gradient starts and then do the math. Because the light gray is at the end, we subtract 0.5em from 2em to properly place first stop. For the smoothness, we take off a tiny bit from the first 1.5em and add 1% to the second 50% so that the round edges blend in with the flat edges.

Now if we enlarged the image by changing the font size to 40px or more, we notice seams between the rounded and flat edges (circled in orange):

Since they appear to be so tiny, we can easily patch them by going back to the body backgrounds and slightly altering the gradient stops as long as everything still looks right when changing the font size back to 10px.

.iphone { background: /* body */ linear-gradient($lg 0.5em, $dg 0.55em, $dg 39.5em, $lg 39.55em) 2.25em 0 / 15.75em 40em, linear-gradient(90deg, $lg 0.5em, $dg 0.55em, $dg 19.175em, $lg 19.25em) 0.25em 2em / 19.75em 36em; ... }

Then in one linear gradient, we’ll add the lock switch and volume buttons to fill the 0.25em space on the left. If a 1px space is going to happen between the buttons and body, we can add a tiny bleed of 0.05em to the background width (making it 0.3em) so that it won’t stick out into the dark gray.

.iphone { background: /* volume buttons */ linear-gradient($lgT 5em, $lg 5em, $lg 7.5em, $lgT 7.5em, $lgT 9.5em, $lg 9.5em, $lg 11em, $lgT 11em, $lgT 13em, $lg 13em, $lg 14.5em, $lgT 14.5em) 0 0 / 0.3em 100%, ... }

It looks like we could’ve used three light gray-to-light gray gradients, but since it was possible, only one was needed. It’s just lots of sudden transitions between the transparent and opaque light grays running downwards.

Next, let’s add the edge of the home button as well as the flat edges of the square inside it. Now the square inside home button will be 1.5 × 1.5em and follow basically the same procedure as the body: two intersecting linear gradients and radials to fill the corners. To place them horizontally in the center, calc() comes in handy. 50% + 0.125em will be the expression; if we centered only the phone body, there will be 0.125em spaces on each side. Therefore, we move it 0.125em more to the right. The same x-positioning will apply to the upper two backgrounds.

.iphone { background: /* home button */ linear-gradient() calc(50% + 0.125em) 36.5em / 0.5em 1.5em, linear-gradient() calc(50% + 0.125em) 37em / 1.5em 0.5em, radial-gradient(3em 3em at calc(50% + 0.125em) 37.25em, $bkT 1.25em, $bk 1.3em, $bk 49%, $bkT 50%), ... }

Similar to how we shaded the linear gradient parts of the phone body, the stops will begin and end with light gray but with transparent in the middle. Notice we left 0.05em gaps between each gray-to-transparent transition (and vice versa). Just like the corners of the body, this is to ensure the blend between a round corner and flat end inside.

.iphone { background: /* home button */ linear-gradient($lg 0.15em, $lgT 0.2em, $lgT 1.35em, $lg 1.35em) calc(50% + 0.125em) 36.5em / 0.5em 1.5em, linear-gradient(90deg, $lg 0.15em, $lgT 0.2em, $lgT 1.3em, $lg 1.35em) calc(50% + 0.125em) 37em / 1.5em 0.5em, radial-gradient(3em 3em at calc(50% + 0.125em) 37.25em, $bkT 1.25em, $bk 1.3em, $bk 49%, $bkT 50%), ... }

By the way, because the outlines will be so small as you’ve seen earlier, we can better see what we’re doing by increasing the font size to at least 20px. It’s like using the zoom tool in image editing software.

Now to get the corners of the gray square to exactly where they should be, let’s focus on the x-position first. We start with calc(50% + 0.125em), then we add or subtract the width of each piece, or should I say the square’s border radius. These backgrounds will go above the last three.

.iphone { background: /* home button */ radial-gradient(200% 200% at 100% 100%, $lgT 0.3em, $lg 0.35em, $lg 0.48em, $lgT 0.5em) calc(50% + 0.125em - 0.5em) 36.5em / 0.5em 0.5em, radial-gradient(200% 200% at 0% 100%, $lgT 0.3em, $lg 0.35em, $lg 0.48em, $lgT 0.5em) calc(50% + 0.125em + 0.5em) 36.5em / 0.5em 0.5em, radial-gradient(200% 200% at 100% 0%, $lgT 0.3em, $lg 0.35em, $lg 0.48em, $lgT 0.5em) calc(50% + 0.125em - 0.5em) 37.5em / 0.5em 0.5em, radial-gradient(200% 200% at 0% 0%, $lgT 0.3em, $lg 0.35em, $lg 0.48em, $lgT 0.5em) calc(50% + 0.125em + 0.5em) 37.5em / 0.5em 0.5em, ... }

Then the screen will be a 17.25 × 30em rectangle. Just like parts of the home button, we’ll horizontally center it using calc(50% + 0.125em). From the top, it’ll be 5em.

.iphone { background: /* screen */ linear-gradient($p, $p) calc(50% + 0.125em) 5em / 17.25em 30em, ... }

Lastly, we’ll add the camera and speaker. The camera is a straightforward 1 × 1 blue-to-gray radial with no fancy calculations. The pure-gray speaker though will be a bit more involved. It will be a 5 × 1em rectangle and have a 0.5em border radius. To draw that, we first draw a rectangle with the first 4ems of the width and center it with calc(50% + 0.125em). Then we use 0.5 × 1em half circles in which the gradient positions are 100% 50% and 0% 50%. The best way to position these left and right of the rectangle is to use some new calc() expressions. For the left, we’ll subtract half the rectangle width and half the half circle width from the body center (50% + 0.125em - 2em - 0.25em). The right will follow the same pattern but with addition, so 50% + 0.125em + 2em + 0.25em.

.iphone { background: /* camera */ radial-gradient(1em 1em at 6.25em 2.5em, $bl 0.2em, $g 0.21em, $g 49%, $gT 50%), /* speaker */ radial-gradient(200% 100% at 100% 50%, $g 49%, $gT 50%) calc(50% + 0.125em - 2em - 0.25em) 2em / 0.5em 1em, radial-gradient(200% 100% at 0% 50%, $g 49%, $gT 50%) calc(50% + 0.125em + 2em + 0.25em) 2em / 0.5em 1em, linear-gradient($g, $g) calc(50% + 0.125em) 2em / 4em 1em, ... }

Remove the gray outline around the div, and the iPhone is complete!

See the Pen iPhone by Jon Kantner (@jkantner) on CodePen.

Animated Images

You might be thinking you could use background-position to animate these sorts of images, but you can only do so much. For instance, it’s impossible to animate the rotation of an individual background by itself. In fact, background-position animations don’t typically perform as well as transform animations, so I don’t recommend it.

To animate any part of an image any way we wish, we can let the :before or :after pseudo-elements be responsible for that part. If we need more selections, then we can revert to multiple child divs, yet not needing one for each little detail. For our animated image example, we’ll create this animated radar:

We draw the static part first, which is everything except the gray frame and rotating hand. Before that, let’s supply our palette (note: We won’t need a $dgnT for $dgn) and base code.

$gn: rgb(0,192,0); $gnT: rgba(0,192,0,0); $dgn: rgb(0,48,0); $gy: rgb(128,128,128); $gyT: rgba(128,128,128,0); $bk: rgb(0,0,0); $bkT: rgba(0,0,0,0); .radar { background-repeat: no-repeat; font-size: 10px; outline: 1px solid #aaa; width: 20em; height: 20em; }

Since this image is going to be completely round, we can safely apply a border radius of 50%. Then, we can use a repeating radial gradient to draw the rings—about 1/3 way apart from each other.

.radar { background: /* rings */ repeating-radial-gradient($dgn, $dgn 2.96em, $gn 3em, $gn 3.26em, $dgn 3.3em); background-repeat: no-repeat; border-radius: 50%; ... }

Also note the extra $dgn at the start. For repeating gradients to start, end, and loop as expected, we need to specify the starting color at 0 (or without 0).

Unlike the previous example, we’re not using calc() to center the lines because Internet Explorer will render the whole thing awkwardly when we use a pseudo-element later. To draw four 0.4em lines that intersect one other in the center, know that half of the line should be half the div at 10em. So then, we subtract and add half of 0.4 (0.4 / 2 = 0.2) on each side. In other words, the left of the green should be 9.8em, and the right should be 10.2em. For the 45deg diagonals though, we must multiply 10em by the square root of 2 to get their center (10 × ?2 ? 14.14). It’s the length of the longest side of a 10em right triangle. As a result, the sides of each diagonal would be approximately at 13.94 and 14.34em.

.radar { background: /* lines */ linear-gradient($gnT 9.8em, $gn 9.8em, $gn 10.2em, $gnT 10.2em), linear-gradient(45deg,$gnT 13.94em, $gn 13.98em, $gn 14.3em, $gnT 14.34em), linear-gradient(90deg,$gnT 9.8em, $gn 9.8em, $gn 10.2em, $gnT 10.2em), linear-gradient(-45deg,$gnT 13.94em, $gn 13.98em, $gn 14.3em, $gnT 14.34em), ... }

To prevent the pixelation of the diagonals, we left a tiny 0.04em gap between green and transparent green. Then, to create some lighting, add this transparent-to-black radial gradient:

.radar { background: /* lighting */ radial-gradient(100% 100%, $bkT, $bk 9.9em,$bkT 10em), ... }

That completes the static part of the radar. Now we draw the gray frame and hand in another background stack under :before and add the animation. There’s a reason we didn’t include the frame here. Because the hand container should fit the whole div, we don’t want it to overlap the frame.

This pseudo-element shall fill the space, and to ensure it stays in there, let’s absolutely position it. We’ll use the same border radius so that it stays round while animated in Safari.

.radar { ... position: relative; &:before { background-repeat: no-repeat; border-radius: 50%; content: ""; position: absolute; width: 100%; height: 100%; } }

Then, to draw the hand, we make it half the size of its container and keep it at the top left corner. Finally, on top of that, we draw the frame.

.radar { ... &:before { animation: scan 5s linear infinite; background: /* frame */ radial-gradient($gyT 9.20em, $gy 9.25em, $gy 10em, $gyT 10.05em), /* hand */ linear-gradient(45deg, $gnT 6em, $gn) 0 0 / 50% 50%; ... } } @keyframes scan { from { transform: rotate(0); } to { transform: rotate(1turn); } }

Now our little gadget is complete!

See the Pen Radar by Jon Kantner (@jkantner) on CodePen.

Benefits (Plus a Drawback)

This approach of drawing CSS images has several advantages. First, the HTML will be very lightweight compared to a rasterized image file. Second, it’s great for tackling images that are impossible to draw well without using experimental properties and APIs that might not be widely supported.

It’s not to say that this method is better than using a parent element nested with children for the shapes. There is a drawback though. You have to give up being able to highlight individual shapes using the browser dev tools. You’ll need to comment and uncomment a background to identify which it is. As long as you group and label each chunk of backgrounds, you can find that particular background faster.

Conclusion

In a nutshell, the method for drawing of CSS images we’ve covered in this post allows us to:

  1. Set up a palette made up of variables for the colors.
  2. Disable the background repeat, set a scale with font-size, and a canvas width and height in em units for the target element.
  3. Use a temporary outline to show the edges as we work.
  4. Draw each shape from bottom to top because backgrounds are rendered in that order. The background syntax for each shape follows image position / size (with or without the position and size).

There’s a lot of thinking outside the box going on as well as experimentation to get the desired result. The three examples we created were just enough to demonstrate the concept. We’ve looked at how we order each background, drawing parts of circles, rounded rectangles, and slightly adjusting gradient stops for smooth edges. To learn more, feel free to dissect and study other examples I’ve made in this CodePen collection!

The post Drawing Images with CSS Gradients appeared first on CSS-Tricks.

Users DO Change Font Size

Css Tricks - Sun, 06/24/2018 - 7:49am

Evan Minto:

The question was “How many users browse the main Internet Archive site with a default font size other than the common value of 16 pixels?” By knowing this, we would determine how many users would be affected by sizing with relative units like rems/ems.

Using the methodology I describe below, we found that the answer is 3.08% of our users.

So if you set type in pixels, and your traffic is anything like the Internet Archive's, 3% of your users won't have their explicitly-asked-for font-size alteration accommodated.

It's true. I made two little reduced test cases. First I left the default medium font-size preference on and set one with pixels and one with ems and sized them to match. Then bumped up the preference to large, and only the ems changed, the pixel-set one stays the same.

As ever, there is more to think about. How does page zooming factor in? How annoyed are those 3%? How annoyed are the 3% on other sites that use pixels but set type pretty large anyway? How much do we care about people who use the preference to size type down?

Direct Link to ArticlePermalink

The post Users DO Change Font Size appeared first on CSS-Tricks.

Animate Calligraphy with SVG

Css Tricks - Fri, 06/22/2018 - 9:35am

From time to time at Stackoverflow, the question pops up whether there is an equivalent to the stroke-dashoffset technique for animating the SVG stroke that works for the fill attribute. But upon closer inspection, what the questions are really trying to ask is something like this:

I have something that is sort of a line, but because it has varying brush widths, in SVG it is defined as the fill of a path.

How can this "brush" be animated?

In short: How do you animate calligraphy?

A mask path covers the calligraphic brush

The basic technique for this is relatively simple: draw a second (smooth) path on top of the calligraphy so that it follows the brush line and then choose the stroke width in such a way that it covers the calligraphy everywhere.

This path on top will be used as a mask for the one beneath it. Apply the stroke-dashoffset animation technique to the mask path. The result will look as if the lower path is being "written" directly on the screen in real-time.

The is a case for a mask, not a clip-path — that would not work. Clip-paths always reference the fill area of a path, but ignore the stroke.

The easiest variant is to set stroke: white for the path in the mask. Then everything outside the area painted white is hidden, and anything inside is shown without alteration.

See the Pen Writing calligraphy: basic example by ccprog (@ccprog) on CodePen.

So far, so simple. Things get tricky, however, when the calligraphic lines overlap. This is what happens in a naive implementation:

See the Pen Writing calligraphy: faulty intersection by ccprog (@ccprog) on CodePen.

At the intersection point, the mask reveals part of the crossing brush. Therefore, the calligraphy has to be cut into non-overlapping pieces. Stack them in drawing order and define separate mask paths for each one.

The cut on the mask path and the calligraphic brush must match

The most tricky part is to maintain the impression that the drawing is a single continuous stroke. If you cut a smooth path, ends will fit together as long as both path tangents have the same direction at their common point. The stroke ends are perpendicular to that, and it is essential that the cut in the calligraphic line aligns exactly. Take care all paths have consecutive directions. Animate them one after the other.

While many line animations can get by with rough math on the length for stroke-dasharray, this scenario requires accurate measurements (although small roundings shouldn't hurt). As a reminder, you can get them in the DevTools console with:

document.querySelector('#mask1 path').getTotalLength()

See the Pen Writing calligraphy: divide up intersections by ccprog (@ccprog) on CodePen.

The "one after the other" part is slightly awkward to write in CSS. The best pattern is probably to give all partial animations the same start time and total duration, then set intermediate keyframes between the stroke-dashoffset changes.

Something like this:

@keyframes brush1 { 0% { stroke-dashoffset: 160; } /* leave static */ 12% { stroke-dashoffset: 160; } /* start of first brush */ 44% { stroke-dashoffset: 0; } /* end of first brush equals start of second */ 100% { stroke-dashoffset: 0; } /* leave static */ } @keyframes brush2 { 0% { stroke-dashoffset: 210; } /* leave static */ 44% { stroke-dashoffset: 210; } /* start of second brush equals end of first */ 86% { stroke-dashoffset: 0; } /* end of second brush */ 100% { stroke-dashoffset: 0; } /* leave static */ }

Further down, you'll see how a SMIL animation enables a more fluent and expressive way to define timing. Keeping with CSS, computations done with Sass might be pretty helpful since it can handle some math.

The mask path (left) and its application (right)

A comparable problem appears if the curve radius of the mask path gets smaller than the stroke width. While the animation runs through that curve, it may happen that an intermediate state looks seriously crooked.

The solution is to move the mask path out of the calligraphic curve. You only need to take care its inner edge still covers the brush.

You can even cut the mask path and misalign the ends, as long as the cutting edges fit together.

The radius stays large enough

See the Pen Writing calligraphy: divide up intersections by ccprog (@ccprog) on CodePen.

And, thus, you can even draw something complex, like the Arabic calligraphy in this example:

See the Pen Tughra Mahmud II - text animation by ccprog (@ccprog) on CodePen.

The original design, the Tughra of Osmanic Sultan Mahmud II., is by an unknown 19th-century calligrapher. The vectorized version was done by Wikipedia illustrator Baba66. The animation is my attempt to visualize the position of the Arabic letters inside the drawing. It builds upon an earlier version by Baba66. Creative Commons Attribution-Share Alike 2.5.

The following code snippet shows the advanced method used to run the animations in order and in a repeatable fashion.

mask path { fill: none; stroke: white; stroke-width: 16; } .brush { fill: #0d33f2; } <mask id="mask1" maskUnits="userSpaceOnUse"> <path stroke-dasharray="160 160" stroke-dashoffset="160" d="..."> <!-- animation begins after document starts and repeats with a click on the "repeat" button --> <animate id="animate1" attributeName="stroke-dashoffset" from="160" to="0" begin="1s;repeat.click" dur="1.6s" /> </path> </mask> <mask id="mask2" maskUnits="userSpaceOnUse"> <path stroke-dasharray="350 350" stroke-dashoffset="350" d="..."> <!-- animation begins at the end of the previous one --> <animate id="animate2" attributeName="stroke-dashoffset" from="350" to="0" begin="animate1.end" dur="3.5s" /> </path> </mask> <!-- more masks... --> <mask id="mask15" maskUnits="userSpaceOnUse"> <path stroke-dasharray="230 230" stroke-dashoffset="230" d="..."> <!-- insert an artificial pause between the animations, as if the brush had been lifted --> <animate id="animate15" attributeName="stroke-dashoffset" from="230" to="0" begin="animate14.end+0.5s" dur="2.3s" /> </path> </mask> <g class="brush"> <path id="brush1" d="..."> <!-- The mask is only applied after document starts/repeats and until the animation has run. This makes sure the brushes are visible in renderers that do not support SMIL --> <set attributeName="mask" to="url(#mask1)" begin="0s;repeat.click" end="animate1.end;indefinite" /> </path> <path id="brush2" d="..."> <set attributeName="mask" to="url(#mask2)" begin="0s;repeat.click" end="animate2.end;indefinite" /> </path> <!-- more paths... --> <path id="brush15" d="..."> <set attributeName="mask" to="url(#mask2)" begin="0s;repeat.click" end="animate15.end;indefinite" /> </path> </g>

In contrast to the other examples we've look at, this animation uses SMIL, which means it will not work in Internet Explorer and Edge.

This article is published in German over at Browser…?unplugged.

The post Animate Calligraphy with SVG appeared first on CSS-Tricks.

Don’t Use The Placeholder Attribute

Css Tricks - Fri, 06/22/2018 - 9:27am

Eric Bailey takes a hardline position on <input placeholder>.

You might be thinking, as I did: yeah, yeah I know the pitfalls. I'm capable of using placeholder responsibly. But when you look at all the negatives together:

  • Can’t be automatically translated;
  • Is oftentimes used in place of a label, locking out assistive technology;
  • Can hide important information when content is entered;
  • Can be too light-colored to be legible;
  • Has limited styling options;
  • May look like pre-filled information and be skipped over.

...and the fact that there are advantages to just moving whatever helper text you would want in there anyway outside the input to real markup...I'm fairly well convinced.

Direct Link to ArticlePermalink

The post Don’t Use The Placeholder Attribute appeared first on CSS-Tricks.

Balancing Time

Css Tricks - Fri, 06/22/2018 - 4:57am

I first wrote this post four years ago. I put it on a blog that no longer exists. Funnily enough, I still refer to it myself, so I figured it might be best served in a place where other people can see it. I've made only a few minor tweaks to the original content. A lot about how I work has changed, but most of these pieces have not.

I work on many personal projects concurrently. I love doing this, as it keeps me in a constant mode of creation. At the same time, it can become a delicate balancing act. In order to keep everything moving forward, I have set up some guidelines for myself and I'm going to share them with you in this post. However, it's more important to understand what works best for you and consider the sage words of Thich Nhat Hanh:

“Don’t follow someone else’s map.”

What works for me might not work for you. However, hearing about how other people set up their workflow might help you reconsider your own, so hopefully this is a useful mental exercise.

Organize

Every three months or so, I compile a list of all my projects. The projects that have time parameters go first in line (but do not always come first if my passion lies elsewhere). For each project, I break down the tasks I need to perform in order to get them done. I try to make each one as small and actionable as possible.

I actually write out the same list multiple ways — some digital, some paper. I find the repetition helps me reinforce and recall what my priorities are. I also find large gridded Moleskine sketchbooks useful for organizing myself. It's important to me that they're large enough to have enough space to write notes, draw terrible sketches, or generally spread out.

Unless they must be done in order, I often place the easiest and quickest tasks first so I can get them out of the way. I love the feeling of checking things off my list because it serves as positive re-enforcement. I make a schedule of due dates for items that have no due dates; having a specific deadline helps me push forward.

Only stop when you know what happens next

This a really simple and useful trick. If you stop when your plan is veering or meandering, then chances are that project will never see the light of day again. If you can help it, try to only stop working when you know what the next actionable item is. You will arrive back at the project with brighter eyes than before.

Of course, this one doesn't work when you've smacked your head on a problem forever and ever. Sometimes you need a break and just leaving it for a little while or coming back to it the next day will help you solve it. Generally speaking though, you still still know what comes next even before you come to a solution. It's more the feeling of malaise that I'm warning against. Stop while you still have a plan.

Even backwards work is forward progress Photo by John Schnobrich, via Unsplash

Allow yourself to make mistakes. Seriously, make them. I used to tell my students that it takes two bad projects to make a good one. Never compare yourself to what others show you — their final output is often the result of many failed attempts. Make a lot and then edit down. Try not to get discouraged if you spend a day or two messing up. You’ll likely learn more from those mistakes than if you had done everything perfectly. Forge ahead.

Push outside of your comfort zone, but slowly

Work on a few things that you know and understand, and a few things you don’t. We should foster personal growth in our projects, but without some semblance of comfort, it’s easy to get discouraged. Let your projects push the limits of your boundaries, but don’t go overboard. Give yourself a foundation to spring off before floating into space.

Figure out your “studio commandments”

What do you need to work? Do you need music? Do you need water? Do you need isolation? Do you work better in a cafe? Maybe you need a certain monitor. Perhaps you concentrate better if you have scheduled breaks? Do you work better if you have a snack in your bag in case you get hungry? Study yourself. Write down 10 things you need in order to be productive and try to sort them out before you get going so that you give yourself fewer excuses to stop making progress. I wrote another post about this on SuperYesMore, posted here.

Make the time

I usually break up my time so that I have certain nights, like appointments, where I work on each project. There are times, however, where you should keep on going and not worry about other outstanding projects. Sometimes working 15 or more continuous hours will gain you traction in a way that you can’t if you break it up over several weeks. However...

Break your own rules

Do you have a consistent schedule and you can’t possibly do X because of Y? Double and triple check that you aren’t setting up guidelines for yourself that give you excuses ti not get things done. Something that worked last week might not work this week, so take the time to re-evaluate your own rules. In other words: be adaptive.

Do things for other people

Make one of your projects something that benefits others. This guideline might sound strange, but if you continuously work on things just for yourself, work starts to feel a little dreary. I’m not talking about your job, either. It needn’t be overkill. Even donating a few hours here or there to people who need it will help you think more broadly about the world around you.

Bonus: If you build a community and reach the point where you're ready to launch that donated project, you might just have other people around you who to share the excitement of a job well done.

Research is productive time

Reading about what you find interesting or doing a little bit of digging about your interests can save you time in process. Find heroes in the field in which you are working and follow them. I have so many.

Poke around at other things. Reverse engineer something. I have a giant private collection on CodePen called "To reverse engineer." When I'm bored at an airport, or sitting on hold, or have an hour to kill, I'm usually poking around in that folder: breaking things, changing things, finding the boundaries of how everything works.

Read a book, read some docs, watch some talks, do a workshop, watch some anime, go to a museum, listen to some music with your eyes closed, play a video game. Need a starting point? CodePen Challenges are good for that. There are all kinds of things that can feed your work. All of this spent time — while it won't make your GitHub contribution graph greener — is important for development.

Make it fun Photo by Hanny Naibaho, via Unsplash

Personal projects are fun because you want to do them, right? Enjoy yourself. I really like mimosas on the weekends so I enjoy one by my window every Saturday morning while writing code. It’s a very simple trick. It’s not drudgery; it’s pure enjoyment. I turn down other plans to do this because I love it. Find ways to make the work a reward in and of itself. Maybe you only get to listen to that one album you like while you work on a side project. Maybe you have a nice fuzzy blanket that you get to wrap yourself in while you read that programming book. Maybe you get to go to the park after you get that last component in. You know the difference between something that genuinely excites you to work or not — use this to your advantage.

I also imagine how I might feel when something is done. This particularly works when the only thing keeping me from finishing something is a bit of drudgery. I imagine it's done and feel the little dopamine rush from accomplishing something and not letting it sit. Then I chase that feeling.

The post Balancing Time appeared first on CSS-Tricks.

Advanced Document Conversions with Filestack

Css Tricks - Fri, 06/22/2018 - 4:00am

You might know Filestack from being an incredible service to add file uploading, storage, and management to your own web apps.

There is another thing Filestack can do for you: convert documents into different formats.

For one thing, it can manipulate documents. Take images. Perhaps you would like to offer some image manipulation for your users uploaded images, like cropping and rotation. That's a common feature for apps that offer avatar uploading. With Filestack, you got it.

It's great to be able to have that kind of functionality without having to build it yourself. You almost surely aren't in the avatar cropping business, you're in your own unique business that just happens to have users with avatars.

I've said it before:

But let's up the ante a little bit here. What if you need to get an entirely different document format out of another document? How about the hardest document format at all, feared by web developers everywhere, the Microsoft Word document format! &#x1f631;

Filestack has you covered! Say you have an invoice document created in Word and you need it as a PDF. But a perfect PDF, not some hack job conversion. And you need to do it programmatically. That's tricky stuff, and Filestack has solved it.

Of course, it isn't just Microsoft Word document formats, they have a whole matrix of in's and out's.

See full size

Just about any file format conversion you need, they got. Personally, I'm impressed by the idea that conversion between PDF and SVG maintains the vectors in both directions.

Document security is a prime concern of course and is handled through policy and signature validation.

See their security docs for all things security related.

Need a way to show users files like PDFs? Browsers can view PDFs, but only as a whole, not embedded into regular web pages. Not a problem with the document viewer!


If you think Filestack might solve some problems for your app, like transforming files, check out their getting started guide.

The post Advanced Document Conversions with Filestack appeared first on CSS-Tricks.

An Almost Ideal React Image Component

Css Tricks - Thu, 06/21/2018 - 9:48am

Yes, this is a React component, but regardless if you care about that part or not, the "ideal image component" part could be of interest. There is a lot to consider with how we put images on web pages these days. This deals with:

  • Placeholder space (and then flexible responsive styles after loading)
  • Low-quality placeholder images
  • Responsive images syntax (srcset)
  • Image formats (e.g. using WebP when you can)
  • Click-to-load on bad network connections
  • Better UX for loading errors, with translatable copy

That's not even all of it. So much to think about with poor little <img>. I enjoyed Alejandro Sanchez's response:

The readme file for this component is amazing to teach you how to think like a front-end developer.

— Alejandro Sanchez (@alesanchezr) June 12, 2018

Direct Link to ArticlePermalink

The post An Almost Ideal React Image Component appeared first on CSS-Tricks.

Using Custom Fonts With SVG in an Image Tag

Css Tricks - Thu, 06/21/2018 - 4:11am

When we produce a PNG image, we use an <img> tag or a CSS background, and that's about it. It is dead simple and guaranteed to work.

PNG is way simpler to use in HTML than SVG

Unfortunately, the same cannot be said for SVG, despite its many advantages. Although you're spoiled for choices when using SVG in HTML, it really boils down to inline, <object> and <img>, all with serious gotchas and trade-offs.

Problems with inline SVG

If you're inlining SVG, you lose the ability to use browser cache, Gzip compression between servers and browsers, and search engine image indexing (inline SVG is not considered as an image). Even though your image may not have changed one bit, they are always reloaded and this causes slower loading times for your website, a trade-off that most are not willing to tolerate.

In addition, inlining SVG also causes complex dependency problems where you cannot easily insert images into HTML and have to resort to scripts (PHP or otherwise). When you have more than a few images, this becomes a huge problem when it comes to maintaining your site, because essentially you can't use the <img> tag anymore.

No doubt, there are areas where inlining SVG shines — that is, if you want your images to display quickly, without waiting for other resources to load. Apart from that, clearly, you just can't inline everything.

Problems with object tag

SVG is well known for its excellent quality when displayed on devices of all resolutions and its ability to refer to external resources — like CSS and fonts — while keeping the file size very small. The idea is to have many SVGs that all share a single CSS or a single font file, to reduce the amount of resources you have to download.

The myth of resource sharing

Unknown to many, sharing external resources for SVG only applies to inline SVG. Because usage of <object> tags allow access to these resources, the perception is that the browser will download a single copy of your CSS, even though you have many <object> tags referring to the same CSS file.

This however, is not true at all:

Multiple object tags will download multiple CSS

Compounding the problem is the fact that <object> tags are not recognized as an image, and therefore image search indexing is not possible.

Further compounding the problem are dependency issues. For example, let’s say you have 100 images, and 25 of them use a Roboto font, another 25 use Lato, 25 use Open Sans, while the rest use a combination of the three fonts. Your CSS would need to refer to all three fonts because it is quite impossible to keep track of which file is using which fonts, meaning you may be loading fonts you may not require on certain pages.

The image tag

That leaves us with the <img> tag, which has a lot going for it. Because it's the same tag used for other image formats, you get familiarity, browser caching, Gzip compression and image search. Each image is self-contained, with no dependency issues.

SVG losing fonts if used with the <img> tag

The only problem is you will lose your fonts. To be more precise, if you have any text in your SVG, unless you embed fonts, your text will be displayed with system fonts, typically Times New Roman. You've spent hours selecting a beautiful font but the moment you use the <img> tag to embed SVG, all that is lost. How can this be acceptable?

Investigating font rasterization Converting fonts into paths

Our first reaction is to see if we can perform font rasterization. It is a commonly used technique to convert fonts into paths, so it'll render well on all devices and maintain zero dependencies. On the surface, this works very well, and on the editor, everything looks perfect.

Although the rasterized SVG came in at a whopping 137 KB compared to 15.7 KB before rasterization, we were optimistic because, after optimizing our SVG using Gzip compression, the rasterized file is reduced to 11 KB, slightly smaller than the equivalent PNG at 11.9 KB.

Original Font rasterization Font rasterization (.svgz) 15.7 KB 137 KB 11.0 KB PNG @ 1x PNG @ 2x PNG @ 3x 11.9 KB 26.5 KB 42.6 KB SVG image with font rasterization

Alas, once we embed the rasterized SVG into HTML, we found our optimism to be premature. Although it might look great on high-resolution displays, quality on low resolution displays are unacceptable.

Rasterized fonts on top and original at the bottom

The bottom of the image is the original, with clearly displayed fonts while, on top, fonts are pixelated with font rasterization.

Cleartype difference when shown on screens

What's happening is that most operating systems will optimize fonts to ensure they are shown clearly and sharp on all screens. On Windows, this is called ClearType, and since we rasterized our fonts, no optimizations will be applied, resulting in blurred text, particularly visible on low-resolution screens.

Obviously, a reduction in quality is unacceptable, so back to the drawing board.

Font embedding to the rescue

Initially, we were extremely skeptical about font embedding, mainly because of the complicated workflow.

To embed fonts in SVG, you first have to know what font families are used. Then you need to find these font files and download them. Once downloaded, you have to convert regular, bold, italics and bold italics to Base64 encoding. If you're doing it manually, it is quite impossible, over a large number of files, to know which file uses bold and which ones does not. Then you have to copy all four Base64 encoded strings into your SVG.

Surely, there has to be a better way. And that’s why we built Nano. Nano scans SVG automatically and inserts only the fonts that are used. For example, if bold is not used or if no text exist, then no fonts will be embedded.

Still, the resulting file is huge and is not competitive with the PNG equivalent, so we plugged away and built our own SVG optimizer (Nano) that will reduce SVG file sizes to a trickle. (See how Nano compresses SVG.) In addition, we also optimized how we embed fonts into SVG, resulting in very small file sizes.

SVG image with text, optimized with Nano and fonts embedded Comparing file sizes and bandwidth savings Original Font rasterization Unoptimized font embedding Nano font embedding Size 15.7 KB 137 KB 65.2 KB 22.0 KB Gzip 3.57 KB 11.0 KB 44.5 KB 11.7 KB PNG @ 1x PNG @ 2x PNG @ 3x Size 11.9 KB 26.5 KB 42.6 KB Gzip 12.1 KB 26.1 KB 41.7 KB

From the above, we can see that Nano produces an SVG that is extremely lightweight even with embedded fonts, coming in at 11.7 KB (Gzipped) compared with the equivalent PNG @1x at 11.9 KB. While this may seem insignificant, the total bandwidth saved on your site will surely be significant.

Let’s assume that 50% of your traffic is low resolution, 40% is 2X resolution and the remaining 10% is 3X resolution. If your website has 10,000 hits on a single image:

5,000 * 11.9 KB + 4,000 * 26.5 KB + 1,000 * 42.6 KB = 208.1 KB

If you use Nano, compressed SVG with GZip:

10,000 * 11.7 KB = 117.0 KB

This will result in: 208.1 KB - 117.0 KB = 91.1KB savings, or 43.7%, bandwidth savings, a significant amount by any measure.

In addition to the bandwidth savings, you get a far simpler workflow without resorting to multiple PNG images with multiple srcset, with much better quality, including operating system font enhancement to ensure your images stay crisp and sharp on devices of all resolutions. Best of all, a better user experience for your users, since your site will load faster — especially so on devices with high resolution.

Thoroughly testing Nano

Not satisfied with all the savings, we began to look for SVG images to thoroughly test Nano. A total 2,571 SVG files of various sizes and designs were used, totaling up 16.3 MB. And after Nano optimization, resulting in 6.2 MB, an astonishing 61.8% savings in size.

A small selection of over 2500 SVG images used to test Nano Showing a visual difference

Because of the sheer number of files that we were testing, and it increases from time to time, we have to build an automated test, including automatically highlighting pixel differences before and after optimization. One of the complaints on other SVG optimizers is the fact that minifying SVG may break your image, causing it to render differently compared to the original.

To this end, we carry over the pixel differentiation in our automated test into Nano itself. That is, Nano will warn you if it detects that the SVG it optimizes has a pixel difference of more than 1% when compared to the original, therefore ensuring Nano's optimization will never break an SVG.

Nano optimization showing visual difference

Because fonts are embedded and preserved, plus SVG being a vector graphics format, rendering quality on all resolution is incomparable to other raster formats.

What's next?

We hope our work will make SVG easier to use everywhere. We're now working on producing even smaller file sizes, porting our codes to work on Node.js so you can automate your production builds with Nano, among others.

Do you think you’ll find Nano helpful in your projects? Let me know in the comments!

The post Using Custom Fonts With SVG in an Image Tag appeared first on CSS-Tricks.

What is SVG good for?

Css Tricks - Wed, 06/20/2018 - 12:25pm

Y'all probably wouldn't be surprised if I told you it's pretty awesome for icons, and icon systems. SVG icon systems can, and perhaps should be quite easy. I'm a fan of just inlining those suckers, particularly when they are pretty simple.

But what else?

Logos is a classic example! A lot of people dip their toes in this way.

You don't have to inline the SVG if you don't want. It could be an <img> or background-image as well.

These are really simple things though. At it's heart, SVG is simply a vector-based image format capable of just about anything. Way higher up the complexity scale, Bustle creates incredibly cool flowcharts using SVG.

Try clicking around those flowcharts and seeing all the wonderful animation. SVG is very flexibly scalable. In that example above, part of what is going on there is an animation of the viewBox specifically.

Speaking of interactive diagrams, pretty much any chart or graph you'll see is either SVG or started life that way. For instance, the incredibly popular d3.js library is SVG based. Anything created with d3 is SVG. In fact, most charting libraries are based on d3. Here's Highcharts:

Charts are so business though. What about art?! Of course, SVG is great for art. Creative tools for artists, like illustrators working on their fancy Wacom tablets, working in Adobe Illustrator, can export their work and display it as SVG.

There are also animation libraries like GSAP which are great at helping animate SVG, and enable vector artists to bring their creations to life:

See the Pen Li´l Vikings by Fabio (@FabioG) on CodePen.

Greensock has some pretty sweet paid features you might wanna check out.

SVG is great for little demonstrative diagrams! Here's a little thing from Rachel Nabors:

See the Pen Key Press SVG illustration with CSS animation by Rachel Nabors (@rachelnabors) on CodePen.

Or games! Here's one by Sarah Dranser:

See the Pen React Game- Elephant Taco Hunt by Sarah Drasner (@sdras) on CodePen.

Not practical enough for you? How about the fact that a single SVG file can encapsulate all the scripts and styles necessary for an interactive banner ad? Here's Chris Gannon explaining:

And a demo advertisement I made one time:

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

Maps are another amazing use-case. amCharts has a bunch of free ones for you, not to mention Wikipedia loves the SVG format especially for anything geographic.

Want more? I have a huge collection of examples of amazing things that can be done with SVG.

Wanna get started learning SVG? I got just the book for you:

Now's the time to buy, as well, because for the next two days 25% of profits go to RAICES:

The Legal Representation, Advocacy, and Education Project will provide universal representation for released unaccompanied kids in Texas. Last year, there were over 13,000 kids who were not represented in immigration court in Texas.

&#x1f44d;

The post What is SVG good for? appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.