Author: techgirl

Chrome Lite Pages

The Chrome team announced a new feature called Lite Pages that can be activated by flipping on the Data Saver option on an Android device:

Chrome on Android’s Data Saver feature helps by automatically optimizing web pages to make them load faster. When users are facing network or data constraints, Data Saver may reduce data use by up to 90% and load pages two times faster, and by making pages load faster, a larger fraction of pages actually finish loading on slow networks. Now, we are securely extending performance improvements beyond HTTP pages to HTTPS pages and providing direct feedback to the developers who want it.

To show users when a page has been optimized, Chrome now shows in the URL bar that a Lite version of the page is being displayed.

All of this is pretty neat but I think the name Lite Pages is a little confusing as it’s in no way related to AMP and Tim Kadlec makes that clear in his notes about the new feature:

Lite pages are also in no way related to AMP. AMP is a framework you have to build your site in to reap any benefit from. Lite pages are optimizations and interventions that get applied to your current site. Google’s servers are still involved, by as a proxy service forwarding the initial request along. Your URL’s aren’t tampered with in any way.

A quick glance at this seems great! We don’t have to give up ownership of our URLs, like with AMP, and we don’t have to develop with a proprietary technology — we can let Chrome be Chrome and do any performance things that it wants to do without turning anything on or off or adding JavaScript.

But wait! What kind of optimizations does a Lite Page make and how do they affect our sites? So far, it can disable scripts, replace images with placeholders and stop the loading of certain resources, although this is all subject to change in the future, I guess.

The optimizations only take effect when the loading experience for users is particularly bad, as the announcement blog post states:

…they are applied when the network’s effective connection type is “2G” or “slow-2G,” or when Chrome estimates the page load will take more than 5 seconds to reach first contentful paint given current network conditions and device capabilities.

It’s probably important to remember that the reason why Google is doing this isn’t to break our designs or mess with our websites — they’re doing this because there are serious performance concerns with the web, and those concerns aren’t limited to developing nations.

The post Chrome Lite Pages appeared first on CSS-Tricks.


, ,

Using Local with Flywheel

Have you seen Local by Flywheel? It’s a native app for helping set up local WordPress developer environments. I absolutely love it and use it to do all my local WordPress development work. It brings a lovingly designed GUI to highly technical tasks in a way that I think works very well. Plus it just works, which wins all the awards with me. Need to spin up a new site locally? Click a few buttons. Working on your site? All your sites are right there and you can flip them on with the flick of a toggle.

Local by Flywheel is useful no matter where your WordPress production site is hosted. But it really shines when paired with Flywheel itself, which is fabulous WordPress hosting that has all the same graceful combination of power and ease as Local does.

Just recently, we moved over to Local and it couldn’t have been easier.

Running locally.

Setting up a new local site (which you would do even if it’s a long-standing site and you’re just getting it set up on Flywheel) is just a few clicks. That’s one of the most satisfying parts. You know all kinds of complex things are happening behind the scenes, like containers being spun up, proper software being installed, etc, but you don’t have to worry about any of it.

(Local is free, by the way.)

The Cross-platform-ness is nice.

I work on ShopTalk with Dave Rupert, who’s on Windows. Not a problem. Local works on Windows also, so Dave can spin up site in the exact same way I can.

Setting up Flywheel hosting is just as clean and easy as Local is.

If you’ve used Local, you’ll recognize the clean font, colors, and design when using the Flywheel website to get your hosting set up. Just a few clicks and I had that going:

Things that are known to be a pain the butt are painless on Local, like making sure SSL (HTTPS) is active and a CDN is helping with assets.

You get a subdomain to start, so you can make sure your site is working perfectly before pointing a production domain at it.

I didn’t just have to put files into place on the new hosting, move the database, and cross my fingers I did it all right when re-pointing the DNS. I could get the site up and running at the subdomain first, make sure it is, then do the DNS part.

But the moving of files and all that… it’s trivial because of Local!

The best part is that shooting a site up to Flywheel from Local is also just a click away.

All the files and the database head right up after you’ve connected Local to Flywheel.

All I did was make sure I had my local site to be a 100% perfect copy of production. All the theme and plugins and stuff were already that way because I was already doing local development, and I pulled the entire database down easily with WP DB Migrate Pro.

I think I went from “I should get around to setting up this site on Flywheel.” do “Well that’s done.” in less than an hour. Now Dave and I both have a local development environment and a path to production.

The post Using Local with Flywheel appeared first on CSS-Tricks.


, ,

Stacked “Borders”

A little while back, I was in the process of adding focus styles to An Event Apart’s web site. Part of that was applying different focus effects in different areas of the design, like white rings in the header and footer and orange rings in the main text. But in one place, I wanted rings that were more obvious—something like stacking two borders on top of each other, in order to create unusual shapes that would catch the eye.

A row of four images, the second of which includes a dashed red border.

I toyed with the idea of nesting elements with borders and some negative margins to pull one border on top of another, or nesting a border inside an outline and then using negative margins to keep from throwing off the layout. But none of that felt satisfying.

It turns out there are a number of tricks to create the effect of stacking one border atop another by combining a border with some other CSS effects, or even without actually requiring the use of any borders at all. Let’s explore, shall we?

Outline and box-shadow

If the thing to be multi-bordered is a rectangle—you know, like pretty much all block elements—then mixing an outline and a spread-out hard box shadow may be just the thing.

Let’s start with the box shadow. You’re probably used to box shadows like this:

.drop-me {   background: #AEA;   box-shadow: 10px 12px 0.5rem rgba(0,0,0,0.5); }
A turquoise box containing the words div text and a heavy box shadow.

That gets you a blurred shadow below and to the right of the element. Drop shadows, so last millennium! But there’s room, and support, for a fourth length value in box-shadow that defines a spread distance. This increases the size of the shadow’s shape in all directions by the given length, and then it’s blurred. Assuming there’s a blur, that is.

So if we give a box shadow no offset, no blur, and a bit of spread, it will draw itself all around the element, looking like a solid border without actually being a border.

.boxborder-me {   box-shadow: 0 0 0 5px firebrick; }
A red box containing a thick red border.

This box-shadow “border” is being drawn just outside the outer border edge of the element. That’s the same place outlines get drawn around block boxes, so all we have to do now is draw an outline over the shadow. Something like this:

.boxborder-me {   box-shadow: 0 0 0 5px firebrick;   outline: dashed 5px darkturquoise; }
A box containing a dashed red border with a turquoise background filling the dash gaps.

Bingo. A multicolor “border” that, in this case, doesn’t even throw off layout size, because shadows and outlines are drawn after element size is computed. The outline, which sits on top, can use pretty much any outline style, which is the same as the list of border styles. Thus, dotted and double outlines are possibilities. (So are all the other styles, but they don’t have any transparent parts, so the solid shadow could only be seen through translucent colors.)

If you want a three-tone effect in the border, multiple box shadows can be created using a comma-separated list, and then an outline put over top that. For example:

.boxborder-me {   box-shadow: 0 0 0 1px darkturquoise,               0 0 0 3px firebrick,               0 0 0 5px orange,               0 0 0 6px darkturquoise;   outline: dashed 6px darkturquoise; }
A box containing a dashed border where the dashes are doubled with red and gold and a turquoise background filling in the dash gaps.

Taking it back to simpler effects, combining a dashed outline over a spread box shadow with a solid border of the same color as the box shadow creates yet another effect:

.boxborder-me {   box-shadow: 0 0 0 5px firebrick;   outline: dashed 5px darkturquoise;   border: solid 5px darkturquoise; }
A box with a dashed red border and a turquoise background that not only fills the dash gaps, but overflows the red border toward the inside edge of the box.

The extra bonus here is that even though a box shadow is being used, it doesn’t fill in the element’s background, so you can see the backdrop through it. This is how box shadows always behave: they are only drawn outside the outer border edge. The “rest of the shadow,” the part you may assume is always behind the element, doesn’t exist. It’s never drawn. So you get results like this:

A box with a turquoise border and heavy box shadow toward the bottom right edge that is set against a turquoise background.

This is the result of explicit language in the CSS Background and Borders Module, Level 3, section 7.1.1:

An outer box-shadow casts a shadow as if the border-box of the element were opaque. Assuming a spread distance of zero, its perimeter has the exact same size and shape as the border box. The shadow is drawn outside the border edge only: it is clipped inside the border-box of the element.

(Emphasis added.)

Border and box-shadow

Speaking of borders, maybe there’s a way to combine borders and box shadows. After all, box shadows can be more than just drop shadows. They can also be inset. So what if we turned the previous shadow inward, and dropped a border over top of it?

.boxborder-me {   box-shadow: 0 0 0 5px firebrick inset;   border: dashed 5px darkturquoise; }
A box with a dashed turquoise border and a solid red border that lies on the inside of the dashed border.

That’s… not what we were after. But this is how inset shadows work: they are drawn inside the outer padding edge (also known as the inner border edge), and clipped beyond that:

An inner box-shadow casts a shadow as if everything outside the padding edge were opaque. Assuming a spread distance of zero, its perimeter has the exact same size and shape as the padding box. The shadow is drawn inside the padding edge only: it is clipped outside the padding box of the element.

(Ibid; emphasis added.)

So we can’t stack a border on top of an inset box-shadow. Maybe we could stack a border on top of something else…?

Border and multiple backgrounds

Inset shadows may be restricted to the outer padding edge, but backgrounds are not. An element’s background will, by default, fill the area out to the outer border edge. Fill an element background with solid color, give it a thick dashed border, and you’ll see the background color between the visible pieces of the border.

So what if we stack some backgrounds on top of each other, and thus draw the solid color we want behind the border? Here’s step one:

.multibg-me {   border: 5px dashed firebrick;   background:     linear-gradient(to right, darkturquoise, 5px, transparent 5px);   background-origin: border-box; }
A box with a dashed red border and a turquoise background filling in the dash gaps along the left edge of the box.

We can see, there on the left side, the blue background visible through the transparent parts of the dashed red border. Add three more like that, one for each edge of the element box, and:

.multibg-me {   border: 5px dashed firebrick;   background:     linear-gradient(to top, darkturquoise, 5px, transparent 5px),     linear-gradient(to right, darkturquoise, 5px, transparent 5px),     linear-gradient(to bottom, darkturquoise, 5px, transparent 5px),     linear-gradient(to left, darkturquoise, 5px, transparent 5px);   background-origin: border-box; }
A box with a dashed red border and a turquoise background that fills in the dash gaps.

In each case, the background gradient runs for five pixels as a solid dark turquoise background, and then has a color stop which transitions instantly to transparent. This lets the “backdrop” show through the element while still giving us a “stacked border.”

One major advantage here is that we aren’t limited to solid linear gradients—we can use any gradient of any complexity, just to spice things up a bit. Take this example, where the dashed border has been made mostly transparent so we can see the four different gradients in their entirety:

.multibg-me {   border: 15px dashed rgba(128,0,0,0.1);   background:     linear-gradient(to top,    darkturquoise, red 15px, transparent 15px),     linear-gradient(to right,  darkturquoise, red 15px, transparent 15px),     linear-gradient(to bottom, darkturquoise, red 15px, transparent 15px),     linear-gradient(to left,   darkturquoise, red 15px, transparent 15px);   background-origin: border-box; }
A diagram showing the same box with a dashed red border and turquoise background, but with transparency to show how the stacked borders overlap.

If you look at the corners, you’ll see that the background gradients are rectangular, and overlap each other. They don’t meet up neatly, the way border corners do. This can be a problem if your border has transparent parts in the corners, as would be the case with border-style: double.
Also, if you just want a solid color behind the border, this is a fairly clumsy way to stitch together that effect. Surely there must be a better approach?

Border and background clipping

Yes, there is! It involves changing the clipping boxes for two different layers of the element’s background. The first thing that might spring to mind is something like this:

.multibg-me {   border: 5px dashed firebrick;   background: #EEE, darkturquoise;   background-clip: padding-box, border-box; }

But that does not work, because CSS requires that only the last (and thus lowest) background be set to a <color> value. Any other background layer must be an image.

So we replace that very-light-gray background color with a gradient from that color to that color: this works because gradients are images. In other words:

.multibg-me {   border: 5px dashed firebrickred;   background: linear-gradient(to top, #EEE, #EEE), darkturquoise;   background-clip: padding-box, border-box; }
A box with a red dashed border, a turquoise background to fill in the dash gaps, and a light gray background set inside the box.

The light gray “gradient” fills the entire background area, but is clipped to the padding box using background-clip. The dark turquoise fills the entire area and is clipped to the border box, as backgrounds always have been by default. We can alter the gradient colors and direction to anything we like, creating an actual visible gradient or shifting it to all-white or whatever other linear effect we would like.

The downside here is that there’s no way to make that padding-area background transparent such that the element’s backdrop can be seen through the element. If the linear gradient is made transparent, then the whole element background will be filled with dark turquoise. Or, more precisely, we’ll be able to see the dark turquoise that was always there.

In a lot of cases, it won’t matter that the element background isn‘t see-through, but it’s still a frustrating limitation. Isn’t there any way to get the effect of stacked borders without wacky hacks and lost capabilities?

Border images

In fact, what if we could take an image of the stacked border we want to see in the world, slice it up, and use that as the border? Like, say, this image becomes this border?

An image of two stacked boxes, the top a square box with a red dashed border and a turquoise and gold striped background filling in the dash gaps. The bottom box is a demonstration using the top box as a border image for the bottom box.

Here’s the code to do exactly that:

.borderimage-me {   border: solid 5px;   border-image: url(triple-stack-border.gif) 15 / 15px round; }

First, we set a solid border with some width. We could also set a color for fallback purposes, but it’s not really necessary. Then we point to an image URL, define the slice inset(s) at 15 and width of the border to be 15px, and finally the repeat pattern of round.

There are more options for border images, which are a little too complex to get into here, but the upshot is that you can take an image, define nine slices of it using offset values, and have those images used to synthesize a complete border around an image. That’s done by defining offsets from the edges of the image itself, which in this case is 15. Since the image is a GIF and thus pixel-based, the offsets are in pixels, so the “slice lines” are set 15 pixels inward from the edges of the image. (In the case of an SVG, the offsets are measured in terms of the SVG’s coordinate system.) It looks like this:

A diagram outlining how the border image is sliced and positioned along the box's edges, corner's and offsets.

Each slice is assigned to the corner or side of the element box that corresponds to itself; i.e., the bottom right corner slice is placed in the bottom right corner of the element, the top (center) slice is used along the top edge of the element, and so on.

If one of the edge slices is smaller than the edge of the element is long—which almost always happens, and is certainly true here—then the slice is repeated in one of a number of ways. I chose round, which fills in as many repeats as it can and then scales them all up just enough to fill out the edge. So with a 70-pixel-long slice, if the edge is 1,337 pixels long, there will be 19 repetitions of the slice, each of which is scaled to be 70.3 pixels wide. Or, more likely, the browser generates a single image containing 19 repetitions that’s 1,330 pixels wide, and then stretches that image the extra 7 pixels.

You might think the drawback here is browser support, but that turns out not to be the case.

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


Chrome Opera Firefox IE Edge Safari
56 43 50 11 12 9.1

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
9.3 46 all* 67 71 64

Just watch out for the few bugs (really, implementation limits) that linger around a couple of implementations, and you’ll be fine.


While it might be a rare circumstance where you want to combine multiple “border” effects, or stack them atop each other, it’s good to know that CSS provides a number of ways to get the job done, and that most of them are already widely supported. And who knows? Maybe one day there will be a simple way to achieve these kinds of effects through a single property, instead of by mixing several together. Until then, happy border stacking!

The post Stacked “Borders” appeared first on CSS-Tricks.



Crafting Reusable HTML Templates

In our last article, we discussed the Web Components specifications (custom elements, shadow DOM, and HTML templates) at a high-level. In this article, and the three to follow, we will put these technologies to the test and examine them in greater detail and see how we can use them in production today. To do this, we will be building a custom modal dialog from the ground up to see how the various technologies fit together.

Article Series:

  1. An Introduction to Web Components
  2. Crafting Reusable HTML Templates (This post)
  3. Creating a Custom Element from Scratch (Coming soon!)
  4. Encapsulating Style and Structure with Shadow DOM (Coming soon!)
  5. Advanced Tooling for Web Components (Coming soon!)

HTML templates

One of the least recognized, but most powerful features of the Web Components specification is the <template> element. In the first article of this series, we defined the template element as, “user-defined templates in HTML that aren’t rendered until called upon.” In other words, a template is HTML that the browser ignores until told to do otherwise.

These templates then can be passed around and reused in a lot of interesting ways. For the purposes of this article, we will look at creating a template for a dialog that will eventually be used in a custom element.

Defining our template

As simple as it might sound, a <template> is an HTML element, so the most basic form of a template with content would be:

<template>   <h1>Hello world</h1> </template>

Running this in a browser would result in an empty screen as the browser doesn’t render the template element’s contents. This becomes incredibly powerful because it allows us to define content (or a content structure) and save it for later — instead of writing HTML in JavaScript.

In order to use the template, we will need JavaScript

const template = document.querySelector('template'); const node = document.importNode(template.content, true); document.body.appendChild(node);

The real magic happens in the document.importNode method. This function will create a copy of the template’s content and prepare it to be inserted into another document (or document fragment). The first argument to the function grabs the template’s content and the second argument tells the browser to do a deep copy of the element’s DOM subtree (i.e. all of its children).

We could have used the template.content directly, but in so doing we would have removed the content from the element and appended to the document’s body later. Any DOM node can only be connected in one location, so subsequent uses of the template’s content would result in an empty document fragment (essentially a null value) because the content had previously been moved. Using document.importNode allows us to reuse instances of the same template content in multiple locations.

That node is then appended into the document.body and rendered for the user. This ultimately allows us to do interesting things, like providing our users (or consumers of our programs) templates for creating content, similar to the following demo, which we covered in the first article:

See the Pen
Template example
by Caleb Williams (@calebdwilliams)
on CodePen.

In this example, we have provided two templates to render the same content — authors and books they’ve written. As the form changes, we choose to render the template associated with that value. Using that same technique will allow us eventually create a custom element that will consume a template to be defined at a later time.

The versatility of template

One of the interesting things about templates is that they can contain any HTML. That includes script and style elements. A very simple example would be a template that appends a button that alerts us when it is clicked.

<button id="click-me">Log click event</button>

Let’s style it up:

button {   all: unset;   background: tomato;   border: 0;   border-radius: 4px;   color: white;   font-family: Helvetica;   font-size: 1.5rem;   padding: .5rem 1rem; }

…and call it with a really simple script:

const button = document.getElementById('click-me'); button.addEventListener('click', event => alert(event));

Of course, we can put all of this together using HTML’s <style> and <script> tags directly in the template rather than in separate files:

<template id="template">   <script>     const button = document.getElementById('click-me');     button.addEventListener('click', event => alert(event));   </script>   <style>     #click-me {       all: unset;       background: tomato;       border: 0;       border-radius: 4px;       color: white;       font-family: Helvetica;       font-size: 1.5rem;       padding: .5rem 1rem;     }   </style>   <button id="click-me">Log click event</button> </template>

Once this element is appended to the DOM, we will have a new button with ID #click-me, a global CSS selector targeted to the button’s ID, and a simple event listener that will alert the element’s click event.

For our script, we simply append the content using document.importNode and we have a mostly-contained template of HTML that can be moved around from page to page.

See the Pen
Template with script and styles demo
by Caleb Williams (@calebdwilliams)
on CodePen.

Creating the template for our dialog

Getting back to our task of making a dialog element, we want to define our template’s content and styles.

<template id="one-dialog">   <script>     document.getElementById('launch-dialog').addEventListener('click', () => {       const wrapper = document.querySelector('.wrapper');       const closeButton = document.querySelector('button.close');       const wasFocused = document.activeElement;       wrapper.classList.add('open');       closeButton.focus();       closeButton.addEventListener('click', () => {         wrapper.classList.remove('open');         wasFocused.focus();       });     });   </script>   <style>     .wrapper {       opacity: 0;       transition: visibility 0s, opacity 0.25s ease-in;     }     .wrapper:not(.open) {       visibility: hidden;     } {       align-items: center;       display: flex;       justify-content: center;       height: 100vh;       position: fixed;         top: 0;         left: 0;         right: 0;         bottom: 0;       opacity: 1;       visibility: visible;     }     .overlay {       background: rgba(0, 0, 0, 0.8);       height: 100%;       position: fixed;         top: 0;         right: 0;         bottom: 0;         left: 0;       width: 100%;     }     .dialog {       background: #ffffff;       max-width: 600px;       padding: 1rem;       position: fixed;     }     button {       all: unset;       cursor: pointer;       font-size: 1.25rem;       position: absolute;         top: 1rem;         right: 1rem;     }     button:focus {       border: 2px solid blue;     }   </style>   <div class="wrapper">   <div class="overlay"></div>     <div class="dialog" role="dialog" aria-labelledby="title" aria-describedby="content">       <button class="close" aria-label="Close">&#x2716;&#xfe0f;</button>       <h1 id="title">Hello world</h1>       <div id="content" class="content">         <p>This is content in the body of our modal</p>       </div>     </div>   </div> </template>

This code will serve as the foundation for our dialog. Breaking it down briefly, we have a global close button, a heading and some content. We have also added in a bit of behavior to visually toggle our dialog (although it isn’t yet accessible). In our next article, we will put custom elements to use and create one of our own that consumes this template in real-time.

See the Pen
Dialog with template with script
by Caleb Williams (@calebdwilliams)
on CodePen.

Article Series:

  1. An Introduction to Web Components
  2. Crafting Reusable HTML Templates (This post)
  3. Creating a Custom Element from Scratch (Coming soon!)
  4. Encapsulating Style and Structure with Shadow DOM (Coming soon!)
  5. Advanced Tooling for Web Components (Coming soon!)

The post Crafting Reusable HTML Templates appeared first on CSS-Tricks.


, , ,

Design Deals for the Week


The Whole Spreadsheets as Databases Thing is Pretty Cool

A spreadsheet has always been a strong (if fairly literal) analogy for a database. A database has tables, which is like a single spreadsheet. Imagine a spreadsheet for tracking RSVPs for a wedding. Across the top, column titles like First Name, Last Name, Address, and Attending?. Those titles are also columns in a database table. Then each person in that spreadsheet is literally a row, and that’s also a row in a database table (or an entry, item, or even tuple if you’re really a nerd).

It’s been getting more and more common that this doesn’t have to be an analogy. We can quite literally use a spreadsheet UI to be our actual database. That’s meaningful in that it’s not just viewing database data as a spreadsheet, but making spreadsheet-like features first-class citizens of the app right alongside database-like features.

With a spreadsheet, the point might be viewing the thing as a whole and understanding things that way. Browsing, sorting, entering and editing data directly in the UI, and making visual output that is useful.

With a database, you don’t really look right at it — you query it and use the results. Entering and editing data is done through code and APIs.

That’s not to say you can’t look directly at a database. Database tools like Sequel Pro (and many others!) offer an interface for looking at tables in a spreadsheet-like format:

What’s nice is that the idea of spreadsheets and databases can co-exist, offering the best of both worlds at once. At least, on a certain scale.

We’ve talked about Airtable before here on CSS-Tricks and it’s a shining example of this.

Airtable calls them bases, and while you can view the data inside them in all sorts of useful ways (a calendar! a gallery! a kanban!), perhaps the primary view is that of a spreadsheet:

If all you ever do with Airtable is use it as a spreadsheet, it’s still very nice. The UI is super well done. Things like filtering and sorting feel like true first-class citizens in a way that it’s almost weird that other spreadsheet technology doesn’t. Even the types of fields feel practical and modern.

Plus with all the different views in a base, and even cooler, all the “blocks” they offer to make the views more dashboard-like, it’s a powerful tool.

But the point I’m trying to make here is that you can use your Airtable base like a database as well, since you automatically have read/write API access to your base.

So cool that these API docs use data from your own base to demonstrate the API.

I talked about this more in my article How To Use Airtable as a Front End Developer. This API access is awesome from a read data perspective, to do things like use it as a data source for a blog. Robin yanked in data to build his own React-powered interface. I dig that there is a GraphQL interface, if it is third-party.

The write access is arguably even more useful. We use it at CodePen to do CRM-ish stuff by sending data into an Airtable base with all the information we need, then use Airtable directly to visualize things and do the things we want.

Airtable alternatives?

There used to be Fieldbook, but that shut down.

RowShare looks weirdly similar (although a bit lighter on features) but it doesn’t look like it has an API, so it doesn’t quite fit the bill for that database/spreadsheet gap spanning.

Zoho Creator does have an API and interesting visualization stuff built in, which actually looks pretty darn cool. It looks like some of their marketing is based around the idea that if you need to build a CRUD app, you can do that with this with zero coding — and I think they are right that it’s a compelling sell.

Actiondesk looks interesting in that it’s in the category of a modern take on the power of spreadsheets.

While it’s connected to a database in that it looks like it can yank in data from something like MySQL or PostgreSQL, it doesn’t look like it has database-like read/write APIs.

Can we just use Google Sheets?

The biggest spreadsheet tool in the sky is, of course, the Google one, as it’s pretty good, free, and familiar. It’s more like a port of Excel to the browser, so I might argue it’s more tied to the legacy of number-nerds than it is any sort of fresh take on a spreadsheet or data storage tool.

Google Sheets has an API. They take it fairly seriously as it’s in v4 and has a bunch of docs and guides. Check out a practical little tutorial about writing to it from Slack. The problem, as I understand it, is that the API is weird and complicated and hard, like Sheets itself. Call me a wimp, but this quick start is a little eye-glazing.

What looks like the most compelling route here, assuming you want to keep all your data in Google Sheets and use it like a database, is Sheetsu. It deals with the connection/auth to the sheet on its end, then gives you API endpoints to the data that are clean and palatable.

Plus there are some interesting features, like giving you a form UI for possibly easier (or more public) data entry than dealing with the spreadsheet itself.

There is also Sheetrock.js, an open source library helping out with that API access to a sheet, but it hasn’t been touched in a few years so I’m unsure the status there.

I ain’t trying to tell you this idea entirely replaces traditional databases.

For one thing, the relational part of databases, like MySQL, is a super important aspect that I don’t think spreadsheets always handle particularly well.

Say you have an employee table in your database, and for each row in that table, it lists the department they work for.

ID  Name                  Department --  --                    -- 1   Chris Coyier          Front-End Developer 2   Barney Butterscotch   Human Resources   

In a spreadsheet, perhaps those department names are just strings. But in a database, at a certain scale, that’s probably not smart. Instead, you’d have another table of departments, and relate the two tables with a foreign key. That’s exactly what is described in this classic explainer doc:

To find the name of a particular employee’s department, there is no need to put the name of the employee’s department into the employee table. Instead, the employee table contains a column holding the department ID of the employee’s department. This is called a foreign key to the department table. A foreign key references a particular row in the table containing the corresponding primary key.

ID  Name                  Department --  --                    -- 1   Chris Coyier          1 2   Barney Butterscotch   2   ID  Department            Manager     --  --                    -- 1   Front-End Developers  Akanya Borbio 2   Human Resources       Susan Snowrinkle

To be fair, spreadsheets can have relational features too (Airtable does), but perhaps it isn’t a fundamental first-class citizen like some databases treat it.

Perhaps more importantly, databases, largely being open source technology, are supported by a huge ecosystem of technology. You can host your PostgreSQL or MySQL database (or whatever all the big database players are) on all sorts of different hosting platforms and hardware. There are all sorts of tools for monitoring it, securing it, optimizing it, and backing it up. Plus, if you’re anywhere near breaking into the tens of thousands of rows point of scale, I’d think a spreadsheet has been outscaled.

Choosing a proprietary host of data is largely for convenience and fancy UX at a somewhat small scale. I kinda love it though.

The post The Whole Spreadsheets as Databases Thing is Pretty Cool appeared first on CSS-Tricks.


, , , , ,

An Introduction to Web Components

Front-end development moves at a break-neck pace. This is made evident by the myriad articles, tutorials, and Twitter threads bemoaning the state of what once was a fairly simple tech stack. In this article, I’ll discuss why Web Components are a great tool to deliver high-quality user experiences without complicated frameworks or build steps and that don’t run the risk of becoming obsolete. In subsequent articles of this five-part series, we will dive deeper into each of the specifications.

This series assumes a basic understanding of HTML, CSS, and JavaScript. If you feel weak in one of those areas, don’t worry, building a custom element actually simplifies many complexities in front-end development.

Article Series:

  1. An Introduction to Web Components (This post)
  2. Crafting Reusable HTML Templates (Coming soon!)
  3. Creating a Custom Element from Scratch (Coming soon!)
  4. Encapsulating Style and Structure with Shadow DOM (Coming soon!)
  5. Advanced Tooling for Web Components (Coming soon!)

What are Web Components, anyway?

Web Components consist of three separate technologies that are used together:

  1. Custom Elements. Quite simply, these are fully-valid HTML elements with custom templates, behaviors and tag names (e.g. <one-dialog>) made with a set of JavaScript APIs. Custom Elements are defined in the HTML Living Standard specification.
  2. Shadow DOM. Capable of isolating CSS and JavaScript, almost like an <iframe>. This is defined in the Living Standard DOM specification.
  3. HTML templates. User-defined templates in HTML that aren’t rendered until called upon. The <template> tag is defined in the HTML Living Standard specification.

These are what make up the Web Components specification.

HTML Imports is likely to be the fourth technology in the stack, but it has yet to be implemented in any of the big four browsers. The Chrome team has announced it an intent to implement them in a future release.

Web Components are generally available in all of the major browsers with the exception of Microsoft Edge and Internet Explorer 11, but polyfills exist to fill in those gaps.

Referring to any of these as Web Components is technically accurate because the term itself is a bit overloaded. As a result, each of the technologies can be used independently or combined with any of the others. In other words, they are not mutually exclusive.

Let’s take a quick look at each of those first three. We’ll dive deeper into them in other articles in this series.

Custom elements

As the name implies, custom elements are HTML elements, like <div>, <section> or <article>, but something we can name ourselves that are defined via a browser API. Custom elements are just like those standard HTML elements — names in angle brackets — except they always have a dash in them, like <news-slider> or <bacon-cheeseburger>. Going forward, browser vendors have committed not to create new built-in elements containing a dash in their names to prevent conflicts.

Custom elements contain their own semantics, behaviors, markup and can be shared across frameworks and browsers.

class MyComponent extends HTMLElement {   connectedCallback() {     this.innerHTML = `<h1>Hello world</h1>`;   } }      customElements.define('my-component', MyComponent);

See the Pen
Custom elements demo
by Caleb Williams (@calebdwilliams)
on CodePen.

In this example, we define <my-component>, our very own HTML element. Admittedly, it doesn’t do much, however this is the basic building block of a custom element. All custom elements must in some way extend an HTMLElement in order to be registered with the browser.

Custom elements exist without third-party frameworks and the browser vendors are dedicated to the continued backward compatibility of the spec, all but guaranteeing that components written according to the specifications will not suffer from breaking API changes. What’s more, these components can generally be used out-of-the-box with today’s most popular frameworks, including Angular, React, Vue, and others with minimal effort.

Shadow DOM

The shadow DOM is an encapsulated version of the DOM. This allows authors to effectively isolate DOM fragments from one another, including anything that could be used as a CSS selector and the styles associated with them. Generally, any content inside of the document’s scope is referred to as the light DOM, and anything inside a shadow root is referred to as the shadow DOM.

When using the light DOM, an element can be selected by using document.querySelector('selector') or by targeting any element’s children by using element.querySelector('selector'); in the same way, a shadow root’s children can be targeted by calling shadowRoot.querySelector where shadowRoot is a reference to the document fragment — the difference being that the shadow root’s children will not be select-able from the light DOM. For example, If we have a shadow root with a <button> inside of it, calling shadowRoot.querySelector('button') would return our button, but no invocation of the document’s query selector will return that element because it belongs to a different DocumentOrShadowRoot instance. Style selectors work in the same way.

In this respect, the shadow DOM works sort of like an <iframe> where the content is cut off from the rest of the document; however, when we create a shadow root, we still have total control over that part of our page, but scoped to a context. This is what we call encapsulation.

If you’ve ever written a component that reuses the same id or relies on either CSS-in-JS tools or CSS naming strategies (like BEM), shadow DOM has the potential to improve your developer experience.

Imagine the following scenario:

<div>   <div id="example">     <!-- Pseudo-code used to designate a shadow root -->     <#shadow-root>       <style>       button {         background: tomato;         color: white;       }       </style>       <button id="button">This will use the CSS background tomato</button>     </#shadow-root>   </div>   <button id="button">Not tomato</button> </div>

Aside from the pseudo-code of <#shadow-root> (which is used here to demarcate the shadow boundary which has no HTML element), the HTML is fully valid. To attach a shadow root to the node above, we would run something like:

const shadowRoot = document.getElementById('example').attachShadow({ mode: 'open' }); shadowRoot.innerHTML = `<style> button {   color: tomato; } </style> <button id="button">This will use the CSS color tomato <slot></slot></button>`;

A shadow root can also include content from its containing document by using the <slot> element. Using a slot will drop user content from the outer document at a designated spot in your shadow root.

See the Pen
Shadow DOM style encapsulation demo
by Caleb Williams (@calebdwilliams)
on CodePen.

HTML templates

The aptly-named HTML <template> element allows us to stamp out re-usable templates of code inside a normal HTML flow that won’t be immediately rendered, but can be used at a later time.

<template id="book-template">   <li><span class="title"></span> &mdash; <span class="author"></span></li> </template>  <ul id="books"></ul>

The example above wouldn’t render any content until a script has consumed the template, instantiated the code and told the browser what to do with it.

const fragment = document.getElementById('book-template'); const books = [   { title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' },   { title: 'A Farewell to Arms', author: 'Ernest Hemingway' },   { title: 'Catch 22', author: 'Joseph Heller' } ];  books.forEach(book => {   // Create an instance of the template content   const instance = document.importNode(fragment.content, true);   // Add relevant content to the template   instance.querySelector('.title').innerHTML = book.title;   instance.querySelector('.author').innerHTML =;   // Append the instance ot the DOM   document.getElementById('books').appendChild(instance); });

Notice that this example creates a template (<template id="book-template">) without any other Web Components technology, illustrating again that the three technologies in the stack can be used independently or collectively.

Ostensibly, the consumer of a service that utilizes the template API could write a template of any shape or structure that could be created at a later time. Another page on a site might use the same service, but structure the template this way:

<template id="book-template">   <li><span class="author"></span>'s classic novel <span class="title"></span></li> </template>  <ul id="books"></ul>

See the Pen
Template example
by Caleb Williams (@calebdwilliams)
on CodePen.

That wraps up our introduction to Web Components

As web development continues to become more and more complicated, it will begin to make sense for developers like us to begin deferring more and more development to the web platform itself which has continued to mature. The Web Components specifications are a set of low-level APIs that will continue to grow and evolve as our needs as developers evolve.

In the next article, we will take a deeper look at the HTML templates part of this. Then, we’ll follow that up with a discussion of custom elements and shadow DOM. Finally, we’ll wrap it all up by looking at higher-level tooling and incorporation with today’s popular libraries and frameworks.

Article Series:

  1. An Introduction to Web Components (This post)
  2. Crafting Reusable HTML Templates (Coming soon!)
  3. Creating a Custom Element from Scratch (Coming soon!)
  4. Encapsulating Style and Structure with Shadow DOM (Coming soon!)
  5. Advanced Tooling for Web Components (Coming soon!)

The post An Introduction to Web Components appeared first on CSS-Tricks.



HONK: Cover Art by Tobias Hall for the Rolling Stones Latest Album


People Digging into Grid Sizing and Layout Possibilities

Jen Simmons has been coining the term intrinsic design, referring to a new era in web layout where the sizing of content has gone beyond fluid columns and media query breakpoints and into, I dunno, something a bit more exotic. For example, columns that are sized more by content and guidelines than percentages. And not always columns, but more like appropriate placement, however that needs to be done.

One thing is for sure, people are playing with the possibilities a lot right now. In the span of 10 days I’ve gathered these links:

The post People Digging into Grid Sizing and Layout Possibilities appeared first on CSS-Tricks.


, , , , , ,

See No Evil: Hidden Content and Accessibility

There is no one true way to hide something on the web. Nor should there be, because hiding is too vague. Are you hiding visually or temporarily (like a user menu), but the content should still be accessible? Are you hiding it from assistive tech on purpose? Are you showing it to assistive tech only? Are you hiding it at certain screen sizes or other scenarios? Or are you just plain hiding it from everyone all the time?

Paul Hebert digs into these scenarios. We’ve done a video on this subject as well.

Feels like many CSS properties play some role in hiding or revealing content: display, position, overflow, opacity, visibility, clip-path

Direct Link to ArticlePermalink

The post See No Evil: Hidden Content and Accessibility appeared first on CSS-Tricks.


, , ,