Front End Web Development

Web Developer Search History

Css Tricks - Wed, 09/18/2019 - 11:41am

Sophie Koonin blogged "Everything I googled in a week as a professional software engineer," which was a fascinating look into the mind of a web developer and what they need to look up during day-to-day work. We all joke that we just Google stuff (or StackOverflow stuff) we don't know off the bat and copy and paste, but this is more to the heart of it.

A few just from one day:

react-apollo release notes
jest silence warnings - don’t judge me, ok?
semantic HTML contact details - wanted to check if the <address> tag was relevant here
dominos accessibility - popcorn.gif

Gift Egwuenu followed up with "The Art of Googling."

A few:

  • Filter an Array with JavaScript - I was working on a chore and needed to see how the filter method works
  • Take a screenshot on Mac
  • Center a div with Grid
  • Undo a git commit
  • Grid with React Native - checking if this was a thing with React Native

Reading these, I alternate from "eeeeesh, good luck" to "I wish I could have been there because I could have probably helped."

This is a fun little blogging trend I'd love to see more people do. (Reminds me of that "How we do CSS at [company]" thing.)

I'll do my last few days, unearthed from Google's My Activity area, filtered to search-only.

This was just a couple of hours yesterday morning, with some noise and distracting stuff removed:

  • Sara Vieira - Was looking for her Twitter to credit a tweet.
  • javascript closest - Was looking for the DOM version rather than the jQuery version
  • jquery parent - Confirming that was a real API it had
  • minimap moz element - Finding an article that was a great use case for the
  • element() function in CSS
  • web unleashed - Going to this conference later in the week and needed to look at the site
  • server log analytics
  • states in australia
  • view html source in spark mail
  • bat crypto
  • html validator
  • html unescape
  • should email html have title?
  • window.scrollto
  • useCallback
  • rails rss feed content type
  • content type for rss feeds
  • river city girls

You next! You next!

The post Web Developer Search History appeared first on CSS-Tricks.

How Web Content Can Affect Power Usage

Css Tricks - Wed, 09/18/2019 - 11:40am

Because we know that all people with battery-powered devices are constantly concerned about their battery levels, and that websites are significant consumers of that battery power, we should probably think about this stuff a lot more than we do.

I'd expect the browser itself to be our main ally here, doing smart things to reduce power consumption without us developers needing to think too much about it. But we've learned over the years that it's always a shared responsibility. We regularly need to help the browser do its job the best it can (think responsive images and will-change).

Some direct tips from Benjamin Poulain and Simon Fraser's article:

  • Minimize the use of timers to avoid waking up the CPU. Try to coalesce timer-based work into a few, infrequent timers. Lots of uncoordinated timers which trigger frequent CPU wake-ups are much worse than gathering that work into fewer chunks.
  • Minimize continually animating content, like animated images and auto-playing video. Be particularly vigilant to avoid “loading” spinner GIFs or CSS animations that continually trigger painting, even if you can’t see them. IntersectionObserver can be used to run animations only when they are visible.
  • Use declarative animations (CSS Animations and Transitions) where possible. The browser can optimize these away when the animating content is not visible, and they are more efficient than script-driven animation.
  • Avoid network polling to obtain periodic updates from a server. Use WebSockets or Fetch with a persistent connection, instead of polling.

I'd like to see more developer tooling along the lines of how macOS makes it easy to see apps that are demanding significant power:

WebKit DevTools does has it:

We used to have a Battery Status API, but that's been deprecated, so not a big part of the story right now.

I was just at the Web Unleashed conferencewhere Kyle Simpson talked about this rather directly in his keynote lecture. His main idea is that we should ask users a bit more directly and solicit their preferences. Hey user, are you in a situation where you want to use as little battery power as possible? Tell us and we'll do what we can to make that happen (even on a site-by-site basis).

Direct Link to ArticlePermalink

The post How Web Content Can Affect Power Usage appeared first on CSS-Tricks.

A Comparison of Static Form Providers

Css Tricks - Wed, 09/18/2019 - 4:17am

Let’s attempt to coin a term here: "Static Form Provider." You bring your HTML <form>, but don’t worry about the back-end processing that makes it work. There are a lot of these services out there!

Static Form Providers do all tasks like validating, storing, sending notifications, and integrating with other APIs. It’s lovely when you can delegate big responsibilities like this. The cost? Typically a monthly or annual subscription, except for a few providers and limited plans. The cost is usually less than fancier "form builders" that help you build the form itself and process it.

In this article, we are going to review some of the most popular static form providers:

Before moving forward, just a note that the information for these comparisons came from visiting the site for each product and learning about the included features. Once I got all the information, I sent an email to each provider to confirm the list of features. Some of them confirmed, some didn't. Special thanks to Kwes, FormKeep, Formspree, FormSubmit, formX, and Netlify Forms teams for confirming.

Form building components and validation Name Custom Components Front-End Validation Back-End Validation Kwes ✅ ✅ ✅ Basin ❌ ❌ ❌ FieldGoal Unable to confirm Unable to confirm Unable to confirm FormCarry ❌ ❌ ❌ FormKeep ✅ ❌ ❌ Formspree ❌ ❌ ❌ FormSubmit ❌ ❌ ❌ formX ❌ ❌ ❌ Getform ❌ ❌ ❌ Netlify Forms ❌ ❌ ❌

Components for building a form are HTML input elements, like text inputs, textareas, checkboxes, and radio buttons. When using a static form, most providers require adding custom HTML attributes. By providing the custom URL in the form action attribute, the form gets submitted on the provider’s side where it gets stored.

If you are looking for a form builder, FormKeep has a form designer feature. That means you embed custom HTML and JavaScript files in the page, and you get a styled form. Otherwise, you have to style the form by yourself.

If you need custom components, like a date picker or card inputs, Kwes and FormKeep are the only providers with this feature. If you want to validate input fields in the browser, you might use third-party libraries or writing your code which means adding additional JavaScript code to the site. Kwes is the only provider that supports front-end validation based on the rules you set in each input component. To enable this feature, you should include additional JavaScript file, which you might do nevertheless. Other static form providers rely only on HTML5 validation.

Kwes is the only provider with back-end validation, too. The rules you set in the front end are passed to the back end side. In case when front-end validation fails, you are safe, the backend validation would work. Other providers don't have this feature; they rely only on spam protection.

Spam protection Name Spam Protection Kwes Artificial intelligence
Automatic Honeypot
Blacklists
Proprietary technology Basin Akismet
CleanTalk
reCAPTCHA
Honeypot FieldGoal Provided, but unable to confirm what powers it FormCarry Akismet
reCAPTCHA FormKeep Akismet
reCAPTCHA
Honeypot
Proprietary technology Formspree reCaptcha
Profanity filter
Automated classification FormSubmit reCaptcha
Honeypot formX reCAPTCHA
Honeypot Getform Akismet
reCAPTCHA Netlify Forms Akismet
reCAPTCHA
Honeypot

Kwes advertises a 99.6% spam block success rate with no setup required.

Once your form is ready for submissions, you might find it hard to deal with spam. That’s why spam protection is essential, especially if you want to keep your sanity and serenity. All providers provide spam protection in this way or another. Some rely on Google reCAPTCHA or Akismet, some on Honeypot techniques, and some use artificial intelligence to get the job done. It is worth noting that adding an additional step to your form, like adding reCAPTCHA might affect the conversion rates on form submissions.

Email notifications Name Confirmations Notifications Email Routing Logic Kwes ✅ ✅ ✅ Basin ✅ ✅ ✅ FieldGoal Unable to confirm Unable to confirm Unable to confirm FormCarry ✅ ✅ ✅ FormKeep ✅ ✅ ✅ Formspree ✅ ✅ ✅ FormSubmit ✅ ✅ ✅ formX ✅ ✅ ✅ Getform ✅ ✅ ✅ Netlify Forms ✅ ✅ ✅

Email confirmations are essential if you want to provide a fast response to your users. With a contact form, for example, you want to get an email for every new submission. That way, you're able to respond to the submission quickly and efficiently.

All providers, except FieldGoal, have confirmation, notification, and email routing logic features. You could set up an email form element which would be used to send an email automatically to the user with confirmation about the submission.

Some providers have other sorts of notifications besides email, like push notifications or Slack messages, which might be handy.

White labeling Name White Label Kwes ✅ Basin ✅ FieldGoal Unable to confirm FormCarry ✅ FormKeep ✅ Formspree ✅ FormSubmit ✅ formX ✅ Getform ✅ Netlify Forms ✅

When communicating via email notifications with your clients, you might want to use your brand and style. It creates better awareness and that way you familiarize your clients with your product. All providers offer this feature, with the exception of FieldGoal, which I was unable to confirm (although it might be under paid plans).

Custom redirects Name Custom Redirects Kwes ✅ Basin ✅ FieldGoal Unable to confirm FormCarry ✅ FormKeep ✅ Formspree ✅ FormSubmit ✅ formX ✅ Getform ✅ Netlify Forms ✅

Once you have captured a response from your user, you may want to let the user continue using your site. Also, you might want to communicate to the user that the submission was received. This feature is called "custom redirect," and every provider has this feature (with another exception for FieldGoal because I was unable to confirm). Note that this feature might not be available in a free plan and require a paid or upgraded account.

Upload storage Name Upload Storage Kwes 200MB per file
20GB storage Basin 100MB per submission FieldGoal Amazon S3 FormCarry 5MB per file
5GB storage FormKeep 2.5G storage Formspree 10MB per file
10GB storage FormSubmit Included, but unconfirmed storage amounts formX ❌ Getform 25MB per submission
25GB storage Netlify Forms 1GB storage

Not every static form provider provides file storage. For example, formX doesn't provide it at all. In most cases, this feature is available under paid plans. You might want to invest additional time to find out which provider offers the best service for you. Be sure to look specifically at single file size and form submission size limitations.

Data export Name Data Export Kwes ✅ Basin ✅ FieldGoal Unable to confirm FormCarry ✅ FormKeep ✅ Formspree ✅ FormSubmit ✅ formX ✅ Getform ✅ Netlify Forms ✅

Data export is important feature if you want to use it for analysis or for import to third-party software. Most providers offers CSV and JSON exports, which are the most commonly used ones.

API access Name API Access Kwes ✅ Basin ✅ FieldGoal Unable to confirm FormCarry ✅ FormKeep ✅ Formspree ✅ FormSubmit ✅ formX On demand Getform ❌ Netlify Forms ✅

If you want to control your data submissions by building custom application or script, you might benefit from having API access. Most providers have this feature, except Getform. formX offers it, but only on demand.

Webhooks/Zapier Name Webhooks Zapier Kwes ✅ ✅ Basin ✅ ✅ FieldGoal Unable to confirm ✅ FormCarry ✅ ✅ FormKeep ✅ ✅ Formspree ✅ ✅ FormSubmit ✅ ❌ formX ✅ ✅ Getform ✅ ✅ Netlify Forms ✅ ✅

When building a custom application or a script is out of budget, you might want to use webhooks to integrate data submissions with third-party software. Zapier is one of the most commonly used services for this, and only FormSubmit doesn't support it (though it does support webhooks).

Analytics Name Analytics Kwes ❌ Basin ✅ FieldGoal Unable to confirm FormCarry ❌ FormKeep ✅ Formspree ❌ FormSubmit ❌ formX ✅ Getform ❌ Netlify Forms ❌

Analytics for static forms is a neat feature that could offer beneficial insight into how your form is performing. It may help you understand how your users interact with it, and you may spot ways to improve the form submission experience as a result. This feature is the least supported of all other features. Only Basin, FormKeep, and formX provide it.

Plan comparison Name Plan 1 Plan 2 Plan 3 Plan 4 Kwes Free Tier
$0/mo.
Build spam-protected, and validated forms quicker than ever.

1 Website
Unlimited Forms
50 Spam Blocks Bronze Tier
$9/mo.
Unlimited spam blocks, more form tools, and submissions.
1 Website
Unlimited Forms
Unlimited Spam Blocks Silver Tier
$29/mo.
Build more powerful forms with integrations and webhooks.
3 Websites
Unlimited Forms
Unlimited Spam Blocks
4 Users Gold Tier
$79/mo.
Enjoy more team members and everything with increased limits.
10 Websites
Unlimited Forms
Unlimited Spam Blocks
11 Users Basin Standard Tier
$4.17/mo. (billed annually) Premium Tier
$12.50/mo. (billed annually) FieldGoal Single Tier
1 form
$5/mo. Freelancer Tier
5 forms
$15/mo. Studio Tier
15 forms
$39/mo. Agency Tier
50 forms
$79/mo. FormCarry Baby Tier
Free Basic Tier
$15/mo. Growth Tier
$40/mo. FormKeep Starter Tier
$4.99/mo. Starter Pack
$7.50 per form per month Freelancer Tier
$5.90 per form per month Agency Tier
$3.30 per form per month Formspree Free Tier
$0/mo. Gold Tier
$10/mo. Platform Tier
$40/mo. FormSubmit Unlimited formX Free Tier
$0/mo.
100 submissions max. Starter Tier
$4.99/mo. SMBs & Freelancers
$49.99/mo. Business & Agencies
$99.99/mo. Getform Free Tier
$0/mo. Basic Tier
Perfect for small businesses
$7.5/mo.
$90 per year Agency Tier
$24/mo.
$290 annually Enterprise Tier
$57.5/mo.
$690 annually Netlify Forms Level 0
$0
100 submissions/mo.
10MB uploads/mo. Level 1
$19/mo. per site
1,000 submissions/mo.
1GB uploads/mo. Level 2
Custom pricing and limits

Static form providers have different plans, from entirely free plans and trials, to enterprise plans for every business need. Depending on a plan, you might have different features enabled. For example, FormSubmit is the only provider that offers all of its features for free, though it doesn't support every feature we've covered here. You will want to invest some time to learn about which features that are most important for you and your product or business. Then go ahead and decide on which provider is most suitable for your needs.

Wrapping up

Having a form of any kind is a must-have for a large number of sites. When you use a static site generator, you might discover that static form providers make adding forms to a site almost trivial. By following a few rules for enabling static forms, you could benefit from essential features like spam protection and email notifications.

I have been using Kwes for a while now and I can honestly tell you it is a great product that fulfills all of my needs. It has smart spam protection, an easy-to-use dashboard, and impressive validation, both on the front end and back end.

Before choosing your static form providers, be sure to put down all requirements to the paper, and then find your perfect provider.

The post A Comparison of Static Form Providers appeared first on CSS-Tricks.

Two Browsers Walked Into a Scrollbar

Css Tricks - Wed, 09/18/2019 - 4:16am

Surprise: scrollbars are complicated, especially cross-browser and cross-platform.

Sometimes they take up space and sometimes they don't. Sometimes that is affected by a setting and sometimes it isn't. Sometimes you can see them and sometimes you can't unless you're actually scrolling. Styling them is handled in all sorts of different ways, including some very recent developments.

Follow Zach's journey toward thinner, native, user-preference-respecting, more aesthetic scrollbars, particularly for element-level scrollbars that ends up here.

Direct Link to ArticlePermalink

The post Two Browsers Walked Into a Scrollbar appeared first on CSS-Tricks.

A Color Picker for Product Images

Css Tricks - Tue, 09/17/2019 - 10:39am

Sounds kind of like a hard problem doesn't it? We often don't have product shots in thousands of colors, such that we can flip out the <img src="product-red.jpg" alt="red product"> with <img src="product-blue.jpg" alt="blue product">. Nor do we typically have products in a vector format such that we can apply SVG fills to them and such.

There is a clever way to do it though, even when your product shots are bitmap graphic files, like JPG or PNG. Kyle Wetton demonstrates, and it's essentially:

  1. Make a vector path that covers the area on the JPG that should change color (probably in Photoshop with the Pen Tool and exporting the vector).
  2. Place that solid vector area exactly on top of the product JPG.
  3. mix-blend-mode: multiply; the SVG.
  4. Change the fill color on the SVG as desired.

Here's the super cool demo I think it originated from:

See the Pen
Color this sofa! – SVG + Blend Mode trick
by Kyle Wetton (@kylewetton)
on CodePen.

And the demo from the article:

See the Pen
Dynamic Colour Picking - Part 3

on CodePen.

The post A Color Picker for Product Images appeared first on CSS-Tricks.

Overflow And Data Loss In CSS

Css Tricks - Tue, 09/17/2019 - 10:38am

"Data Loss" is a funny term. My brain thinks of it like packet loss on the way from the server to your browser, resulting in missing content in files. Perhaps it is that on some level, but in CSS parlance, it has to do with the overflow property. Too much content for sized container + hidden overflow = data loss.

But it isn't only overflow that can cause this "data loss." Alignment can cause data loss too. Imagine flexbox or grid with some alignment that causes content to be pushed off the top or left edges of the screen, where scrollbars do not venture.

Rachel Andrew:

To prevent accidental data loss caused by alignment, CSS now has some new keywords which can be used along with the alignment properties. These are specified in the Box Alignment specification — the specification which deals with alignment across all layout methods including Grid and Flexbox. They are currently only supported in Firefox. In our example above, if we set align-items: safe center, then the final item would become aligned to start rather than forcing the content to be centered. This would prevent the data loss caused by the item being centered and therefore pushed off the side of the viewport.

Direct Link to ArticlePermalink

The post Overflow And Data Loss In CSS appeared first on CSS-Tricks.

A Proof of Concept for Making Sass Faster

Css Tricks - Tue, 09/17/2019 - 4:19am

At the start of a new project, Sass compilation happens in the blink of an eye. This feels great, especially when it’s paired with Browsersync, which reloads the stylesheet for us in the browser. But, as the amount of Sass grows, compilation time increases. This is far from ideal.

It can be a real pain when the compilation time creeps over one or two seconds. For me, that's enough time to lose focus at the end of a long day. So, I would like to share a solution that's available in a WordPress CSS Editor called Microthemer, as a proof of concept.

This is a two-part article. The first part is for the attention of Sass users. We will introduce the basic principles, performance results, and an interactive demo. The second part covers the nuts and bolts of how Microthemer makes Sass faster. And considers how to implement this as an npm package that can deliver fast, scalable Sass to a much broader community of developers.

How Microthemer compiles Sass in an instant

In some ways, this performance optimisation is simple. Microthemer just compiles less Sass code. It doesn’t intervene with Sass’ internal compilation process.

In order to feed the Sass compiler less code, Microthemer maintains an understanding of Sass entities used throughout the code base, like variables and mixins. When a selector is edited, Microthemer only compiles that single selector, plus any related selectors. Selectors are related if they make use of the same variables for instance, or one selector extends another. With this system, Sass compilation remains as fast with 3000 selectors as it does with a handful.

Performance results

With 3000 selectors, the compile time is around 0.05 seconds. It varies, of course. Sometimes it might be closer to 0.1 seconds. Other times the compilation happens as fast as 0.01 seconds (10ms).

To see for yourself, you can watch a video demonstration. Or mess around with the online Microthemer playground (see instructions below).

Online Microthemer playground

The online playground makes it easy to experiment with Microthemer yourself.

Instructions
  1. Go to the online Microthemer playground.
  2. Enable support for Sass via General ? Preferences ? CSS / SCSS ? Enable SCSS.
  3. Go to View ? full code editor ? on to add global variables, mixins, and functions.
  4. Switch back to the main UI view (View ? full code editor ? off).
  5. Create selectors via the Target button.
  6. Add Sass code via the editor to the left of the Font property group.
  7. After each change, you can see what code Microthemer included in the compile process via View ? Generated CSS ? Previous SCSS compile.
  8. To see how this works at scale, you can import vanilla CSS from a large stylesheet into Microthemer via Packs ? Import ? CSS stylesheet (importing Sass isn't supported - yet).
Do you want this as an npm package?

Microthemer’s selective compilation technique could also be delivered as an npm package. But the question is, do you see a need for this? Could your local Sass environment do with a speed boost? If so, please leave a comment below.

The rest of this article is aimed at those who develop tools for the community. As well as those who might be curious about how this challenge was tackled.

The Microthemer way to compile Sass

We will move on to some code examples shortly. But first, let's consider the main application goals.

1. Compile minimal code

We want to compile the one selector being edited if it has no relationship with other selectors, or multiple selectors with related Sass entities — but no more than necessary.

2. Responsive to code changes

We want to remove any perception of waiting for Sass to compile. We also don't want to crunch too much data between user keystrokes.

3. Equal CSS output

We want to return the same CSS a full compile would generate, but for a subset of code.

Sass examples

The following code will serve as a point of reference throughout this article. It covers all of the scenarios our selective compiler needs to handle. Such as global variables, mixin side-effects, and extended selectors.

Variables, functions, and mixins $primary-color: green; $secondary-color: red; $dark-color: black; @function toRem($px, $rootSize: 16){ @return #{$px / $rootSize}rem; } @mixin rounded(){ border-radius: 999px; $secondary-color: blue !global; } Selectors .entry-title { color: $dark-color; } .btn { display: inline-block; padding: 1em; color: white; text-decoration: none; } .btn-success { @extend .btn; background-color: $primary-color; @include rounded; } .btn-error { @extend .btn; background-color: $secondary-color; } // Larger screens @media (min-width: 960px) { .btn-success { border:4px solid darken($primary-color, 10%); &::before { content: "\2713"; // unicode tick margin-right: .5em; } } } The Microthemer interface

Microthemer has two main editing views.

View 1: Full code

We edit the full code editor in the same way as a regular Sass file. That’s where global variables, functions, mixins, and imports go.

View 2: Visual

The visual view has a single selector architecture. Each CSS selector is a separate UI selector. These UI selectors are organized into folders.

Because Microthemer segments individual selectors, analysis happens at a very granular scale — one selector at a time.

Here’s a quick quiz question for you. The $secondary-color variable is set to red at the top of the full code view. So why is the error button in the previous screenshots blue? Hint: it has to do with mixin side effects. More on that shortly.

Third party libraries

A huge thanks to the authors of the following JavaScript libraries Microthemer uses:

  • Gonzales PE - This converts Sass code to an abstract syntax tree (AST) JavaScript object.
  • Sass.js - This converts Sass to CSS code in the browser. It uses web workers to run the compilation on a separate thread.
Data objects

Now for the nitty gritty details. Figuring out an appropriate data structure took some trial and error. But once sorted, the application logic fell into place naturally. So we’ll start by explaining the main data stores, and then finish with a brief summary of the processing steps.

Microthemer uses four main JavaScript objects for storing application data.

  1. projectCode: Stores all project code partitioned into discreet items for individual selectors.
  2. projectEntities: Stores all variables, functions, mixins, extends and imports used in the project, as well as the locations of where these entities are used.
  3. connectedEntities: Stores the connections one piece of code has with project Sass entities.
  4. compileResources: Stores the selective compile data following a change to the code base.
projectCode

The projectCode object allows us to quickly retrieve pieces of Sass code. We then combine these pieces into a single string for compilation.

  • files: With Microthemer, this stores the code added to the full code view described earlier. With an npm implementation, fileswould relate to actual .sass or .scss system files.
  • folders: Microthemer’s UI folders that contain segmented UI selectors.
  • index: The order of a folder, or a selector within a folder.
  • itemData: The actual code for the item, explained further in the next code snippet.
var projectCode = { // Microthemer full code editor files: { full_code: { index: 0, itemData: itemData } }, // Microthemer UI folders and selectors folders: { content_header: { index:100, selectors: { '.entry-title': { index:0, itemData: itemData }, } }, buttons: { index:200, selectors: { '.btn': { index:0, itemData: itemData }, '.btn-success': { index:1, itemData: itemData }, '.btn-error': { index:2, itemData: itemData } } } } }; itemData for .btn-success selector

The following code example shows the itemData for the .btn-success selector.

  • sassCode: Used to build the compilation string.
  • compiledCSS: Stores compiled CSS for writing to a stylesheet or style node in the document head.
  • sassEntities: Sass entities for single selector or file. Allows for before and after change analysis, and is used to build the projectEntities object.
  • mediaQueries: Same data as above, but for a selector used inside a media query.
var itemData = { sassCode: ".btn-success { @extend .btn; background-color: $primary-color; @include rounded; }", compiledCSS: ".btn-success { background-color: green; border-radius: 999px; }", sassEntities: { extend: { '.btn': { values: ['.btn'] } }, variable: { primary_color: { values: [1] } }, mixin: { rounded: { values: [1] } } }, mediaQueries: { 'min-width(960px)': { sassCode: ".btn-success { border:4px solid darken($primary-color, 10%); &::before { content: '\\2713'; margin-right: .5em; } }", compiledCSS: ".btn-success::before { content: '\\2713'; margin-right: .5em; }", sassEntities: { variable: { primary_color: { values: [1] } }, function: { darken: { values: [1] } } } } } }; projectEntities

The projectEntities object allows us to check which selectors use particular Sass entities.

  • variable, function, mixin, extend: The type of Sass entity.
  • E.g. primary_color: The Sass entity name. Microthemer normalizes hyphenated names because Sass uses hyphens and underscores interchangeably.
  • values: An array of declaration values or instances. Instances are represented by the number 1. The Gonzales PE Sass parser converts numeric declaration values to strings. So I’ve elected to use the integer 1 to flag instances.
  • itemDeps: An array of selectors that makes use of the Sass entity. This is explained further in the next code snippet.
  • relatedEntities: Our rounded mixin has a side effect of updating the global $secondary-color variable to blue, hence the blue error button. This side effect makes the rounded and $secondary-color entities co-dependent. So, when the $secondary-color variable is included, the roundedmixin should be included too, and vice versa.
var projectEntities = { variable: { primary_color: { values: ['green', 1], itemDeps: itemDeps }, secondary_color: { values: ["red", "blue !global", 1], itemDeps: itemDeps, relatedEntities: { mixin: { rounded: {} } } }, dark_color: { values: ["black", 1], itemDeps: itemDeps } }, function: { darken: { values: [1] }, toRem: { values: ["@function toRem($px, $rootSize: 16){? @return #{$px / $rootSize}rem;?}", 1], itemDeps: itemDeps } }, mixin: { rounded: { values: ["@mixin rounded(){? border-radius:999px;? $secondary-color: blue !global;?}", 1], itemDeps: itemDeps, relatedEntities: { variable: { secondary_color: { values: ["blue !global"], } } } } }, extend: { '.btn': { values: ['.btn', '.btn'], itemDeps: itemDeps } } }; itemDeps for the $primary-color Sass entity

The following code example shows the itemDeps for the $primary-color (primary_color) variable. The $primary-color variable is used by two forms of the .btn-success selector, including a selector inside the min-width(960px) media query.

  • path: Used to retrieve selector data from the projectCode object.
  • mediaQuery: Used when updating style nodes or writing to a CSS stylesheet.
var itemDeps = [ { path: ["folders", 'header', 'selectors', '.btn-success'], }, { path: ["folders", 'header', 'selectors', '.btn-success', 'mediaQueries', 'min-width(960px)'], mediaQuery: 'min-width(960px)' } ]; connectedEntities

The connectedEntities object allows us to find related pieces of code. We populate it following a change to the code base. So, if we were to remove the font-size declaration from the .btn selector, the code would change from this:

.btn { display: inline-block; padding: 1em; color: white; text-decoration: none; font-size: toRem(21); }

...to this:

.btn { display: inline-block; padding: 1em; color: white; text-decoration: none; }

And we would store Microthemer’s analysis in the following connectedEntities object.

  • changed: The change analysis, which captures the removal of the toRem function.

    • actions: an array of user actions.
    • form: Declaration (e.g. $var: 18px) or instance (e.g. font-size: $var).
    • value: A text value for a declaration, or the integer 1 for an instance.
  • coDependent: Extended selectors must always compile with the extending selector, and vice versa. The relationship is co-dependent. Variables, functions, and mixins are only semi-dependent. Instances must compile with declarations, but declarations do not need to compile with instances. However, Microthemer treats them as co-dependent for the sake of simplicity. In the future, logic will be added to filter out unnecessary instances, but this has been left out for the first release.
  • related: the rounded mixin is related to the $secondary-color variable. It updates that variable using the global flag. The two entities are co-dependent; they should always compile together. But in our example, the .btn selector makes no use of the rounded mixin. So, the related property below is not populated with anything.
var connectedEntities = { changed: { function: { toRem: { actions: [{ action: "removed", form: "instance", value: 1 }] } } }, coDependent: { extend: { '.btn': {} } }, related: {} }; compileResources

The compileResources object allows us to compile a subset of code in the correct order. In the previous section we removed the font-size declaration. The code below shows how the compileResources object would look after that change.

  • compileParts: An array of resources to be compiled.

    • path: Used to update the compiledCSS property of the relevant projectCodeitem.
    • sassCode: Used to build the sassString for compilation. We append a CSS comment to each piece (/*MTPART*/) . This comment is used to split the combined CSS output into the cssParts array.
  • sassString: A string of Sass code that compiles to CSS.
  • cssParts: CSS output in the form of an array. The array keys for cssParts line up with the compileParts array.
var compileResources = { compileParts: [ { path: ["files", "full_code"], sassCode: "/*MTFILE*/$primary-color: green; $secondary-color: red; $dark-color: black; @function toRem($px, $rootSize: 16){ @return #{$px / $rootSize}rem; } @mixin rounded(){ border-radius:999px; $secondary-color: blue !global;}/*MTPART*/" }, { path: ["folders", "buttons", ".btn"], sassCode: ".btn { display: inline-block; padding: 1em; color: white; text-decoration: none; }/*MTPART*/" }, { path: ["folders", "buttons", ".btn-success"], sassCode: ".btn-success { @extend .btn; background-color: $primary-color; @include rounded; }/*MTPART*/" }, { path: ["folders", "buttons", ".btn-error"], sassCode: ".btn-error { @extend .btn; background-color: $secondary-color; }/*MTPART*/" } ], sassString: "/*MTFILE*/$primary-color: green; $secondary-color: red; $dark-color: black; @function toRem($px, $rootSize: 16){ @return #{$px / $rootSize}rem; } @mixin rounded(){ border-radius:999px; $secondary-color: blue !global;}/*MTPART*/"+ ".btn { display: inline-block; padding: 1em; color: white; text-decoration: none;}/*MTPART*/"+ ".btn-success {@extend .btn; background-color: $primary-color; @include rounded;}/*MTPART*/"+ ".btn-error {@extend .btn; background-color: $secondary-color;}/*MTPART*/", cssParts: [ "/*MTFILE*//*MTPART*/", ".btn, .btn-success, .btn-error { display: inline-block; padding: 1em; color: white; text-decoration: none;}/*MTPART*/", ".btn-success { background-color: green; border-radius: 999px;}/*MTPART*/", ".btn-error { background-color: blue;}/*MTPART*/" ] }; Why were four resources included?
  1. full_code: The toRem Sass entity changed and the full_code resource contains the toRem function declaration.
  2. .btn: the selector was edited.
  3. .btn-success: Uses @extend .btn and so it must always compile with .btn. The combined selector becomes .btn, .btn-success.
  4. .btn-error: This also uses @extend .btn and so must be included for the same reasons as .btn-success.

Two selectors are not included because they are not related to the .btn selector.

  1. .entry-title
  2. .btn-success (inside the media query)
Recursive resource gathering

Aside from the data structure, the most time consuming challenge was figuring out how to pull in the right subset of Sass code. When one piece of code connects to another piece, we need to check for connections on the second piece too. There is a chain reaction. To support this, the following gatherCompileResources function is recursive.

  • We loop the connectedEntities object down to the level of Sass entity names.
  • We use recursion if a function or mixin has side effects (like updating global variables).
  • The checkObject function returns the value of an object at a particular depth, or false if no value exists.
  • The updateObject function sets the value of an object at a particular depth.
  • We add dependent resources to the compileParts array, using absoluteIndex as the key.
  • Microthemer calculates absoluteIndex by adding the folder index to the selector index. This works because folder indexes increment in hundreds, and the maximum number of selectors per folder is 40, which is fewer than one hundred.
  • We use recursion if resources added to the compileParts array also have co-dependent relationships.
function gatherCompileResources(compileResources, connectedEntities, projectEntities, projectCode, config){ let compileParts = compileResources.compileParts; // reasons: changed / coDependent / related const reasons = Object.keys(connectedEntities); for (const reason of reasons) { // types: variable / function / mixin / extend const types = Object.keys(connectedEntities[reason]); for (const type of types) { // names: e.g. toRem / .btn / primary_color const names = Object.keys(connectedEntities\[reason\][type]); for (const name of names) { // check side-effects for Sass entity (if not checked already) if (!checkObject(config.relatedChecked, [type, name])){ updateObject(config.relatedChecked, [type, name], 1); const relatedEntities = checkObject(projectEntities, [type, name, 'relatedEntities']); if (relatedEntities){ compileParts = gatherCompileResources( compileResources, { related: relatedEntities }, projectEntities, projectCode, config ); } } // check if there are dependent pieces of code const itemDeps = checkObject(projectEntities, [type, name, 'itemDeps']); if (itemDeps && itemDeps.length > 0){ for (const dep of itemDeps) { let path = dep.path, resourceID = path.join('.'); if (!config.resourceAdded[resourceID]){ // if we have a valid resource let resource = checkObject(projectCode, path); if (resource){ config.resourceAdded[resourceID] = 1; // get folder index + resource index let absoluteIndex = getAbsoluteIndex(path); // add compile part compileParts[absoluteIndex] = { sassCode: resource.sassCode, mediaQuery: resource.mediaQuery, path: path }; // if resource is co-dependent, pull in others let coDependent = getCoDependent(resource); if (coDependent){ compileParts = gatherCompileResources( compileResources, { coDependent: coDependent }, projectEntities, projectCode, config ); } } } } } } } } return compileParts; } The application process

We’ve covered the technical aspects now. To see how it all ties together, let’s walk through the data processing steps.

From keystroke to style render
  1. A user keystroke fires the textarea change event.
  2. We convert the single selector being edited into a sassEntities object. This allows for comparison with the pre-edit Sass entities: projectCode > dataItem > sassEntities.
  3. If any Sass entities changed:

    • We update projectCode > dataItem > sassEntities.
    • If an @extend rule changed:
      • We search the projectCode object to find matching selectors.
      • We store the path for matching selectors on the current data item: projectCode > dataItem > sassEntities > extend > target > [ path ].
    • We rebuild the projectEntities object by looping over the projectCode object.
    • We populate connectedEntities > changed with the change analysis.
    • If extend, variable, function, or mixin entities are present:

      • We populate connectedEntities > coDependent with the relevant entities.
  4. The recursive gatherCompileResources function uses the connectedEntities object to populate the compileResources object.
  5. We concatenate the compileResources > compileParts array into a single Sass string.
  6. We compile the single Sass string to CSS.
  7. We use comment dividers to split the output into an array: compileResources > cssParts. This array lines up with the compileResources > compileParts array via matching array keys.
  8. We use resource paths to update the projectCode object with compiled CSS.
  9. We write the CSS for a given folder or file to a style node in the document head for immediate style rendering. On the server-side, we write all CSS to a single stylesheet.
Considerations for npm

There are some extra considerations for an npm package. With a typical NodeJS development environment:

  • Users edit selectors as part of a larger file, rather than individually.
  • Sass imports are likely to play a larger role.
Segmentation of code

Microthemer’s visual view segments individual selectors. This makes parsing code to a sassEntities object super fast. Parsing whole files might be a different story, especially large ones.

Perhaps techniques exist for virtually segmenting system files? But suppose there is no way around parsing whole files. Or it just seems sensible for a first release. Maybe it’s sufficient to advise end users to keep Sass files small for best results.

Sass imports

At the time of writing, Microthemer doesn’t analyse import files. Instead, it includes all Sass imports whenever a selector makes use of any Sass entities. This is an interim first release solution that is okay in the context of Microthemer. But I believe an npm implementation should track Sass usage across all project files.

Our projectCode object already has a files property for storing file data. I propose calculating file indexes relative to the main Sass file. For instance, the file used in the first @import rule would have index: 0, the next, index: 1, and so on. We would need to scan @import rules within imported files to calculate these indexes correctly.

We would need to calculate absoluteIndex differently, too. Unlike Microthemer folders, system files can have any number of selectors. The compileParts array might need to be an object, storing an array of parts for each file. That way, we only keep track of selector indexes within a given file and then concatenate the compileParts arrays in the order of the files.

Conclusion

This article introduces a new way to compile Sass code, selectively. Near instant Sass compilation was necessary for Microthemer because it is a live CSS editor. And the word 'live' carries certain expectations of speed. But it may also be desirable for other environments, like Node.js. This is for Node.js and Sass users to decide, and hopefully share their thoughts in the comments below. If the demand is there, I hope an npm developer can take advantage of the points I’ve shared.

Please feel free to post any questions about this in my forum. I'm always happy to help.

The post A Proof of Concept for Making Sass Faster appeared first on CSS-Tricks.

An Updated List of Our Favorite Jetpack Features for WordPress

Css Tricks - Tue, 09/17/2019 - 4:18am

It's hard to articulate every reason to use Jetpack for your WordPress site. It's taken us a series of posts to unpack it because it's capable of doing so gosh darn much — a lof of which we put to use right here on CSS-Tricks.

The thing is that Jetpack is very much an active project and keeps improving with each and every release. While we've covered many Jetpack features and uses over the years, it's worth revisiting here in 2019 to compile a list of personal favorites, both classic and new.

It monitors downtime

Wouldn't it be nice to be notified if your site crashes for some reason? Well, Jetpack can monitor your site for you and alert you if something's gone awry. Sure, there are other services, like New Relic or Pingdom that do this as well, but how great is it to not have to integrate yet another service on another platform? That's the benefit of using Jetpack. You're gonna get so many other features with it already, so there's need to look outside for a solution it already provides.

It lets people follow your blog

Let's say you're interested in starting a newsletter so you can send new posts to subscribers and you're looking into services like Mailchimp and Campaign Monitor to carry the lift. At the same time, you're trying to keep costs down and would rather not pay an additional service for this ability.

Well, you guessed it, Jetpack will do that for you. All it takes is flipping on the feature and a subscribe option will be added to your post comment form. Anyone who signs up will receive a notification in their inbox each time a new post is published.

Even better, you can see all your subscribers and flip an additional toggle that allows visitors to subscribe just to follow the comments for a specific post.

It comes with a CDN

Jetpack includes a free Content Delivery Network (CDN) that optimizes and delivers all your static files for you. And that's any static file, including images, videos, CSS and JavaScript. Yep, again, there's really no need to look outside the box to serve the most efficient assets to your visitors and get a hefty speed boost for your site.

Speaking from a cost/value perspective, especially since this feature is available on the free Jetpack plan as well, this tops the charts.

It embeds rich media for you

Want to embed a YouTube video in your post? Or a tweet? Maybe an Instagram post or a gist? A Spotify playlist? Jetpack will embed any and all of those among many, many others with either a simple URL or a WordPress shortcode. And it works whether you're using the Block Editor, the Classic Editor, or even a sidebar widget. It's the easiest way to embed media in a WordPress post with having to get into iframes or touching any code.

Like the other features we've covered here, all it takes to enable this is the flip of a switch, on the Jetpack → Settings → Writing screen.

It adds tons of options to the Block Editor

The new Block Editor (aka Gutenberg) already includes a number of blocks that make editing and publishing posts more flexible and versatile than ever, but Jetpack gives it an extra dose of additional blocks to make designing page/post layouts even more awesome.

In fact, we covered this in greater detail including each of the blocks Jetpack includes and how they can be used.

It supports Markdown

Working in the Block and Visual Editors in WordPress is great most of the time, but have you ever needed to adjust the markup of a post to get things juuuust right? WordPress has the "Text" editor as well as an HTML block, but of course, that only supports HTML.

Markdown is much easier to write and Jetpack lets you use it in the editor.

As you can tell, we love Jetpack around here and think anyone with a WordPress site ought to give it a try. It packs so many features into a single package that you get the same benefit as using dozens of other plugins, without the constant update madness.

The post An Updated List of Our Favorite Jetpack Features for WordPress appeared first on CSS-Tricks.

Underground World & the man who (thought he) knew everything

Typography - Mon, 09/16/2019 - 7:51pm

Often described as the man who knew everything, Athanasius Kircher (1602–80) was a German Jesuit polymath of international renown during his own lifetime. He was a prolific author with an astoundingly broad range of interests, writing about everything, from geology and geography to sinology and egyptology, biology, medicine, engineering, theology, anthropology, music theory and linguistics. […]

The post Underground World & the man who (thought he) knew everything appeared first on I Love Typography.

CSS-Tricks Chronicle XXXVI

Css Tricks - Mon, 09/16/2019 - 9:48am

This is one of these little roundups of things going on with myself, this site, and the other sites that are part of the CSS-Tricks family.

I was recently in Zürich for Front Conference. It was my first time there and I very much enjoyed the city and the lovely staff of the conference. I was terribly jetlagged for my opener talk so I feel like I didn't quite nail it how I wanted to, but whattyagonnado.

It's named "How to Think Like a Front-End Developer" but it's really more like an adaptation of "ooooops I guess we’re full-stack developers now."

I've packed in several more conferences this fall:

  1. 13 SEP 2019 - Web Unleashed - Toronto, Canada
  2. 18 SEP 2019 - Dot All - Montreal, Canada
  3. 30 SEP 2019 - ARTIFACT - Austin, Texas - Use coupon code LASTCHANCE200 for this one.
  4. 13 OCT 2019 - All Things Open - Raleigh, North Carolina
  5. 16 OCT 2019 - JAMstack_conf - San Francisco, California

Speaking of conferences, if you know of any coming up that aren't on our master list of front-end related web conferences, please do a pull request or contact me.

If we've got anything at ShopTalk Show, it's consistency! I don't even remember the last time we've missed a week, and I enjoy making the show just as much now as I ever have.

Perhaps my favorite show of late was just chatting with Dave about what technology we would pick if on a greenfield (from scratch) project under different circumstances.

But mostly we chat with folks like Tyler McGinnis, Adam Argyle, Rachel Andrew, and Lara Hogan.

We're moving right along at CodePen as well!

  • You can now export Pens with a build process, meaning after an npm install, you have an offline version of CodePen to work with. Need to spin up a little processing environment for like Markdown/Sass/React/Babel? Just set up a blank Pen that way, export it, and you've got it.
  • We're building more and more of CodePen in React, and I think we're past the tipping point where the value in that becomes more and more clear. It's a good technological fit for our type of site. For example, we re-wrote how items are displayed and grids-of-items across the site. So now we build some little feature into it like "pinning" items, and it instantly sprinkles out to all the grids on the entire site. Same with filtering and view options.
  • Along those same lines, little moments like this feel very satisfying to me. That's related to our "Private by Default" feature.
  • We released a feature so you can block other users if it comes down to that (as well as report them to us).
  • We released some high contrast syntax highlighting themes that are both more accessible and darn nice to look at.

I got to be on Giant Robots!

On Giant Robots @chriscoyier, cofounder of @CodePen, creator of CSS-Tricks, & host of @ShopTalkShow, candidly shares how a weekend project turned into a full-time business and aspirations for the future.https://t.co/vPNDflGOwz pic.twitter.com/RChQcVBfeY

— thoughtbot (@thoughtbot) September 16, 2019

We started an Instagram account at @real_css_tricks. The plan is just little educational tidbits.

The post CSS-Tricks Chronicle XXXVI appeared first on CSS-Tricks.

(Why) Some HTML is “optional”

Css Tricks - Mon, 09/16/2019 - 6:34am

Remy Sharp digs into the history of the web and describes why the <p> tag doesn’t need to be closed like this:

<p>Paragraphs don’t need to be closed <p>Pretty weird, huh?

Remy writes:

Pre-DOM, pre-browsers, the world's first browser was being written by Sir Tim Berners-Lee. There was no reference implementation and certainly no such thing as a parsing specification. The first browser, the WorldWideWeb.app, parsed HTML character by character applying styles as it went along. As opposed to today's methods whereby a document object model is built up, then rendered.

[...] The paragraph tag (yes, in upper case) was intended to separate paragraphs, not wrap them.

<P> Paragraph one. <P> Paragraph two. <P> Paragraph three.

Weird, huh! Remy wrote this in response to Chris’ post the other day about optional HTML and how browsers will close certain tags for us or even insert the right elements in place.

Direct Link to ArticlePermalink

The post (Why) Some HTML is “optional” appeared first on CSS-Tricks.

Web Development Merit Badges

Css Tricks - Mon, 09/16/2019 - 4:30am
Changed a DNS record and everything worked just fine Comprehended someone else's RegEx Built an accordion from scratch Exited VIM Accidentally created own CMS Pulled off a design you didn’t think you could Told a client/boss "No, we're not doing that." Wrote an HTAccess redirect that included a capture group Refactored a large portion of CSS and didn't break anything Centered an element vertically and horizontally Migrated a database without character encoding issues Pushed to production on Friday and didn't roll it back over the weekend Merged master into a six month old branch Had a neglected site get hacked and spammed Used CSS Grid in production Someone you don't know starred one of your GitHub Repositories Hand-coded a HTML email Gave someone useful feedback on a Pull Request Debugged something for over one hour where the fix was literally one character Solved a bug by taking a nap Became extremely confused by a CORS error Quoted the exact number of hours it took to do the job Renewed an SSL certificate without any drama Found an answer to an issue on StackOverflow Rocked the Checkbox Hack on a project Your personal website hasn't been updated in at least 5 years

The post Web Development Merit Badges appeared first on CSS-Tricks.

5G Will Definitely Make the Web Slower, Maybe

Css Tricks - Mon, 09/16/2019 - 4:27am

Scott Jehl has written this wonderful piece about how 5G is on the horizon and how it could cause problems for users. But first, he starts by talking about the overwhelming positive news about it:

[...] as it matures 5G is predicted to improve network speeds dramatically. Carriers are predicting download speeds in 2019 for anywhere from 100Mb to 1 Gbit per second on average.

This is...bonkers! Numbers like this make it seem as though the web’s performance problems are merely a matter of infrastructure. But Scott continues:

Faster networks should fix our performance problems, but so far, they have had an interesting if unintentional impact on the web. This is because historically, faster network speed has enabled developers to deliver more code to users—in particular, more JavaScript code.

During the years 2011 through 2019, 4g coverage spread from 5% to 79% of the world. During that same time period, the median average JavaScript transfer size to mobile devices increased by 611%, from 52kb to 372.9 KB.

When I read this, I thought of how adding extra lanes to highways actually causes more traffic, which is equally weird and counterintuitive. But networks are like highways in this way, as Scott shows above. He continues to look at how most phones won’t be using the latest and greatest tech and we’ll always have to consider the users that are using the slowest devices on the slowest networks, regardless of how fast our connection might be:

As networks improve, we have a huge opportunity to improve the web we build, but it’s on us to take that opportunity, or squander it.

Direct Link to ArticlePermalink

The post 5G Will Definitely Make the Web Slower, Maybe appeared first on CSS-Tricks.

caniemail.com

Css Tricks - Sat, 09/14/2019 - 4:03pm

As long as I can remember the main source for feature support in HTML email clients is Campaign Monitor's guide. Now there is a new player on the block: caniemail.com.

HTML email is often joked about in how you have to code for it in such an antiquated way (<table>s! really!) but that's perhaps not a fair shake. 2 years ago Kevin Mandeville talked about how he used CSS grid (not kidding) in an email:

Our Apple Mail audience at Litmus is approximately 30%, so a good portion of our subscriber base is able to see the grid desktop layout.

Where CSS Grid isn't supported (and for device/window widths of less than 850 pixels), we fell back to a one-column layout.

Just like websites, right? They don't have to look the same everywhere, as long as the experience is acceptable everywhere.

Rémi announces the new site:

... we have more than 50 HTML and CSS features tested across 25 emails clients. And we’ve got a lot more coming up in the following weeks and months.

We’re also delighted to present the Email Client Support Scoreboard. For the first time in history, we provide an objective ranking of email clients based on their support for HTML and CSS features.

Interested in grid support? They got it. The data is tucked into Front Matter in Markdown files in the repo.

Direct Link to ArticlePermalink

The post caniemail.com appeared first on CSS-Tricks.

Where should “Subscribe to Podcast” link to?

Css Tricks - Fri, 09/13/2019 - 12:20pm

For a while, iTunes was the big dog in podcasting, so if you linked "Subscribe to Podcast" to like:

https://podcasts.apple.com/podcast/id493890455

...that would make sense. It's a web URL anyway, so it will work for anyone and has information about the podcast, as well as a list of recent shows you can even listen to right there. For Apple folks, you might be redirected in-app (mobile) or it becomes one click away (desktop). But for folks on Android or Linux or Windows or something, that's not particularly useful.

What are the other possibilities?

Podcasts are essentially dressed up RSS, so giving people a link to the feed isn't out of the question. We do that on both ShopTalk and CodePen Radio:

I like PocketCasts for my podcasts. I feel like this used to be more obvious, but pasting in an RSS link to search does seem to find the feeds.

I would think (and hope!) that most podcast apps have some way to subscribe manually via feed. But... pretty nerdy and probably a little too dangerous for just a "Subscribe to Podcast" link.

For Android specifically, there is a site where you can put your feed URL after "subscribeonandroid.com" and get a special page just for that:

https://subscribeonandroid.com/blog.codepen.io/feed/podcast/

They say:

If the listener has a one click supported app on their android device, the App will load automatically.

And clearly there are some options:

I find the most common option on podcasts is to link to a soup of popular options:

I think that's probably a safe thing to do. For one, it signals that you're on top of your game a bit and that your show is working on major platforms. But more importantly, podcast listeners probably know what platform they mainly use and clicking on a link specifically for that platform is probably quite natural.

Speaking of major platforms, Spotify is going big on podcasts, so linking directly to Spotify probably isn't the worst choice you could make.

https://open.spotify.com/show/2PUoQB330ft0sTzSNoCPrH?si=ZUYOtZSZQZyrDdo81l7TcA

But there are situations where you only get one link. Instagram is notable for this. No links on posts — only the one link on your profile. You could send them to your website, but of course, with podcasts, the name of the game is making it easy to subscribe. That means getting people right there is best. But also with stuff like tweets, you can't always deliver a smorgasbord of links. Hence the title of this blog post. If you gotta link to just one place to subscribe, where should it be?

Looks like that's what Plink does.

Here's ShopTalk: https://plnk.to/shoptalk

Visiting on desktop gets you the smorgasbord of links. Visiting on my iPhone, I get a direct link to Apple Podcasts.

That's what they do:

Auto-open installed Podcast Apps native to listener's iOS, Android, and other mobile and smart watch devices. Each smart link also has a Show Page that desktop users will see with links to that show in Apps like Apple & Google Podcasts, Spotify, Stitcher, Overcast, and other podcatchers.

They apparently use all kinds of data to figure it out.

... will detect the listener's device, geo, and other factors and send them to your show in pre-installed podcast apps.

Anybody can make a redirect link to particular platforms. Like, we could have built shoptalkshow.com/spotify and shoptalkshow.com/itunes and redirected to those places, but what you get here is fancy auto-detection in a single link.

I signed up for it for ShopTalk, so we'll see if we end up using it much or not.

The post Where should “Subscribe to Podcast” link to? appeared first on CSS-Tricks.

Meditations on Snowflakes

Typography - Fri, 09/13/2019 - 5:52am

Born in December 1571 in southwest Germany, Johannes Kepler would go on to become one of the greatest observational astronomers of all time. He would also write books that forever transformed our view of the cosmos. He is best known for his three laws of planetary motion that describe the motion of planets around the […]

The post Meditations on Snowflakes appeared first on I Love Typography.

Ghost Buttons with Directional Awareness in CSS

Css Tricks - Fri, 09/13/2019 - 3:49am

It would surprise me if you'd never come across a ghost button &#x1f47b;. You know the ones: they have a transparent background that fills with a solid color on hover. Smashing Magazine has a whole article going into the idea. In this article, we’re going to build a ghost button, but that will be the easy part. The fun and tricky part will be animating the fill of that ghost button such that the background fills up in the direction from which a cursor hovers over it.

Here’s a basic starter for a ghost button:

See the Pen
Basic Ghost Button &#x1f47b;
by Jhey (@jh3y)
on CodePen.

In most cases, the background-color has a transition to a solid color. There are designs out there where the button might fill from left to right, top to bottom, etc., for some visual flair. For example, here’s left-to-right:

See the Pen
Directional filling Ghost Button &#x1f47b;
by Jhey (@jh3y)
on CodePen.

There's a UX nitpick here. It feels off if you hover against the fill. Consider this example. The button fills from the left while you hover from the right.

Hover feels off &#x1f44e;

It is better if the button fills from our initial hover point.

Hover feels good &#x1f44d;

So, how can we give the button directional awareness? Your initial instinct might be to reach for a JavaScript solution, but we can create something with CSS and a little extra markup instead.

For those in camp TL;DR, here are some pure CSS ghost buttons with directional awareness!

See the Pen
Pure CSS Ghost Buttons w/ Directional Awareness ✨&#x1f47b;&#x1f60e;
by Jhey (@jh3y)
on CodePen.

Let’s build this thing step by step. All the code is available in this CodePen collection.

Creating a foundation

Let’s start by creating the foundations of our ghost button. The markup is straightforward.

<button>Boo!</button>

Our CSS implementation will leverage CSS custom properties. These make maintenance easier. They also make for simple customization via inline properties.

button { --borderWidth: 5; --boxShadowDepth: 8; --buttonColor: #f00; --fontSize: 3; --horizontalPadding: 16; --verticalPadding: 8; background: transparent; border: calc(var(--borderWidth) * 1px) solid var(--buttonColor); box-shadow: calc(var(--boxShadowDepth) * 1px) calc(var(--boxShadowDepth) * 1px) 0 #888; color: var(--buttonColor); cursor: pointer; font-size: calc(var(--fontSize) * 1rem); font-weight: bold; outline: transparent; padding: calc(var(--verticalPadding) * 1px) calc(var(--horizontalPadding) * 1px); transition: box-shadow 0.15s ease; } button:hover { box-shadow: calc(var(--boxShadowDepth) / 2 * 1px) calc(var(--boxShadowDepth) / 2 * 1px) 0 #888; } button:active { box-shadow: 0 0 0 #888; }

Putting it all together gives us this:

See the Pen
Ghost Button Foundation &#x1f47b;
by Jhey (@jh3y)
on CodePen.

Great! We have a button and a hover effect, but no fill to go with it. Let’s do that next.

Adding a fill

To do this, we create elements that show the filled state of our ghost button. The trick is to clip those elements with clip-path and hide them. We can reveal them when we hover over the button by transitioning the clip-path.

Child element with a 50% clip

They must line up with the parent button. Our CSS variables will help a lot here.

At first thought, we could have reached for pseudo-elements. There won't be enough pseudo-elements for every direction though. They will also interfere with accessibility... but more on this later.

Let's start by adding a basic fill from left to right on hover. First, let's add a span. That span will need the same text content as the button.

<button>Boo! <span>Boo!</span> </button>

Now we need to line our span up with the button. Our CSS variables will do the heavy lifting here.

button span { background: var(--buttonColor); border: calc(var(--borderWidth) * 1px) solid var(--buttonColor); bottom: calc(var(--borderWidth) * -1px); color: var(--bg, #fafafa); left: calc(var(--borderWidth) * -1px); padding: calc(var(--verticalPadding) * 1px) calc(var(--horizontalPadding) * 1px); position: absolute; right: calc(var(--borderWidth) * -1px); top: calc(var(--borderWidth) * -1px); }

Finally, we clip the span out of view and add a rule that will reveal it on hover by updating the clip. Defining a transition will give it that cherry on top.

button span { --clip: inset(0 100% 0 0); -webkit-clip-path: var(--clip); clip-path: var(--clip); transition: clip-path 0.25s ease, -webkit-clip-path 0.25s ease; // ...Remaining div styles } button:hover span { --clip: inset(0 0 0 0); }

See the Pen
Ghost Button w/ LTR fill &#x1f47b;
by Jhey (@jh3y)
on CodePen.

Adding directional awareness

So, how might we add directional awareness? We need four elements. Each element will be responsible for detecting a hover entry point. With clip-path, we can split the button area into four segments.

Four :hover segments

Let's add four spans to a button and position them to fill the button.

<button> Boo! <span></span> <span></span> <span></span> <span></span> </button> button span { background: var(--bg); bottom: calc(var(--borderWidth) * -1px); -webkit-clip-path: var(--clip); clip-path: var(--clip); left: calc(var(--borderWidth) * -1px); opacity: 0.5; position: absolute; right: calc(var(--borderWidth) * -1px); top: calc(var(--borderWidth) * -1px); z-index: 1; }

We can target each element and assign a clip and color with CSS variables.

button span:nth-of-type(1) { --bg: #00f; --clip: polygon(0 0, 100% 0, 50% 50%, 50% 50%); } button span:nth-of-type(2) { --bg: #f00; --clip: polygon(100% 0, 100% 100%, 50% 50%); } button span:nth-of-type(3) { --bg: #008000; --clip: polygon(0 100%, 100% 100%, 50% 50%); } button span:nth-of-type(4) { --bg: #800080; --clip: polygon(0 0, 0 100%, 50% 50%); }

Cool. To test this, let's change the opacity on hover.

button span:nth-of-type(1):hover, button span:nth-of-type(2):hover, button span:nth-of-type(3):hover, button span:nth-of-type(4):hover { opacity: 1; } So close

Uh-oh. There's an issue here. If we enter and hover one segment but then hover over another, the fill direction would change. That's going to look off. To fix this, we can set a z-index and clip-path on hover so that a segment fills the space.

button span:nth-of-type(1):hover, button span:nth-of-type(2):hover, button span:nth-of-type(3):hover, button span:nth-of-type(4):hover { --clip: polygon(0 0, 100% 0, 100% 100%, 0 100%); opacity: 1; z-index: 2; }

See the Pen
Pure CSS Directional Awareness w/ clip-path &#x1f47b;
by Jhey (@jh3y)
on CodePen.

Putting it all together

We know how to create the fill animation, and we know how to detect direction. How can we put the two together? Use the sibling combinator!

Doing so means when we hover a directional segment, we can reveal a particular fill element.

First, let's update the markup.

<button> Boo! <span></span> <span></span> <span></span> <span></span> <b>Boo!</b> <b>Boo!</b> <b>Boo!</b> <b>Boo!</b> </button>

Now, we can update the CSS. Referring to our left-to-right fill, we can reuse the styling. We only need to set a specific clip-path for each element. I've approached the ordering the same as some property values. The first child is top, the second is right, and so on.

button b:nth-of-type(1) { --clip: inset(0 0 100% 0); } button b:nth-of-type(2) { --clip: inset(0 0 0 100%); } button b:nth-of-type(3) { --clip: inset(100% 0 0 0); } button b:nth-of-type(4) { --clip: inset(0 100% 0 0); }

The last piece is to update the clip-path for the relevant element when hovering the paired segment.

button span:nth-of-type(1):hover ~ b:nth-of-type(1), button span:nth-of-type(2):hover ~ b:nth-of-type(2), button span:nth-of-type(3):hover ~ b:nth-of-type(3), button span:nth-of-type(4):hover ~ b:nth-of-type(4) { --clip: inset(0 0 0 0); }

Tada! We have a pure CSS ghost button with directional awareness.

See the Pen
Pure CSS Ghost Button w/ Directional Awareness &#x1f47b;
by Jhey (@jh3y)
on CodePen.

Accessibility

In its current state, the button isn't accessible.

The extra markup is read by VoiceOver.

Those extra elements aren't helping much as a screen reader will repeat the content four times. We need to hide those elements from a screen reader.

<button> Boo! <span></span> <span></span> <span></span> <span></span> <b aria-hidden="true">Boo!</b> <b aria-hidden="true">Boo!</b> <b aria-hidden="true">Boo!</b> <b aria-hidden="true">Boo!</b> </button>

No more repeated content.

See the Pen
Accessible Pure CSS Ghost Button w/ Directional Awareness &#x1f47b;
by Jhey (@jh3y)
on CodePen.

That’s it!

With a little extra markup and some CSS trickery, we can create ghost buttons with directional awareness. Use a preprocessor or put together a component in your app and you won't need to write out all the HTML, too.

Here's a demo making use of inline CSS variables to control the button color.

See the Pen
Pure CSS Ghost Buttons w/ Directional Awareness ✨&#x1f47b;&#x1f60e;
by Jhey (@jh3y)
on CodePen.

The post Ghost Buttons with Directional Awareness in CSS appeared first on CSS-Tricks.

Weekly Platform News: Apple Deploys Web Components, Progressive HTML Rendering, Self-Hosting Critical Resources

Css Tricks - Thu, 09/12/2019 - 1:33pm

In this week's roundup, Apple gets into web components, how Instagram is insta-loading scripts, and some food for thought for self-hosting critical resources.

Apple deploys web components built using Stencil

The new Apple Music web app (beta) uses a JavaScript framework (Ember.js) but also standard web components such as <apple-music-video-player> that are built using Stencil, a web component compiler.

Stencil is a build-time tool that generates standard web components with minimal overhead, while providing core features such as templating, state management, and routing, as well as performance features such as code-splitting and lazy-loading.

Apple just deployed into production nearly 50 web components powering a major app they have a significant amount of revenue and strategic value riding on. You can’t say that “no one uses web components” or they are “solving problems that don‘t exist or have been solved better in user land” with a straight face anymore.

(via Max Lynch)

Instagram makes use of chunked transfer encoding and progressive HTML rendering

Instagram’s website uses HTTP chunked transfer encoding to stream the contents of the HTML document to the browser as each part of the page is generated on the server.

We can flush the HTML <head> to the browser almost immediately ... This allows the browser to start downloading scripts and stylesheets while the server is busy generating the dynamic data in the rest of the page.

They also use this technique to flush JSON data to the page in <script> elements. The client script waits for this data (using Promise) instead of requesting it via XHR.

(via Glenn Conner)

Consider self-hosting your critical resources

One section of University of Notre Dame’s website used to load jQuery from Google’s CDN, which could result in very long loading times (100+ seconds) when visiting the site from China. They’ve resolved the issue by self-hosting jQuery instead.

(via Erik Runyon)

Read even more news in my weekly Sunday issue. Visit webplatform.news for more information.

The post Weekly Platform News: Apple Deploys Web Components, Progressive HTML Rendering, Self-Hosting Critical Resources appeared first on CSS-Tricks.

Simplicity

Css Tricks - Thu, 09/12/2019 - 8:14am

Earlier this week, Bastian Allgeier published some interesting thoughts about complexity in web development and how changing simple things can often feel far more difficult than they need to be:

You want to build a JS file? Please update Webpack first. Oh, that new version of Webpack is no longer compatible with your Node version. Oh, your new Node version is no longer compatible with that other dependency. Oh, now you have 233 detected security issues in all your node_modules but you can't fix them because that would break something completely unrelated.

It's a UX nightmare and I haven't found a single exception yet. Vue Cli or Parcel are the most positive examples, where positive means: not as horrible as the rest.

This dependency hell is also the reason why old projects are almost like sealed capsules. You can hardly let a project lie around for more than a year, because afterwards it's probably broken.

A couple of weeks ago, I returned to a web app that was built with a variety of tools I hadn’t updated in quite some time and realized that it would be an enormous effort to fix all the packages and dependencies; instead I should just start over again. I can certainly empathise with Bastian on this stuff.

This reminds me that Chris wrote a great essay not so long about simple web development and collected a ton of thoughts from other developers out there.

Direct Link to ArticlePermalink

The post Simplicity appeared first on CSS-Tricks.

Using Custom Properties to Wrangle Variations in Keyframe Animations

Css Tricks - Thu, 09/12/2019 - 4:22am

Have you ever wondered how to customize CSS animations keyframes without using any preprocessor feature, like mixins? I keep reaching for preprocessors for this reason, but it would be so nice to drop yet one more dependency and go with vanilla CSS.

Well, I found a way to account for variations within a keyframe animation using nothing but CSS and it’s thanks to custom properties! Let’s learn a little more about how CSS keyframes work and how we can enhance them with CSS and a touch of custom properties.

Understanding CSS animations inheritance

When we assign an animation to an element, we can customize some of its properties such as duration, delay, and so on. Let me show you a dummy example: we have two classes: .walk and .run. Both share the same animation (named breath) and .run executes the animation faster than .walk (0.5s to 2s, respectively).

@keyframes breath { from { transform: scale(0.5); } to { transform: scale(1.5); } } /* Both share the same animation, but walking is _slower_ than running */ .walk { animation: breath 2s alternate; } .run { animation: breath 0.5s alternate; }

Each time we reuse an animation, it can behave differently based on the properties we assign it. So, we can say that an animation inherits its behavior based on the element where it’s applied.

But what about the animation *rules* (the scale in this case)? Let’s go back to the breath animation example: The .walk class executes breath slower but it also needs to be deeper, so we need to change its scale value to be larger than it is for the .run class, which takes smaller, more frequent breaths.

The common approach in plain CSS is to duplicate the original animation and tweak the values directly in the class:

@keyframes breath { /* same as before... */ } /* similar to breath, but with different scales */ @keyframes breathDeep { from { transform: scale(0.3); } to { transform: scale(1.7); } } .walk { animation: breathDeep 2s alternate; } .run { animation: breath 0.5s alternate; }

While this works fine, there’s a better solution which allow us to reuse both the animation’s properties and its values! How? By taking advantage of CSS variables inheritance! Let’s see how:

/* breath behaves based on the CSS variables values that are inherited */ @keyframes breath { from { transform: scale(var(--scaleStart)); } to { transform: scale(var(--scaleEnd)); } } .walk { --scaleStart: 0.3; --scaleEnd: 1.7; animation: breath 2s alternate; } .run { --scaleStart: 0.8; --scaleEnd: 1.2; animation: breath 0.5s alternate; }

Cool, right? Now we don’t need to write duplicate animations to get varying effects from the same animation!

If you need to go even further, remember that we can also update CSS custom properties with JavaScript. Not only root variables, but also in specific elements. I find this incredible powerful because we can create more efficient animations by taking advantage of JavaScript without losing the native optimizations from CSS animation. It’s a win-win!

See the Pen
Dynamic CSS @keyframes w/ CSS Vanilla
by Sandrina Pereira (@sandrina-p)
on CodePen.

The post Using Custom Properties to Wrangle Variations in Keyframe Animations appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.