Web Standards

Fast, Good, Local Site Search with Jetpack

Css Tricks - Thu, 07/12/2018 - 3:43am

If you have, say, 20 posts/pages on your WordPress site, the search functionality that is baked right into your self-hosted WordPress site will probably do a great job. Search is a pretty cool feature to ship with WordPress, truth be told. But as a site grows, you'll find limits. How it works behind the scenes is a touch over my head, but as I understand it, it does a MySQL LIKE query on your post titles and post content. It tries its best to order by relevance (like if it finds an exact sentence match), then largely orders by date.

If search is super important to your site (here on CSS-Tricks, on-site search gets used a ton) you'll probably look for other options.

TLDR: Jetpack Search is quite good out of the box, customizable, and requires very little effort.

A quick jaunt through a decade-long journey.

I started with Google Site Search, which ultimately became Google Custom Search Engine. No bones about it, Google does incredible search results, and you can focus that lens directly on your own site. There is a catch here though. You're either going to have a bunch of ads in your search results, or you'll have to use the JSON API at a cost of $5 per 1,000 queries capped at 10k/day.

I'm all about paying a reasonable amount of money for quality search, so I tried Algolia for a while, as they have a WordPress plugin. I found it quite nice, but I couldn't quite get the search results as good as I liked. Nothing against Algoia here, it's quite an amazing product (we use it on CodePen for some stuff), but it wasn't a perfect fit for this site's blog search for me.

I considered trying out some similarly hardcore options like Amazon Cloudsearch (which also has a plugin) or even spinning up a Solr instance (same). But I was nervous about the technical debt. I've learned over the years that the solutions that I like and will last are the ones with the least maintenance and least work to get going.

I was pretty stoked when...

Jetpack rolled out search, powered by Elasticsearch. Because...

  • It's a feature of Jetpack, which I already have installed and working.
  • It's extremely little work to use. I pretty much just turned it on.
  • It has good search results right out of the box.
  • The little work there was included:
  • There is no load on my server.
  • I have total control over the design. It's a WordPress theme search.php page like any other.
Plus, filters!

Another killer feature here is being able to offer filters on the original search to users. This uses any taxonomy, most likely the built-in categories and tags that many sites already have:

Here on CSS-Tricks, I could, say, search for "grid" then further refine it to content that we've specifically tagged "css grid."

WP Tavern said it well

The Jetpack Professional plan’s $299/year price point is highly competitive for access to a hosted Elasticsearch engine. Ordinarily, developers looking for the most economical way to implement Elasticsearch on a WordPress site will have to host and manage their own instances on Amazon AWS or other cloud services. This often comes with more ongoing maintenance and setup.

What I like most about powering my search this way is that it feels like The WordPress Way.

It feels like it will be supported forever. Plus, I'll have a support network for any issues and it will improve over time. There is little technical debt here, and in fact, I've reduced technical debt because of it. It's similar to what it felt like when I made a similar decision to use WooCommerce to sell things, bringing eCommerce under the WordPress roof, or when I moved our forums from other software to bbPress.

The post Fast, Good, Local Site Search with Jetpack appeared first on CSS-Tricks.


Css Tricks - Wed, 07/11/2018 - 9:11am

I recently wrote Here’s the thing about "unused CSS" tools, where I tried to enumerate all the challenges any tool would have in finding truly "unused" CSS. The overarching idea is that CSS selectors match elements in the DOM, and those elements in the DOM come from all sorts of places: your static templates, dynamic templates based on server-side state, and of course, JavaScript, which can manipulate the DOM in any way at all, including pull things from APIs and third parties.

With all that at play, how can any tool give us a truly accurate picture of unused CSS, to the point that actually removing that CSS isn't just as dangerous as leaving it alone?

So, I said:

And yet, I don't think these tools are useless — they are just...tools. Their use can actually be a positive step toward better code. Their use says OK, I admit it, I'm a little afraid our CSS. You could use this tool to get a broad picture of what your unused CSS might be, then combine that with your own knowledge of your CSS code base to make more informed decisions.

I stand by that, and it's worth pointing out some successful use cases.

Sarah Dayan just wrote How I dropped 250KB of dead CSS weight with PurgeCSS. She was using Tailwind CSS, an atomic CSS library that a lot of people have had success with.

In my case, not only did I load the entire Tailwind CSS library, but I also added several variants to some modules. That ended up making the final minified CSS file weight 259 KB (before GZip).

It's a tenth of that when gzipped, but still, that's a lot of CSS. Tailwind recommends using PurgeCSS, and that's what Sarah did. PurgeCSS doesn't handle any of things I mentioned, like state variations and JavaScript and whatnot, but it does look at any static files you'd like it to—both content and CSS—and do analysis from those. Even better, Sarah knew she had some third-party stuff going on, so handled that situation specifically:

PurgeCSS can’t detect that I need to keep selectors such as .ais-Highlight, because the components that use it only show up in the DOM at runtime.

So she split off some of that CSS and updated the configuration. Then...

With this new configuration, my final CSS file has gone from 259 KB to…9 KB!

I love it. Using the tool, being super aware of what is happening on your site, and making final choices for a combined win.

Sarah also mentions how this concept of unused CSS is related in spirit to the concept of unused JavaScript. In JavaScript, it's referred to as tree shaking, and as Jeremy Wagner puts it:

Tree shaking is a form of dead code elimination.

I trust the tooling for tree shaking much more implicitly. These are tools written in JavaScript to look at JavaScript to discover JavaScript that isn't used. It seems like the intersection of technology isn't as wide when we're talking about tree shaking. Still, there could be things like configured third parties that call public functions on your site, or event handlers directly on HTML elements. Those things seem a bit more rare to me these days, but that's just my own experience bias.

The post Unused appeared first on CSS-Tricks.

Emojis as Icons

Css Tricks - Wed, 07/11/2018 - 9:07am

There are lots of unicode symbols that make pretty good icons already, like arrows (?), marks (?), and objects (✂?).You can already colorize these like a normal font glyph. Then, there are emojis, those full-color suckers we all know about. What if you could take just the shape of an emoji and use it like a normal glyph? You can!

Preethi Sam shows how:

.icon { color: transparent; text-shadow: 0 0 #ec2930; }

Plus, an alternate technique using background-clip. Note that emojis render differently across platforms, so careful!

Direct Link to ArticlePermalink

The post Emojis as Icons appeared first on CSS-Tricks.

Hyperlinking Beyond the Web

Css Tricks - Wed, 07/11/2018 - 3:50am

Hyperlinks are the oldest and the most popular feature of the web. The word hypertext (which is the ht in http/s) means text having hyperlinks. The ability to link to other people’s hypertext made the web, a web — a set of connected pages. This fundamental feature has made the web a very powerful platform and it is obvious that the world of apps needs this feature. All modern platforms support a way for apps to register a URI (custom protocol) and also have universal links (handling web links in an app).

Let’s see why we’d want to take advantage of this feature and how to do it.

Why have app links at all?

Creating URIs that apps can open provides a unique set of benefits. A URL encapsulates the entire state of the webpage (it used to before the advent of Single Page Applications (SPAs) heavy with JavaScript and even in them, it is best practice to maintain this functionality) or a web application and it is advisable to have routing in applications so that a URL navigation is never broken. URLs have allowed browsers to have consistent back and forward buttons and reload and bookmark pages. And things like Google’s search depend on webpage addresses and web applications to navigate users to the correct place. Allowing applications to open URLs provides a way to link content and functionality in your application from other applications, websites and even internally within the application, like help/tutorial pages.

Trivia! Desktop applications have had hyperlinks even before the world wide web like Hypercard on the Mac in 1987 and Windows Help in 1990. The revolutionary thing about hyperlinks in the web is that you can link content that was created and is owned by others. This concept of cross app linking was not popular in traditional platforms until the rise of smartphones.

App links over the command line

There is already a shell for the command line interface and it supports passing arguments, redirecting the results from one application to anther, and even scripting. Still, the need for having support for hyperlinks is desirable for various reasons:

  • Security: The command line script is too complicated to get right. It is very risky to expect users of technology (who are not developers) to understand how to sanitize a command line script and make sure that the script does not accidentally call something, like rm -rf ~/Documents. The command line is not sand-boxed and though it provides a power, it puts responsibility on users and is prone to exploits.
  • Browser support: The browser cannot provide the command line interface. It is built to run untrusted third party code in a sandbox and that cannot be broken. And, if we don’t respect the rules of web technology, the app would silo itself out of the Internet. That is too much to lose.
  • Mobile: In the world of mobile, a touch keyboard is not as good and intuitive as the physical ones used on the desktop. Therefore, even if command line was present, it would be very difficult to use. All the power of redirection and chaining is not as effective as it is over a keyboard-based command line. A simpler solution like URL is more desirable in this context.
  • State: Theoretically, the command line interface can provide a way to have the application available in any state. But, practically, it was built for a separate purpose: to launch the application to perform a task and then return with a code. Additionally, it was de-prioritized by the GUIs in Windows and Mac. Many applications (like Microsoft Word and Adobe Photoshop) never had full-fledged command line support. They are not even present in the environment PATH and need the full path to be launched. URIs provide a fresh way to look at connecting information as well as functionality between applications. They are a secure, modern way of inter-app communication where the user does not have to think.
Linking Terminology Deep Link

Deep link is the concept where a specific page/functionality within the website/application can be linked to. For example, https://css-tricks.com/link/to/this/page is a deep link for this page within the broader https://css-tricks.com link. Unlike superficial links that open applications, deep links open the application in a specific state, with passed data, ready to be consumed. Custom URI (described below) were the first ways to achieve deep linking within the app and "deep linking" in many contexts is now synonymous with custom URI, though it can also mean Universal links.

Custom URI

The web always had certain custom URIs that linked to default applications, like mailto:username@host.com and tel:1234567890 for email and telephone, respectively. It was an obvious choice to extend this and all major platforms provide a way for an app to register a URI protocol — like css-tricks://<link details> — that can open a deep linked native application. It should encapsulate the entire state and provide all routing benefits to open the app if it is available on the system. These provide a good interface for inter-app communication when the application is already installed and the desire is to open the user’s preferred application (like the browser or email client) that implements the desired protocol.

Custom URIs are great for the class of applications where the user wants to have a choice to select an app to perform a certain choice, but they are not great for the task of linking the website to the native application due to the following reasons:

  • Installation: Unlike the web, native apps need installation and, if they are not installed, you have two options: send the user to the app store (which also provides a custom URI) or properly fall back. Both these tasks require additional code which the URI does not encapsulate. The app store URI would be another separate URI that we need to store. Additionally, we have to detect whether the app is installed, which requires navigating to the URI and handling the error in navigation akin to a 404 since the protocol is not registered. This is not as simple as an anchor tag (<a href="{URL}"></a>) and, therefore, is a frequent source of developer complaints.
  • Lack of a central registry: Even if everything is done perfectly right, users can still be thrown into an application that they should not have been linked to. Unlike the DNS system (which guarantees uniqueness of domain names), application platforms do not have a central repository. So, multiple apps could register csstricks as a custom URI. Now, someone else could also register the same URI as one app and if the other application is installed on the system instead of the desired one, it could launch instead. The freedom of a custom URI for app selection works against the case where we always want to open a specific application.
  • Third Party Linking: Giving a custom URI to third parties because of the issues we’ve covered above is cumbersome and verifying them is painful. It is also a new protocol. Every website has links to the web content and updating the entirety of the Internet is not possible. It may not even be desired for SEO purposes.

Therefore, if we want to give the user the experience where the app is the preferred way to view content, custom URIs are not the perfect solution. This can be mitigated with smart app banners to some extent, where the banner would be displayed when the browser gets the custom URI and the app store link to identify the application. But this will not be seamless.

Trivia! URI and URLs are slightly different by definition, although they are used interchangeably. URI stands for Uniform Resource Identifier which means that it encapsulates everything required to get a resource. URL (Uniform Resource Locator) is a special type of URI that identifies the resource on the web. So, technically, a web address is a URL but something like csstricks:// would be just a URI.

These are all possible use cases where a custom URI might make sense:

  • You need to provide a URI that many third party client apps can register. Say you have a git:// in your app and the user’s favorite git client could register that URI and clone the repo when the the link is clicked.
  • You do not have a fully featured website.
  • You need a URI that is easy for users to remember.
  • You are willing to handle all edge cases related to navigation.

You can use custom URIs in parallel to the Universal link we’ll cover next and they can benefit from exposing the custom URL for inter-app communication while leaving the Universal link for the special case of web-to-app navigation. Android officially calls custom URIs deep links.

Control flows for Custom URI, Universal Link and Instant Apps Universal link, App Link or App URI

The solution to the problem of web-to-app redirection can be solved with the Universal link (as it’s called in Mac and iOS), App Link (as it’s called in Android) or App URI (as it’s called in Windows UWP), which are different names of the same concept. This encapsulates the logic that every website needs to write in order to detect installed apps, launch correct pages and handle navigation failures in the case of custom URLs. It is very similar to the smart app banner in the sense that you need to provide an app store link to the application on your website for verification but it removes all the redundancy. Since the existing http(s) URL already contains the entire state, registering the custom URI is redundant. The original URL could itself navigate to the app with the website providing a fallback experience in case the application is not installed.

Once you register your app with a universal link, when the app is installed, the OS goes to the Internet to figure out the set of links that the app supports. Whenever any of those links get clicked, the native app gets launched instead of the browser. Full addressing support is now available in the application where a more customized experience can be provided falling back to the browser if the application is not installed. On important distinction with universal links is that they do affect regular browsing and therefore the OS providers keep then under tight lock and key.

A few good use cases for Universal links include:

  • You have a fully featured website for a fallback.
  • The desired flow for users is from the website to the app.
  • You have already built up a lot of karma by having content from your website linked around the web.
Instant Link or Deferred Deep Link

Deferred deep links provide the missing piece to the deep links if the user goes on to install the app when the link is opened. The user can be forwarded to the app store and the app store takes care of maintaining the context when the app is eventually launched after installation. This provides continuity in the case where an app is installed. Currently this method is only supported by Android (as Google Play Instant) and it is the option where you want to require users to move from the app to get the desired functionality. The hyperlink system on the web is seamless and clicking on a link gets you to the destination almost instantly (though a lot of things happen behind the scenes). Deferred deep links provide the same functionality for apps where clicking on a link can download the app and launch it with the correct page making all the tasks on app installation as seamless as possible.

You might consider using instant links if:

  • You need the users to use the app and not the website, even if they come from the browser (except for rare cases where they are low on disk space or have turned this feature off to save bandwidth).
  • Your key pages are always up-to-date in your application.
  • OK, always use them. With the extra SEO advantages that Google throws in for instant apps, there is no reason not to enable "instant" apps for an app that has Universal links.

Now that we have a summary of what each term means, let’s see how we can go about creating these on specific platforms.

Setting up application hyperlinks MacOS and iOS Custom URI

Registering a custom URI in MacOS and iOS is extremely easy. In Xcode, go to the Info.plist file of the project and select the option URL Types. Create an item of type URL Schemes inside the file where you can add all of the URL schemes you wish to support.

Note: The default URL Identifier filled in by Xcode within URL Types is optional.

URL Scheme in Xcode <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>css-tricks</string> </array> </dict> </array>

For MacOS, you will receive calls to the AppDelegate where you can override the function:

func application(_ application: NSApplication, open urls: [URL]) { // Select the first URL in the list of URL to open let url = urls[0]; // Log the entire URL NSLog("%@", url.absoluteString) } -(void)application:(NSApplication *)application openURLs:(NSArray<NSURL *> *)urls { NSLog(@"%@", urls[0].absoluteString); }

In iOS, the function to receive the same call in AppDelegate is:

func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { NSLog("%@", url.absoluteString) return true } -(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options: (NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { NSLog(@"%@", url.absoluteString); return true; }

The URL type in all these cases contains the usual URL pieces like the path, the query and the search parameters.

Universal Links

Universal links are not supported in MacOS. To get universal links on iOS, you need to be registered with the Apple Developer Program or be an Apple Developer Enterprise Program member. Universal links on iOS are part of a wider concept of associated domains where the secrets of the website, like stored credentials, can be accessed from within the app and Apple does not allow regular Xcode users to dabble with universal links (if you accidentally enable the functionality for your App ID but do not put this in the entitlements, be prepared to get a validation error: ERROR ITMS-90046: "Invalid Code Signing Entitlements").

Trivia! Universal links are a new concept and many of the Mac and Windows desktop applications are built with their own network stack, do not use the app store and may have been released years ago. Therefore, the OS does not have the control required to force all applications to follow the Universal link concept and open the app. Apple has chosen to not implement Universal Links in MacOS yet, while on Windows they only work in the Microsoft Edge browser and other UWP apps (which use the same technology).

To register for Universal links on iOS, you need to do the following things:

  1. Enable the App ID on the Apple Developer website to get the feature for associated domains.
  2. Add the associated domains to the entitlements file.
  3. Add a apple-app-site-association file to the web domain to provide ownership verification for the application.
  4. Add code to handle clicks on Universal links.

Steps 1 and 2 can be performed together in the Capabilities tab on Xcode if you are signed in and have the right profile selected (which is from an Apple Developer or Enterprise account). The Xcode UI provides an indication that the both items have been completed.

Associated Domains in the Capabilities section in Xcode

In the image above, Step 2 has been successfully completed, while Step 1 is pending. You can click on the exclamation mark to find the issue. It is important to prefix the domain with applinks: (that identifies that you need app links functionality; the same is used for shared credentials). This identifies that the App Link capability has been enabled.

The above steps can also be accomplished individually.

For Step 1, enable Associated Domains in the App ID section on the developer website (shown at the bottom of the image):

Apple Developer website to enable associated domains

For Step 2, add the following to the entitlements file:

Entitlements plist <key>com.apple.developer.associated-domains</key> <array> <string>applinks:css-tricks.com</string> </array>

Now, for Step 3, host a association file apple-app-site-association like https://css-tricks.com/apple-app-site-association with mime type application/json with the following JSON data from the root of your website:

{ "applinks": { "apps": [], "details": { "ABCDEFGHIJ.com.ccs-tricks.mobile": { "paths": [ "*" ] } } } }

The above snippet grants the app with ID ABCDEFGHIJ.com.ccs-tricks.mobile and provides access to all requests on the https://css-tricks.com domain. Note that this works with https but http is not supported. You can also use an alternative location like https://css-tricks.com/.well-known/apple-app-site-association for this. This URL is preferred as it can keep the Android, iOS and UWP association files in a safe separate folder that cannot be accidentally deleted.

Trivia! Universal links do not guarantee that the app is opened. If the user goes back to the website from the header in iOS, the OS decides to default to the website from then on until the user decides to use the app by clicking on the header again from Safari.

For Step 4, add the following code to the app:

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool { if userActivity.activityType == NSUserActivityTypeBrowsingWeb { let url = userActivity.webpageURL! print(url.absoluteString) } return true } -(BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler { if(userActivity.activityType == NSUserActivityTypeBrowsingWeb) { NSLog(@"%@", userActivity.webpageURL.absoluteString); } return true; }

Smart app banners on iOS are much simpler and can be added via a simple meta HTML tag in the head section like this:

<meta name="apple-itunes-app" content="app-id=123456789, app-argument=https://css-tricks.com/linkto/this/article, affiliate-data=optionalAffiliateData">

They call the same method as Custom URIs we covered earlier.

Windows (Traditional)

On the traditional Windows platform (Win32/.NET), the custom URI (called Custom Pluggable Protocol Handler) is the only feature supported. Adding a custom URI in Windows involves adding a registry entry within HKEY_CLASSES_ROOT. The following will open the app with the absolute path given when clicking on a link to css-tricks://<text>. Due to using the command line, this always opens a new instance of the app and does not send the URL to the existing running application.

Registry Entry for providing application name Registry entry for open command Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\css-tricks] "URL Protocol"="" @="CSS Tricks (Application name)" [HKEY_CLASSES_ROOT\css-tricks\shell] [HKEY_CLASSES_ROOT\css-tricks\shell\open] [HKEY_CLASSES_ROOT\css-tricks\shell\open\command] @=""C:\\Windows\\notepad.exe" "%1""

The above launches notepad with the command line argument corresponding to the URL supplied. Be aware that Notepad does not support custom URI and will not know what to do with the URL.

This behave is similar to passing this on the console and the application needs to make sure it properly distinguishes between the argument being a regular CLI or a custom URI, as shown here:

namespace ConsoleApplication1 { class Program { static void Main(string[] args) { if (args.Length > 0 && args[0].IndexOf("css-tricks:") == 0) { Console.Write(args[0]); } } } } int main(int argc, char*argv[]) { if (argc > 1) { // argv[0] is the file name. std::string word(argv[1]); if (word.compare(0, 11, "css-tricks:") == 0) { std::cout<<word; } } return 0; } Universal Windows Platform (UWP)

On the Universal Windows Platform, you can use the package manifest to register both the custom URI and the Universal link (called App URI Handler).

Custom URI

Add a protocol declaration in the package.appxmanifest:

Protocol Declaration in package.appxmanifest

The same can be achieved in code:

<Extensions> <uap:Extension Category="windows.protocol"> <uap:Protocol Name="css-tricks" DesiredView="default"> <uap:DisplayName>CSS Tricks</uap:DisplayName> </uap:Protocol> </uap:Extension> </Extensions>

...and this can now be handled within the app.

protected override void OnActivated(IActivatedEventArgs args) { base.OnActivated(args); if (args.Kind == ActivationKind.Protocol) { var e = args as ProtocolActivatedEventArgs; System.Diagnostics.Debug.WriteLine(e.Uri.AbsoluteUri); } } // In App.xaml.h virtual void OnActivated(Windows::ApplicationModel::Activation::IActivatedEventArgs^ e) override; // In App.xaml.cpp void App::OnActivated(Windows::ApplicationModel::Activation::IActivatedEventArgs ^ e) { if (e->Kind == Windows::ApplicationModel::Activation::ActivationKind::Protocol) { auto args = (ProtocolActivatedEventArgs^)e; auto url = args->Uri->AbsoluteUri; } } Universal Links (App URI)

App URIs are only supported in the Microsoft Edge browser. They do not work in Internet Explorer, Chrome or Firefox. App URIs also have a package entry similar to the custom URI. It is not available in the UI of Visual Studio Code 2017. The package.appxmanifest entries are almost the same:

<Extensions> <uap3:Extension Category="windows.appUriHandler"> <uap3:AppUriHandler> <uap3:Host Name="css-tricks.com" /> </uap3:AppUriHandler> </uap3:Extension> </Extensions>

If uap3 is not available, it can be added to the Package tag where uap is also defined:


App URI is a relatively new feature of Windows and many UWP projects target older versions of windows as the minimum version. You might need to bump that up in order to support this feature.

Just like iOS, the website needs to verify the ownership of the domain for this to function. The can be done by hosting a file with mime type application/json at the root of your website, like https://css-tricks.com/windows-app-web-link or https://css-tricks.com/.well-known/windows-app-web-link over https with the content:

{ "packageFamilyName": "YourPackageFamilyNameHere", "paths": ["*"], "excludePaths": ["/none/*", "/robot.txt"] }

To get the package family name, run the following in Powershell and search for your package path:


Handling App URIs requires the same code as custom URIs on Windows. By design, all you need to do is see the protocol field in the provided URI and write the corresponding logic.

Just like iOS, Windows users have a choice to disable opening apps. Windows provides registry settings to force apps to open (used for testing) and also a validator tool (located at %windir%\system32\AppHostRegistrationVerifier.exe) to verify if the above settings are correct.

Android Custom URI

Android has supported custom URIs from the very beginning. This can be done with code. In AndroidManifest.xml add:

<activity android:name=".CustomUriActivity"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="css-tricks" /> </intent-filter> </activity>

The category DEFAULT is to ensure that there is no user action needed to enable it. BROWSABLE ensures that the custom URIs work in the browser.

This can then be handled in the CustomUriActivity.java on creation:

public class CustomUriActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = getIntent(); if (Intent.ACTION_VIEW.equals(intent.getAction())) { Uri uri = intent.getData(); } } } Universal Links

Universal links in Android are very similar to App URIs. Android Studio provides a GUI tool to create this. Go to Tools > App Link Assistant. This will provide the three tasks needed to create app links:

App Link Assistant in Android

For Step 1, enter the URL mapping editor and click on the + button to open the URL mapping dialog:

URL Mapping dialog

Once you click OK, it will show the code that could have been used alternatively in the AndroidManifest.xml:

<activity android:name=".CustomUriActivity"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="http" android:host="css-tricks.com"/> </intent-filter> </activity>

Note: This exactly the same as as it is for a custom URI. In the Step 2, select the activity you assigned and it will add the code to load the action. The code is also exactly the same as was used for custom URIs above.

In the Step 3, it will generate the JSON file that needs to be added to the website as application/json mime at https://css-tricks.com/.well-known/assetlinks.json.

[{ "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "css_tricks", "package_name": "com.css-tricks.android", "sha256_cert_fingerprints": ["17:CC:87:9C:C8:39:B1:89:48:E8:2E:9E:6F:FC:7D:03:69:4D:05:90:2A:84:B8:AE:5D:6B:30:97:F8:1C:2B:BF"] } }]

Android Studio automates the fingerprint generation that verifies the application identity. This identity is different for debug and the release version of the application.

Instant Link

Instant apps on Android require minor changes from the App links we covered earlier. To enable instant apps, modify the intent declared above to look like this:

<activity android:name=".CustomUriActivity"> <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="http" android:host="css-tricks.com"/> <data android:scheme="https"/> </intent-filter> </activity>

This allows both http and https URLs to be associated with the app, and the autoVerify tells the Android (Google Play) store to verify the manifest item automatically. Instant app is a Play Store/Google Chrome feature. The changes on the app are minimal to support this.


Electron apps are traditional MacOS and Windows apps with the chromium runtime. These platforms only support custom URIs that can be enabled without touching the compiled code.

For MacOS, edit info.plist as described in the MacOS section. The events are received by the app object as:

// In main.js require('electron').app.on('open-url', (event, url) => { console.log(url); });

For Windows, add the registry entry as defined in the Windows section. The app will receive the custom URL in process.argv:

// In main.js console.log(process.argv[2])

In electron, you can load external web pages that can open URLs. If it is desired to handle only those URLs internally, that can be registered via an electron API:

require('electron').protocol.registerHttpProtocol('css-tricks', (req, cb) => { console.log(req.url) }); Web

Going a complete circle, a website can also register custom URIs (like handling mailto: links via a website). Note that these only affect links provided in other websites and have nothing to do with links in other applications. The API is very restrictive and can be used only for a selected link type: web+<insert anything here>. Browsers allow a pre-defined list of top level protocols to be registered:

  • Chrome: mailto, mms, nntp, rtsp, webcal
  • Firefox: bitcoin, geo, im, irc, iris, magnet, mailto, mms, news, sip, sms, smite, ssh, tel, urn, webcal, wti, xmpp

To register a protocol, you need to provide the same domain as the website that registers it (i.e. https://www.css-tricks.com can register only https://www.css-tricks.com and not https://css-tricks.com).

if (navigator.registerProtocolHandler) { navigator.registerProtocolHandler("web+csstricks", "https://css-ticks.com/?s=%s", "CSS Tricks custom URI"); }

The custom URIs are not indexed by search engines and therefore there is not much use to these apart from handling the links like mailto, webcal etc., that are already present in the web at multiple places.

Wrapping Up

Adding hyperlinks to native apps is an easy and effective way to seamlessly move the user across applications with graceful handling in case the application is not installed. With these links, applications can have provide paths all over the Internet which can be an effective promotional mechanism. Links also give websites a way to provide data and launch the applications on a specific page without the security worries that plague the downloadable files or command line scripts allowing effective tutorials and bug reports. Routing and URLs provide for the core features of the World Wide Web like navigation, the back button, bookmarks and search. Hyperlinks in apps bring these learning from the (almost) 30 years of world wide web to native applications.

The post Hyperlinking Beyond the Web appeared first on CSS-Tricks.

Random Day in the Life of a Developer

Css Tricks - Tue, 07/10/2018 - 12:20pm

Yesterday, I started going through my email as soon as I got to work. I always start my day with email. I kinda like email. I read some interesting things in keeping up with the industry. I deal with some business things. I handle with some personal things. I make a note of the most important stuff going on.

Then I kept working!

I fixed a bug that was affecting Firefox exclusively. This code would set some elements in a row with flexbox, let them wrap, then looked at all of them to see which ones wrapped and which ones didn't. Then it put the ones that wrapped in an overflow menu. Seemed simple enough. But some of the items were in bold text and some were not. The ones that were not bold were somehow pushed down 1.5px in Firefox (but in no other browser I looked at). The code checked to see if the top position was anything higher than 0 in order to check if they wrapped, and thus incorrectly marked some elements as being wrapped. The code had to be loosened up to accommodate that.

I tweeted some things that looked particularly interesting that day.

I had logged a bug a few days ago where a couple of small buttons were not styled or aligned how they should be in a common modal dialog. In diagnosing the issue, it looks like we had a weird git merge where some newer CSS was merged in that was assuming some HTML that wasn't quite live yet.

I decided the cleanest way forward was to make the small HTML change forthcoming in the new branch in a new fixer branch that could go out quickly. The alternative was reverting the CSS back and my guess was that would have caused worse merge conflicts later, plus it was worth taking advantage of the newer, nicer styling now.

Then, because of course it did, the small HTML change caused another bug. The JavaScript that was watching those buttons couldn't find them anymore and I failed to test it or, ideally, write a test for it. So, I had to fix that too, but sadly only after a user reported it. Gosh, I gotta improve our integration tests there.

I was in two meetings. One was a standard weekly catchup meeting. One was with a new person I'd never met before and we were exploring if there was an interesting way we could work together.

I fixed a bug with some bad backend logic (that I had written myself, of course). I wanted to display some information to a user based on, I thought, if they were on a team or not. I got that logic right, but it turns out the messaging was depended on that team being active (i.e. not expired in some way), so I had to update the logic to account for that. My team member helped me think it through because I didn't understand the way billing and active subscriptions were tied to the user well enough.

I fixed a bug where a UI element was showing a strong warning state, but there was no way to find out what the problem was. It was a big red box with an exclamation point in it. It even had a hover state. But clicking it did nothing.

Turns out it was just a problem with event delegation. It was being added to the page after click handlers attempted to bind two elements like that. I fixed it by re-binding those click handlers after of the error UI was appended. It didn't feel great. A better fix might have been updating the event delegation to be more efficient about this case. But, I'd been burned by that in the past, so this fix seemed more robust, even if less elegant and efficient.

It made me pine for the page being ported to React, where a silly event delegation bug would have never been an issue. Not long after, I fixed another bug where a click handler had been bound to a span.class_name, and the span was updated to be a button. That was a semantic and accessibility win, but broke the handler.

Again, something that just doesn't happen in React.

Then I wrote this blog post and went home.

The post Random Day in the Life of a Developer appeared first on CSS-Tricks.

Delivering WordPress in 7KB

Css Tricks - Tue, 07/10/2018 - 3:43am

Over the past six months, I've become increasingly interested in the topic of web sustainability. The carbon footprint of the Internet was not something I used to give much thought to, which is surprising considering my interest in environmental issues and the fact that my profession is web-based.

The web in a warming world

As a brief recap, I attended MozFest in London last year. In between sessions, I was scanning a noticeboard to see what was coming up, and I spotted a session entitled, "Building a Planet-Friendly Web." I felt a little dumbstruck. What on Earth was this going to be about?

I attended the session and the scales fell from my eyes. In what now seems obvious — but at the time was a revelation — I learned of the colossal energy demand of the Internet. This demand makes it the largest coal-fired machine on Earth, meaning that its CO? emissions are probably at least equivalent to global air travel. More and more people are coming online, but this, coupled with the rise of ever more obese websites, means that the Internet's energy demands are growing exponentially. Every additional byte transferred means more energy, which in most countries means more CO?.

It is widely accepted that we should avoid printing emails to save trees, but this leads to a false assumption that the web is a green medium. I'm afraid to say, it is not.

Is there another way?

The good news is, it needn't be this way. Since 2009, Greenpeace has been auditing Internet companies on their energy usage, and lobbying them to improve by way of their Clicking Clean campaign. The Green Web Foundation has an ever-growing database of hosting companies who use renewable energy, or who are at least committed to being carbon neutral. And new tools are emerging to help those working on the web measure the environmental impact of our products.

There are also some great resources out there such as Tim Frick's Designing for Sustainability, three year's worth of talks from the SustainableUX conference, and peripheral material that, while not explicitly focused on sustainability, can help us build lower carbon websites.

Enter Susty WP

I decided to challenge myself to see how efficiently I could package a WordPress website. While I was at it, I thought, “Why not make the website about sustainability and WordPress?" I know, WordPress/sustainability inception. Cool, huh?

And so, sustywp.com is born. With its accompanying theme, Susty. I'm rather chuffed to say I managed to get the load of the homepage down to 7KB of data transfer. I did actually get it down to 6KB, but the meta stuff added by Yoast bumped it up almost a whole KB! &#x1f61b; However, given I'm trying to spread a message, I deemed this to be an acceptable trade-off.

Before I get into the nuts and bolts, I just want to share a few headline facts:

So, how does it work?

The remarkable thing about this is actually how mundane it is. Heavily inspired by Heydon Pickering's evangelizing about writing less damn code, and projects like Brad Frost's Death to Bullshit, I embarked on a root and branch pruning of Underscores, removing everything I possibly could. And to be clear, it's not as though Underscores is full of cruft. It's a very lean starting point for building a theme. I'm a great admirer of it and thoroughly endorse using it. However, it includes certain assumptions that didn't chime with my spartan goal of making the smallest possible WordPress site.

Such as, you ask?

Nav? No. Sidebar? Get rid of it. Classes? Not in my socialist utopia.

Given the constraints I had set, anything making it to the DOM had to have a very good reason to be there. With this being an experiment, I took the somewhat radical approach of relegating the navigation to its own page. This is wonderfully liberating and means I didn't have to go through the almost always disappointing dance of wondering how I would make it look presentable, hide it for the many users who won't care, make sure it's robust enough to be infinitely long with never-ending dropdowns, etc.

This means less HTML, less CSS, and definitely no JavaScript! Win, win, win.

As for the sidebar? Well I've always had an aversion to sidebars, so that was an easy thing to remove. Susty has no widget area. I'm sure it'll get over it.

Is there more fat we can trim? Well, if we're going to have hardly any HTML, and we want minimal CSS, do we really need all those classes? I wanted to try my hand at writing CSS in the way it was intended to be used, instead of bowing to the class-ititis and div-ititis that pervade the industry.

You might not need web fonts

Alongside images, video and JavaScript, the other item that has become a significant factor in bloated websites is web fonts. Given that it's now a Silicon Valley fashion for every startup to commission its own typeface as a first order of business, it seems as though every website you visit incurs downloading a bunch of font files. It may not seem so bad to tack on a hundred kilobytes for some nice type, but when you multiply this by the many different people visiting your website across different devices and browsers, fonts can easily account for hundreds of megabytes of data transfer — if not gigabytes/terabytes/petabytes for higher traffic websites.
Custom web fonts are also a potential antipattern for our users, for whom:

  1. Page loads are slowed down as they see either a flash of unstyled text or, potentially even worse, no text while the font loads.
  2. By the time the font has loaded, they don't notice or care.

If you do have to use custom fonts or are in combat with the flash of un-styled text, font-display is an new property designed to instruct the browser how to handle font downloads. This post goes into it even more.

Almost every device these days has a half-decent set of fonts installed, so why not compose a stack of potential fonts you'd like to see, ending with either “serif “ or “sans-serif." Or embrace those default fonts altogether with a system font stack.

I wanted Susty to have a bit of a Swiss Style aesthetic, so my font stack ranges from the perfectly proportioned Helvetica (which all Apple devices have by default) to sans-serif, by way of Arial, Frutiger and Nimbus Sans L.

As an Ubuntu user, I see Arial, which is perfectly pleasant. On my Android devices I see the default sans-serif font (Droid Sans I believe), which actually works rather well on mobile — you'd almost think that's what it was designed for!

What else? Standard stuff. Few or no images and SVG where possible

Beyond this, it's really just the standard. The homepage of sustywp.com has no images and just one SVG which is loaded inline rather than by an HTTP request. The CSS is minified. Everything gets Gzipped. The server is tuned with NGINX and Fast-CGI cache to serve content from memory.

Bonus SPA-like features without the work or code

When I was boring my girlfriend, Daisy, with my plans, I asked her how she felt conceptually about a website not having a navigation, and it instead being on its own page, found via a "menu" button. She thought it sounded ok. So, when I came to show it to her, I watched eagerly as she clicked the menu link. Her response was that she didn't really think about clicking to see the menu, and the menu appearing, as changing pages. This confirmed one of my fears that my previous obsession with eliminating page loads when building Single Page Apps (SPAs) is something that only really bothers web developer-y types. Most people don't really notice it or think about it. So, if you make your website lightning fast, the page loads themselves are almost imperceptible anyway.

With that being the case, I figured why not just pretend it was a menu overlay? So, I added a cross dismiss button and a tiny bit of JavaScript to take you from the menu back to the previous page if you click it. (I did initially implement this in PHP using the $_SERVER superglobal and HTTP_REFERER, but this breaks when using something like FastCGI cache to serve pages (i.e. those pages there is no $_SERVER superglobal.)

There’s still more to come

We all know that things can always be better. Here are a few of the things I’m working on to improve Susty:

  • Finish reading Jeremy Keith's book Going Offline so I can implement a Service Worker and make Susty even more performant.
  • Look to see how I can implement Gutenberg. It's going to add a bunch of kilobytes and that makes me sad! &#x1f609;
  • Currently, sustywp.com is hosted in one data center in London, and served globally from that location. This means that someone in Wellington, New Zealand is not going to get the full experience! I have a longer-term plan of establishing my own little CDN of edge servers (each one hosted by a 100% renewable energy powered host in each location that I can find one) just running NGINX and serving cached versions of the site. This is a simplified way of how we do things on WordPress.com VIP.
In conclusion

Susty is an example of taking sustainable design techniques to an extreme. I'm not suggesting that we should all start building websites with this exact method. But I do think sustainability should be a much higher priority in the web design industry. It's good to think about saving any kilobytes we can, and to think in terms of kilobytes rather than megabytes. If you do want to use a JavaScript interface library, why not try out Choo.js, which has React-like features and comes in at just 4KB. Remember, NASA managed to put a man on the moon with about 50KB of data storage at their disposal.

The best thing about all this is that efficient websites means faster websites, which means:

  • Happier users
  • Better search engine placement
  • Happier servers

The post Delivering WordPress in 7KB appeared first on CSS-Tricks.


Css Tricks - Mon, 07/09/2018 - 8:26am

Mark this down as one of the strangest things I’ve seen in a good long while. Nicholas Jitkoff has made a tool called itty.bitty that creates websites with all of the assets being contained within their own link. You can create a website without any HTML or CSS resources at all because it’s all been base64 encoded into the URL itself.

Take this crazy looking URL, for example:


This link contains all of the HTML and CSS that makes up the website. The really cool thing about this is that you don’t need a server to make an itty.bitty site — once you paste the link above into the browser it’ll fetch some code from the itty bitty domain then extract and inflate the data from there.

I’m not entirely sure how useful this is but it’s certainly a novel concept to me! Go ahead and start making your own itty.bitty sites.

Direct Link to ArticlePermalink

The post itty.bitty appeared first on CSS-Tricks.

Little Tip: Draw Your Grid in ASCII in Your CSS Comments for Quick Reference

Css Tricks - Mon, 07/09/2018 - 6:57am

Say you declared a grid like this:

body { display: grid; grid-template-columns: min-content 1fr; grid-template-rows: min-content auto min-content; }

This depends on content, for sure, but how it's likely to play out is like this:

+---+-------------+ | | | | | | +-----------------+ | | | | | | | | | | | | | | | | | | +-----------------+ | | | +---+-------------+

That's really easy to draw out quick in ASCIIFlow Infinity.

Now you want to place elements in that grid, and arguably the easiest way to do that is to specify the grid rows/columns they should start/end at.

/* grid-area: row-start / column-start / row-end / column end */ .logo { grid-area: 1 / 1 / 2 / 2; } .site-header { grid-area: 1 / 2 / 2 / 3; } .sidebar-nav { grid-area: 2 / 1 / 3 / 2; } .main-content { grid-area: 2 / 2 / 3 / 3; } .site-footer { grid-area: 3 / 1 / 4 / 3; }

There are other ways to do this. You could use longhand CSS properties. You could name the areas. But say you like doing it this way because it is succinct or whatever. That's where the ASCII is useful! Leave it in a CSS comment and number the lines.

/* 1 2 3 1 +---+-------------+ | | | | | | 2 +-----------------+ | | | | | | | | | | | | | | | | | | 3 +-----------------+ | | | 4 +---+-------------+ */

Now you've got an visual reference to pick out those grid numbers from.

If you like native apps and wanna get real fancy, there is Monodraw.

The post Little Tip: Draw Your Grid in ASCII in Your CSS Comments for Quick Reference appeared first on CSS-Tricks.

The CSS Paint API

Css Tricks - Mon, 07/09/2018 - 3:53am

The CSS Paint API is extremely exciting, not only for what it is, but what it represents, which is the beginning of a very exciting time for CSS. Let’s go over what it is, why we have it and how to start using it.

What is the CSS Paint API?

The API is just one part of a whole suite of new specifications all under the umbrella of what is known as CSS Houdini. Houdini, in essence, gives developers lower level access to CSS itself. No kidding.

The CSS Paint API specifically allows you to call a paint() function wherever you would normally write a value where an image is expected. A common example is the background-image property, where you might use the url() function to a link to an image file, like this:

area { background-image: url('assets/myimage.jpg'); }

The CSS Paint API allows you to call the paint() function instead and pass in a paint worklet that you have defined through JavaScript. Think of as a bit of code that allows you to programmatically draw (pretty much) whatever you like. And because it's JavaScript, you can make it dynamic, too. The API itself is very much like the HTML5 <canvas> API (and we'll get to how that works in a minute).

This sounds cool, but complicated. I'm already happy using regular images...

That's great! There's absolutely nothing wrong with using regular images like you have been doing. Just because something is new and probably cool doesn't mean we all have to start using it for everything. However, images are static and the idea of generating something dynamic is enticing!

Let’s think about linear-gradient for a moment. It’s extremely powerful. I mean, check these out. But, can you imagine how much less work it would be creating those layered patterns without multiple background images? Not only this, but digging in to the CSS Paint API should also help you understand how these kind of images are generated during runtime, which could be really helpful (and is something we’re about to do).

What about conic-gradient which has no browser support yet...without a polyfill, that is. Harnessing the Paint API would allow you to create a conic gradient and some properties to change it much the same as the actual specification. So, in reality, you would actually be creating your own native polyfill. That’s pretty neat!

Remember, this is all part of the bigger CSS Houdini group of features. Here’s a quote from the CSS Houdini Wiki:

The objective of the CSS-TAG Houdini Task Force (CSS Houdini) is to jointly develop features that explain the "magic" of Styling and Layout on the web.

Sounds nice, right? It is and these new features are aimed at allowing developers to extend the functionality of CSS itself, providing better control, cross-browser support and polyfilling.

The standards process can take a while: from proposing a new CSS feature, to writing a specification, to having the browser vendors implement this new specification. And since developers are often eager to start using a new feature as soon as possible, we have to consider that legacy browsers may not support it and possibly any changes to the specification if it hasn’t been fully implemented — and that’s not to mention the typical nuances of cross-browser implementation. Houdini could go quite a way to help with that, by allowing us to implement browser functionality ourselves while we wait for vendors to catch up.

Philip Walton does a great job of explaining these benefits of Houdini and more in this great article on Smashing Magazine.

You can see how Ana Tudor has already put it to use to create complex animations.

So, can I use it now?

You can! The CSS Paint API is only supported in Chrome 65 at the time of writing, but here’s a support chart that will stay updated over time:

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

DesktopChromeOperaFirefoxIEEdgeSafari6552NoNoNoNoMobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid FirefoxNoNoNo6767No

But, there's still a ways to go.

Regardless, let's take a look at how we go about creating the code to use it. I'm going to break this down into three stages. There's some new JavaScript features we're going to use along the way, but the code is there for you and we'll go through each.

Step 1: The CSS

First, we need to name our worklet and call it in the CSS. I'm going to call it awesomePattern, so my CSS would look something like this:

section { background-image: url('fallback.png'); background-image: paint(awesomePattern); };

We’re all set up, but nothing is going to happen just yet.

Step 2: The JavaScript

Now, we need to add our paint worklet to our main JavaScript, which is loading another JavaScript file like so:


Still, nothing will happen at this point because it's within our patternWorklet.js file, where all the work is going to be done.

In patternWorklet.js, we need to register a paint worklet class:

registerPaint('awesomePattern', Shape);

So we call the registerPaint() function and pass what we want to call the paint worklet, in this case awesomePattern, and then a reference to the class we are about to write, in this case Shape. Remember to add this after the class we’re about to define next. Unlike function hoisting in JavaScript, you do need to define classes before you can use them.

Next, we are going to use the ECMAScript2015 classes syntax to write a class that will draw our background for us. Because it is now registered as a paint worklet class, we get some things for free.

class Shape { paint(ctx, geom, properties) { ctx.strokeStyle = 'white'; ctx.lineWidth = 4; ctx.beginPath(); ctx.arc( 200, 200, 50, 0, 2*Math.PI); ctx.stroke(); ctx.closePath(); } }

In the paint callback, we have ctx, geom and properties. ctx is the same as a 2D context we would get from a <canvas> element. (Well, almost: a <canvas> element allows the ability to read back pixel data, whereas you can’t with the CSS Paint API.) It allows us to use all the same methods to draw as we would if we were on canvas. In the example above, I am simply drawing a circle with the arc function.

The first two values of the arc function are the X and Y coordinates of where the circle is positioned, in pixels, from the top-left of the element. But, I would like the circle to be central and this is where the geom data comes in handy. It's actually passing back the PaintSize, which is the size of the area the image would normally fill and we can access width and height information, which is precisely what I need to make the circle central:

See the Pen Simple Circle: CSS Paint API Example by Rumyra (@Rumyra) on CodePen.

Great, but this is a pretty simple example. Let's switch out the circle for something a little more awesome:

See the Pen Simple Circle: CSS Paint API Example by Rumyra (@Rumyra) on CodePen.

Here, I’ve added a method to the class called drawStar and there’s a whole bunch of canvas functions going on there, that draw the CSS-Tricks logo."

Step Three: Custom Properties

We can do more! We can harness the power of CSS custom properties (aka variables). We've all been really excited by them and this is one of the reasons why.

Let's say I want to be able to change the size or color of our CSS-Tricks logo? Well we can put those parameters as custom properties in our CSS and access them with the third piece of callback data, properties.

Let's add a --star-scale property to our CSS, which will eventually make our logo bigger and smaller, and a --star-color property to easily change the color of the logo directly in the CSS.

section { --star-scale: 2; --star-color: hsla(200, 50%, 50%, 1); background-image: paint(awesomePattern) };

Back in our paint worklet class, we need to access those custom properties. We do this with the inputProperties method, which gives us access to all CSS properties and their given values:

static get inputProperties() { return ['--star-scale','--star-color']; }

Now, we can access them within the paint method:

const size = parseInt(properties.get('--shape-size').toString());

...and use that value within our code. So, if we change either the --star-scale or --start-color properties within out CSS, it will update the background!

It’s also worth noting that all your usual CSS background properties work as expected, such as background-size and background-repeat. Which is great to know and still really useful!


This is pretty powerful stuff, and not just for custom background images. Imagine a half or a double border on your element. You might normally use the ::before or ::after pseudo-elements, or maybe a cleverly thought-out box-shadow. Well, you could implement that (and more) with the CSS Paint API and the border-image property.

This API really pulls together a lot of cool features, like worklets, ECMAScript2015 classes and canvas. Plus, it gives us the whole interaction layer that comes with JavaScript. You could easily add events to update the custom properties and thus the image itself, like this example from Surma, who harnesses the click event to start updating properties within a requestAnimationFrame function to create an animation every time the user clicks on a button. It even takes the coordinates of the click into account.

This may seem a little convoluted on the face of it, but let’s take a look at some of the other parts of the Houdini suite we’re about to encounter:

  • The CSS Layout API, which should allow us to do something like display: layout('myCustomLayout'), for which the typical example would be a custom masonry type layout, but the scope is a lot more.
  • The CSS Properties and Values API which allows us to specify types for custom properties.
  • The CSS Animation Worklet API, which takes animation processing from the main thread, which should result in silky smooth animations.

So, regardless of whether you’re really interested in this specific new feature or not, it is part of a whole bunch of new technology that will unlock a great deal of power. Watch this space because CSS is about to get even more awesome!

The post The CSS Paint API appeared first on CSS-Tricks.

CSS Grid in IE: Faking an Auto-Placement Grid with Gaps

Css Tricks - Fri, 07/06/2018 - 4:03am

This is the third and final part in a three-part series about using CSS grid safely in Internet Explorer 11 (IE11) without going insane.

In Part 1, I covered some of the common misconceptions that people have about IE11’s native CSS grid implementation. In Part 2, I showed the world how easy it actually is to write IE-friendly CSS grid code.

Today, I’m going step away from CSS grid for a moment to show you a flexbox technique that replicates basic CSS grid auto-placement functionality. This CSS grid replica will even look like a grid-gap has been applied to it. I need to be super clear though: this is not about how to make actual CSS grid auto-placement work in IE.

Article Series:
  1. Debunking Common IE Grid Misconceptions
  2. CSS Grid and the new Autoprefixer
  3. Faking an auto-placement grid with gaps (This Post)
How to make a fake grid with cell gaps Step 1: HTML

I’ll use this basic HTML as an example:

<div class="grid-wrapper"> <div class="grid"> <div class="grid-cell"></div> <div class="grid-cell"></div> <div class="grid-cell"></div> <div class="grid-cell"></div> <div class="grid-cell"></div> <div class="grid-cell"></div> </div> </div> Step 2: Border-box box sizing

The first thing that we need to do in the CSS is make sure that all of the boxes are being sized based on border-box rather than content-box. The best way to do that is using the box-sizing: border-box inheritance technique:

html { box-sizing: border-box; } *, *::before, *::after { box-sizing: inherit; }

That will be applied globally. If you are working on an an existing project that doesn’t have box-sizing set to border-box, then change html in the snippet to a selector that targets the element you want to turn into a grid.

Step 3: Flex

Next, you will need to turn on some flexbox settings:

.grid { /* Forces equal cell heights */ display: flex; flex-wrap: wrap; } Step 4: Widths

Now, set up your column widths. We’ll make ourselves a simple three-column grid:

.grid-cell { /* Sets column count */ width: calc(100% / 3); /* calc() method */ width: 33.33%; /* percentage method */ }

The calc() method allows the column widths to be changed a bit more easily. You state how many columns you want and the browser does the math for you. This is especially handy for when you need a larger number of columns, like 7 or 8. The browser support for calc() is strong but not as strong as a raw percentage value which has been supported by browsers since the dawn of CSS.

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

DesktopChromeOperaFirefoxIEEdgeSafari19*154*10126*Mobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox6.0-6.1*46No676760

The percentage method has slightly better browser support and can be a bit more stable in IE. If you don't need to support Opera Mini, I would still recommend going with the calc() method first. Test in IE, and if the layout breaks, first try using 99.999% instead of 100% in the calc function (calc(99.999% / 3)). If that doesn't work, then try switching to the percentage method. I will be using the calc() method in all of my examples. Note that if you are using a CSS pre-processor like SCSS, you can have the best of both worlds by getting the pre-processor to do the math for you. This comes at the cost of not being as easily able to edit or review the column counts in browser dev tools.

/* Set column count using SCSS */ .grid-cell { width: (100% / 3); } /* CSS output into the browser */ .grid-cell { width: 33.3333333333%; }

Let’s give the grid cells some height and an inner box-shadow so that we can see what’s going on. I’m not adding border — I’ll be using that later. &#x1f609;

.grid-cell { /* So that we can see the grid cells */ box-shadow: inset 0 0 0 1px #000; height: 100px; } .grid-wrapper { /* Allows us to see the edges of the grid */ box-shadow: 0 0 10px 2px green; }

You should now have something that looks like this:

A basic 3 x 2 grid with no gaps

That’s boring though, right? Everyone knows how to do that. Where are these grid gaps I keep talking about? I want my gaps!!!

Step 5: Border

Here’s where we get to the interesting part. Since we set box-sizing to border-box, the 33.33% width now includes the border. What this means is that we can start safely mixing fixed and percentage based units! &#x1f603;

.grid { /* Creates an equal outer gap */ padding: 20px 0 0 20px; } .grid-cell { /* Creates gaps */ border: 0 solid transparent; border-width: 0 20px 20px 0; }

This results in something that looks like a grid with equal spacing everywhere:

A 3 x 2 grid with equal space between each cell and the outer edges of the grid

To help give you a better idea of what is going on, take a look at the following image:

Color-coded diagram of the grid

The blue area on the top and left sides of the grid is the padding for the .grid element. The yellow outlines show the area that each .grid-cell element takes up. The red areas on the bottom and right sides of each cell are the border for each .grid-cell element.

That might be the look that you actually want. On the other hand, that isn’t what a grid with a grid-gap setting looks like. That is why we have another step.

Step 6: Margin and overflow

In order to get the grid pressing hard up against the edges of its container, we need a bit of help from negative margins and overflow: hidden:

.grid { /* Pulls grid cells hard against edges */ margin: -20px; } .grid-wrapper { /* Prevents odd margin behavior */ overflow: hidden; }

We need to apply overflow: hidden to prevent this from happening:

Top and bottom negative margin is ignored if overflow is not hidden

Applying the negative margin and overflow: hidden will get us to this beautiful recreation of basic grid-gap functionality:

A 3 x 2 grid that looks identical to a CSS grid with a gap setting

The top and left padding on the grid is actually optional. You can opt to leave off the padding and change the margin value as shown below if you prefer:

.grid { /* Margin needs to be this if leaving off the top and left .grid padding */ margin: 0 -20px -20px 0; }

But, hold on! The job isn’t quite over yet. Take a look at what happens if we add a background color to one of the grid cells:

A pink background applied to the top left cell overflows into the grid gap

Not exactly what we want, so there is one more step.

Step 7: background-clip

In order to prevent the grid cell background from bleeding into our fake grid-gap, we need to add background-clip: padding-box to it.

.grid-cell { /* Prevents background bleed */ background-clip: padding-box; }

Now we have this:

The background bleed has been fixed!

If you have never heard of the background-clip property before, you might be worried about browser support… well don’t be. background-clip has been around since IE9!

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

DesktopChromeOperaFirefoxIEEdgeSafari1510.549127Mobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox7.0-7.110all4.46760 Step 8: Media Queries!

Most of the time, grids need to be able to change the number of columns that they have as they grow and shrink. Using other methods can be a massive pain. You might have to calculate a bunch of nth-childs so you can remove the right margin or whatever. With this method, you only have to change a single value! &#x1f603;

.grid-cell { /* Sets the default column count */ width: calc(100% / 1); /* 1 column */ } @media (min-width: 400px){ .grid-cell { width: calc(100% / 2); /* 2 columns */ } } @media (min-width: 600px){ .grid-cell { width: calc(100% / 3); /* 3 columns */ } } 3 x 2 grid with gaps 2 x 3 grid with gaps 1 x 6 grid with gaps

Here’s how it looks when we put it all together:

See the Pen Fake grid by Daniel Tonon (@daniel-tonon) on CodePen.

Ain’t nobody got time for dat!

That’s a lot of work compared to what modern Grid can do in just three lines of CSS! To make the task easier, I created an SCSS-powered mixin I call Gutter Grid. Once Gutter Grid is installed in the project, you can quickly create a three-column grid with 20px gaps using the following SCSS code:

.grid-wrapper { overflow: hidden; /* Need this for the chrome bug */ } .grid { @include grid($cols: 3, $gutter: 20px); }

You can write it even shorter like this if that feels too verbose:

.grid-wrapper { overflow: hidden; } .grid { @include grid(3, 20px); }

Gutter Grid comes pre-built with a few sets of breakpoints so you may not have to write any breakpoints at all if your grid spans the whole page! If you do need custom breakpoints, though, then Gutter Grid lets you easily customize them like so:

// Verbose custom breakpoints @include grid($cols: 7, $gutter: 20px, $breakpoints: ( 4 : 960px, // At 960px or below, there will be 4 columns 2 : (max, 600px), // You can use mq-scss syntax here as well 1 : 480px, )); // Short version @include grid(7, 20px, ( 4 : 960px, 2 : 600px, 1 : 480px, ));

As you might have noticed in the example, Gutter Grid also supports the same media query syntax that this thing called mq-scss uses. If you are wondering what that is, well, it’s a Sass mixin that I created that makes writing and managing media queries about a million times easier. Using mq-scss statements to dictate column count allows for very fine control over when the column count changes.

Adding shadows to the grid cells

Since we are working with shadows now, I’ll take the box shadow off of the example image. Our starting grid looks like this now:

A basic 3 x 2 grid with gaps and a green border around the outside

If we try to add an outer box-shadow to each grid cell right now… well it doesn’t look so good:

Adding shadows to the grid cells causes the shadows to be out of alignment

Let’s fix that.

Step 1: New HTML

In order to create nice shadows, we need to add an extra div inside each grid cell. You can’t really use ::before or ::after for this since they are unable to contain HTML content inside of them.

<div class="grid-wrapper"> <div class="grid"> <div class="grid-cell"> <div class="grid-cell-inner"></div> </div> <div class="grid-cell"> <div class="grid-cell-inner"></div> </div> <div class="grid-cell"> <div class="grid-cell-inner"></div> </div> <div class="grid-cell"> <div class="grid-cell-inner"></div> </div> <div class="grid-cell"> <div class="grid-cell-inner"></div> </div> <div class="grid-cell"> <div class="grid-cell-inner"></div> </div> </div> </div> Step 2: Flex it

Now, we need to make each grid cell a flex container. This will allow the inner part of the grid cell to take up the full height of its parent. We will also need to set the inner element to a width of 100%. This ensures that it will take up the full dimensions of its parent, both horizontally and vertically:

.grid-cell { /* Forces inner to take up full grid cell height */ display: flex; } .grid-cell-inner { /* Forces inner to take up full grid cell width */ width: 100%; }

Let’s see what we get if we try adding box shadows to the inner elements:

.grid-cell-inner { box-shadow: 0 0 10px 3px blue; } Box shadows appear around grid cells but are getting cut off

That’s much nicer, but it is still not quite there yet. The hidden overflow that we are using to prevent the Chrome bug is getting in the way.

Step 3: Hacky padding

So, we need to allow overflow but still avoid this Chrome bug. The only other safe way I’ve found to do that is with padding. By adding 1px of padding to the top and bottom of the outer grid wrapper element, it will fix the Chrome bug.

.grid-wrapper { /* Prevents odd margin behaviour in Chrome */ padding: 1px 0; }

This comes at the expense of having an extra 1px of space at the top and bottom of the grid. The image below demonstrates how this ends up looking. The shadows have been lightened to show the 1px gap more clearly.

1px of padding at the top and bottom of the grid

Note: You can avoid the 1px of top padding by opting not to include the top padding gap value on the grid element. The 1px of bottom padding can’t be avoided though.

A border width applied to the outer grid wrapper will also work, so technically I didn’t need to apply the padding to the example above. Most of the time, if we are applying a shadow to grid cells, then we probably don’t want to see a border wrapped around them. The above example was more demonstrating how minor the padding is.

This is what the grid looks like without the outer border:

3 x 2 shadow cell grid 2 x 3 shadow cell grid 1 x 6 shadow cell grid

Here is a Pen showing the final product:

See the Pen Fake grid with shadows by Daniel Tonon (@daniel-tonon) on CodePen.

Gutter Grid shadows

Let’s cover how to add shadows on Gutter Grid cells. You can use the same HTML structure we used in the previous example.

Now, apply this SCSS to create a three-column grid that has a 20px gutter:

.grid { @include grid(3, 20px, $inners: true); }

This new $inners: true property tells Gutter Grid that the grid cells each have a single child element that needs to take up the full height and width of its parent grid cell.

Instead of using overflow: hidden, use 1px of bottom padding on the wrapper element.

.grid-wrapper { padding-bottom: 1px; }

Gutter Grid will not output a top outer gutter if it doesn’t need to. This helps avoid issues around the Chrome negative margin bug. After all, if there is no top outer gutter to negate with a faulty negative margin, then there is no bug to worry about. The bottom outer gutter is still a problem, though, and that is why we need the 1px of bottom padding. This 1px of bottom padding tends to be barely noticeable (if at all), so don’t worry about it too much.

Now, add your shadows and you’ve got yourself a Gutter Grid with shadow cells!

.grid-cell-inner { box-shadow: 0 0 10px 3px blue; } 3 x 2 shadow cell grid

I’ve only scraped the surface of what Gutter Grid can do in this article. Make sure to read the full documentation to learn what else it’s capable of.

We come to the end of our IE grid adventure

I hope you have enjoyed this foray into the world of IE and CSS grid. Make sure to read through Part 1 and Part 2 if you haven’t already. Having read all three articles, you will now be fully equipped to make some truly stunning layouts that look just as good in IE as they do in modern browsers.

If you ever see anyone complaining about not being able to use CSS grid because of IE, you know what to do. Playfully slap them on the head for being so foolish and send them here to get the truth.

Now go forth, my friends, and build some grids! &#x1f603;&#x1f389;

Article Series:
  1. Debunking Common IE Grid Misconceptions
  2. CSS Grid and the new Autoprefixer
  3. Faking an auto-placement grid with gaps (This Post)

The post CSS Grid in IE: Faking an Auto-Placement Grid with Gaps appeared first on CSS-Tricks.

Prototyping in the Browser

Css Tricks - Thu, 07/05/2018 - 4:04am

Prototyping animations and interactions is vital for a number of reasons: they can make your interface feel deceptively fast, they can help focus the user on a specific task, and they can provide a better sense of the current state of your application. Is data being loaded? Is something now unclickable? How long do they have to wait until they can perform an action?

At Gusto, I’ve been working on a lot of tiny interaction details and prototypes lately for these very reasons — sadly there’s not much that I can show you all in detail just yet. But, I think the process of how I’m doing this is far more interesting than what I’m actually working on so that's what I'm going to share here.

The problem I’ve faced with prototyping animations comes down to the tools because they ultimately feel restrictive to me. Whenever I’ve experimented with them in the past, I feel like one hand is always tied behind my back. It could very well be that I’m not using them correctly, but I feel that none of them really mimic browser behavior quite right and, although I’ve been fascinated to watch tools like Framer, Marvel, Zeplin and Principle gain traction, I don’t think they’re for me. At least not yet anyway.

In my opinion, the best way to prototype a lot of interactions is still with plain ol’ HTML, CSS and (gasp!) a sprinkle of jQuery when I need it.

How I’m prototyping today

With my recent project, I decided to invest a little bit of time into CodePen to help our design team quickly prototype things. Here’s what I built:

See the Pen Gusto Prototype: Header by Robin Rendle (@robinrendle) on CodePen.

No really, that’s it. It’s just a simple prototype that looks like our app.

It’s a pen with all the HTML for the app navigation — and it contains all the CSS, too. This way, a designer at Gusto can fork that pen and start writing HTML and CSS to experiment with a specific bit of UI without all the added pressure of having to write production code. It’s important to note that this prototype isn’t for figuring out UX, as tools like Figma and Sketch do a much better job of that. Prototypes like this are mostly useful when figuring out finicky UI interactions like tables, spreadsheets and dropdowns — components that can get complicated real quick.

To make this prototype, I simply copied and pasted all of the HTML and CSS from our web app into a new pen. (In the future, we should probably have a system where we’re always prototyping with the latest up-to-date code from our app but, for now, I think this is a fine starting point.) This pen contains all of the menu and navigation items we need to make it look like the Gusto app. We have a a separate pen for the footer which closes off all the divs that we open up in the header. Lastly, we have one more pen that imports those two other pens like so:

<!-- HEADER --> [[[http://codepen.io/robinrendle/pen/481a88853820067752e28cdb479c91f3]]] <!-- HTML GOES HERE --> <h1>App Prototype</h1> <p>You can fork this pen and write all the HTML and CSS you need to prototype interactions and explore ideas right here in your browser.</p> <!-- FOOTER --> [[[http://codepen.io/robinrendle/pen/0dcaa93954f06f4d03b7e23e8ea54cac]]]

See the Pen Gusto Prototype: Full by Robin Rendle (@robinrendle) on CodePen.

What’s that weird syntax with all the [[[ ]]]? That’s the HTML Include syntax for CodePen. If we put the URL of a pen in between those brackets, CodePen will fetch the code from that pen and place it straight into this new pen. That’s it! Pretty sweet, right?

To wrap things up, I wanted to make a couple of notes about what I’ve learned with this new setup.

Lesson 1: Prototypes should be super easy to share

Ideally, prototypes are easy to share with other designers and engineers, exceptionally fast to get setup, and don’t require prior training or expertise — and Codepen is perfect for that. I like this setup for a bunch of reasons. For one, we don’t have to teach designers CoffeeScript like we have to with Framer and we don’t have to run React or Vue workshops to get them up and running with a complex prototyping app.

Yes, folks do need to learn how HTML and CSS works to make prototypes like this but I think learning the very basics of those two languages is vital for a designer working on the web anyway.

Lesson 2: Bad code is a-okay

Here’s another thing I recently learned while doing prototyping: bad code is okay at this stage. In fact, we should be writing terrible, unforgivable code when prototyping in the browser. We ought to write the sort of CSS and HTML that would keep Harry Roberts up at night because clean, maintainable code gets in the way of the design process when the focus should be on iterating as quickly as possible.

To be quite honest, I don’t care about front-end best practices when I’m making these prototypes — I don’t think about BEM, semantic HTML or even performance. Oh, and I certainly don’t care about the most proficient way to render a React thingamijig.

As long as we ditch all of that prototype code and start from scratch later, and as long as there’s step to break the design into components and ensure that those lego pieces are maintainable, well documented, and highly performant in our production environment, then I believe that writing bad should not only be allowed, but actively encouraged.

This leads to my final takeaway.

Lesson 3: Designers and developers should always translate their code

I reckon that the first time a designer and/or front-end developer writes code, it should never be in a production environment. Having the leeway and freedom to go crazy with the code in a safe environment focuses your attention on the design and making it compatible with a browser’s constraints. After this, you can think about grooming the code from a hot, steaming heap of garbage into lovely, squeaky-clean, production-ready poetry. Translating the static mockups into an interactive prototype is the first step, but it’s vital to have a next step to enforce your code standards.

Does your app use BEM? How should you abstract each of these components into separate files? What do you call all of these new components that you’re introducing into the design system?

I believe all of these questions are easier to answer once you have that interactive prototype. And I would highly recommend that designers and front-end engineers alike experiment making little tools like this. It might feel a little odd at first, but I promise that it will produce much better work in the long run.

The post Prototyping in the Browser appeared first on CSS-Tricks.

?Reinvest Your Time with HelloSign API

Css Tricks - Thu, 07/05/2018 - 3:01am

HelloSign API makes it simple to embed secure and legally binding eSignatures directly into any website. It's 2x faster to implement than other eSign solutions and is also the only eSign API that allows customers to completely white label the integration, meaning our customers can give their customers a seamless, native signing experience. The three key features of the HelloSign API are the ability to collect signatures, request signatures, and format documents for signing directly on any site. Integrations go smoothly with help from tools like the API Dashboard, an industry-first feature that makes it easy for developers to debug and view critical information about API requests and responses. What are you going to do with all that time you saved by using HelloSign API?

Try it free today

The post ?Reinvest Your Time with HelloSign API appeared first on CSS-Tricks.

4 UX Necessities That All Food Delivery Apps Should Have

Usability Geek - Wed, 07/04/2018 - 12:35pm
As Apple’s trademarked saying goes, “There’s an app for that”. For the sake of making users’ lives more comfortable, I could not agree more. Picture this: You are...
Categories: Web Standards

The Eleventh Fourth

Css Tricks - Wed, 07/04/2018 - 6:18am

Holy heck it feels like the last year has flown by! Longtime readers will remember that the fourth of July is CSS-Tricks birthday and we blog it each year. We turned 10 last year, and now we welcome our first palindromic number birthday.

Huge thank you

First, as ever, thank you for being part of CSS-Tricks. However you end up here, we hope that we're useful to you, know that we're always trying to be even more useful to you, and know that you make the site possible.

Can we ask you some questions?

The whole point of this survey is to understand you better and use that understanding to make choices that serve you better. That's it! It's super helpful to us and totally anonymous.

Take the CSS-Tricks Reader Survey

A new design is coming

Hate to be a tease, as there is nothing to show you yet and no timeline to share, but I suppose this should be of little surprise to you as we've never been shy for a bit of a redesign around here. This will be version 17, believe it or not. I mention it in part because of above. We're asking you questions because you can help inform how the design takes shape.

What's new in this past year?

What stands out to me is that in the last year we've invested way more into CSS-Tricks (literally financially) than ever before. What that means for you is that we've brought you way more articles from way more authors than we ever have before. Plus stuff that is higher-budget and longer-form for us, like our new Gutenberg Guide.

We hope the result of that investment is that it makes CSS-Tricks both a more interesting site to subscribe to and read regularly, and adds more referential content for years to come. Articles may come across your path today that are only of passing interest, but become more valuable later should that subject become part of a more active project for you.

It also means a more integrated staff here. We've always had a small staff of part-time writers and collaborators, like the venerable Sarah Drasner, who has brought you big stuff like an entire guide to Learning Vue and fascinating insights like how she created a VS Code theme.

Now, notably, we have Geoff Graham as lead editor keeping the site rolling nicely. I've gotten to watch Geoff really step into the editor role and become a very strong editor in every way, which is extra challenging on a site like this where that job isn't just spelling, grammar, readability, formatting and all that, but also very technical. Between Geoff and I, we hope we're bringing a high level of editorial quality to all our technical posts.

We also have Robin Rendle who produces the newsletter each week, bringing his own voice to that and providing another way to read CSS-Tricks with content unique to it. Robin keeps an eye on our industry quite well, sharing great links and producing his own typography-focused newsletter.

The world of technical writing has exploded.

I don't think I'm imagining it, there is simply way more technical blogging happening now than there ever has been. My guess is because there are more developers than there ever has been. The world economy is more and more technology focused, so there are massive job opportunities in tech, and education has sprung up to help people get those jobs. So the world has far more educated developers living and loving this world, writing about what they know, and making a name for themselves along the way.

All the classic publications are still around that I immediately think of in this genre, like A List Apart, Smashing Magazine, SitePoint, and Envato's blogs.

But now we have Medium which is loaded with technical writing. Just look at the JavaScript topic, or huge publications on Medium like freeCodeCamp, UX Planet, and Hacker Noon. freeCodeCamp alone is publishing like 5 articles a day!

How about DEV Community, which, like Medium, has become a hive of technical writing open to anyone. There there are incredibly prolific writers like Flavio Copes who publishes great guides and reference posts literally every day.

It very certainly a good thing for our industry. But since we're trying to be a business in this atmosphere, it means we need to really stay on our game here and make sure we're doing the best we can.


I posted this same graph last year, now updated for this year:

I like it because of how zoomed out it is. That's the entire history of CSS-Tricks traffic in pageviews. Perhaps we're not growing as fast as the industry is, but we're growing. That peak in May 2018 is cool to see: it's the most traffic in a single month in our history. It's almost a silly statistic, as it's much more meaningful to know how impactful you are being and how people feel about you, but hey, basic analytics are what we got on a wide scale.

What a wild year of life.

Personal note! Last year in July I got married. Then we sold our house in Milwaukee, Wisconsin and moved to Bend, Oregon where we're renting a house. We got a brand new business office in Bend. Then we had a baby (Ruby!). Then we bought a new car so we'd have a mountain-worthy 4-wheel drive car that's super safe. Now we're looking to close on a new house in Bend. As far as a 12-month period goes, this has been the busiest of my life, not factoring in anything business related at all, which had its own roller coasters.

At Todd Lake in Bend, Oregon

It's been a wonderful journey, but not without significant stress. I'm living in a whole new world of purpose and worry. Hi.

Speaking of businesses...

Dave Rupert and I are trucking along well past episode 300 now on ShopTalk Show. The ideas come easy and the conversation is as fun and enlightening as it ever was. I consider Dave a mentor, as his broad experience is constantly growing and with it, his perspective. I'm still pretty convinced that podcasts are in the early days of popularity, so it feels good to be still on that train. Gosh I wish we could make time to really redesign that site though. The current one is something I kinda slapped together after we did this big round of cleaning up data on the back end. Now we have great data to work with, but my lame design. Someday!

Most of my time though of course is on CodePen. We have big ideas for what CodePen can become and are always striving to get there as we tend to the lovely place that CodePen already is. We have features of all kinds, from huge to little, coming your way. Hardly a day goes by without us shipping some kind of improvement to CodePen.

CodePen has a podcast too, ya know!

See the Pen Elenium fireworks by JK (@funxer) on CodePen.


I'd love to give a bonus high five to all the sponsors that have generously supported the site. We don't really sell anything at the moment here at CSS-Tricks, so sponsors entirely make the site possible. I've long been a fan of this model. Companies can focus on building the best products and services they can (rather than building an audience), and publications like us can focus on an audience. Then we trade! Companies support us, we can tell you about those companies. Companies that align with our values, of course.

Media Temple has been our long time sponsor and web host. You may have noticed Jetpack sponsorship around here recently, which is quite definitely my favorite WordPress plugin. Those companies power this site!

And a warm welcome to other newcomers like Netlify, HelloSign, Pusher, and An Event Apart.

If your company is interested, here's more information. We can build custom packages to meet your needs.

What can we do for you?

We have the survey like I mentioned, but I mean more directly. Feel free to comment below or contact us directly.

If your wish was our command, what would you have us do? Is there anything you'd like help learning? A reference guide you wish existed? A resource you'd like to be handed? We're in the business of making those things happen the best we can for you.

Again, thank you

Whether you ever see this or not, I like writing it. Thanks for all your support. Here's to another year!

The post The Eleventh Fourth appeared first on CSS-Tricks.

CSS Grid in IE: CSS Grid and the New Autoprefixer

Css Tricks - Wed, 07/04/2018 - 5:00am

In Part 1 of this series, I debunked a few misconceptions that many people have around the Internet Explorer (IE) implementation of CSS grid. This article builds on that knowledge. It would be best to go back and read that article first if you haven’t already.

Today I’m going to be tackling the biggest misconception of all: that utilizing the IE implementation of CSS grid is extremely difficult. You can easily use CSS grid in IE right now without having to give it any sort of crappy fallback layout. It really isn't that hard.

Article Series:
  1. Debunking Common IE Grid Misconceptions
  2. CSS Grid and the new Autoprefixer (This Post)
  3. Faking an auto-placement grid with gaps

Giving IE a crappy fallback layout is a bit of a tough sell to clients. It is especially tough if this is for an intranet where 90% of the users are using IE. If you want IE compatibility, first you need to resign to the fact that you can't use all of the fancy bells and whistles that can be found in the modern CSS grid spec. Don’t let this get you down though, you would be amazed by how much IE11 can handle, especially if it has some help from Autoprefixer.

Before I get too far into this, you need to know that this isn’t a general "how to use CSS grid" article. This article is for those that understand CSS grid, but are either too afraid or not allowed to use it, thanks to IE.

I’ll be assuming that you already have a good understanding of how to use CSS grid in modern browsers for this article. If you aren’t sure about how to use CSS grid yet, go watch Rachel Andrew’s excellent CSS grid video tutorial series. After that, go play some levels of the browser game Grid Garden to get some hands-on CSS grid experience. Once you understand the basics of how to use CSS grid in modern browsers, come back here and learn how to use it in a way that produces identical results in IE10 and 11.

Setting up Autoprefixer

Before you do anything else, you will want to get Autoprefixer up and running. Autoprefixer is a tool used for automatically adding browser-specific CSS prefixes to your CSS so that you don’t have to. It’s a bit like Babel but for CSS. (We have a great overview by the creator of Autoprefixer here on CSS Tricks.)

If you have never used Autoprefixer (or any build tool) before, then first install Node on your computer then follow this guide on how to get a basic workflow up and running. The bit in the guide specifically about Autoprefixer is found here. (I recommend the Gulp setup over Grunt if you aren’t sure which to go with.)

If you are already using Autoprefixer in your projects, make sure to update it to the latest version using this command:

npm i autoprefixer@latest -D

Some features used in the latest version of Autoprefixer are not supported in PostCSS version 5. This means that you may also need to update your version of PostCSS to at least version 6. If using Gulp, that means updating gulp-postcss to at least v7.0.0. If using Grunt, you may need to update grunt-postcss to at least v0.9.0.

Once you have an environment up and running, you will need to set the Autoprefixer grid setting to true. Without that setting turned on, Autoprefixer will not be able to do any of the cool stuff that I’m about to show you.

The exact method for turning the grid setting on depends a lot on how you compile your code. If you were using the guide that I linked to earlier, you would have seen this snippet of code:

var processorsArray = [ // snipped for brevity require('autoprefixer')({ browsers: ['last 2 versions', 'ie 6-8', 'Firefox > 20'] }) ];

Add grid: true to the options to turn grid prefixing on:

var processorsArray = [ // snipped for brevity require('autoprefixer')({ grid: true, browsers: ['last 2 versions', 'ie 6-8', 'Firefox > 20'] }) ];

By the way, the browser settings in the tutorial are pretty outdated and will be outputting far more prefixes than you actually need. Just going with ">1%" will mean that when a browser dies, Autoprefixer will automatically stop writing prefixes for that browser. It bases browser usage on global browser data retrieved from caniuse.com.

So, these are the Autoprefixer settings that you should end up using:

var processorsArray = [ require('autoprefixer')({ grid: true, browsers: ['>1%'] }) ];

Now onto the fun stuff! &#x1f603;

Autoprefixer has new super powers!

You may have read Rachel Andrew’s article "Should I try to use the IE implementation of CSS Grid Layout?" That article is all about CSS grid and understanding it’s support in IE10 and 11. It’s a great article and very useful for understanding IE’s limitations. Definitely still worth a read if you haven’t already checked it out. Note that it is extremely outdated in terms of its information on Autoprefixer though.

Autoprefixer has come a long way since Rachel wrote her IE11 CSS grid article and Autoprefixer now supports far more CSS grid translations. Take a look at this new, updated version of Rachel’s table based on Autoprefixer version 8.6.4. Note that items in bold represent a change in Autoprefixer support compared to Rachel's article:

CSS Grid Property IE10 Implementation Autoprefixer? Notes grid-template-columns -ms-grid-columns Yes grid-template-rows -ms-grid-rows Yes grid-template-areas NA Yes Autoprefixer uses this to understand what the grid looks like but does not add any extra properties. grid-template NA Yes Shorthand for grid-template-columns, grid-template-rows, and grid-template-areas grid-auto-columns NA No IE doesn’t support auto-placement grid-auto-rows NA No IE doesn’t support auto-placement grid-auto-flow NA No IE doesn’t support auto-placement grid NA No See this GitHub issue as to why this isn’t supported grid-row-start -ms-grid-row Yes1 Span syntax requires grid-row-end to be defined grid-column-start -ms-grid-column Yes1 Span syntax requires grid-column-end to be defined grid-row-end NA Yes1 grid-row-start must be defined grid-column-end NA Yes1 grid-column-start must be defined grid-row NA Yes1 grid-column NA Yes1 grid-area NA Yes2 Autoprefixer translates the grid area into column/row coordinates grid-row-gap NA Yes3 Generates extra rows/columns in IE. grid-column-gap NA Yes3 Generates extra rows/columns in IE. grid-gap NA Yes3 Generates extra rows/columns in IE. NA -ms-grid-column-span Yes Translated from grid-column-end and grid-area. NA -ms-grid-row-span Yes Translated from grid-row-end and grid-area. align-self -ms-grid-row-align Yes justify-self -ms-grid-column-align Yes Table disclaimers

I will cover these in far more detail later in the article:

  1. Autoprefixer cannot prefix negative integers.
  2. Each grid element must have unique area names.
  3. Autoprefixer only prefixes grid-gap if both grid-template-areas and grid-template-columns have been defined. It also cannot inherit grid-gap through media queries.
grid-template-areas is your new best friend

As you can see from the updated (and much more positive-looking) table, there are a lot of cool new features in Autoprefixer now. The most important of which is its support for grid-template-areas (and by extension grid-template). By supporting grid-template-areas, Autoprefixer now understands exactly what your grid looks like. This paved the way for Autoprefixer to also support (in a limited capacity) grid-gap.

Note that Autoprefixer still does not support the shortcut grid property. This was an intentional design decision that you can learn more about in this GitHub issue. The short story is that the grid property is not only a shortcut for the templating settings but also the auto-placement settings. Since IE can’t do auto-placement and the grid-template property can essentially do anything that the grid property can do (that IE can handle), it was decided that the grid property wasn’t worth supporting.

Back when Rachel wrote her article, this was the sort of grid code you would need to write in order to support IE:

/* IE-friendly source code 26 November 2016 */ /* Code needed to make Autoprefixer work properly */ .grid { display: grid; grid-template-columns: 1fr 10px 1fr; grid-template-rows: 100px 10px 100px; } .cell-A { grid-column: 1; grid-row: 1; } .cell-B { grid-column: 3; grid-row: 1; } .cell-C { grid-column: 1; grid-row: 3; } .cell-D { grid-column: 3; grid-row: 3; }

Now, you can write code like this instead:

/* Today’s IE-friendly source code */ /* Autoprefixer can now make this code IE safe */ .grid { display: grid; grid-gap: 10px; grid-template: "a b" 100px "c d" 100px / 1fr 1fr; } .cell-A { grid-area: a; } .cell-B { grid-area: b; } .cell-C { grid-area: c; } .cell-D { grid-area: d; }

Autoprefixer will take the above code and translate it into this much more IE-friendly code for you:

/* Autoprefixer’s IE-friendly translation */ .grid { display: -ms-grid; display: grid; grid-gap: 10px; -ms-grid-rows: 100px 10px 100px; -ms-grid-columns: 1fr 10px 1fr; grid-template: "a b" 100px "c d" 100px / 1fr 1fr; } .cell-A { -ms-grid-row: 1; -ms-grid-column: 1; grid-area: a; } .cell-B { -ms-grid-row: 1; -ms-grid-column: 3; grid-area: b; } .cell-C { -ms-grid-row: 3; -ms-grid-column: 1; grid-area: c; } .cell-D { -ms-grid-row: 3; -ms-grid-column: 3; grid-area: d; }

Best of all, you can then simply change the grid-template or grid-template-areas property with a media query and Autoprefixer will automatically update all of the grid cell coordinates for you:

/* Changing a grid-template with a media-query */ .grid { display: grid; grid-gap: 10px; grid-template: "a b" 100px "c d" 100px "e f" 100px / 1fr 1fr; } @media (min-width: 600px){ .grid { /* Autoprefixer 8.6.4 doesn't inherit grid gaps :( */ grid-gap: 10px; grid-template: "a b c" 100px "d e f" 100px / 1fr 1fr 1fr; } } .cell-A { grid-area: a; } .cell-B { grid-area: b; } .cell-C { grid-area: c; } .cell-D { grid-area: d; } .cell-E { grid-area: e; } .cell-F { grid-area: f; }

The above gets translated into this IE-friendly code:

/* Autoprefixer’s IE-friendly media query translation */ .grid { display: -ms-grid; display: grid; grid-gap: 10px; -ms-grid-rows: 100px 10px 100px 10px 100px; -ms-grid-columns: 1fr 10px 1fr; grid-template: "a b" 100px "c d" 100px "e f" 100px / 1fr 1fr; } @media (min-width: 600px) { .grid { /* Autoprefixer 8.6.4 doesn't inherit gaps :( */ grid-gap: 10px; -ms-grid-rows: 100px 10px 100px; -ms-grid-columns: 1fr 10px 1fr 10px 1fr; grid-template: "a b c" 100px "d e f" 100px / 1fr 1fr 1fr; } } .cell-A { -ms-grid-row: 1; -ms-grid-column: 1; grid-area: a; } .cell-B { -ms-grid-row: 1; -ms-grid-column: 3; grid-area: b; } .cell-C { -ms-grid-row: 3; -ms-grid-column: 1; grid-area: c; } .cell-D { -ms-grid-row: 3; -ms-grid-column: 3; grid-area: d; } .cell-E { -ms-grid-row: 5; -ms-grid-column: 1; grid-area: e; } .cell-F { -ms-grid-row: 5; -ms-grid-column: 3; grid-area: f; } @media (min-width: 600px) { .cell-A { -ms-grid-row: 1; -ms-grid-column: 1; } .cell-B { -ms-grid-row: 1; -ms-grid-column: 3; } .cell-C { -ms-grid-row: 1; -ms-grid-column: 5; } .cell-D { -ms-grid-row: 3; -ms-grid-column: 1; } .cell-E { -ms-grid-row: 3; -ms-grid-column: 3; } .cell-F { -ms-grid-row: 3; -ms-grid-column: 5; } }

The duplicate media query might look a bit ugly but I assure you that this is the best possible way that Autoprefixer can handle the media query translation. The new IE grid cell coordinates could not be placed into the same media query as the grid template definition. Doing so would lead to one of two possible outcomes. One outcome is that the default grid cell positions would override the altered positions stated in the media query. This would cause the media query to have no effect in IE. The other outcome would be for Autoprefixer to shift all of the styles inside the media query (yes, that includes all of the styles that you wrote yourself) to another location in the style sheet, potentially causing horrific CSS specificity issues. You can learn more about the thinking behind this decision in the now closed GitHub issue for it.

Autoprefixer still can’t save you from everything

Even Superman can’t always save everyone and Autoprefixer is no different. While Autoprefixer is able to cut down on a lot of the workload involved in making our grids IE-compatible, it can’t fix everything. It can only translate things that IE can understand. These are the many critical things that you need to be aware of if you don’t want to open the site up in IE one day and have it blow up in your face.

Grid Gap has limited support

As you may have seen in that last example, grid-gap isn’t currently able to be inherited through media queries. If you want to use grid-gap, you will need to duplicate the grid-gap setting across all of the media queries where you define a grid template for that grid. There is an issue open on GitHub about this. Go give it a thumbs up if you want Autoprefixer to support it. Hopefully the issue is fixed soon.

That isn’t the only problem around using grid-gap though. It is only supported by Autoprefixer when both grid-template-areas and grid-template-columns have been defined.

Autoprefixer adds grid-gap support by using grid-template-areas to understand what your grid looks like. It then takes your grid-template-columns and grid-template-rows definitions and injects the grid-gap value between each row and column, creating extra rows and columns in IE.

If you try to use grid-gap on its own without grid-template-areas, Autoprefixer has no way of knowing what cell belongs to what grid. Without that critical knowledge, it cannot safely inject the extra columns and rows that IE needs.

That explains grid-template-areas but why do we also need to define grid-template-columns? Shouldn’t something like this be just as easy for Autoprefixer to translate?

.grid { display: grid; grid-gap: 20px; grid-template-areas: "a b c" "d e f"; } .cell-a { grid-area: a; } .cell-f { grid-area: f; }

Rows and columns in CSS grid default to a value of auto so can’t Autoprefixer just add something like -ms-grid-columns: auto 20px auto 20px auto;? It does that for rows, so why can’t it do the same thing for columns?

Well my inquisitive friend, I explained in Part 1 that auto in IE acts a bit differently to auto in modern browsers. When columns are set to auto in IE, they will always shrink down to the value of max-content. Modern grid columns, on the other hand, will expand to 1fr if there are no other fr units being used in that grid template declaration. This discrepancy can cause a massive difference in appearance between the modern and the IE version of a grid. The Autoprefixer team felt that it was too dangerous to make assumptions about this, so they made grid-template-columns a mandatory setting in order for grid-gap to take effect.

So that explains why Autoprefixer doesn’t support grid-gap when grid-template-columns is missing. If auto behaves so differently in IE, then why does Autoprefixer support grid-gap without the user explicitly having to define grid-template-rows? Isn’t that just as bad?

Not really. When you set display: grid; on something, it’s width will grow to the full width of its container. Its height, on the other hand, typically shrinks to the height of its content. Of course this isn’t always the case. There are a number of reasons why a grid might be taller than its content. If the grid is also a flex item and the flex container is taller than the grid, then that would be one reason why the grid might be taller than its content. In general though, if there are no other forces involved, then a grid container will always be the same height as its content.

Since the height of a typical grid is the same height as its content, in most cases, auto in both IE and modern browsers will behave identically to one another. It will only differ in functionality if the height of the grid exceeds the height of the content inside of it. For the best balance between user convenience and browser consistency, the Autoprefixer team made a choice. They decided that supporting a missing grid-template-rows property but not a missing grid-template-columns property was the best way to handle grid-gap support.

No auto-placement! No auto-placement! No auto-placement!

I really can’t say this enough. The most important thing to remember when using CSS grid in IE is that everything must be placed manually. The instant you start thinking about using auto-placement is the instant your site blows up in IE. I have a method for dealing with grids that have an unknown number of cells in them. I’m covering that in Part 3 of this series. The main thing to know right now is that if you want to use CSS grid in an IE-friendly way, you should only ever use it if there are a known number of cells for a known number of rows and columns.

It’s this lack of auto-placement in IE that makes having access to grid areas through Autoprefixer such a blessing. Instead of having to calculate all of the coordinates manually, you can instead name each cell and then let Autoprefixer do the math for you. When using media queries, you only need to redefine the grid template and autoprefixer will recalculate all of the coordinates for you. You rarely have to do any column or row counting. It’s great!

Area names must be unique

The ability to use grid-template-areas is one of Autoprefixer’s greatest strengths, though it has its limits. Autoprefixer does not have any access to the DOM. Due to this, Autoprefixer is entirely dependent on using the area name for understanding where each cell needs to be placed in the grid. This can cause clashes if you use the same area name twice in the same stylesheet.

Here is a small example. Early in the stylesheet, Grid Alpha has grid-template-areas: "delta echo". Later in the stylesheet, Grid Beta has grid-template-areas: "echo delta". We say that our grid cell belongs to area echo... so does it go in column 1 or 2?

.grid-alpha { grid-template-areas: "delta echo"; } .grid-beta { grid-template-areas: "echo delta"; } .grid-cell { /* What column does .grid-cell go in? */ -ms-grid-column: ???; grid-area: echo; }

Modern browsers know exactly what column to place the grid cell in because they have access to the DOM. If the cell is placed inside Grid Alpha, it will go in the first column. If it is placed in Grid Beta it will go in the second column. Autoprefixer can only read your CSS. It has no idea if the grid cell is placed in Grid Alpha or Grid Beta. All it knows is that the grid cell needs to be placed in the "echo" area. Autoprefixer resolves this conundrum by going with whichever one came last in the stylesheet. In this case, Autoprefixer will honor Grid Beta's "echo delta" areas definition since it occurs last. If you placed the grid cell inside Grid Alpha, it would look great in modern browsers but it would be placed in the wrong column in IE.

This also means that you can’t really use the strategy of giving a component a single designated area name that is repeatedly referenced. Referencing that area name in more than one grid-template-areas property will break IE for sure. Every single area name across every single grid in your style sheet needs to be unique or Autoprefixer will freak the heck out.

Autoprefixer currently does not warn you when you have used a duplicate area name in your stylesheet. If you would like to start seeing warnings for duplicate area names, there is an issue open on GitHub that you can add your support to. In the meantime, the easiest way to ensure that each area name is unique is probably adopting a BEM style approach to naming the areas.

.grid-alpha { grid-template-areas: "grid-alpha__delta grid-alpha__echo"; } .grid-beta { grid-template-areas: "grid-beta__echo grid-beta__delta"; } .grid-cell { /* No more conflict :) */ -ms-grid-column: 2; grid-area: grid-alpha__echo; }

This can be pretty verbose if there are lots of columns and rows. You might want to shorten it down to an abbreviation instead. Of course, the less verbose your area names, the more chance there is of a conflict.

.grid-alpha { grid-template-areas: "ga_delta ga_echo"; } .grid-beta { grid-template-areas: "gb_echo gb_delta"; } .grid-cell { -ms-grid-column: 2; arid-area: ga_echo; }

There is one major exception. Grid areas in media queries are allowed to be duplicates of other areas as long as the area names defined in the media query are targeted at the same element. Without this exception, it would be impossible to change the grid areas based on screen size. The main thing to remember is that each grid has to have its own set of unique area names that must not be shared with any other grids.

@media (min-width: 600px) { .grid-one { grid-template-areas: "alpha bravo" "alpha charlie"; } } @media (min-width: 900px) { .grid-one { /* This is fine */ /* It is targeting the same element */ grid-template-areas: "alpha bravo charlie"; } } @media (min-width: 900px) { /* NOT FINE! */ /* The "alpha" area is being reused on a different element! */ .grid-two { grid-template-areas: "alpha delta"; } } Autoprefixer has limited column and row spanning support

There are only two properties in IE’s implementation of CSS grid that will help you span multiple columns. The main one being -ms-grid-column/row-span which tells IE how many columns/rows to span. The other being -ms-grid-column/row which tells IE where to start counting from.

.grid-cell { -ms-grid-column-span: 2; /* number of cells to span */ -ms-grid-column: 1; /* starting cell */ }

In modern browsers, you have access to far more options.

Autoprefixer friendly

Out of the modern ways to span multiple cells, Autoprefixer fully supports the following. Feel free to use any of these methods as much as you like:

Specify a starting line and the number of lines to span (similar to IE):

.grid-cell { grid-column: 1 / span 2; }

Specify an end line, then span backwards:

.grid-cell { grid-column: span 2 / 3; }

Specify a starting line and an end line directly:

.grid-cell { grid-column: 1 / 3; }

Specify only a number of cells to span using grid-column/row-end. Remember that IE can’t do auto-placement though. A starting line will still need to be specified elsewhere in the style sheet:

.grid-cell { /* Make sure you specify a starting line elsewhere */ grid-column-end: span 2; }

Specify only a starting line:

.grid-cell { /* The short way */ grid-column: 1; /* The more verbose way */ grid-column-start: 1; } Autoprefixer unfriendly. Here be dragons!

Now this is where Autoprefixer reaches its limit. The following methods are supported in modern browsers but are not supported by Autoprefixer. This is mainly due to Autoprefixer having no idea what grid the grid cell belongs to since it can only base its decisions on what is in the stylesheet.

Specify a starting line and how many lines from the end of the explicit grid to span:

.grid-cell { grid-column: 1 / -1; }

Specify both the start and end line from the end of the explicit grid:

.grid-cell { grid-column: -3 / -1; }

Specify only how many lines to span using the shorthand syntax (issue in GitHub):

.grid-cell { grid-column: span 2; }

Specify only a backwards span (IE can’t span backwards):

.grid-cell { grid-column-start: span 2; }

Specify only an end line (IE doesn’t understand end and Autoprefixer doesn’t know where the start is):

.grid-cell { grid-column-end: 3; }

So, basically avoid counting backwards from the end of the grid and you’ll be fine. &#x1f60a;

Avoid using line names for now

One of the cool features of modern grids is giving grid templates line names. Instead of using numbers to reference a line, you can give the line a name and reference that instead. Since Autoprefixer supports grid areas, you would think that they would also support line names. Unfortunately, that isn't the case. As of version 8.6.4, Autoprefixer does not support line names (at the time of writing). Don't worry though! It's not that it is impossible to support (at least not entirely), it just hasn't been a high priority for them. If you love using line names in your grids then let them know about it in the GitHub issue for it. Post your use cases and it will surely increase the priority of the feature. In the meantime, see if you can use grid areas instead for now.

Keep in mind that, if it is going to be implemented, then every line name across your stylesheet would need to be unique. Like with grid areas, Autoprefixer wouldn’t know what line name belongs to what grid. The only way it can tell is if every line name in the stylesheet is unique (excluding media queries).

You still need to test!

IE will behave itself most of the time as long as you follow all of the rules we’ve covered so far. That said, IE can still be a bit unpredictable. Just recently, I made a grid item a vertical flowing flex container and encountered an odd bug in IE11. The column width was set to minmax(min-content, 350px) but IE seemed to treat min-content like max-content in this circumstance. This completely broke the layout. Changing it to minmax(0, 350px) fixed the issue. Just goes to show that IE’s grid implementation isn’t quite perfect.

There are also times when you might accidentally forget to explicitly place grid cells. We build our grids in modern browsers because they have the nice grid development tools (especially Firefox). Modern browsers have auto-placement, though. This means that you might be halfway through building your grid then get called away for a moment. When you return to your desk, you see the layout looking beautiful in your browser, but you completely forget that you haven’t explicitly placed any grid cells yet. You move onto the next thing, blissfully unaware that you have left IE in a completely broken state.

Neither of those issues will reveal themselves until you test your site in IE11. Any time that you get a grid looking good in a modern browser, open it up in IE and double-check that it still looks the way you expect it to.

Autoprefixer control comments

Despite Autoprefixer's best efforts, there are still some rare occasions when it seems like Autoprefixer is hindering you more than it is helping you. If you ever find yourself in a situation where it would be easier to not have Autoprefixer translating your code, you can turn Autoprefixer off using something called a "control comment."

autoprefixer: off

This control comment will turn off Autoprefixer translations for the entire CSS block. It will not prefix any styles before or after the point where the comment is made.

/* Input CSS */ .normal-behavior { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; } .off-behavior { display: grid; /* autoprefixer: off */ grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; } .normal-behavior-again { display: grid; } /* Output CSS */ .normal-behavior { display: -ms-grid; display: grid; -ms-grid-columns: 1fr 1fr; grid-template-columns: 1fr 1fr; -ms-grid-rows: 1fr 1fr; grid-template-rows: 1fr 1fr; } .off-behavior { display: grid; /* autoprefixer: off */ grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; } .normal-behavior-again { display: -ms-grid; display: grid; } autoprefixer: ignore next

If you are after more of a scalpel than a sledge hammer, the /* autoprefixer: ignore next */ control comment is more for you. "Ignore next" will skip the next CSS declaration rather than ignoring the entire CSS block.

/* Input CSS */ .normal-behavior { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; } .ignore-next-behavior { display: grid; /* autoprefixer: ignore next */ grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; } /* Output CSS */ .normal-behavior { display: -ms-grid; display: grid; -ms-grid-columns: 1fr 1fr; grid-template-columns: 1fr 1fr; -ms-grid-rows: 1fr 1fr; grid-template-rows: 1fr 1fr; } .ignore-next-behavior { display: -ms-grid; display: grid; /* autoprefixer: ignore next */ grid-template-columns: 1fr 1fr; -ms-grid-rows: 1fr 1fr; grid-template-rows: 1fr 1fr; } Pre-processor comments

If you are using Sass (or another CSS pre-processor) in your project, do not use the double slash (//) method for writing these comments. Sass will strip those comments out before Autoprefixer has a chance to translate the code.

/* Input SCSS */ .normal-behavior { display: grid; } .failed-off-behavior { // autoprefixer: off display: grid; } .successful-off-behavior { /* autoprefixer: off */ display: grid; } /* Output CSS */ .normal-behavior { display: -ms-grid; display: grid; } .failed-off-behavior { display: -ms-grid; display: grid; } .successful-off-behavior { /* autoprefixer: off */ display: grid; } Let’s recap!

So, after all that, here is the list of all the things you need to remember to be an IE11 CSS grid master:

  • Use the latest version of Autoprefixer (npm i autoprefixer@latest -D).
  • Turn on the Autoprefixer grid setting.
  • Do not attempt to use auto-placement, every cell must be placed manually.
  • Use grid-template-areas as your primary method for placing grid cells into position.
  • Use grid-template (not grid) as a shortcut.
  • Don’t use duplicate area names unless they are inside a media query targeting the same element. Also, give this GitHub issue your support if you would like Autoprefixer to warn you when you have used a duplicate area name.
  • You can use grid-gap as long as you define both grid-template-areas and grid-template-columns.
  • grid-gap is currently not inherited through media queries. Go give this GitHub issue a thumbs up if you want to write less grid-gap code.
  • When spanning multiple columns and rows, avoid counting backwards from the end of the grid. Autoprefixer doesn't understand your grids well enough to supports this.
  • Avoid using line names for now. Give this GitHub issue a thumbs up if you want to start using them.
  • Use control comments /* autoprefixer: off */ and /* autoprefixer: ignore next */ to prevent Autoprefixer from translating certain parts of your style-sheet that are causing problems.
  • Don’t forget to test!

...and from Part 1:

  • IE does have an implicit grid.
  • IE supports repeat functionality.
  • minmax(), min-content and max-content are all natively supported.
  • fit-content() isn’t natively supported but you can work around this with auto and max-width settings.
  • IE auto is not equal to auto in modern browsers.

If you have any questions, or if this really helped you out, let me know in the comments! I’m also @Daniel_Tonon on Twitter. &#x1f601;

Up next...

In Part 3, I will be covering how to make a fully responsive flexbox-based grid in IE11. This flexbox technique even replicates grid-gap functionality!

Article Series:
  1. Debunking Common IE Grid Misconceptions
  2. CSS Grid and the new Autoprefixer (This Post)
  3. Faking an auto-placement grid with gaps

The post CSS Grid in IE: CSS Grid and the New Autoprefixer appeared first on CSS-Tricks.

Clearfix: A Lesson in Web Development Evolution

Css Tricks - Tue, 07/03/2018 - 3:15am

The web community has, for the most part, been a spectacularly open place. As such, a lot of the best development techniques happen right out in the open, on blogs and in forums, evolving as they’re passed around and improved. I thought it might be fun (and fascinating) to actually follow this creative exchange all the way through. To take a look at a popular CSS trick, the clearfix, and find out exactly how a web design technique comes to be.

The clearfix, for those unaware, is a CSS hack that solves a persistent bug that occurs when two floated elements are stacked next to each other. When elements are aligned this way, the parent container ends up with a height of 0, and it can easily wreak havoc on a layout. All you might be trying to do is position a sidebar to the left of your main content block, but the result would be two elements that overlap and collapse on each other. To complicate things further, the bug is inconsistent across browsers. The clearfix was invented to solve all that.

An early illustration of the issue from Position is Everything

But to understand the clearfix, you have to go back even further, to the 2004 and a particular technique called the Holly hack.

2004: The Holly Hack and the origin of Clearfix

The Holly hack is named for its creator, Holly Begevin, a developer and blogger at CommunityMX. The Holly hack combines two different CSS techniques that worked in the days of Netscape Navigator and Internet Explorer (IE) 4 to solve some layout issues. Begevin noticed that if you apply a height of just 1% to each of the floated elements in the above scenario, the problem would actually fix itself (and only because it activated an entirely different bug) in Internet Explorer for Windows.

Unfortunately, the 1% trick didn’t work on a Mac. For that, Begevin added a conditional comment which used a backslash inside of her CSS, which strangely enough, blocked individual CSS rules from IE for Mac in the old days. The result was a CSS trick that looked like this:

/* Hides from IE5-mac \*/ * html .buggybox {height: 1%;} /* End hide from IE5-mac */

Odd, I know, but it only gets more complicated.

That same year, in May, there were a few more browsers to deal with, and not all of them could be patched with one line of CSS. Tony Aslett posted a new thread to his message board, CSS Creator, proposing a new approach. He called the trick a clearfix because it centered around clearing the floated elements to fix the issue.

Aslett’s approach took advantage of what were, at the time, still very new CSS pseudo-selectors (specifically :after) to automatically clear out two floated elements. There was one pretty massive drawback in Aslett’s first version of the clearfix. Having never heard of the Holly Hack, Aslett’s code required a bit of JavaScript to fix issues that were specifically popping up on IE for Mac. In those days, JavaScript was a relatively untested technology, and relying on it in such a fundamental way was less than ideal.

Thankfully, the web is a place of iteration, and one message board user pointed Aslett in the direction of the aforementioned Holly Hack. By sprinkling in Begevin’s conditional comment, Aslett was able to make his code work in just about every browser with no JavaScript at all.

.floatcontainer:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } /* Mark Hadley's fix for IE Mac */ .floatcontainer { display: inline-block; } /* Hides from IE Mac \*/ * html .floatcontainer {height: 1%;} .floatcontainer{display:block;} /* End Hack */

If you want to pick apart an important slice of web history and innovation, the discussion that followed Aslett’s post about clearfix is a great place to start. One by one, people began to experiment with the new technique, testing it in obscure browsers and devices. When they were done, they’d post their results to the message thread, sometimes alongside a helpful tweak.

For example, the user zulaica pointed out that in Mozilla browsers, the bottom border of floated elements had to be explicitly defined. User pepejeria noticed that you could leave out the dot from content, and user co2 tested the clearfix in the very first version of Apple’s Safari browser. Each time, Aslett would update his code a bit until, after more than a few rapid iterations, the clearfix was ready and, thanks to the community, pretty darn bulletproof.

2006: Clearfix gets an update

But browsers kept on advancing. Some of the more quirky bits of the clearfix code worked because of bugs that were built into older browsers. As browsers patched those bugs, in brand new versions, the clearfix stopped working. When IE 7 came out at the end of 2006, a few adjustments to the technique were needed to make it work.

Fortunately, John “Big John” Gallant was maintaining a page on his blog Position is Everything with an up to date version of the clearfix. After getting some feedback from his readers, Gallant updated his blog to reflect a few new fixes for IE 7 using a new kind of conditional comment that would work inside of Internet Explorer.

<style type="text/css"> .clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } </style><!-- main stylesheet ends, CC with new stylesheet below... --> <!--[if IE]> <style type="text/css"> .clearfix { zoom: 1; /* triggers hasLayout */ } /* Only IE can see inside the conditional comment and read this CSS rule. Don't ever use a normal HTML comment inside the CC or it will close prematurely. */ </style> <![endif]-->

And once again, users took to their own browsers to test out the latest code to ensure it worked everywhere. And once again, for a time, it did.

2010: Clearfix Reloaded

In fact, this iteration of the clearfix would last until about 2010, when the team at the Yahoo! User Interface Library (YUI) noticed a few issues with the clearfix. The Holly Hack, for instance, was now long gone (IE 5 was but a distance memory), and after switching the box model, margins were handled a bit differently by modern browsers.

But the folks at YUI still needed to line up one element next to another. In fact, the need had only increased, as designers experimented with more advanced grid layouts. In 2010, there were very little options for grid layout, so clearfix had to work. They eventually came up with a few additional tweaks to the CSS ruleset, most notably by taking of advantage of both available pseudo-selectors (:before and :after), to clear out any margins. They posted their new take to their own blog and called it “clearfix reloaded."

.clearfix:before, .clearfix:after { content: "."; display: block; height: 0; overflow: hidden; } .clearfix:after { clear: both; } .clearfix { zoom: 1 ;} /* IE < 8 */ 2011: The Micro Clearfix

But even when it was published in 2010, clearfix reloaded brought with it some unnecessary baggage from older browsers. The height equals 0 trick wasn’t really a requirement anymore, and in fact, the trick was a lot more reliable when display: table was used instead. People began swapping various variations on the technique on Twitter and on blogs. About a year after the release of clearfix reloaded, developer Nicolas Gallagher compiled these variations into a much more compact version of the hack, which he appropriately labeled the micro clearfix.

After years of back and forth and slight adjustments, the clear fix now required just four CSS rules:

/* * For modern browsers * 1. The space content is one way to avoid an Opera bug when the * contenteditable attribute is included anywhere else in the document. * Otherwise it causes space to appear at the top and bottom of elements * that are clearfixed. * 2. The use of `table` rather than `block` is only necessary if using * `:before` to contain the top-margins of child elements. */ .cf:before, .cf:after { content: " "; /* 1 */ display: table; /* 2 */ } .cf:after { clear: both; } /* * For IE 6/7 only * Include this rule to trigger hasLayout and contain floats. */ .cf { zoom: 1; } The End of Clearfix?

These days, almost 15 years after it was first proposed, the clearfix is losing a bit of relevance. CSS Grid and Flexbox are filling in the gaps for advanced layout on the web. In January of 2017, Rachel Andrew wrote an article for her blog titled "The end of the clearfix hack?" In it, she describes a way to replace the clearfix hack with a single line of code using a new display mode rule known as flow-root.

.container { display: flow-root; }

We are approaching the day when clearfix will no longer be necessary at all.

Even without flow-root, there’s lots of ways to make a grid these days. If you were just starting out on the web, there’d be little reason to even learn about it. That’s a good thing! From the beginning it was always meant as a workaround to make the best of what was available. The irony being that without the dedication and experimentation of the developers who hacked away on the clearfix for so many years, we wouldn’t have the tools today to never have to rely on it again.

Enjoy learning about web history with stories just like this? Jay Hoffmann has a weekly newsletter called The History of the Web you can sign up for here.

The post Clearfix: A Lesson in Web Development Evolution appeared first on CSS-Tricks.

Writing Good Support Requests

Css Tricks - Mon, 07/02/2018 - 9:10am

My take on trying to be helpful to a support staff.

One bit is just as relevant for learning development:

Writing out a ticket will help you figure out the problem.

Sometimes when you have to take a second to collect your thoughts and explain something, the problem will become clear and maybe even the solution. Oftentimes, a bug is a bug and just needs to be fixed — but sometimes your support ticket might actually be something you can sort out for yourself and writing things out might be the first step toward that.

You know what they say, the best way to learn something is to teach it.

Just replace "ticket" with "forum topic" or whatever, on something like Spectrum.

Direct Link to ArticlePermalink

The post Writing Good Support Requests appeared first on CSS-Tricks.

How To Conduct UX Research For Maximum Value

Usability Geek - Mon, 07/02/2018 - 8:54am
Good design starts with thorough user research. Without sufficient research, it is impossible to distinguish between a product that merely looks good and one that solves a real user problem. Whether...
Categories: Web Standards


Css Tricks - Mon, 07/02/2018 - 5:26am

There is this sentiment that you don't design the homepage of a site first. For most sites, it's an anomaly. It's unlike any other page and not something to base the patterns you use for the rest of the site or help inform other pages.

You might call it a one-off.1

One-offs are OK! A world without one-offs is very boring. But a site chock-full of one-offs leads to familiar problems: inconsistency and non-reusable CSS that leads to bloating and maintainers that don't really know what's used and what isn't.

What are we to do?

Brad Frost thought about this recently with his article Where to put one-off components?:

It’s quite likely that individual applications contain components that fit the very real needs of a specific application (think calculators, holiday-season parallax hero units, context-specific interactive maps, and so on), but may not be able to be immediately (or ever) abstracted into a generic, reusable component that’s included in the design system.

And Ethan Marcotte:

Here’s an example: let’s say you’ve designed a splashy-looking hero image. (Nice work, by the way. It looks very splashy.) Let’s also say its scope is fairly limited: perhaps it’s being used on a small number of pages, or it’s tied to one specific section of your website. In other words, it’s generic enough to be a pattern, but it’s not a widely-used one.

As you might have guessed, this is a dangerous place for a pattern to be. If a pattern feels a little idiosyncratic, that should always prompt us to ask: should your team keep the pattern, or remove it?

Thing is, there’s no single, easy answer to that question. Every pattern is different, and each pattern’s value is variable. Maybe we’ll drop that pattern altogether; maybe we’ll combine it with another, similar pattern

Brad connected the idea of a one-off to Harry Robert's shame.css concept:

The idea of shame.css is that you have a totally new stylesheet reserved just for your hacky code. The code you have to write to get the release out on time, but the code that makes you ashamed.

But maybe a CSS file like that doesn't need to be reserved just for "hacks" or shamefully quickly-written fixes (hey, it's better than inline styles), but also for one-offs.

From a developer-in-charge-of-styling perspective, it's interesting to consider how different styling methologies come into play here. For those travelling the atomic CSS road, in a sense, everything is a one-off. You might still have a pattern that is visually or behaviorly a one-off because of how you've built it, but not because it uses a different set of CSS. Callum Jefferies on his experience with atomic CSS:

I no longer had to think about how to organise my CSS. I didn't have to think about what to name my 'components', where to draw the line between one component and another, what should live where, and crucially, how to refactor things when new requirements came in.

So, too, with the 36 flavors of CSS-in-JS. When your styles are attached to your components, all components are one-offs. Stop using that component, stop using those styles.

1 Apparently one-off is a fairly new expression:

As William Safire observed in a 2007 On Language column, one-off meaning "something unique" is a British expression that has been creeping into American speech and writing in recent years. And as with other Briticisms that impinge on these shores (gone missing comes to mind), the idiomatic origins of one-off are mostly lost on American ears.

The post One-Offs appeared first on CSS-Tricks.

CSS Grid in IE: Debunking Common IE Grid Misconceptions

Css Tricks - Mon, 07/02/2018 - 3:53am

This is the first in a three-part series all about how to use CSS grid in a way that will work not only in modern browsers but also in Internet Explorer (IE). Imagine writing CSS grid code without having to write a fallback layout! Many of us think that this is some far off future that is many years away. If the only thing holding you back from that reality is IE11 (check caniuse.com), then you’re in luck! That day is today! Or at least it will be when you finish reading this series. &#x1f609;

Article Series:
  1. Debunking Common IE Grid Misconceptions (This Post)
  2. CSS Grid and the new Autoprefixer
  3. Faking an auto-placement grid with gaps

To start off, this first part is going to debunk some common misconceptions around IE11’s native grid implementation.

In Part 2, I’m going to blow the lid off the myth that using CSS grid in IE11 is super hard. No more crappy fallback layouts for IE11!

In Part 3, I’ll show you a cool flexbox technique that I use for creating simple auto-placement grids. These fake auto-placement grids have fixed pixel-based grid gaps that line up perfectly with ones created using real CSS grid. They work perfectly in IE11, are fully responsive, and updating their column count based on screen width only requires changing a single width value in a media query.

That’s enough intro’s lets get started on these misconceptions!

IE does have an implicit grid

In CSS grid, the explicit grid is the one that you manually define with all of the grid-template-* properties. The implicit grid is how the browser handles the placement of cells that are placed outside of the explicit grid.

When using CSS grid in modern browsers, the implicit grid is pretty obvious since the grid will continue to create and place grid cells automatically on new rows without having to define them. IE doesn’t have auto-placement, so it’s easy to assume that IE doesn’t have an implicit grid. It does though — you just need to be a bit more explicit when it comes to using it.

See the Pen Explicit vs implicit grid by Daniel Tonon (@daniel-tonon) on CodePen.

The most common use case for using IE’s implicit grid is using it to generate your rows for you. If you want all the rows in the grid to have their height dictated by the height of their content, you do not need to bother defining -ms-grid-rows (the IE version of grid-template-rows). The rows will automatically be generated for you in IE when placing your grid cells.

An important thing to note though is that modern browsers have access to the properties grid-auto-rows and grid-auto-columns. These properties allow you to control how the browser handles the size of rows and columns in the implicit grid. IE has no concept of these properties. IE’s implicit rows and columns can only ever be sized as auto.

IE has repeat functionality

Do not fear! There is no need to write out 1fr 20px 12 times for your precious 12-column grid (IE doesn’t have native grid-gap support). IE comes pre-packaged with full repeat() functionality. It’s just hiding behind a different syntax.

The modern syntax for repeating values in columns and rows is repeat(12, 1fr 20px) meaning, "repeat the 1fr 20px pattern 12 times." The IE version of the syntax is (1fr 20px)[12]. The IE version has identical functionality, just a different syntax.

/* This grid... */ .grid-one { display: -ms-grid; display: grid; -ms-grid-columns: 1fr 20px 1fr 20px 1fr 20px 1fr; grid-template-columns: 1fr 20px 1fr 20px 1fr 20px 1fr; } /* ...is exactly the same as this grid: */ .grid-two { display: -ms-grid; display: grid; /* IE repeat syntax */ -ms-grid-columns: 1fr (20px 1fr)[3]; /* Modern repeat syntax */ grid-template-columns: 1fr repeat(3, 20px 1fr); }

Other than syntax, there is only one difference between the way modern browsers and IE implement the repeat() function. Modern browsers added the auto-fit and auto-fill keywords to the function. Since IE doesn’t support auto-placement, those keywords are pretty meaningless to IE so avoid using them.

minmax() is natively supported in IE

minmax() is a CSS sizing function that is exclusive to CSS grid (at the moment, anyway). Its functionality is pretty self explanatory. You provide it a minimum value in the first parameter and a maximum value in the second parameter. The column or row that this is applied to is then able to shrink and grow between those two values as the space available to it increases and decreases. Try resizing the codepen below to see it in action.

See the Pen minmax() demo by Daniel Tonon (@daniel-tonon) on CodePen.

People often think that this awesome little feature isn’t supported in IE but it is in fact natively supported. I’m guessing this is due to at least one of these two reasons:

  1. It’s cool functionality and they think IE can’t have cool things like this because IE sucks.
  2. Everyone has seen this magical code snippet and had their dreams shattered when they realised that it wouldn’t work in IE: grid-template-columns: repeat( auto-fit, minmax(250px, 1fr) );.

(If you have never seen that snippet before, watch this short video and prepare to have your mind blown.)

Since the magic snippet doesn’t work in IE, people probably assume that nothing in the snippet is IE-friendly. In reality, the only reason why the code snippet isn’t replicable in IE is because IE doesn’t support the auto-fit keyword and auto-placement.

min-content and max-content are both 100% IE-friendly

IE has full native support for both the min-content and max-content values.

min-content is a keyword value that will shrink the column/row down to the minimum possible width that the content can shrink down to. If applied to a column, this essentially means that the column will be the width of the longest word.

See the Pen min-content demo by Daniel Tonon (@daniel-tonon) on CodePen.

max-content, on the other hand, will grow the column/row up to the maximum possible width that its content takes up, and no further. If you have ever set white-space: nowrap on a large section of text, this will appear very similar.

See the Pen max-content demo by Daniel Tonon (@daniel-tonon) on CodePen.

I wasn’t expecting IE to support these values mainly because of reason one under minmax(). I was happily surprised when I was proven wrong while researching IE11 grid support. In combination with minmax(), there aren’t many grids that a modern browser can make that IE can’t handle (as long as the grids don’t involve auto-placement).

fit-content() is not IE friendly but...

fit-content() doesn’t work natively in IE. &#x1f622;

Fortunately, fit-content() is kind of a shorthand syntax and when you write it out the long way, IE does support it! &#x1f389;

The long way to write it is by applying auto (or more specifically, minmax(min-content, max-content)) to the column/row in the grid template, then setting max-width: [value] on the child element.

Here is an example of how you might use the fit-content() function in a modern browser:

/* This is not IE-friendly */ .grid { display: grid; grid-template-columns: 100px fit-content(300px) 1fr; } .cell { grid-column: 2; }

What fit-content() is basically saying here is, "make the middle column take up the maximum possible width of its content (i.e. its max-content value) up until it reaches 300px at which point, don’t grow any larger unless forced to."

See the Pen fit-content() modern example 1 by Daniel Tonon (@daniel-tonon) on CodePen.

If you are reading this on mobile, view this sections Codepen demos in landscape orientation for a better understanding.

In order to make IE behave in kind of the same way, you would need to write the code like this:

/* IE-friendly `fit-content()` alternative */ .grid { display: -ms-grid; display: grid; -ms-grid-columns: 100px auto 1fr; grid-template-columns: 100px auto 1fr; } .cell { -ms-grid-column: 2; grid-column: 2; max-width: 300px; }

See the Pen fit-content IE hack by Daniel Tonon (@daniel-tonon) on CodePen.

Note that this is not a full-proof method of replicating fit-content() in IE. If there is another grid cell that has content that takes up more width than the max-width setting of the other cell, the grid column will grow to fit the larger cell. It will not be clamped at 300px like it would with fit-content().

See the Pen Broken fit-content hack by Daniel Tonon (@daniel-tonon) on CodePen.

Compare that to the modern fit-content() function which clamps the entire column:

See the Pen fit-content() modern example by Daniel Tonon (@daniel-tonon) on CodePen.

While I'm on the subject, I should clear up a common misconception around the fit-content() function itself. The misconception is that the column (or row) that it is applied to can never exceed the value that you provided the function. This is not the case. If a column is set to a width of fit-content(300px), and a grid cell inside that column is set to a width of 400px, the column width will be 400px, not 300px as many people might expect.

See the Pen Broken modern fit-content by Daniel Tonon (@daniel-tonon) on CodePen.

IE auto != Modern auto

The auto value in IE behaves a bit differently than auto in modern browsers. In IE, auto strictly equals minmax(min-content, max-content). A column or row set to auto in IE can never shrink any smaller than min-content. It also can never grow any larger than max-content.

Modern browses treat the auto value a bit differently. For the most part, when the value is used on its own, they still treat auto like minmax(min-content, max-content). There is one small but critical difference though: auto in modern browsers is able to be stretched by the align-content and justify-content properties. IE doesn't allow that.

When auto is used for sizing columns in a modern browser, auto behaves more like 1fr if there isn’t enough content to fill the column. IE does not. IE will always shrink the column down to the size of max-content.

So, if you have this code defining your grid:

.grid { display: -ms-grid; display: grid; -ms-grid-columns: auto auto; grid-template-columns: auto auto; }

You will end up with this in modern browsers:

Modern browser auto width columns with little content. Columns fill the grid.

...and this in IE:

IE auto width columns with little content. Columns shrink to the content.

Ok, the modern browser one looks a lot like what we get when we use 1fr. Can we use minmax(min-content, 1fr) for IE then? That will stretch it out like it does in modern browsers won’t it?

Yes, but then we run into this issue:

.grid { display: -ms-grid; display: grid; -ms-grid-columns: minmax(min-content, 1fr) minmax(min-content, 1fr); grid-template-columns: auto auto; }

Modern browsers:

Modern browser auto width columns with lots of content in one cell. Columns are different widths.


IE minmax(min-content, 1fr) columns with lots of content in one cell. Columns are equal widths.

FYI, minmax(min-content, 1fr) is essentially 1fr and 1fr and does not equal auto. I also tried minmax(min-content, 100%) in IE but that just resulted in the same looking grid as using 1fr. As far as I can tell, it’s not possible to replicate the modern browser auto functionality in IE.

There is another critical difference between IE and modern versions of the auto value though. Since the IE version of auto explicitly equals minmax(min-content, max-content), auto cannot be used in minmax() expressions. minmax() cannot be used inside another minmax() function so auto is disqualified.

Modern browsers are a bit more nuanced. They recognize that auto can mean different things in different contexts. If used on its own, it essentially equals minmax(min-content, max-content) but with the added ability to stretch. When used as a max value, auto is identical to max-content. When used as a min value it essentially equals min-content.

If, right now, you are vowing to never use auto in your grid templates ever again, you may want to rethink that. There are only three circumstances where auto will behave differently between modern browsers and IE. Those are:

  1. auto is being used in grid-template-columns without an fr unit in the same declaration.
  2. auto is being used in grid-template-rows without an fr unit in the same declaration and the height of the grid is greater than the height of its grid cells.
  3. auto is being used in a minmax() function.

That's it! Those are the only times when auto will behave differently in IE to how it behaves in modern browsers. auto is much easier to write than minmax(min-content, max-content) so it's not really worth condemning it over a few little browser inconsistencies that are easily avoidable.

So what have we learned?
  • IE does have an implicit grid.
  • IE supports repeat functionality.
  • minmax(), min-content and max-content are all natively supported.
  • fit-content() isn’t supported but you can work around it with auto and max-width settings.
  • IE auto is not equal to auto in modern browsers.

Don’t get the grids out just yet though. There are still a lot of things that you need to know before you can start safely implementing IE grids into your websites. Make sure to stick around for Part 2! I will be showing you everything you need to know to safely build sites for both IE and modern browsers using only CSS grid. Best of all, there will be no more need for crappy fallback layouts!

Article Series:
  1. Debunking Common IE Grid Misconceptions (This Post)
  2. CSS Grid and the new Autoprefixer
  3. Faking an auto-placement grid with gaps

The post CSS Grid in IE: Debunking Common IE Grid Misconceptions appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.