An argument against sliders!

Tabs: It’s Complicated™

I’ve said before one quick and powerful thing you can learn as a front-end developer just getting starting with JavaScript is changing classes.

const button = document.querySelector(".my-button"); const element = document.querySelector(".content");  button.addEventListener("click", function() {   element.classList.toggle("sparkles"); });

We could use that skill to build some tabs, right? Right.

We got this.

Say we have this changing classes ability in our skillset now and we need to build a tabbed interface. If we just add a little more code that deals with click handlers, we could probably wire up some simple tabs, like this:

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

Totally functional tabs. I might pat myself on the back a little here. See how I used those anchor links to create jump links between the link and the tabbed section? That’s mighty semantic, don’t you think? The tabs are accessible with a keyboard, have focus styles, and can be activated with the Return key.

Did we win? Case closed? Perfect tabs?

Nothing is ever so easy, is it?

One issue here is that we didn’t do anything special with keyboard handling, which tabbed interfaces may require. Heydon Pickering wrote about this:

Unlike a same-page link, a tab does not move the user to the associated section/panel of content. It just reveals the content visually. This is advantageous to sighted users (including sighted screen reader users) who wish to flit between different sections without having to wade back up the page each time they want to choose a new one.

This comes with an unfortunate side effect: If the user wishes to move to a section by keyboard and interact with its internal content, they have to step through any tabs to the right of the current tab, which are in focus order.

Turns out there is a whole checklist of other behavioral things tabs interfaces can and should be doing. In Heydon’s explanation, the Tab key actually acts as a way to jump from the tab itself to the content related to that tab, actually moving the focus. Shift+Tab brings them back. Then the arrow keys are used to change tabs. All this requires more JavaScript and even some HTML to allow for the focus state… plus a sprinkle of aria-* attributes which I lack the expertise to explain you why they are important at all.

In the end, like this:

See the Pen
Tab Interface (PE)
by Heydon (@heydon)
on CodePen.

So the question becomes: are our class-changing skills actually a detriment to the web because they don’t account for things like this? Is doing things with whatever basic tools we have a net loss for web accessibility? I dunno. Too big of a question for my little brain. It’s interesting to consider, though.

Part of it comes down to muscle memory.

If we learn to code tabs like that first demo there, we’ll tend to reach for that over and over so long as nobody bites our fingers off for doing it. I coded that demo in about three minutes because I’ve done it so many times. Creating those tabs is certainly part of my muscle memory.

There is plenty of talk about JavaScript frameworks being a scourge across the web because they seem to be ushering in an era of worst-in-class accessibility. But what if your muscle memory for building tabs was reaching for a pre-built tabs UI that brings along all the right functionality and left styling largely to you?

That’s what Reach UI tabs are (which assumes we’re working with React…).

I’m not telling you to go out and switch your projects to React so you can get some free tabs, but React is already massive. If good patterns like this become the defacto choice, then it’s possible that the effect is a net gain on accessibility. Seems possible to me, anyway. It might just stop me from poorly hand-coding a tabbed interface for the 359th time.

The post Tabs: It’s Complicated™ appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

Inclusively Hidden

Scott O’Hara recently published “Inclusively Hidden,” a nice walkthrough of the different ways to hide things on the web. Nothing is ever cut and dry when it comes to the web! What complicates this is that hidden begs the question: hidden for whom? Different answers to that have different solutions:

  • Hidden for everyone? display: none; or visibility: hidden; or the hidden attribute. (But watch out for that hidden attribute, says Monica Dinculescu.)
  • Hidden visually, but present for assistive tech? A .screen-reader-only class with a smattering of properties to do the job correctly.
  • Hidden for assistive tech, but not visually? The aria-hidden="true" attribute/value.

It’s worth grokking all this because it’s is a perfect example of why HTML and CSS is not some easy bolt-on skill for front-end web development. This is critical stuff that isn’t done as correctly as it should be.

If you like video, I did one called “Hiding Things with CSS” that goes over a lot of this.


As I write this, I’m freshly back from Smashing Conf in San Francisco. Sara Soueidan had a wonderful talk that covered some “hiding things” situations that are even less intuitive than what we might be accustomed to seeing.

One thing she covered was the inert attribute and how it can be used to skip interactive elements from keyboard tabbing. It can even be used on a parent element, nullifying everything inside it. I understood that part, but not entirely why it’s useful since it seems like you might as well use display: none; if an element is hidden and the elements inside aren’t meant to be in focus. But I’m sure it’s my lack of understanding, so I’m looking forward to Sara’s video to come out so I can re-watch it. It had to do with maintaining a non-awkward tabbing order.

Another thing Sara covered is that some folks who use assistive technology also tend to explore touch screens with haptics, moving about the page with their fingers looking for interactive elements. If you, say, replace a native checkbox with a styled checkbox, it’s possible to do that in a way thats mostly accessible by using a real checkbox that you hide and replace with a graphic, but Sara demoed how you can resize the checkbox over the top of the replacement and hide visually with opacity: 0; — that ensures someone can still find the element by touch. That doesn’t seem to be the default way this kind of thing is taught or built, so it’s great to see Sara calling it out. Yet another example of HTML and CSS being nuanced and tricky languages.

Direct Link to ArticlePermalink

The post Inclusively Hidden appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]

How to Get a Progressive Web App into the Google Play Store

PWA (Progressive Web Apps) have been with us for some time now. Yet, each time I try explaining it to clients, the same question pops up: “Will my users be able to install the app using app stores?” The answer has traditionally been no, but this changed with Chrome 72 which shipped a new feature called TWA (Trusted Web Activities).

Trusted Web Activities are a new way to integrate your web-app content such as your PWA with yourAndroid app using a protocol based on Custom Tabs.

In this article, I will use Netguru’s existing PWA (Wordguru) and explain step-by-step what needs to be done to make the application available and ready to be installed straight from the Google Play app store.

Some of the things we cover here may sound silly to any Android Developers out there, but this article is written from the perspective of a front-end developer, particularly one who has never used Android Studio or created an Android Application. Also, please do note that a lot of what we’re covering here is still extremely experimental since it’s limited to Chrome 72.

Step 1: Set up a Trusted Web Activity

Setting up a TWA doesn’t require you to write any Java code, but you will need to have Android Studio. If you’ve developed iOS or Mac software before, this is a lot like Xcode in that it provides a nice development environment designed to streamline Android development. So, grab that and meet me back here.

Create a new TWA project in Android Studio

Did you get Android Studio? Well, I can’t actually hear or see you, so I’ll assume you did. Go ahead and crack it open, then click on “Start a new Android Studio project.” From there, let’s choose the “Add No Activity” option, which allows us to configure the project.

The configuration is fairly straightforward, but it’s always good to know what is what:

  • Name The name of the application (but I bet you knew that).
  • Package name: An identifier for Android applications on the Play Store. It must be unique, so I suggest using the URL of the PWA in reverse order (e.g. com.netguru.wordguru).
  • Save location: Where the project will exist locally.
  • Language: This allows us to select a specific code language, but there’s no need for that since our app is already, you know, written. We can leave this at Java, which is the default selection.
  • Minimum API level: This is the version of the Android API we’re working with and is required by the support library (which we’ll cover next). Let’s use API 19.

There are few checkboxes below these options. Those are irrelevant for us here, so leave them all unchecked, then move on to Finish.

Add TWA Support Library

A support library is required for TWAs. The good news is that we only need to modify two files to fill that requirement and the both live in the same project directory: Gradle Scripts. Both are named build.gradle, but we can distinguish which is which by looking at the description in the parenthesis.

There’s a Git package manager called JitPack that’s made specifically for Android apps. It’s pretty robust, but the bottom line is that it makes publishing our web app a breeze. It is a paid service, but I’d say it’s worth the cost if this is your first time getting something into the Google Play store.

Editor Note: This isn’t a sponsored plug for JitPack. It’s worth calling out because this post is assuming little-to-no familiarity with Android Apps or submitting apps to Google Play and it has less friction for managing an Android App repo that connects directly to the store. That said, it’s totally not a requirement.

Once you’re in JitPack, let’s connect our project to it. Open up that build.gradle (Project: Wordguru) file we just looked at and tell it to look at JitPack for the app repository:

allprojects {   repositories {     ...     maven { url 'https://jitpack.io' }     ...   } }

OK, now let’s open up that other build.gradle file. This is where we can add any required dependencies for the project and we do indeed have one:

// build.gradle (Module: app)  dependencies {   ...   implementation 'com.github.GoogleChrome:custom-tabs-client:a0f7418972'   ... }

TWA library uses Java 8 features, so we’re going to need enable Java 8. To do that we need to add compileOptions to the same file:

// build.gradle (Module: app)  android {   ...   compileOptions {     sourceCompatibility JavaVersion.VERSION_1_8     targetCompatibility JavaVersion.VERSION_1_8   }   ... }

There are also variables called manifestPlaceholders that we’ll cover in the next section. For now, let’s add the following to define where the app is hosted, the default URL and the app name:

// build.gradle (Module: app)  android {   ...   defaultConfig {     ...     manifestPlaceholders = [       hostName: "wordguru.netguru.com",       defaultUrl: "https://wordguru.netguru.com",       launcherName: "Wordguru"     ]     ...   }   ... }

Provide app details in the Android App Manifest

Every Android app has an Android App Manifest (AndroidManifest.xml) which provides essential details about the app, like the operating system it’s tied to, package information, device compatibility, and many other things that help Google Play display the app’s requirements.

The thing we’re really concerned with here is Activity (<activity>). This is what implements the user interface and is required for the “Activities” in “Trusted Web Activities.”

Funny enough, we selected the “Add No Activity” option when setting up our project in Android Studio and that’s because our manifest is empty and contains only the application tag.

Let’s start by opening up the manfifest file. We’ll replace the existing package name with our own application ID and the label with the value from the manifestPlaceholders variables we defined in the previous section.

Then, we’re going to actually add the TWA activity by adding an <activity> tag inside the <application> tag.

  <manifest   xmlns:android="http://schemas.android.com/apk/res/android"   package="com.netguru.wordguru"> // highlight    <application     android:allowBackup="true"     android:icon="@mipmap/ic_launcher"     android:label="$ {launcherName}" // highlight     android:supportsRtl="true"     android:theme="@style/AppTheme">      <activity       android:name="android.support.customtabs.trusted.LauncherActivity"       android:label="$ {launcherName}"> // highlight        <meta-data         android:name="android.support.customtabs.trusted.DEFAULT_URL"         android:value="$ {defaultUrl}" /> // highlight               <intent-filter>         <action android:name="android.intent.action.MAIN" />         <category android:name="android.intent.category.LAUNCHER" />       </intent-filter>               <intent-filter android:autoVerify="true">         <action android:name="android.intent.action.VIEW"/>         <category android:name="android.intent.category.DEFAULT" />         <category android:name="android.intent.category.BROWSABLE"/>         <data           android:scheme="https"           android:host="$ {hostName}"/> // highlight       </intent-filter>     </activity>   </application> </manifest>

And that, my friends, is Step 1. Let’s move on to Step 2.

Step 2: Verify the relationship between the website and the app

TWAs require a connection between the Android application and the PWA. To do that, we use Digital Asset Links.

The connection must be set on both ends, where TWA is the application and PWA is the website.

To establish that connection we need to modify our manifestPlaceholders again. This time, we need to add an extra element called assetStatements that keeps the information about our PWA.

// build.gradle (Module: app)  android {   ...   defaultConfig {     ...     manifestPlaceholders = [       ...       assetStatements: '[{ "relation": ["delegate_permission/common.handle_all_urls"], ' +         '"target": {"namespace": "web", "site": "https://wordguru.netguru.com"}}]'       ...     ]     ...   }   ... }

Now, we need to add a new meta-data tag to our application tag. This will inform the Android application that we want to establish the connection with the application specified in the manifestPlaceholders.

  <manifest   xmlns:android="http://schemas.android.com/apk/res/android"   package="$ {packageId}">    <application>     ...       <meta-data         android:name="asset_statements"         android:value="$ {assetStatements}" />     ...   </application> </manifest>

That’s it! we just established the application to website relationship. Now let’s jump into the conversion of website to application.

To establish the connection in the opposite direction, we need to create a .json file that will be available in the app’s /.well-known/assetlinks.json path. The file can be created using a generator that’s built into Android Studio. See, I told you Android Studio helps streamline Android development!

We need three values to generate the file:

  • Hosting site domain: This is our PWA URL (e.g. https://wordguru.netguru.com/).
  • App package name: This is our TWA package name (e.g. com.netguru.wordguru).
  • App package fingerprint (SHA256): This is a unique cryptographic hash that is generated based on Google Play Store keystore.

We already have first and second value. We can get the last one using Android Studio.

First we need to generate signed APK. In the Android Studio go to: Build → Generate Signed Bundle or APK → APK.

Next, use the existing keystore, if you already have one. If you need one, go to “Create new…” first.

Then let’s fill out the form. Be sure to remember the credentials as those are what the application will be signed with and they confirm your ownership of the application.

This will create a keystore file that is required to generate the app package fingerprint (SHA256). This file is extremely important as it is works as a proof that you are the owner of the application. If this file is lost, you will not be able to do any further updates to your application in the store.

Next up, let’s select type of bundle. In this case, we’re choosing “release” because it gives us a production bundle. We also need to check the signature versions.

This will generate our APK that will be used later to create a release in Google Play store. After creating our keystore, we can use it to generate required app package fingerprint (the SHA256).

Let’s head back to Android Studio, and go to Tools → App Links Assistant. This will open a sidebar that shows the steps that are required to create a relationship between the application and website. We want to go to Step 3, “Declare Website Association” and fill in required data: Site domain and Application ID. Then, select the keystore file generated in the previous step.

After filling the form press “Generate Digital Asset Links file” which will generate our assetlinks.json file. If we open that up, it should look something like this:

[{   "relation": ["delegate_permission/common.handle_all_urls"],   "target": {     "namespace": "android_app",     "package_name": "com.netguru.wordguru",     "sha256_cert_fingerprints": ["8A:F4:....:29:28"]   } }]

This is the file we need to make available in our app’s /.well-known/assetlinks.json path. I will not describe how to make it available on that path as it is too project-specific and outside the scope of this article.

We can test the relationship by clicking on the “Link and Verify” button. If all goes well, we get a confirmation with “Success!”

Yay! We’ve established a two-way relationship between our Android application and our PWA. It’s all downhill from here, so let’s drive it home.

Step 3: Get required assets

Google Play requires a few assets to make sure the app is presented nicely in the store. Specifically, here’s what we need:

  • App Icons: We need a variety of sizes, including 48×48, 72×72, 96×96, 144×144, 192×192… or we can use an adaptive icon.
  • High-res Icon: This is a 512×512 PNG image that is used throughout the store.
  • Feature Graphic: This is a 1024×500 JPG or 24-bit PNG (no alpha) banner that Google Play uses on the app details view.
  • Screenshots: Google Play will use these to show off different views of the app that users can check out prior to downloading it.

Having all those, we can proceed to the Google Play Store developers console and publish the application!

Step 4: Publish to Google Play!

Let’s go to the last step and finally push our app to the store.

Using the APK that we generated earlier (which is located in the AndroidStudioProjects directory), we need to go to the Google Play console to publish our application. I will not describe the process of publishing an application in the store as the wizard makes it pretty straightforward and we are provided step-by-step guidance throughout the process.

It may take few hours for the application to be reviewed and approved, but when it is, it will finally appear in the store.

If you can’t find the APK, you can create a new one by going to Build → Generate signed bundle / APK → Build APK, passing our existing keystore file and filling the alias and password that we used when we generated the keystore. After the APK is generated, a notice should appear and you can get to the file by clicking on the “Locate” link.

Congrats, your app is in Google Play!

That’s it! We just pushed our PWA to the Google Play store. The process is not as intuitive as we would like it to be, but still, with a bit of effort it is definitely doable, and believe me, it gives that great filling at the end when you see your app displayed in the wild.

It is worth pointing out that this feature is still very much early phase and I would consider it experimental for some time. I would not recommend going with a production release of your application for now because this only works with Chrome 72 and above — any version before that will be able to install the app, but the app itself will crash instantly which is not the best user experience.

Also, the official release of custom-tabs-client does not support TWA yet. If you were wondering why we used raw GitHub link instead of the official library release, well, that’s why.

The post How to Get a Progressive Web App into the Google Play Store appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

5 aspects to keep in mind when working with one-page website design

[Top]

An Event Apart Boston is Coming. Save Now!

(This is a sponsored post.)

An Event Apart Boston is almost here! We’re talking, like, less than a month away. If you’ve been holding off from registering, this might be your last chance because time and seating are both limited. Besides, we’re talking about three days of pure knowledge-dropping by an impressive lineup of speakers on a wide range of topics. Seriously, just look at the full schedule and prepare to be get stoked for a great time.

But, if a couple of weeks until show time is a little too tight for your liking, that’s where An Event Apart has you totally covered because there’s another one taking place in Washington D.C. this summer. And three more throughout the rest of the year in Chicago, Denver and San Francisco.

The reason an Event Apart is so near-and-dear to the CSS-Tricks family is that it scratches a common itch that we see come up around here often: how can we possibly stay on top of our careers as front-enders when our industry is changing at lightning speed and when we’re all-consumed trying to keep on top of our actual jobs? An Event Apart is our chance to take intention time away from the day-to-day and invest in our careers by learning from some of the best in the business, meeting folks who do what we do, and having those micro-interactions with others in the hallways that spark the interesting types of dialogues you just can’t get from Twitter.

Think about it: 17 speakers over three days covering everything from design systems and Progressive Web Apps to variable fonts and CSS Grid Layout. There’s so much to gain by attending. Just look at the awesome takeaways Chris got from An Event Apart Seattle in March.

And, to sweeten the pot, An Event Apart gave us a special discount code for CSS-Tricksters like yourself. Enter the AEACP at checkout to knock $ 100 off the price.

Hope to see you at one of the upcoming events!

Register Today

Direct Link to ArticlePermalink

The post An Event Apart Boston is Coming. Save Now! appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Creating Reusable Base Classes in TypeScript with a Real-Life Example

Hey CSS-Tricksters! Bryan Hughes was kind enough to take a concept from an existing post he published on converting to TypeScript and take it a few couple steps further in this post to elaborate on creating reusable base classes. While this post doesn’t require reading the other one, it’s certainly worth checking it out because it covers the difficult task of rewriting a codebase and writing unit tests to help the process.

Johnny-Five is an IoT and robotics library for Node.js. Johnny-Five makes it easy to interact with hardware by taking a similar approach that jQuery took to the web a decade ago: it normalizes the differences between various hardware platforms. Also like jQuery, Johnny-Five provides higher-level abstractions that make it easier to work with the platform.

Johnny-Five supports a wide array of platforms via IO Plugins, from the Arduino family, to the Tessel, to the Raspberry Pi, and many more. Each IO Plugin implements a standardized interface for interacting with lower-level hardware peripherals. Raspi IO, which I first created five years ago, is the IO plugin that implements support for the Raspberry Pi.

Any time there are multiple implementations that conform to one thing, there is a chance to share code. IO Plugins are no exception, however, we have not shared any code between IO Plugins to date. We recently decided, as a group, that we wanted to change this. The timing was fortuitous since I was planning on rewriting Raspi IO in TypeScript anyways, so I agreed to take on this task.

The goals of a base class

For those who many not be familiar with using class-based inheritance to enable code sharing, let’s do a quick walk-through of what I mean when I say “creating a base class to reuse code.”

A base class provides structure and common code that other classes can extend. Let’s take a look at a simplified TypeScript example base class that we will extend later:

abstract class Automobile {   private _speed: number = 0;   private _direction: number = 0;   public drive(speed: number): void {     this._speed = speed;   }      public turn(direction: number): void {     if (direction > 90 || direction < -90) {       throw new Error(`Invalid direction "$  {direction}"`);     }     this._direction = direction;   }      public abstract getNumDoors(): number; }

Here, we have created a base class that we call Automobile. This provides some basic functionality shared between all types of automobiles, whether it’s a car, a pickup, etc. Notice how this class is marked as abstract, and how there is one abstract method called getNumDoors. This method is dependent on the specific type of automobile. By defining it as an abstract class, we are saying that we require another class to extend this class and implement this method. We can do so with this code:

class Sedan extends Automobile {   public getNumDoors(): number {     return 4;   } }  const myCar = new Sedan(); myCar.getNumDoors(); // prints 4 myCar.drive(35);     // sets _speed to 35 myCar.turn(20);      // sets _direction to 20

We’re extending the Automobile class to create a four-door sedan class. We can now call all methods on both classes, as if it were a single class.

For this project, we’ll create a base class called AbstractIO that any IO plugin author can then extend to implement a platform-specific IO Plugin.

Creating the Abstract IO base class

Abstract IO is the base class I created to implement the IO Plugin spec for use by all IO Plugin authors, and is available today on npm.

Each author has their own unique style, some preferring TypeScript and others preferring vanilla JavaScript. This means that, first and foremost, this base class must conform to the intersection of TypeScript best practices and JavaScript best practices. Finding the intersection of best practices isn’t always obvious though. To illustrate, let’s consider two parts of the IO Plugin spec: the MODES property and the digitalWrite method, both of which are required in IO Plugins.

The MODES property is an object, with each key having a human readable name for a given mode type, such as INPUT, and the value being the numerical constant associated with the mode type, such as 0. These numerical values show up in other places in the API, such as the pinMode method. In TypeScript, we would want to use an enum to represent these values, but JavaScript doesn’t support it. In JavaScript, the best practice is to define a series of constants and put them into an object “container.”

How do we resolve this apparent split between best practices? Create one using the other! We start by defining an enum in TypeScript and define each mode with an explicit initializer for each value:

export enum Mode {  INPUT = 0,  OUTPUT = 1,  ANALOG = 2,  PWM = 3,  SERVO = 4,  STEPPER = 5,  UNKNOWN = 99 }

Each value is carefully chosen to map explicitly to the MODES property as defined by the spec, which is implemented as part of the Abstract IO class with the following code:

public get MODES() {  return {    INPUT: Mode.INPUT,    OUTPUT: Mode.OUTPUT,    ANALOG: Mode.ANALOG,    PWM: Mode.PWM,    SERVO: Mode.SERVO,    UNKNOWN: Mode.UNKNOWN  } }

With this, we have nice enums when we’re in TypeScript-land and can ignore the numerical values entirely. When we’re in pure JavaScript-land, we still have the MODES property we can pass around in typical JavaScript fashion so we don’t have to use numerical values directly.

But what about methods in the base class that derived classes must override? In the TypeScript world, we would use an abstract class, as we did in the example above. Cool! But what about the JavaScript side? Abstract methods are compiled out and don’t even exist in the output JavaScript, so we have nothing to ensure methods are overridden there. Another contradiction!

Unfortunately, I couldn’t come up with a way to respect both languages, so I defaulted to using the JavaScript approach: create a method in the base class that throws an exception:

public digitalWrite(pin: string | number, value: number): void {  throw new Error(`digitalWrite is not supported by $  {this.name}`); }

It’s not ideal because the TypeScript compiler doesn’t warn us if we don’t override the abstract base method. However, it does work in TypeScript (we still get the exception at runtime), as well as being a best practice for JavaScript.

Lessons learned

While working through the best way to design for both TypeScript and vanilla JavaScript, I determined that the best way to solve discrepancies is:

  1. Use a common best practice shared by each language
  2. If that doesn’t work, try to use the TypeScript best practice “internally” and map it to a separate vanilla JavaScript best practice “externally,” like we did for the MODES property.
  3. And if that approach doesn’t work, default to using the vanilla JavaScript best practice, like we did for the digitalWrite method, and ignore the TypeScript best practice.
  4. These steps worked well for creating Abstract IO, but these are simply what I discovered. If you have any better ideas I’d love to hear them in the comments!

    I discovered that abstract classes are not useful in vanilla JavaScript projects since JavaScript doesn’t have such a concept. This means that they are an anti-pattern here, even though abstract classes are a TypeScript best practice. TypeScript also doesn’t provide mechanisms to ensure type-safety when overriding methods, such as the override keyword in C#. The lesson here is that you should pretend that abstract classes don’t exist when targeting vanilla JavaScript users as well.

    I also learned that it’s really important to have a single source of truth for interfaces shared across modules. TypeScript uses duck typing as its core type system pattern, and is very useful inside any given TypeScript project. However, synchronizing types across separate modules using duck typing turned out to be more of a maintenance headache than exporting an interface from one module and importing it into another. I had to keep publishing little changes to modules until I got them aligned on their types, leading to excess version number churn.

    The final lesson I learned isn’t a new one: get feedback throughout the design process from library consumers. Knowing this going in, I set up two primary rounds of feedback. The first round was in person at the Johnny-Five collaborator’s summit where we brainstormed as a group. The second round was a pull request I opened against myself, despite being the only collaborator on Abstract IO with permission to merge pull requests. The pull request proved invaluable as we sifted through the details as a group. The code at the beginning of the PR bared little resemblance to the code when it was merged, which is good!

    Wrapping up

    Producing base classes destined to be consumed by both TypeScript and vanilla JavaScript users is a mostly straightforward process, but there are some gotchas. Since TypeScript is a superset of JavaScript, the two mostly share the same best practices. When differences in best practices do arise, a little creativity is required to find the best compromise.

    I managed to achieve my goals with Abstract IO, and implemented a base class that serves both TypeScript and vanilla JavaScript IO Plugin authors well. Turns out, it’s (mostly) possible to have your cake and eat it too!

    The post Creating Reusable Base Classes in TypeScript with a Real-Life Example appeared first on CSS-Tricks.

    CSS-Tricks

, , , , , ,
[Top]

Faking env() to Use it Now

There is already an env() function in CSS, but it kinda came out of nowhere as an Apple thing for dealing with “The Notch” but it has made it’s way to be a draft spec. The point will be for UAs or authors to declare variables that cannot be changed. Global const for CSS, sorta.

That spec doesn’t seem to suggest how we’ll actually set those env() values just yet. If you want them now, the easiest way to fake them would be using regular ol’ CSS custom properties and simply not change them.

But if you want that env() syntax though, there is a PostCSS plugin for emulating it. The way the plugin handles them is through a JavaScript file that declares them.

postcssCustomProperties({   importFrom: 'path/to/file.js' /* module.exports = {     environmentVariables: {       '--branding-padding': '20px',       '--branding-small': '600px'     }   } */ });

Having them start life as JavaScript is interesting, as it means we could perhaps have a single place to set variables that are accessible both to JavaScript and CSS.

That’s what Harry Nicholls covers more in his article, “Why you should use CSS env()” like some gotchas when dealing with units and such. But if you really needed a single source for unchangeable variables in both CSS and JavaScript, then I’d say this is a good way to go — and could potentially be ripped out once support for env() formally arrives.

The post Faking env() to Use it Now appeared first on CSS-Tricks.

CSS-Tricks

[Top]

Clever code

This week, Chris Ferdinandi examined a clever JavaScript snippet, one that’s written creatively with new syntax features, but is perhaps less readable and performant. It’s a quick read, but his callout of our industry’s fixation on cleverness is worth… calling out:

…we’ve become obsessed as an industry with brevity and clever code, and it results in code that’s sometimes less performant, and typically harder to read and make sense of for most people.

He made a similar argument late last month when he wrote about code readability, noting that brevity might look cool but ultimately leads to all sorts of issues in a codebase:

Often, web developers are obsessed with brevity. There’s this thing were developers will try to write the same function in the fewest number of characters possible.

Personally, I think brevity is pointless. Readability is a lot more important.

I entirely agree with Chris on this point, however, I think there is one important distinction to make and that’s the difference between code that’s intended as a prototype and code that’s intended for production. As Jeremy Keith argued a short while ago:

What’s interesting is that—when it comes to prototyping—our usual front-end priorities can and should go out the window. The priority now is speed. If that means sacrificing semantics or performance, then so be it. If I’m building a prototype and I find myself thinking “now, what’s the right class name for this component?”, then I know I’m in the wrong mindset. That question might be valid for production code, but it’s a waste of time for prototypes.

I agree with Chris that we should be writing code that is easy to read when we’re in production. I also think experimenting with code in this way is a good thing when it comes to prototypes. We shouldn’t ever shy away from playing with code and pushing things a little bit – so long as we’re not doing that in a giant web app with a a team of other developers working alongside us.


I’ve noticed that there are some folks that are doing genuinely ingenious things with Sass. I consistently sit back and think, “Wow, I’ve never seen anything like this before.” But when it comes to a production web app that has to be understood by hundreds of people at the same time, I don’t believe that this is the reaction we want when someone looks at the code.

As a result, I’ve been trying to write Sass code that is actually so simple that it almost looks dumb. One easy way to make code a lot simpler is to reduce the amount of nesting:

.element {   .heading { ... } }

This looks fine when there’s code inside — and it’s pretty easy to understand — but add a complex bit of design in the mix (say, using pseudo elements and media queries) and you suddenly have a rather complex set of rules in front of you. Creativity and cleverness can be harder to scan and identify one small part of the code that you’re looking for. Plus, in this example, we’ve unnecessarily made our .heading class a little bit more specific which might encourage us to override things in a hacky way elsewhere in the codebase.

We could write the following:

.element { ... }  .element-heading { ... }

I know this looks foolishly simple but the relationship between these two classes is easier to see and easier to extend in the future. Bundling all that code into a single nested class can get out of hand real fast. Even if it happens to look a lot cooler.

(As an aside, Andy Bell’s post on using the ampersand in Sass — and the resulting comments — is a great example of the clash between creativity and practicality.)

Anyway, the point I’m trying to make here is that CSS (and JavaScript for that matter) is a strange language because there are no definite rules you can make about it. It all really depends on the codebase and the project. But I think we can safely say that our code ought to be a lot more boring than our prototypes when it moves to production.

Continue to make prototypes that are wild and experimental or impossibly weird! Code quality be damned.

The post Clever code appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]

One or More of These 10 Top WordPress Plugins Can Take Your Site to The Next Level

[Top]