Front End Web Development

Accessibility Events

Css Tricks - Thu, 04/11/2019 - 7:56am

“There isn't some way to know when—…?”

There is always a pause here. The client knows what they're asking, and I know what they're asking, but putting it into words—saying it out loud—turns unexpectedly difficult.

In the moments before the asking, it was a purely technical question—no different from "can we do this when a user is on their phone." But there's always a pause, because this question doesn't come easy; not like all the other questions about browsers and connection speeds did. A phrase like "in an assisted browsing context" doesn't spring to mind as readily as "on a phone," "in Internet Explorer," or "on a slow connection." The former, well, that's something I would say—a phrase squarely in the realm of accessibility consultants. The latter the client can relate to. They have a phone, they've used other browsers, they've been stuck with slow internet connections.

“There isn't some way to know when—… a user is… using something like a screen reader…?”

An easy question that begets a complicated answer is standard fare for almost any exchange with a web developer. This answer has, for a long time, been a refreshing deviation from that norm: "no, we can't."

The matter is, I'll offer, technically impossible; computers, you see, can't talk to each other that way. Often, there's a palpable relief here: "no" to the technical part; "no" to the the computers part. That is, of course, all they had meant to ask. I truly believe that.

Even if we could, I'll explain, we wouldn't really want to. Forking our codebase that way would put more burden on us maintainers, not less. There's an easy parallel to the "when they're on a phone" conversation, here; one we've surely had already. We can never know a user's browsing context for certain, and making assumptions will only get us and our users into trouble. Whenever a feature, component, or new design treatment was added or changed, we'd be left having all the same conversations around how to translate it over to the "accessible" experience. If those features aren't essential in the first place, well, are they worth having at all? If those features are essential—well, we'll still need to find a way to make them work in both contexts.

It could seem like an enticing option for our users, at first glance: an enhanced, fully-featured website, on the one hand, a fully accessible alternative experience on the other. That unravels with even the slightest examination, though: if the fully-featured website isn't accessible, the accessible website won't be fully featured. By choosing to have the "accessible experience" deviate from the "real website," we end up drawing a sharper line between those two definitions, and we nudge the "accessible experience" closer to an afterthought—limited and frustratingly out-of-sync with the "real" website, like so many dedicated mobile sites quickly became.

There's never any disagreement, here. Again: this is all relatable. We've all found ourselves inescapably opted into using the "mobile" version of a website at some point. We've been here before as users; we've made these mistakes before as developers. We know better now.

But this isn't a strictly technical question. This isn't as simple as browser features and screen sizes—a question of one privileged browsing context or another. Technical questions come easy. Partway through the asking—in the hesitation, in the pause, in the word stumbled over—what was meant to be a mundane development question became something much more fraught. Because there was a word that fit.

“Is there a way we can know when a user has a disability?”

The easy "no" felt empowering; a cop-out. "It doesn't matter; it can't be done" in response to a deeply fraught question was an unexpected balm for both the asked and the answered. There was, again, that palpable relief—"no" to the technical part; "no" to the the computers part. That was, of course, all they had meant to ask.

We no longer have that easy answer. In iOS 12.2 and MacOS 10.14.4, a toggle switch has appeared in Apple's VoiceOver preferences, innocuously labeled "accessibility events." It was rolled out to no fanfare—short of a brief mention in Apple's iPhone User Guide—and we're still not sure how it's meant to be used. The most generous interpretation of the intention behind this feature is that it was developed with the same intention as a "UA string"-style identifier for users browsing via VoiceOver.

We do know this much: when this setting is enabled—and it is, by default—your browser will identify you as using VoiceOver to help you browse the web. If you're using Apple's VoiceOver, both your phone and your computer will broadcast your assumed disability to the entire internet, unless and until you specifically tell it to stop.

If you're not furious at this change, you should be—not just for what it means for users, but what it foists upon you. Apple has burdened you with the knowledge that, now, yes, you can know whether a user has a disability. We can use this information to serve up a limited alternative version of a website, into which we can very easily opt people of a protected class. And once we choose to start listening for "accessibility events," well, we can capture that information, as anything else broadcast to the web. A user's disability can and will be reduced to a single data point—a cold, impersonal true, inexorably bound to their name, stored in a database, perhaps destined to be sold, leaked, passed along to insurance providers, reduced to a targeted marketing opportunity. All under the auspice of inclusivity.

At some point, the developers responsible for the "accessibility events" feature were, I'm certain, asked whether such a feature were possible. Their answer was "yes." I don't doubt that they meant well. I'm just as certain that, in the moment, it felt like the right answer; a technical solution to a technical problem, and a simple matter of browsing context.

Someday—not far in the future, I trust—I'll be asked a similar question. It will be asked hesitantly, haltingly. The pauses will ring all too familiar. I will no longer have the easy, familiar comfort of technical impossibility—no easy "no" to insulate me from the uncomfortable conversations I should have been having with clients all along. Now, there's no technical reason that I can't know whether a user is using "something like a screen reader." I—my clients, their databases, their organizations, their parent companies, their partners, their VC funders, their advertisers, and so on unto infinity—can absolutely know when a user is disabled.

But I won't play a part in helping to propagate the mistake Apple's developers made. I'll let my answer hang heavy and uncomfortable in the air: no. Not because we can't—we can. Not because we shouldn't, though, no, we still shouldn't. No—now, I will allow the word to become as coarse as I had always wanted it to be, because I no longer have the cold comfort of "well, technically" to hide behind.



The post Accessibility Events appeared first on CSS-Tricks.

Edge Goes Chromium: What Does it Mean for Front-End Developers?

Css Tricks - Thu, 04/11/2019 - 4:32am

In December 2018, Microsoft announced that Edge would adopt Chromium, the open source project that powers Google Chrome. Many within the industry reacted with sadness at the loss of browser diversity. Personally, I was jubilant. An official release date has yet to be announced, but it will be at some point this year. With its release, a whole host of HTML, JavaScript and CSS features will have achieved full cross-browser support.

The preview build is now available for Windows, and coming soon for Mac.

📣 Calling all web devs and tinkerers! 📣

The first preview builds of the next version of #MicrosoftEdge are ready for you – try it out now!

— Microsoft Edge Dev (@MSEdgeDev) April 8, 2019

Not so long ago, I penned an article titled "The Long Slow Death of Internet Explorer." Some of us are lucky enough have abandoned that browser already. But it wasn’t the only thing holding us back. Internet Explorer was the browser we all hated and Edge was meant to be its much-improved replacement. Unfortunately, Edge itself was quite the laggard. EdgeHTML is a fork of Trident, the engine that powered Internet Explorer. Microsoft significantly under-invested in Edge. The apple didn’t fall far from the tree. Edge’s User Voice website was a nice idea, allowing developers to vote for which features they wanted to be implemented. Unfortunately, as Dave Rupert put it, voting on the site was "like throwing coins in a wishing well." The most requested features were left unimplemented for years.

There are a lot of features that pre-Chromium Edge doesn’t currently support but are available in other modern browsers and, once they’ve made the switch, we’ll be able to use them. Many of them can’t be polyfilled or worked around, so this release is a big deal.

Features we can look forward to using

So just what are those features, exactly? Let’s outline them right here and start to get excited about all the new things we’ll be able to do.

Custom Elements and Shadow DOM

Together, custom elements and shadow DOM allow developers to define custom, reusable and encapsulated components. A lot of people were asking for this one. People have been voting for its implementation since 2014, and we’re finally getting it.

HTML details and summary elements

The <details> and <summary> elements are part of HTML5 and have been supported since 2011 in Chrome. Used together, the elements generate a simple widget to show and hide content. While it is trivial to implement something similar using JavaScript, the <details> and <summary> elements work even when JavaScript is disabled or has failed to load.

See the Pen
by CSS GRID (@cssgrid)
on CodePen.

Javascript Font Loading API

This one means a lot to some people. All modern browsers now support the CSS font-display property. However, you still might want to load your fonts with JavaScript. Font-loading monomaniac Zach Leatherman has an explainer of why you might want to load fonts with JavaScript even though we now have broad support for font-display. Ditching polyfills for this API is important because this JavaScript is, according to Zach:

[...] usually inlined in the critical path. The time spent parsing and executing polyfill JavaScript is essentially wasted on browsers that support the native CSS Font Loading API."

In an article from 2018, Zach lamented:

[...] browser-provided CSS Font Loading API has pretty broad support and has been around for a long time but is confoundedly still missing from all available versions of Microsoft Edge."

No longer!

JavaScript flat and flatMap

Most easily explained with a code snippet, flat() is useful when you have an array nested inside another array.

const things = ['thing1', 'thing2', ['thing3', ['thing4']]] const flattenedThings = things.flat(2); // Returns ['thing1', 'thing2', 'thing3', 'thing4']

As its name suggests, flatMap() is equivalent to using both the map() method and flat().

These methods are also supported in Node 11. &#x1f389;

JavaScript TextEncoder and TextDecoder

TextEncoder and TextDecoder are part of the encoding spec. They look to be useful when working with streams.

JavaScript Object rest and object spread

These are just like rest and spread properties for arrays.

const obj1 = { a: 100, b: 2000 } const obj2 = { c: 11000, d: 220 } const combinedObj = {...obj1, ...obj2} // {a: 100, b: 2000, c: 11000, d: 220} JavaScript modules: dynamic import

Using a function-like syntax, dynamic imports allow you to lazy-load ES modules when a user needs them.

button.addEventListener("click", function() { import("./myModule.js").then(module => module.default()); }); CSS background-blend-mode property

background-blend-mode brings Photoshop style image manipulation to the web.

CSS prefers-reduced-motion media query

I can’t help feeling that not making people feel sick should be the default of a website, particularly as not all users will be aware that this setting exists. As animation on the web becomes more common, it’s important to recognize that animation can cause causes dizziness, nausea and headaches for some users.

CSS caret-color property

Admittedly a rather trivial feature, and one that could have safely and easily been used as progressive enhancement. It lets you style the blinking cursor in text input fields.

8-digit hex color notation

It’s nice to have consistency in a codebase. This includes sticking to either
the RGB, hexadecimal or HSL color format. If your preferred format is hex, then you had a problem because it required a switch to rgba() any time you needed to define transparency. Hex can now include an alpha (transparency) value. For example, #ffffff80 is equivalent to rgba(255, 255, 255, .5). Arguably, it’s not the most intuitive color format and has no actual benefit over rgba().

Intrinsic sizing

I’ve not seen as much hype or excitement for intrinsic sizing as some other new CSS features, but it’s the one I’m personally hankering for the most. Intrinsic sizing determines sizes based on the content of an element and introduces three new keywords into CSS: min-content, max-content and fit-content(). These keywords can be used most places that you would usually use a length, like height, width, min-width, max-width, min-height, max-height, grid-template-rows, grid-template-columns, and flex-basis.

CSS text-orientation property

Used in conjunction with the writing-mode property, text-orientation, specifies the orientation of text, as you might expect.

See the Pen
text-orientation: upright
by CSS GRID (@cssgrid)
on CodePen.

CSS :placeholder-shown pseudo-element

placeholder-shown was even available in Internet Explorer, yet somehow never made it into Edge... until now. UX research shows that placeholder text should generally be avoided. However, if you are using placeholder text, this is a handy way to apply styles conditionally based on whether the user has entered any text into the input.

CSS place-content property

place-content is shorthand for setting both the align-content and justify-content.

See the Pen
by CSS GRID (@cssgrid)
on CodePen.

CSS will-change property

The will-change property can be used as a performance optimization, informing the browser ahead of time that an element will change. Pre-Chromium Edge was actually good at handling animations performantly without the need for this property, but it will now have full cross-browser support.

CSS all property">all is a shorthand for setting all CSS properties at once.

For example, setting button { all: unset; } is equivalent to:

button { background: none; border: none; color: inherit; font: inherit; outline: none; padding: 0; }

Sadly, though, the revert keyword still hasn’t been implemented anywhere other than Safari, which somewhat limits the mileage we can get out of the all property.

CSS Shapes and Clip Path

Traditionally, the web has been rectangle-centric. It has a box model, after all. While we no longer need floats for layout, we can use them creatively for wrapping text around images and shapes with the shape-outside property. This can be combined with the clip-path property, which brings the ability to display an image inside a shape.

Clippy is an online clip-path editor CSS :focus-within pseudo-class

If you want to apply special styles to an entire form when any one of its inputs are in focus, then :focus-within is the selector for you.

CSS contents keyword

This is pretty much essential if you’re working with CSS grid. This had been marked as "not planned" by Edge, despite 3,920 votes from developers.

For both flexbox and grid, only direct children become flex items or grid items, respectively. Anything that is nested deeper cannot be placed using flex or grid-positioning. In the words of the spec, when display: contents is applied to a parent element, "the element must be treated as if it had been replaced in the element tree by its contents," allowing them to be laid out with a grid or with flexbox. Chris goes into a more thorough explanation that’s worth checking out.

There are, unfortunately, still some bugs with other browser implementations that affect accessibility.

The future holds so much more promise

We’ve only looked at features that will be supported by all modern browsers when Edge makes the move to Chromium. That said, the death of legacy Edge also makes a lot of other features feel a lot closer. Edge was the only browser dragging its feet on the Web Animation API and that showed no interest in any part of the Houdini specs, for example.

Credit: The impact on browser testing Testing in BrowserStack (left) and various browser apps on my iPhone (right)

Of course, the other huge plus for web developers is less testing. A lot of neglected Edge during cross-browser testing, so Edge users were more likely to have a broken experience. This was the main reason Microsoft decided to switch to Chromium. If your site is bug-free in one Chromium browser, then it’s probably fine in all of them. In the words of the Edge team, Chromium will provide "better web compatibility for our customers and less-fragmentation of the web for all web developers." The large variety of devices and browsers makes browser testing one of the least enjoyable tasks that we’re responsible for as front-end developers. Edge will now be available for macOS users which is great for the many of us who work on a Mac. A subscription to BrowserStack will now be slightly less necessary.

Do we lose anything?

To my knowledge, the only feature that was supported everywhere except Chrome is SVG color fonts, which will no longer work in the Edge browser. Other color font formats (COLR, SBIX, CBDT/CBLC) will continue to work though.

Uh, @GoogleChrome Are you planning to support #OpenTypeSVG soon? Supported in Safari (12+), Firefox (26+) even EdgeHTML (38+) Photoshop, Illustrator - but not Chrome
/cc @colorfontswtf

— Chris Lilley (@svgeesus) February 15, 2019

What about other browsers?

Admittedly, Edge wasn’t the last subpar browser. All the features in this article are unsupported in Internet Explorer, and always will be. If you have users in Russia, you’ll need to support Yandex. If you have users in Africa, you’ll need to support Opera Mini. If you have users in China, then UC and QQ will be important to test against. If you don’t have these regional considerations, there’s never been a better time to ditch support for Internet Explorer and embrace the features the modern web has to offer. Plenty of PC users have stuck with Internet Explorer purely out of habit. Hopefully, a revamped Edge will be enough to tempt them away. An official Microsoft blog entry titled "The perils of using Internet Explorer as your default browser" concluded that, "Internet Explorer is a compatibility solution...developers by and large just aren’t testing for Internet Explorer these days." For its remaining users, the majority of the web must look increasingly broken. It’s time to let it die.

Is Google a megalomaniac?

Life is about to get easier for web developers, yet the response to the Microsoft’s announcement was far from positive. Mozilla, for one, had a stridently pessimistic response, which accused Microsoft of "officially giving up on an independent shared platform for the internet." The statement described Google as having "almost complete control of the infrastructure of our online lives" and a "monopolistic hold on unique assets." It concluded that "ceding control of fundamental online infrastructure to a single company is terrible."

Many have harked back to the days of IE6, the last time a browser achieved such an overwhelming market share. Internet Explorer, having won the browser war, gave in to total stagnation. Chrome, by contrast, ceaselessly pushes new features. Google participates actively with the web standards bodies the W3C and the WHATWG. Arguably though, it has an oversized influence in these bodies and the power to dictate the future shape of the web. Google Developer Relations does have a tendency to hype features that have shipped only in Chrome.

From competition to collaboration

Rather than being the new IE, Edge can help innovate the web forward. While it fell behind in many areas, it did lead the way for CSS grid, CSS exclusions, CSS regions and the new HTML imports spec. In a radical departure from historical behavior, Microsoft have become one of the world’s largest supporters of open source projects. That means all major browsers are now open source. Microsoft have stated that they intend to become a significant contributor to Chromium — in fact, they’ve already racked up over 300 merges. This will help Edge users, but will also benefit users of Chrome, Opera, Brave, and other Chromium-based browsers.

The post Edge Goes Chromium: What Does it Mean for Front-End Developers? appeared first on CSS-Tricks.

Get a CSS Custom Property Value with JavaScript

Css Tricks - Thu, 04/11/2019 - 4:31am

Here’s a neat trick from Andy Bell where he uses CSS Custom Properties to check if a particular CSS feature is supported by using JavaScript.

Basically, he's using the ability CSS has to check for browser support on a particular property, setting a custom property that returns a value of either 0 or 1 (Boolean!) and then informing the JavaScript to execute based on that value.

Here's his example:

.my-component { --supports-scroll-snap: 0; } @supports (scroll-snap-type: x mandatory) { .my-component { --supports-scroll-snap: 1; } } const myComponent = document.querySelector('.my-component'); const isSnapSupported = getCSSCustomProp('--supports-scroll-snap', myComponent, 'boolean');

As Andy mentions, another common way to do this is to use pseudo elements on the body element and then access them with JavaScript, but this approach with @supports seems a whole lot cleaner and less hacky to me, personally. I wonder how many more intuitive things we’ll find we can do with CSS Custom Properties because this is an interesting case where CSS instructs JavaScript, instead of the other way around.

Direct Link to ArticlePermalink

The post Get a CSS Custom Property Value with JavaScript appeared first on CSS-Tricks.

While solving for collaboration, we built a product that our own teams love and use everyday!

Css Tricks - Thu, 04/11/2019 - 4:29am

(This is a sponsored post.)

Flock is a messaging and collaboration tool built for both designers and developers. With close-to-zero setup, it brings together all your team’s conversations, appointments, and files in one place, helping you spend more time on what you are best at — building awesome stuff!

Building software is hard. Building software that is a delight to use every day is even harder, given the exacting standards most of us in the design and development community have for our tools. So, when we set out to change how people communicate in the modern workplace, we had but one goal - build something that we would objectively love!

Today, thousands of design and development teams use Flock every day, validating our UX-led approach to building a team collaboration tool for all kinds of teams. But how did we get here? Here’s our story.

At Flock, our designers frequently share creatives and design assets with the rest of the organization and using email to share links to files gets real old, real fast. So we started by looking at one of the biggest challenges to efficient collaboration at work — the "app-juggling" one had to master even for something as simple as sharing a file.

"Emails on one platform, files on another, real-time conversations on yet another one, and we would often need to shuffle between these apps to find and share relevant files with team members. That was an invisible time-sink!"
—Aaron Durham, Designer at Flock

We realized that bringing together our files and the conversations around them in one place would save us a lot of time and effort, and built integrations for Flock with Google Drive, OneDrive, Box, and Dropbox. Now, it is incredibly easy to find and share relevant files from the sidebar and discuss them with the team immediately, with dynamic previews and permission controls.

The next challenge we tackled was the time spent in getting feedback on designs and prototypes from colleagues in our geographically distributed design and development team. We knew that it was difficult to convey visual feedback on creatives through plain text/emails because our designers often struggled to understand what part of an illustration the feedback was aimed at.

And then, we thought, "Wouldn’t it be so much easier if we could hop on a call and show colleagues exactly what we see?" So, we built a seamless video and audio conferencing experience into Flock that allows us to start a video call with one or more team members and walk them through the feedback by sharing screens.

Like most startups, we have a few irons in the fire at any given time. So, one group of designers and developers might be working on a prototype of our newest product while another group works on landing pages for a marketing campaign. Conversations around these projects need to happen simultaneously and seamlessly. But with a team of over a hundred rock-stars, it’s difficult to keep track of conversations on various projects and keep those conversations on track. We had to create a system that accomplished both.

So, for every project, the Project Lead creates a Channel on Flock (a group conversation) where everyone involved can discuss the project. We create other channels for shared interests and water-cooler chats, so conversations in project channels are focused and more efficient.

Another reason for the dreaded "app-juggling" act? Our designers and developers use a lot of apps and services that they have to check for updates at various times of the day. So we built integrations for third-party services right into Flock. Now, team members receive notifications from all their favorite apps in one place — Flock — and can choose to take action when required.

Our App Store has over 60 integrations with popular third-party business apps and services, so we can work with all our favorite tools in one place. And we can connect hundreds of applications and web services to Flock using Zapier and IFTTT. From Dribble and Asana to Jira and GitHub, we connect almost every service we use to Flock. Last but not least, developers can build custom apps and integrations using our open API.

Many early adopters of Flock were teams with designers and developers who were happy to share feedback. We found that a lot of these teams worked with external consultants or clients, particularly at creative agencies. And these conversations were, again, on email, on the phone or, sometimes, verbal instructions with no record for later reference.

To ensure all these conversations could be brought into one window, we created Guests in Flock, an incredibly simple way of adding external collaborators to team workflows while maintaining a firewall of access between conversations within the team and conversations with guest users. This makes it easier to collaborate with clients and consultants, feedback can be shared and acted upon in real-time, and the built-in image annotation feature allows designers to share visual feedback on creatives.

Our thinking from the get-go has been that effective communication is a basic utility in every workplace, and it should add to productivity way more than it does to expenses. Which is why we priced Flock starting from free, with an option to unlock all functionality for $4.50 a user per month on the Pro plan — a third as much as our competitors.

Our designers and developers have found incredible success in building Flock and becoming its first power users, and the business case for adopting a team collaboration platform has never been clearer. Whether one wants to discuss ideas, share collateral's, collect feedback from teammates and clients, or get code-push notifications from Gitlab, Flock just works.

Try Flock Now

Direct Link to ArticlePermalink

The post While solving for collaboration, we built a product that our own teams love and use everyday! appeared first on CSS-Tricks.

Using “box shadows” and clip-path together

Css Tricks - Wed, 04/10/2019 - 1:55pm

Let's do a little step-by-step of a situation where you can't quite do what seems to make sense, but you can still get it done with CSS trickery. In this case, it'll be applying a shadow to a shape.

You make a box .tag { background: #FB8C00; color: #222; font: bold 32px system-ui; padding: 2rem 3rem 2rem 4rem; } You fashion it into a nice tag shape

You use clip-path because it's great for that.

.tag { /* ... */ clip-path: polygon(30px 0%, 100% 0%, 100% 100%, 30px 100%, 0 50%) } You want a shadow on it, so you...

Try to use box-shadow.

.tag { /* ... */ box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5); }

But it doesn't work. Nothing shows up. You think you're going crazy. You assume you have the syntax wrong. You don't. The problem is that clip-path is cutting it off.

You can drop-shadow a parent element instead

There is a filter that does shadows as well: drop-shadow(). But you can't use it directly on the element because the clip-path will cut it off as well. So you make a parent:

<span class="tag-wrap"> <span class="tag"> Tag </span> </span>

You can't use box-shadow on that parent either, because the parent is still a rectangle and the shadow will look wrong. But you can use filter, and the shadow will follow the shape.

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

That's all.

The post Using “box shadows” and clip-path together appeared first on CSS-Tricks.

Under-Engineered Toggles

Css Tricks - Wed, 04/10/2019 - 5:39am

Toggles. Switches. Whatever you want to call them, they've been with us for some time and have been a dominant a staple for many form interfaces. They're even baked right into many CSS frameworks, including Bootstrap and Foundation.

It's easy to think of them in binary terms: on and off. Off and on. Click to change the state and call it a day, right? I mean, it's just a checkbox with a styled visual representation.

Well, Adrian Roselli shows us that there's a lot more to think about. And, not only that, but he shows how we can under-engineer them:

I am only going to provide styles to visually convert a standard checkbox into a visual toggle. No ARIA, no script, no special features. A progressively enhanced checkbox that will continue to work if the CSS file does not load

There's a lot to digest here. His approaches to accessibility run the gamut, from hover, active, focus and disabled states to contrast in both light and dark modes, and many things in between. What's particularly key is the progressive enhancement he mentions in that quote above.

I think the most interesting thing about Adrian’s post is just how flexible his approach is to handle any situation, including color schemes and writing modes. He also takes note of the indeterminate checkbox, that state that's nether on or off, but something perhaps in between. We have a CSS pseudo-selector for that and it could warrant a post its own, given that it's a purely visual state that cannot be set in the HTML and needs to be registered via JavaScript. It's interesting to think of an "in between" state for a switch and Adrian's use case for the default state Airplane Mode is pretty compelling.

It’s an awful lot of work that we have to do to ensure that the front-end is designed well and I think this post is the best example I’ve seen in a while as to why our work is not a problem to be solved and more of a challenge to better understand the tools of our craft.

Direct Link to ArticlePermalink

The post Under-Engineered Toggles appeared first on CSS-Tricks.

In Defense of the Ternary Statement

Css Tricks - Wed, 04/10/2019 - 4:31am

Some months ago I was on Hacker News (as one does) and I ran across a (now deleted) article about not using if statements. If you’re new to this idea (like I was), you’re in a for a real treat. Just search for "if statements" on Hacker News. You'll get articles proposing that you might not need them, articles that refer to them as a code smell and even the quintessential "considered harmful." Listen, you know a programming concept is legit when people start suggesting that using it is actually gonna hurt somebody.

And if that's not enough for you, there is always the "Anti-If Campaign." If you join, you get a nifty banner and your name on the website. IF you join. Oh the sweet, sweet irony.

The first time that I ran across this bizarre "if anathema" phenomenon, I thought it was interesting, but probably just more people mad on the internet. You are always one Google search away from finding someone who is mad about anything. Like this person who hates kittens. KITTENS.

Some time later, I was watching Linus Torvald's TED interview. In that interview, he shows two slides. The first slide contains code that he deems is "bad taste."

And the second is that same code, but in what Linus would consider, "good taste."

I realize that Linus is a bit of a polarizing figure, and you might not agree with the "good taste" vs. "bad taste" phrasing. But I think we can universally agree that the second slide is just easier on the old eye balls. It's concise, has fewer logical paths to follow, and contains no if statement. I want my code to look like that. It doesn't have to be some genius algorithm (it never will be), but I think it can be clean, and remember what Billy Corgan of Smashing Pumpkins said about cleanliness...

Cleanliness is godliness. And god is empty. Just like me.

- Billy Corgan, "Zero"

So dark! But what an amazing album.

Aside from making your code look cluttered, if statements, or "branching logic," requires your brain to hold and evaluate two separate paths at one time along with all of the things that might occur on those paths. If you nest if statements, the problem intensifies because you are creating and tracking a decision tree and your brain has to bounce around all over that tree like a drunk monkey. This kind of thing is what makes code hard to read. And remember, you should write your code thinking of the moron who comes after you that is going to have to maintain it. And that moron is probably you.

As my own favorite moron, I've been making a conscious effort lately to avoid writing if statements in my JavaScript. I don't always succeed, but what I've noticed is that at the very least, it forces me to think about solving the problem from an entirely different angle. It makes me a better developer because it compels me to engage a part of my brain that is otherwise sitting on a beanbag eating peanut M&M's while the if statement does all the work.

In the process of not writing if statements, I’ve discovered my love for the way JavaScript lets you compose conditional logic with ternary statements and logical operators. What I would like to propose to you now is that ternary has gotten a bad rap, and you can use it along with the && and || operators to write some pretty concise and readable code.

The much maligned ternary

When I first started as a programmer, people used to say, "Never use a ternary. They are too complex." So I didn’t use them. Ever. I never used a ternary. I never even bothered to question whether or not those people were right.

I don't think they were.

Ternaries are just one-line if statements. Suggesting that they are implicitly too complicated in any form is just... not true. I mean, I'm not the frostiest donut in the box, but I have no problems at all understanding a simple ternary. Is it possible that we are infantilizing ourselves here just a tad when we say to always avoid them. I think that a well-structured ternary beats an if statement every time.

Let’s take a simple example. Say we have an application where we want to test and see if the user is logged in. If they are, we send them to their profile page. Otherwise, we send them to the home page. Here is the standard if statement to do that...

if (isLogggedIn) { navigateTo('profile'); } else { navigateTo('unauthorized'); }

That's a damn simple operation to split out over six lines. SIX LINES. Remember that every time you move through a line of code, you have to remember the code that came above it and how it affects the code below it.

Now the ternary version...

isLoggedIn ? navigateTo('profile') : navigateTo('unauthorized');

Your brain only has to evaluate one line here, not six. You don’t have to move between lines, remembering what was on the line before.

One of the drawbacks to the ternary, though, is that you cannot evaluate for only one condition. Working from the previous example, if you wanted to navigate to the profile page if the user was logged in, but take no action at all if they weren't, this won't work...

// !! Doesn't Compile !! logggedIn ? navigateTo('profile')

You would have to write out an actual if statement here. Or would you?

There is a trick that you can use in JavaScript when you only want to evaluate one side of the condition and you don't want to use an if statement. You do this by leveraging the way JavaScript works with the || (or) and && (and) operators.

loggedIn && navigateTo('profile');

How does that work!?

What we're doing here is asking JavaScript, "Are both of these things true?" If the first item is false, there is no reason for the JavaScript virtual machine to execute the second. We already know that both of them aren't true because one of them is false. We're exploiting the fact that JavaScript won't bother to evaluate the second item if the first one is false. This is the equivalent of saying, "If the first condition is true, execute the second."

Now what if we wanted to flip this around? What if we wanted to navigate to the profile page only if the user is not logged in? You could just slap a ! in front of the loggedIn variable, but there is another way.

loggedIn || navigateTo('profile');

What this says is, "Are either of these things true?" If the first one is false, it has to evaluate the second to know for sure. If the first one is true though, it will never execute the second because it already knows that one of them is true; therefore the whole statement is true.

Now, is that better than just doing this?

if (!loggedIn) navigateTo('profile');

No. In that form, it is not. But here’s the thing: once you know that you can use the && and || operators to evaluate equality outside of if statements, you can use them to vastly simplify your code.

Here is a more complex example. Say we have a login function where we pass a user object. That object may be null, so we need to check local storage to see if the user has a saved session there. If they do, and they are an admin user, then we direct them to a dashboard. Otherwise, we send them to a page that tells them they are unauthorized. Here is what that looks like as a straight-up if statement.

function login(user) { if (!user) { user = getFromLocalStorage('user'); } if (user) { if (user.loggedIn && user.isAdmin) { navigateTo('dashboard'); } else { navigateTo('unauthorized'); } } else { navigateTo('unauthorized'); } }

Ouch. This is complicated because we're doing a lot of null condition checking on the user object. I don't want this post to be too strawman-y, so let's simplify this down since there is a lot of redundant code here that we would likely refactor into other functions.

function checkUser(user) { if (!user) { user = getFromLocalStorage('user'); } return user; } function checkAdmin(user) { if (user.isLoggedIn && user.isAdmin) { navigateTo('dashboard'); } else { navigateTo('unauthorized'); } } function login(user) { if (checkUser(user)) { checkAdmin(user); } else { navigateTo('unauthorized'); } }

The main login function is simpler, but that's actually more code and not necessarily “cleaner” when you consider the whole and not just the login function.

I would like to propose that we can do all of this in two lines if we forgo the if statements, embrace the ternary, and use logical operators to determine equality.

function login(user) { user = user || getFromLocalStorage('user'); user && (user.loggedIn && user.isAdmin) ? navigateTo('dashboard') : navigateTo('unauthorized') }

That's it. All of that noise generated by if statements collapses down into two lines. If the second line feels a bit long and unreadable to you, wrap it so that the conditions are on their own line.

function login(user) { user = user || getFromLocalStorage("user"); user && (user.loggedIn && user.isAdmin) ? navigateTo("dashboard") : navigateTo("unauthorized"); }

If you are worried that maybe the next person won't know about how the && and || operators work in JavaScript, add some comments, a little white space and a happy tree. Unleash your inner Bob Ross.

function login(user) { // if the user is null, check local storage to // see if there is a saved user object there user = user || getFromLocalStorage("user"); // Make sure the user is not null, and is also // both logged in and an admin. Otherwise, DENIED. &#x1f332; user && (user.loggedIn && user.isAdmin) ? navigateTo("dashboard") : navigateTo("unauthorized"); } Other things you can do

While we’re at it, here are some other tricks you can play with JavaScript conditionals.


One of my favorite tricks (which I used above), is a one-liner to check if an item is null and then reassign it if it is. You do this with an || operator.

user = user || getFromLocalStorage('user');

And you can go on forever like this...

user = user || getFromLocalStorage('user') || await getFromDatabase('user') || new User();

This also works with the ternary...

user = user ? getFromLocalStorage('user') : new User(); Multiple conditions

You can provide multiple conditions to a ternary. For instance, if we want to log that the user has logged in and then navigate, we can do that without needing to abstract all of that into another function. Wrap it in some parentheses and provide a comma.

isLoggedIn ? (log('Logged In'), navigateTo('dashboard')) : navigateTo('unauthorized');

This also works with your && and || operators...

isLoggedIn && (log('Logged In'), navigateTo('dashboard')); Nesting ternary expressions

You can nest your ternary expressions. In his excellent article on the ternary, Eric Elliot demonstrates that with the following example...

const withTernary = ({ conditionA, conditionB }) => ( (!conditionA) ? valueC : (conditionB) ? valueA : valueB );

The most interesting thing Eric is doing there is negating the first condition so that you don’t end up with the question marks and colons together, which makes it harder to read. I would take this a step further and add a little indentation. I also added the curly braces and an explicit return because seeing one parenthesis and then immediately another makes my brain start to anticipate a function invocation that is never coming.

const withTernary = ({ conditionA, conditionB }) => { return ( (!conditionA) ? valueC : (conditionB) ? valueA : valueB ) }

As a general rule, I think that you should consider not nesting ternaries or if statements. Any of the above articles on Hacker News will shame you into the same conclusion. Although I’m not here to shame you, only to suggest that perhaps (and just maybe) you will thank yourself later if you don’t.

That’s my pitch on the misunderstood ternary and logical operators. I think that they help you write clean, readable code and avoid if statements entirely. Now if only we could get Linus Torvalds to sign off on all this as being “good taste.” I could retire early and and live the rest of my life in peace.

The post In Defense of the Ternary Statement appeared first on CSS-Tricks.

The Serif Tax

Css Tricks - Tue, 04/09/2019 - 8:19am

Fonts are vector. Vector art with more points makes for larger files than vector art with fewer points. Custom fonts are downloaded. So, fonts with less points in their vector art are smaller. That's the theory anyway. Shall we see if there is any merit to it?

Open Sans (top) and Garamond (bottom)

Let's take two fonts off of Google Fonts: Open Sans and EB Garamond. The number of points isn't a dramatic difference, but the seriffed Garamond does have more of them, particularly in looking at the serif areas.

It's not just serifs, but any complication. Consider Bleeding Cowboys, a masterpiece of a font and a favorite of pawn shops and coffee carts alike where I live in the high desert:

Let's stick to our more practical comparison.

We get some hint at the size cost by downloading the files. If we download the default "Latin" set, and compare the regular weight of both:

OpenSans-Regular.ttf 96 KB EBGaramond-Regular.ttf 545 KB

I'm not 100% sure if that's apples-to-apples there, as I'm not exactly a font file expert. Maybe EB Garamond has a whole ton of extra characters or something? I dunno. Also, we don't really use .ttf files on the web where file size actually matters, so let's toss them through Font Squirrel's generator. That should tell us whether we're actually dealing with more glyphs here.

It reports slightly different sizes than the Finder did and confirms that, yes, Garamond has way more glyphs than Open Sans.

In an attempt to compare sizes with a font file with the same number of available characters, I did a custom subset of just upper, lower, punctuation, and numbers (things that both of them will have), before outputting them as .woff2 files instead of .ttf.

After that...

opensans-regular-webfont.woff2 10 KB ebgaramond-regular-webfont.woff2 21 KB

I didn't serve them over a network with GZIP or brotli or anything, but my understanding is that WOFF2 is already compressed, so it's not super relevant.

Roughly two-to-one when comparing the file size of these two pretty popular fonts? Seems somewhat significant to me. I'm not above picking a font, assuming it works with the brand and whatnot because of size.

What made me think of this is a blog post about a font called Ping. Check out this "human hand" drawing principle it's made from:

Whoa! A single stroke? Unfortunately, I don't think actual fonts can be make from strokes, so the number-of-points savings can't come from that. I purchased the "ExtraLight" variation and the points are like this:

Still pretty lean on points.

The TTF is 244 KB, so not the sub-100 of Open Sans, but again I'm not sure how meaningful that is without a matching subset and all that. Either way, I wasn't able to do that as it's against the terms of Ping to convert it.

The post The Serif Tax appeared first on CSS-Tricks.

Using a Mixin to Take the Math out of Responsive Font Sizes

Css Tricks - Tue, 04/09/2019 - 4:20am

Responsive Font Size (RFS) is an engine that automatically calculates and updates the font-size property on elements based on the dimensions of the browser viewport.

If you’re thinking that sounds familiar, that’s because there is a slew of tools out there that offer various approaches for fluid typography. In fact, Chris compiled a bunch of those a little while back. Check that out because it’s always good to know what’s out there and what fits best for a particular task.

RFS is different in that it makes writing code for fluid type feel a lot like writing native CSS (or, more accurately, like writing with a preprocessor) directly in the stylesheets you’re already working in — only without having to wrangle and manage a bunch of media queries. It’s even compatible with Sass, Less, Stylus and PostCSS, so it plugs into just about any stack.

Just how integrated is it? Well, let’s compare a snippet for fluid typography that uses the calc() function...

html { font-size: 16px; } @media screen and (min-width: 320px) { html { font-size: calc(16px + 6 * ((100vw - 320px) / 680)); } } @media screen and (min-width: 1200px) { html { font-size: 22px; } }

...with a similar example of how it can be done with RFS in Sass:

.title { @include font-size(4rem); }

Which compiles to:

.title { font-size: 4rem; } @media (max-width: 1200px) { .title { font-size: calc(1.525rem + 3.3vw); } }

Curious how that works? Let’s check it out and then go into how to set it up for a project.

The magic behind automatic re-scaling

Here’s a graph to get a better understanding of how RFS re-scales font sizes:

Every color represents a font size that gets passed to the font-size() mixin provided by RFS. The y-axis of the graph represents the font size (in px) and the x-axis represents the width of the viewport (again, in px).

Let’s focus on the green line, which is generated by applying a mixin to an element:

.title { @include font-size(40); }

In this case, a font size of 40px is passed into the mixin. That value serves as the maximum font size of the element and reaches that size when the viewport is 1200px or wider, at which point it stays at that size.

Conversely, the font size will bottom out at 20px, never going below that mark.

Everything else? Well, that’s where the font size value is automatically calculated, using a function behind the scenes to determine the number according to the current width of the viewport.

RFS is also a little opinionated in that it limits itself to font sizes that are 20px and above. The reasoning is that smaller text (e.g. normal body text) normally does not need to flex as much and is a lot easier to manage than larger pieces of content, like titles and such. That’s very much in line with FitText, which also prefers being used on large text (even though it will not stop you from doing it).

If you’re the type of person who likes to look under the hood, the mixin for each preprocessor is available to view in the RFS GitHub repo. For example, here’s a direct link to the SCSS version. It’s a lot of math!

Note that every font size is generated in a combination of rem and vw units, but they are mapped to px in the graph to make it easier to understand. In other words, it really takes all the mathwork out of the mix.

Everything is configurable

Seriously. Every. Single. Thing.

For example, you may have wondered why the font size capped out at viewports 1200px and wider in the previous example. That can be changed, as well as a ton of other things, including:

  • Base font size: The lowest font size value.
  • Font size unit: The type of unit to use in the output value (px or em).
  • Breakpoint: The maximum width of the viewport where the font size of the element reaches its maximum value.
  • Breakpoint unit: The unit used for the media query that the mixin generates (px, em or rem).
  • Factor: This serves as a sorta volume control that informs the mixin how aggressive it should be in calculating font sizes from the maximum viewport width all the way down.
  • Rem value: This defines the value of 1rem in pixel (px) units.
  • Two dimensional: A feature that sniffs out the smallest side of a viewport and uses it to calculate the font size value. This comes in handy when, say, you’d like to keep the font from getting smaller when a device is rotated from a portrait orientation to landscape.
  • Class: Provides class names that can be added to an element in the HTML to either enable or disable fluid sizing.

So, yeah. A lot of options and flexibility here. The important thing to know is that all of these options are variables that can be defined in your stylesheets.

All this said, the default settings are pretty safe to use, and they will prevent a lot of longer words truncating from the viewport. This is especially true for some languages — like German or Dutch — that contain a lot of compound words.

Using RFS in a project

Let’s dive straight into to the code. It would be exhaustive to look at the code for each preprocessor, so I’ll be explaining everything in the .scss syntax. But if you prefer something else, you can check out the examples in other languages in the GitHub repo in the Usage section.

First and foremost, RFS needs to be installed on the project. It’s available in npm and Yarn:

## npm npm install rfs ## Yarn yarn add rfs ## Bower is available, but has been deprecated bower install rfs --save

Then, gotta make sure the mixin is imported with the rest of the styles, wherever you do your imports for other partials:

@import "~rfs/scss";

Now, we can start cooking with the mixin!

.title { color: #333; @include font-size(64px); } .subtitle { color: #666; @include font-size(48px); } .paragraph { @include font-size(16px); }

I passed values in px, but rem units are also supported. If a value without a unit is passed, px is used by default. The font sizes are always rendered in rem (in combination with vw) to make sure the font sizes also increase when the default font size is increased in the browser (this is a feature often used by visually impaired people).

The output is:

.title { color: #333; font-size: 4rem; } @media (max-width: 1200px) { .title { font-size: calc(1.525rem + 3.3vw); } } .subtitle { color: #666; font-size: 3rem; } @media (max-width: 1200px) { .subtitle { font-size: calc(1.425rem + 2.1vw); } } .paragraph { font-size: 1rem; }

Notice that the mixin is font-size(), but RFS will also let you use it in two other ways:

.title { @include font-size(4rem); // or @include responsive-font-size(64px); // or @include rfs(64); } RFS is baked right into Bootstrap

Here’s a little story for you.

One day, I had this incredibly impulsive idea to put RFS into Bootstrap. I actually did not use Bootstrap at that time, but believed it was a feature Bootstrap could definitely use. I made a pull request and waited a couple months to see what would happen.

In the meantime, I was getting more and more intrigued by Bootstrap and version 4 had just been released. Slowly but surely, I got more involved in contributing to the project and a whole new world opened for me when I discovered the community behind it. It was during hacktoberfest (oh yes, I got my t-shirt) in October 2018 that I got asked to join the Bootstrap team by mdo.

I believe contributing to open source projects is such a fun and rewarding thing. Andrés Galante has a great post on the topic if you're interested in becoming a contributor.

Since then, RFS has become a project of the Bootstrap team, and on February 11th this year, we launched Bootstrap 4.3 which includes RFS right out of the box. It’s currently disabled by default, but can easily be switched on by setting the Sass variable $enable-responsive-font-sizes: true.

But make no mistake: RFS can still be used on its own. Just cool that it's baked right into a widely used framework.

Oh yeah, let's talk browser support

Support is pretty darn good! In fact, RFS will work anywhere that supports media queries and viewport units. RFS will set a font size for Legacy browsers, like Internet Explorer 8, but the fluidity won't be there. In other words, should be safe for production!

What’s next for RFS

The next major version of Bootstrap is version 5 and we’re planning to enable RFS by default. We don’t have any plans to change the way it works for now. More than likely, the $enable-responsive-font-sizes variable will simply be set to true and that’s it.

In the future, I hope I can make use of the min() function because it would generate less CSS and make things a lot less complex. Browsers don’t seem to support this function all too well just yet, but if you’re interested in this feature, you can follow the progress in this GitHub issue.

Anything else? No, but I can leave you with a little song and dance: Na na na na, na na na na, hey hey hey goodbye!

The post Using a Mixin to Take the Math out of Responsive Font Sizes appeared first on CSS-Tricks.

Native Lazy Loading

Css Tricks - Mon, 04/08/2019 - 12:28pm

IntersectionObserver has made lazy loading a lot easier and more efficient than it used to be, but to do it really right you still gotta remove the src and such, which is cumbersome. It's definitely not as easy as:

<img src="celebration.jpg" loading="lazy" alt="..." />

Addy Osmani says it's coming in Chrome 75:

The loading attribute allows a browser to defer loading offscreen images and iframes until users scroll near them. loading supports three values:

  • lazy: is a good candidate for lazy loading.
  • eager: is not a good candidate for lazy loading. Load right away.
  • auto: browser will determine whether or not to lazily load.

I'll probably end up writing a WordPress content filter for this site that adds that attribute for every dang image on this site. Hallelujah, I say, and godspeed other browsers.

Easy lazy loading of images will have the biggest impact on the site as a whole, but lazy loaded iframes will be even bigger for the individual sites that use them. I'm into it.

Yes yes whatever native lazy loading of images but lazy loading of iframes is gonna be a goddamn game changer for ad tech:

— Laurie Voss (@seldo) April 8, 2019

I hope this pushes along the need for native aspect ratios as well, since a major reason for that is preventing content reflow from things loading later. We do have ways now, though.

The post Native Lazy Loading appeared first on CSS-Tricks.

CSS book Table of Contents &#8212; draft 1

QuirksBlog - Mon, 04/08/2019 - 6:23am

I am likely going to write a “CSS for JavaScripters” book, and therefore I need to figure out how to explain CSS to JavaScripters. This series of article snippets are a sort of try-out — pre-drafts I’d like to get feedback on in order to figure out if I’m on the right track.

Today I present the first draft of the book’s table of contents for feedback — both on the topics, and on the chapter order.

h5,h5 + ul { margin-left: 2em; } Part 1: How CSS works
  • CSS Is (Not) A Programming Language
  • Imperative vs declarative languages
  • The CSS mental model
  • A style sheet as kind-of a JSON file: all commands are executed simultaneously. (Don't take this comparison too far)
  • CSS engines in the browser
  • layout vs appearance -> layout module vs paint module. Consequences for transitions -> use opacity and transform whenever possible
  • Formal syntax: rules, selectors, declarations, values. Semi-colon is REQUIRED.
  • CSS Is Global
  • CSS classes === JS objects (good comparison? take care). Multiple classes for 'OO'
  • Backward compatibility as a design principle. Drawback: past mistakes (box model; margin collapse) won't ever be fixed.
  • Vendor prefixes. History and purpose. Current status: don't use, unless you must.
Part 2: How to work with CSS
  • Test in several browsers; start with Chrome Win/Mac/Android, Firefox, Safari Mac/iOS, Samsung Internet, and one odd one, just to keep you on your toes.
    Ex: Fonts because a beginners mistake is to assume that browsers (oses) render fonts similarly and the space is consumed unequally, depending on input (asian characters, emojis,..).
  • Browsers are a reality to be experienced.
  • A WebSite Does Not Need To Look Exactly The Same In All Browsers.
  • Trial and error is OK.
  • Put borders around the elements you're working with. Makes it easier to see what's going on. More such tricks.
  • Better to be clear but verbose than succinct but incomprehensible -> shorthand properties
    • "Shorthands reset all components to their initial value, so you can avoid inheriting things you don't intend on.
    • Things like font (which *technically* isn't a shorthand) can avoid accidentally inheriting boldness or italicness, which is useful."
    • Exceptions: margin, padding, border, border-radius
  • If the answer is "add more divs", it’s the wrong answer - or the wrong question.
  • Please give me practical tips and tricks for this chapter.
Part 3: technical chapters Section 1: What makes CSS special

Selectors should have their own chapter. Not sure about the rest, though; maybe combine them into one.

  • how selectors are read right-to-left
    Harry: I would never encourage anyone to write selectors *for* performance, but it just so happens that the traits of a ‘good’ selector also happen to make a selector very fast.
  • and how to write them well
  • pseudos
  • focus, :hover, :focus-within (Adrian)
  • CSS selectors can be very complicated giving one great satisfaction at one’s cleverness. Avoid the temptation to be clever. In 99% of circumstances use the dumbest selectors possible.
  • How it works; purpose; drawbacks; using !important to identify problems
  • How to work out which CSS rules apply to an element, and why they do.
  • Example: style.display = ''; allows regular cascade to return
  • Too little for its own chapter? Combine with cascade or specificity?
  • Example: font inheritance good
  • Example: margin inheritance bad
  • Example: opacity inheritance confusing. Font-size may have similar problems
  • cascade VS. inheritance (Harry)
  • Formal rules
  • How one selector overrides (or doesn't) another. How specific to make your selectors.
Section 2: CSS fundamentals Units
  • px, em, rem, vw/vh PERCENTAGES, nonsense units such as cm, pica, pt, in
  • Px fundamental CSS unit; em and rem relative to font size; vw/vh relative to viewport (which viewport; what if toolbars disappear?)
  • Keywords, global such as inherit, property-specific, and nonsense keywords such as initial and unset.
  • percentages: relative to WHAT?
Box model
  • width, height, margin, padding, border. Border-box. Percentages (or in Units chapter?)
  • border vs outline
  • Mistakes were made: box model, margin collapse
  • Block-level vs inline
  • display (inline, block, grid, flex)
  • display is secretly display-inside (grid, flex) and display-outside (block, inline, table-*)
    td {display: flex} -> td is not a table cell any more;
  • vertical aligmnent
  • Line boxes? (Here or elsewhere?) Be brief.
  • Flexbox and grid
  • More fundamental stuff? If so, what?
  • Old techniques: floats and tables. Do not use. Distrust any resource that tells you to use floats.
  • flexbox order isn't reflected in the accessibility tree
  • reordering consequences and options in css
Positioning and z-index
  • Positioning basics
  • Stacking contexts
  • * {position: relative} <- why not?
Special HTML elements
  • inputs
  • scrollbars
  • <progress>, <details>, <meter>, and <hr> are harder than they should be.
  • Table elements have their gotchas.
Advanced thingies
  • Better title needed
  • variables/custom properties: Highlight local scoping possibilities
  • calc()
  • Advanced math stuff (max() and so on) Ask Tab again in December.
  • Enough for separate chapter? Split up?
Section 3: Other topics

These are the most sketchy chapters.

  • ? Mostly because I'm the worldwide specialist and writing this chapter would be easy. Not 100% certain it belongs in a beginners handbook, though.
  • Visual viewport, layout viewport, meta viewport.
  • Why so complicated? What problem does it solve?
Media queries and @supports
  • Especially width (and warning not to use device-width)
  • The limits of @supports (transition-property: nonsense)
  • Explanation.
  • Dangers of offsetWidth and related -> re-layout
  • How JavaScript can change styles and style sheets
  • Typed Opject Model
  • Not sure yet if I should include this chapter.
  • Inline CSS and why it's generally bad
  • CSS modules
  • Ordering your stylesheet
  • BEM
  • CSS in JS

Testing for Visual Regressions with Percy

Css Tricks - Mon, 04/08/2019 - 5:14am

While this post is not sponsored (it is based on Paul’s own personal experience), we have worked with Percy before on a sponsored video, that also goes through the process of setting up Percy on a site. It’s fascinating, powerful, useful stuff and I highly recommend checking it out.

Let me set the stage:

  1. You've pushed some code and all the meticulously unit tests you wrote pass. Fantastic! Let’s get this branch into QA.
  2. You receive a Slack message from your QA team asking why a button is now floating off the screen?
  3. "But... I didn't touch any code in that part of the application," you think to yourself.
  4. Then you remember you did change some CSS.
  5. Panic! What else has changed in the UI? Does this affect iPad? Will Firefox behave differently than Chrome? What about mobile?

This is a very common scenario many of us face when building large-scale applications that deal with different screen sizes and browsers. It’s a Herculean task to test UI for each and every change to code.

What now, throw in the towel and move to the mountains? Thankfully, no. We have Percy to help save the day! And it’s really the best friend we have for testing unexpected outcomes that impact design and layout. Percy has become an indispensable part of my development stack and I convinced CSS-Tricks to let me share some things about it that have made my code stronger and helped prevent errors from shipping.

Plus, it integrates well with other tooling and is a relative breeze to set up. So hang with me a bit as we walk through what Percy is and how to leverage it for your projects.

So, what exactly is Percy?

According to Percy’s site, it’s an “all in one visual review platform."

I’ve found that holds true. What it boils down to is that Percy provides a way to test visual regressions. That’s pretty awesome if you think about it. Many changes to a codebase — especially working with CSS — can introduce breaking changes to a site’s design. If you’ve ever inherited a large legacy stylesheet, modified a class, and hit Save, then you probably have a great idea of how nerve-wracking that can feel. Percy’s goal is to provide confidence in those types of situations where it’s difficult to know all of the UI that depends on the same line of code.

Excited? Let's get started.

Setting up an example site

Let’s set up a little site that Percy can hook into and test some UI we’re going to make together. These days, this couldn't be easier, thanks to Gatsby and Netlify. It is way beyond the scope of this article to do a deep dive into these technologies, but rest assured, they are wonderful as well and can get us online without a bunch of server setup.

Head over over to Netlify templates and click the "Deploy to Netlify" button, which will set up a git repo on your GitHub account and also deploy the app using Netlify.

After completing the setup steps, we should get something like this (after the site is deployed):

Magically, our site is now live! We will use this to get to grips with Percy.

Using CircleCI for automated testing

Percy works best in a continuous integration (CI) environment that will trigger testing based on an action. We will use CircleCI to make it happen by integrating with the example site’s GitHub repo and running the builds, allowing us to test every commit.

The first thing we need to do is clone down our new repo on GitHub, I clone mine as follows:

git clone

With our repo now cloned, we can head over to CircleCI and sign up with a GitHub account.

We now need to add our project, so click "Add Projects" in the side navigation and you should see a screen like the following screenshot. Find the project we just cloned and click “Set Up Project."

In the Set Up Project area, we want to select Linux as our operating system and Ruby as our language (pery-cli is in Ruby). Here are the rest of the steps for this part:

CircleCI tells us that we need a .circleci directory and that we need a config.yml file in it. Create the following structure within your project.

CircleCI offers a configuration snippet to copy and paste for our configuration, but it is far too verbose for us; we only need a simple config.yml file.

Go ahead and use the following snippet. You’ll see that we install the percy-cli gem along with Percy in our tests:

version: 2 jobs: build: docker: - image: circleci/ruby:2.4.1-node-browsers working_directory: ~/repo steps: - checkout - run: name: install dependencies command: | npm install gem install percy-cli - run: name: run our tests command: | npm run build percy snapshot public

This config is all we need.

At first, It took me a while to figure out why my build was failing and turned out I was trying to install percy-cli as an npm module. Yikes!

We now have the CircleCI configuration set up so finally we can start using Percy!

As a sanity check, comment out the run our tests step above and push your code to the master branch.

Now click the "Start building" button which will use the configuration you just pushed to create a build. Here's what you should see in the workflows section:

From here on out, CircleCI will create a build for us whenever we do a push.

Hooking Percy up to CircleCI

A Percy account is needed to use the service. Head over to Percy’s site and sign up with your GitHub account.

Once signed up, you can create a new organization (if you don't already have one) and call it whatever you want.

Next thing to do is add a project to the organization. It’s probably a good idea to call the project something matching the name of the repo so that it’s recognizable later.

Now we need to add a Percy token to CircleCI. Percy tokens are located under "Project Settings."

My access token is blocked out.

Alright, let’s add the token in CircleCI in Environment Variables under “Build Settings." You can find Build Settings by clicking the gear icon beside your project in the workflows section.

Again, my token is blocked out.

It’s time to run Percy! If you commented out the run our tests line in the config file earlier, then remove the comment because that command will run Percy. Push to master again and then head over to the Percy app — we will see Percy has started its own build for creating snapshots. If all goes well, this is what we should get:

If you click on this build, then you can see all the screens Percy has snapped of the application.

You might be wondering what the deal is with that empty left column. That's where the original screen normally is, but since this is the first test, Percy informs us that there are no previous snapshots to compare.

The final thing we need to do to wrap up this connection is link our repo to Percy. So, in Percy, click “Project Settings" then click on the “install an integration" link.

Select the organization and hit install for all repositories:

Finally! We can link to our repository.

Unlocking the true power of Percy

Since we now have everything set up, we can see how Percy can be used in a code review workflow! The first thing we will do is create a branch from master. I’m calling my branch "changing-color."

Go to the /src/components/all.sass file, change Line 5 to use the color pink, then push the change to the repo. This is what we’re going to evaluate in our visual test.

Create a pull request for the change in GitHub.

CircleCI is carrying out checks for us but the one we are focused on is the Percy step. It may need a minute or two for Percy to pop up:

Percy is letting us know that we need to review changes we made, which in this case, is the change from red to pink. We can see the impact of that change:

Although the changes on the right are red, that is highlighting the areas that have been changed to pink. In other words, red is indicating the change rather than the actual appearance.

We can give this a quick glance and then click the “Approve" button which will give us a green tick on GitHub indicating we’re free to merge the pull request.

This is the true power of Percy: allowing us to see the impact of a small change and giving us the option to approve the changes.

Fantastic! We have now taking a tour on how to set Percy up in our projects along with how to integrate CircleCI. I really hope this will save you many headaches in the future when managing your UI.

The post Testing for Visual Regressions with Percy appeared first on CSS-Tricks.

Undefined: The Third Boolean Value

Css Tricks - Fri, 04/05/2019 - 4:20am

I wanted to implement a notification message in one of my projects, similar to what you’d see in Google Docs while a document is saving. In other words, a message shows up indicating that the document is saving every time a change is made. Then, once the changes are saved, the message becomes: “All changes saved in Drive.”

Let’s take a look at how we might do that using a boolean value, but actually covering three possible states. This definitely isn’t the only way to do this, and frankly, I’m not even sure if it’s the best way. Either way, it worked for me.

Here’s an example of that “Saving...” state:

The “Saving” notification displays any time a change is made to the document.

...and the “Saved” state:

The “Saved” notification displays once a change or set of changes has completed.

Using a Boolean value for to define the state was my immediate reaction. I could have a variable called isSaving and use it to render a conditional string in my template, like so:

let isSaving;

...and in the template:

<span>{{ isSaving ? ‘Saving...’ : ‘All changes saved’ }}</span>

Now, whenever we start saving, we set the value to true and then set it to false whenever no save is in progress. Simple, right?

There is a problem here, though, and it’s a bit of a UX issue. The default message is rendered as “All changes saved.” When the user initially lands on the page, there is no saving taking place and we get the “Saved” message even though no save ever happened. I would prefer showing nothing until the first change triggers the first “Saving” message.

This calls for a third state in our variable: isSaving. Now the question becomes: do we change the value to a string variable as one of the three states? We could do that, but what if we could get the third state in our current boolean variable itself?

isSaving can take two values: true or false. But what is the value directly after we have declared it in the statement: let isSaving;? It's undefined because the value of any variable is undefined when it’s declared, unless something is assigned to it. Great! We can use that initial undefined value to our advantage... but, this will require a slight change in how we write our condition in the template.

The ternary operator we are using evaluates to the second expression for anything that can’t be converted to true. The values undefined and false both are not true and, hence, resolve as false for the ternary operator. Even an if/else statement would work a similar way because else is evaluated for anything that isn’t true. But we want to differentiate between undefined and false . This is fixable by explicitly checking for false value, too, like so:

<span> {{ isSaving === true ? ‘Saving...’ : (isSaving === false ? ‘All changes saved’: ‘’) }} </span>

We are now strictly checking for true and false values. This made our ternary operator a little nested and difficult to read. If our template supports if/else statements, then we can refactor the template like this:

<span> {% if isSaving === true %} Saving... {% elseif isSaving === false %} All changes saved {% endif %} </span>

Aha! Nothing renders when the variable is neither true nor false?— exactly what we want!

The post Undefined: The Third Boolean Value appeared first on CSS-Tricks.

Revisiting the Rendering Tier

Css Tricks - Fri, 04/05/2019 - 4:17am

Have you ever created a well-intentioned, thoughtful design system only to watch it grow into an ever-increasing and scary codebase? I've been working in sort of the opposite direction, inheriting the scary codebase and trying to create a thoughtful system from it.

Here's Alex Sanders on the topic, explaining how his team at The Guardian has tackled the task of creating design systems while combating complexity:

Systems that try to contain complexity over long periods of time by convention will inevitably tend toward entropy, because one significant characteristic of convention is that it is trivially simple to break one.

You do not even need to be malicious. A convention is not a line in the sand. You can have a very good case for breaking or stretching one, but once a convention is no longer fully observed, subsequent cases for breaking or stretching it are automatically stronger, because the convention is already weakened. The more this happens, the weaker it gets.

Complexity and entropy can be two outcomes in the same situation, but need not be mutually exclusive. Interesting to think that our best intentions to guard against complexity can be somewhat destructive.

I also love how Alex explains why it’s not possible for their team to use a Tachyons-esque approach to writing styles because of the way that their development environment is kinda slow. It would be painful for the team to make that switch, despite how it could solve some other problems. This reminded me that measuring problems in this way is why there can never be a single way to write CSS. We need that inherent flexibility, even at the expense of introducing inconsistencies. Hence, conventions being less of a line in the sand and more of a guide post.

On a separate note, I really like how Alex describes styles and attributes as the reasons why his team is writing those styles. It's about aligning with business objectives:

...tens of thousands of rules that are intended to describe a maintainable set of responses to business and design problems.

That’s interesting since I don’t think we spend much time here talking specifically about the business side of CSS and the functional requirements that a styled user interface needs to accomplish.

And perhaps thinking about that can help us write better styles in the long term. Is this line of CSS solving a problem? Does this new class resolve an issue that will help our customers? These are good questions to keep in mind as we work, yet I know I don’t spend enough time thinking about them. I often see the design I’m turning into code as a problem to be solved instead.

Perhaps we should expand the way we styling a webpage because maybe, just maybe, it will help us write more maintainable code that's built to solve a real business objective.

Direct Link to ArticlePermalink

The post Revisiting the Rendering Tier appeared first on CSS-Tricks.

In search of the Miui Browser

QuirksBlog - Thu, 04/04/2019 - 5:14am

Today it’s time for an old-fashioned browser detective story about the Miui Browser, the current state of non-Google Chromia on Android, and assumptions about browsers and UA strings. In addition, this article will highlight a few principles of mobile browser research, one of which was vindicated rather nicely.

Update: severe vulnerability discovered in Miui/Mint Browser.

The old gang

A client wants me to see how the the old gang of non-Google Chromium browsers on Android is doing. We all know Samsung Internet is doing fine, thanks so much for asking. But what about the others? Several of them, such as HTC Chromium, have silently disappeared. What’s the exact current score? Who are the survivors?

When in doubt, tweet. I asked my followers for non-Google Chromium browsers, and enough of them responded to get a first impression. Samsung Internet, obviously, but also the Miui Browser for Xiaomi devices, using mostly Chromium 61, but sometimes 63. That was interesting.

The device

In order to say anything useful about such a browser, you need the device it’s made for — even though it may be available for download, as is the case for the Miui Browser. I needed a Xiaomi phone. (This, by the way, is the principle that was vindicated. We’ll get to that in due time.)

So I went to the local friendly phone shop and ordered a RedMi 5, a model that was present in several browser strings my followers sent me. (And why didn’t I order it online? Because such small shops allow you to test phones before buying them, so that I can be certain they contain the browser I want. The shop going out of business would be bad for my business. So I ordered the device there and allowed them to take their margin.)

The home screen

I did this on Thursday, and picked up the phone on Friday afternoon, politely declining their testing offer (I was tired, and the end of the week was very near). I only got around to firing it up on Tuesday. And when I did ... deception! There was just a regular boring old Google Chrome on the home screen!

Mistake #1 on my side: I plain missed the “Browser” icon in the upper left.

In my defense, this default home screen is non-standard. In fact, it’s the first time I see this particular configuration of icons.

I expected the “Browser” icon to be in the favourite bar at the bottom of the screen, in the exact spot the Chrome icon takes up. That’s the proper place for the browser that the vendor wants its users to use. If Google Chrome is there, it means the device vendor has no browser of its own. (Or that the operator put it there, but this phone was unlocked, so there’s no operator hanky-panky going on.)

I lamented the fate that made me throw away hundreds of euros on a worthless device, dutifully noted that the default browser was a Chrome 67, which after an update became a 73, yawned widely, and put the RedMi away. No Xiaomi Chromium for me or my client.

The WebView

Later that day I hit on what I thought was mistake #2. I re-checked the browser strings my followers had sent me, and sure enough, there it was, in every single browser string I received: the telltale Version/4.0 that denotes a WebView.

A WebView is a secondary browser on a mobile device that is available for apps such as Twitter and Facebook. Clicking on a link in those apps opens web pages not in the device browser, but in the device WebView. That way the users don’t have to leave the app. Engagement stuff.

On iOS you are not allowed to install other rendering and JavaScript engines. Therefore, browsers such as Chrome and Firefox iOS are not in fact Chrome or Firefox. They use the Safari WebView for their actual browsing.

On Android you can install any browser you want, but Google requires all device vendors to use the Google WebView. It is updated regularly and is at most one or two versions behind Google Chrome.

I assumed these Xiaomi users had seen my tweet in their Twitter app and clicked on the link, firing up the system WebView. It was a bit odd that all these devices used Chromium 61 instead of the expected 71 or 72 — but apparently Chinese manufacturers did not have to worry about that rule as much. Or something.

I thought I had found my mistake. In fact, I hadn’t. In fact, I’d done exactly the right thing by buying the device and ignoring the Version/4.0. But I didn’t know that yet.


On Wednesday I felt bad for my client, whom I’d promised a Xiaomi Chromium that I couldn’t deliver. So I decided to check in on the one definite non-Google Chromium: Samsung Internet. Samsung claims you can install that browser on pretty much any Android device nowadays. Let’s put that to the test and install it on the RedMi 5.

Play Store, install, no hitch, done. Load test site, works. “Make Samsung Internet your default browser?” Since I was feeling vengeful and spiteful towards Google Chrome, I decided to do it. The phone sent me to a settings menu where I could select my default browser. (Incidentally, I like this idea. Instead of allowing browsers to set themselves as the default, merely allow them to open the system setting for the default browser. This might even be a solution to the latest Google-EU conundrum.)

Anyway, the menu gave me the options for my default browser: Google Chrome, Samsung Internet ... or “Browser.”


Wait a minute. There IS a vendor browser on the RedMi 5! Called Browser. (Browser and Internet are the only two names allowed for a vendor browser in Asian mythology. Don’t ask me why.)

I finally noticed the icon on the homescreen, tapped it, saw an unknown browser open before my very eyes, sent it to my test site with trembling fingers, and lo and behold, there was MiuiBrowser 10.1.2 in all its glory:

Mozilla/5.0 (Linux; U; Android 8.1.0; en-gb; Redmi Note 5 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.1.2

Another surviving member of the old gang! I hadn’t wasted my client’s time and my money after all! Good days and weird browsers are here again! I was in paradise.

Then I noticed the snake: Version/4.0. A WebView.

Again the WebView

What was this? Why was this application that was clearly a browser pretending to be a WebView?

One possible answer is that it’s in fact only a skinny app that uses the WebView for all its actual browsing. I saw that before in the curious case of the Indian Micromax.

I didn’t believe this was a skinny app, though. My gut feeling told me that this is a real browser. So I downloaded an app that tests the WebView, and it gave me this for the WebView UA String on the RedMi 5:

Mozilla/5.0 (Linux; Android 8.1.0; Redmi Note 5 Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3683.90 Mobile Safari/537.36

That sounds about right. It’s a Chromium 73, which fits, because I just updated the device. It has the crucial wv bit in the Android/device part of the string, which denotes a WebView.

Version/4.0 and wv

So Miui is a true browser, and not a WebView. But why does the Miui Browser incorporate Version/4.0 in its browser string?

I don’t know the answer. Maybe it wants to end up on the right side of browser detects written by clueless web developers? Maybe they just plain forgot to change it? (For a short while early in its history, Chrome’s navigator.vendor was “Apple.” They obviously forgot to change that field. A scenario like this is not impossible for Miui.)

In any case, Version/4.0 no longer necessarily denotes a WebView, though I think wv still does. So we’ll have to use that last substring to identify WebViews from now on. Duly noted.

Market share

We have now positively identified the Miui Browser as the Chromium-based system default browser on the Xiaomi RedMi 5, and likely other models as well.

The first question any web developer will ask is: OK, what’s its market share?

I don’t know. There’s only one source for this sort of data, StatCounter’s global statistics, and it doesn’t count Miui Browser as a separate browser. Miui’s stats are part of the general Google Chrome stats.

StatCounter counts Samsung Internet as a separate browser, but only after the entire Samsung Internet team threatened to holds its collective breath for days on end. Apparently nobody issued a similar threat for the Miui Browser. So we have no data.

I may be able to find data from a different source, though. Let’s see what happens. But even if that succeeds I would be hugely surprised if Miui Browser holds more than 1-2% of the mobile browser market.

Zoom reflow

If talking about market share yields nothing useful, let’s talk about features instead. Is the Miui Browser browser different from a regular Google Chrome 61?

Normal zooming: you only see part of the line.

Miui zooming: the lines reflow to fit on the screen.

Yes, it most definitely is. Miui Browser supports zoom reflow, one of my absolute favourite mobile browser features, and one that Google Chrome never supported.

If a user zooms in to a visual viewport size where lines of text do not fit on screen, most browsers do nothing. The lines go off-screen, and if users want to read them they’ll have to pan left or right. Safari, Chrome, Firefox, Samsung Internet, and most other mobile browsers work like that.

Miui Browser and Opera Mobile, however, support zoom reflow. If the user zooms in to where lines of text do not fit on screen, the browser reacts by shortening these lines, so that the text stll fits. This does wonders for readability, especially with those annoying sites that have far too long lines.

Zoom reflow has a down side as well: the browser has to recalculate the layout of most of the page. Elements may suddenly contain many more lines of text, and therefore grow in height. Other elements below the affected elements will be moved downward, even if their height isn’t adjusted. This causes massive reflows and recalculations of the layout. Worse, if the user zooms out the entire process has to run in reverse.

Despite this, the presence of zoom reflow is enough to make me consider switching devices in order to have the Miui Browser available. I simply LOVE it. (OK, Opera Mobile supports it as well.)


Christian Schaefer pointed out the Miui Browser can also be downloaded. Would that yield the same browser as the one on the device?

Christian referred me to the APK Mirror site (a site so horrible that I refuse to link to it, although it does appear to be trustworthy). At first I didn’t want to mess with a complicated site, so I just searched the Play Store for “Miui Browser” and got a hit. Download, install, try. This is the browser:

Mozilla/5.0 (Linux; U; Android 5.0.1; en-gb; GT-I9505 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/Mint Browser/1.6.2

There are two important differences with the pure Miui on the RedMi: it’s a different device (Galaxy S4, because it happend to be within reach of my hands), and the name is not Miui Browser but Mint Browser, though it’s still branded Xiaomi. Also, the Version/4.0 is very much present in this browser, which is downloaded and thus certainly not a WebView.

But is there an actual difference in features? Yup, of course there is. Mint Browser does not support zoom reflow, instead handling zooming exactly as the other, boring browsers.

That leads to the question if the Mint Browser is truly a Miui Browser, or just a downloadable variant. I’m currently assuming the latter, and have concluded that testing on Mint Browser cannot stand in for testing on Miui Browser.

Then I gritted my teeth, steeled my soul, and dove deep into APK Mirror and its terrible process flow. It took me twenty minutes to figure out how to download something, and I could only do that because I browsed the site on Chrome Mac, then copied the correct clicks to my phone. It was an awful experience — but I heroically snatched Miui Browser 10.6 from the claws of this site:

Mozilla/5.0 (Linux; U; Android 8.0.0; en-gb; SM-G930F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.6.1

This one is now on my Galaxy S7, hence the different device string. It’s a later version than the one on the RedMi 5, though it still uses Chromium 61. But the browser name is Miui Browser, and not Mint Browser. Also, it supports zoom reflow. That’s enough for a positive identification. The APK Mirror version is a true Miui Browser.

Conclusion: non-Google Chromia

I have now identified Miui Browser as one of the few surviving non-Google Chromium browsers on Android, in addition to Samsung Internet.

Update: severe vulnerability discovered in Miui/Mint Browser.

Also, I feel vindicated by my insistence on buying an actual device. If I’d just searched on the Play Store I would have got the Mint Browser, which is not the native browser on Xiaomi devices. Now I’ve got the real thing. Also, I could experimentally verify that the APK Mirror download actually is the real thing as well.

It’s interesting that, like Samsung, Xiaomi thinks it’s useful to offer its browser for download. Also, Miui Browser is not restricted to Xiaomi phones any more, just as Samsung Internet is not restricted to Samsung phones any more. I now have a Xiaomi phone with Samsung Internet, and a Samsung phone with Miui Browser. Interoperability FTW!

It appears Samsung’s web developer communication strategy is partly being copied — and that shouldn’t come as a surprise, since it’s a pretty successful one. Web developers are aware of the existence of Samsung Internet, and can download it for testing even on non-Samsung devices. If Xiaomi made the downloading process easier, and did something about web developer outreach, it could have similar success.

That leaves two minor mysteries to be solved: its market share, and its use of Version/4.0 in the UA string of a true browser. I hope to be able to offer new insights later.

For now, though, I will continue my search for other surviving non-Google Chromia. If you think you’ve discovered one, please go here, add a note as to the device or the browser, and hit Send Info. The Internetz will thank you later.

Decaying Sites

Css Tricks - Thu, 04/04/2019 - 4:37am

Websites have a tendency to decay all by themselves. Link rot, they call it. Unpaid domain name registrations. Companies that have gone out of business. Site owners that have lost interest. What's sadder than a 404? Landing on a holding page of a URL that used to exist, but now has fallen into the hands of some domain hoarder after it expired, hoping someone will pay a premium to get it back.

That stuff is no fun. But what about sites that are totally still around, just old? What kind of fun things could we do to indicate oldness that's, like, on purpose?

On the CodePen blog, we call out blog posts that haven't been updated in at least a couple of years. We update documentation, sure, but we tend to leave blog posts alone as a historical record. So, we're pretty clear about that:

<?php if (get_the_modified_date("Y") < 2017) { ?> <p class="callout"><strong>Heads up!</strong> This blog post hasn't been updated in over 2 years. CodePen is an ever changing place, so if this post references features, you're probably better off checking the <a href="/documentation/">docs</a>. Get in touch with <a href="">support</a> if you have further questions.</p> <?php } ?>

We style it up like a little warning:

But what if it was less obvious? What if the text just kinda started going all to crap? Words falling off their lines and going out of focus? The older the content, the more decay:

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

What if you let a site decaye on purpose? Say, perhaps, you're holding oto client work and the client hasn't paid their bill. Dragoi Ciprian has a little idea (repo) for that. You set the due date and deadline:

var due_date = new Date('2017-02-27'); var days_deadline = 60;

Here's a demo of that. As I write, I'm 30 days into a 90-day deadline. If the demo looks blank to you, well, I guess I should have paid my bill so this code could have been removed &#x1f609;

See the Pen
not-paid Demo
by Chris Coyier (@chriscoyier)
on CodePen.

Or maybe the screen could kinda flash red, like you're getting hit in a video game.

Dave once mentioned this would be a cool browser extension, like the browser window could flash red when certain bad things are happening, like layout jank.

Or you could get all glitchy! (This demo is click-to-load, fast colors and motion warning.)

See the Pen
Glitchy loader
by Nathaniel Inman (@NathanielInman)
on CodePen.

See the Pen
CSS Glitched Text
by Lucas Bebber (@lbebber)
on CodePen.

Perhaps rather than basing things off a payment due date or the age of the content, these effects come into play based on how long it's been since the site's dependencies have been updated. Or at least had some kind of deployment push.

This is only sorta tangentially related, but it reminds me of the very, very scary game Lose/Lose:

Lose/Lose is a video-game with real life consequences. Each alien in the game is created based on a random file on the players [sic] computer. If the player kills the alien, the file it is based on is deleted. If the players [sic] ship is destroyed, the application itself is deleted.

Although touching aliens will cause the player to lose the game, and killing aliens awards points, the aliens will never actually fire at the player. This calls into question the player's mission, which is never explicitly stated, only hinted at through classic game mechanics. Is the player supposed to be an aggressor? Or merely an observer, traversing through a dangerous land?

The post Decaying Sites appeared first on CSS-Tricks.

A Couple of New Wufoo Tips

Css Tricks - Thu, 04/04/2019 - 4:33am

(This is a sponsored post.)

High fives to Wufoo, our long-time sponsor here on CSS-Tricks. It's powered the vast majority of forms I've built over the past decade. If you've never used it or heard of it: it's a form builder. It makes the arduous task of implementing forms trivially easy. Building a form on Wufoo means you'll get a form that does everything right UX-wise, gives you full design control, integrates with anything, and that you can put anywhere.

The feature list is too long to cover in the confines of a single post, so I always like to cover little bits that I've used recently and liked.

  1. They just released a much quicker way to rename a form both in the Form Manager and inside the form itself.
  2. Don't forget they have a robust API. I used the API to submit form entries on a form just the other day. I wanted to do some special things on a form, like be able to react to the DOM event of submitting the form. That's not really possible when the form is in an <iframe>, but just fine when you host the form yourself and submit via API. Worked great.

Direct Link to ArticlePermalink

The post A Couple of New Wufoo Tips appeared first on CSS-Tricks.

Fixed Headers, On-Page Links, and Overlapping Content, Oh My!

Css Tricks - Wed, 04/03/2019 - 11:38am

Let's take a basic on-page link:

<a href="#section-two">Section Two</a>

When clicked, the browser will scroll itself to the element with that ID: <section id="section-two"></section>. A browser feature as old as browsers themselves, just about.

But as soon as position: fixed; came into play, it became a bit of an issue. The browser will still jump to bring the newly targeted element into view, but that element may be obscured by a fixed position element, which is pretty bad UX.

I called this "headbutting the browswer window" nearly 10 years ago, and went over some possible solutions. Nicolas Gallager documented five different techniques. I'm even using a fixed position header here in v17 of CSS-Tricks, and I don't particularly love any of those techniques. I sort of punted on it and added top padding to all my <h3> elements, which is big enough for the header to fit there.

There is a new way though! Finally!

Šime Vidas documented this in Web Platform News. There are a bunch of CSS properties that go together as part of CSS scroll snapping, but it turns out that scroll-padding and scroll-margin can be used outside of a scroll snapping container.

body { scroll-padding-top: 70px; /* height of sticky header */ }

This only works in Chromium browsers:

See the Pen
Scroll Padding on Fixed Postion Headers
by Chris Coyier (@chriscoyier)
on CodePen.

This is such a useful thing we should hoot and holler for WebKit and Firefox to do it.

The post Fixed Headers, On-Page Links, and Overlapping Content, Oh My! appeared first on CSS-Tricks.

Responsible JavaScript

Css Tricks - Wed, 04/03/2019 - 11:38am

We just made a note about this article by Jeremy Wagner in our newsletter but it’s so good that I think it’s worth linking to again as Jeremy writes about how our obsession with JavaScript can lead to accessibility and performance issues:

What we tend to forget is that the environment websites and web apps occupy is one and the same. Both are subject to the same environmental pressures that the large gradient of networks and devices impose. Those constraints don’t suddenly vanish when we decide to call what we build “apps”, nor do our users’ phones gain magical new powers when we do so.

It’s our responsibility to evaluate who uses what we make, and accept that the conditions under which they access the internet can be different than what we’ve assumed. We need to know the purpose we’re trying to serve, and only then can we build something that admirably serves that purpose—even if it isn’t exciting to build.

That last part is especially interesting because it's in the same vein as what Chris wrote just the other day about embracing simplicity in our work. But it’s also interesting because I've overheard a lot of engineers at work asking how we might use CSS-in-JS tools like Emotion or Styled Components, both of which are totally neat in and of themselves. But my worry is about jumping to a cool tool before we understand the problem that we want to tackle first.

Jumping on a bandwagon because a Twitter celebrity told us to do so, or because Netflix uses tool X, Y or Z is not a proper response to complex problems. And this connects to what Jeremy says here:

This is not to say that inaccessible patterns occur only when frameworks are used, but rather that a sole preference for JavaScript will eventually surface gaps in our understanding of HTML and CSS. These knowledge gaps will often result in mistakes we may not even be aware of. Frameworks can be useful tools that increase our productivity, but continuing education in core web technologies is essential to creating usable experiences, no matter what tools we choose to use.

Just – yikes. This makes me very excited for the upcoming articles in the series.

Direct Link to ArticlePermalink

The post Responsible JavaScript appeared first on CSS-Tricks.

What Are Design Tokens?

Css Tricks - Wed, 04/03/2019 - 4:32am

I’ve been hearing a lot about design tokens lately, and although I’ve never had to work on a project that’s needed them, I think they’re super interesting and worth jotting down a few notes about. As I understand it, the general idea is this: design tokens are an agnostic way to store variables such as typography, color, and spacing so that your design system can be shared across platforms like iOS, Android, and regular ol’ websites.

Design tokens are starting to gain a bit of momentum in the design systems community, but they're not an entirely new concept. There’s a great talk with Jina Anne and Jon Levine from 2016 where they talk about how design tokens are used in the Lightning Design System at Salesforce. They describe the complexity of the world we’re living in where a single organization that is building multiple web apps and native applications need to feel and look the same whilst not slowing down the development team. Jina also has made an in-depth video course about design tokens and in the preview for that she writes:

With design tokens, you can capture low-level values and then use them to create the styles for your product or app. You can maintain a scalable and consistent visual system for UI development.

Let’s take just one example: you probably have a typographic scale that you want to be identical across a bunch of platforms. Instead of storing the values for that scale in a CSS file and replicating them in every app or website, they can be stored in a JSON file that will then be transformed into the code needed for all those other platforms. Something like this:

{ "global": { "type": "token", "category": "typography" }, "aliases": { "TYPE_SIZE_SM": { "value": "14px" }, "TYPE_SIZE_MD": { "value": "25px" }, "TYPE_SIZE_LG": { "value": "44px" } },

You could write your own code to take this JSON file and convert it into all the variables you might need, for example, a Sass file would depend upon these tokens and might consume them as variables to be used elsewhere in a web app. One example of a tool that can do a lot of the hard work for us is Amazon’s Style Dictionary and here’s an example of how that works in practice:

I think this is ridiculously neat stuff. And I can see how it saves a ton of duplicate code and confusion across multiple teams since it serves as a single source of truth as opposed to having several codebases that have the same design requirements and their own stylesheets to maintain. Cristiano Rastelli also wrote about managing design tokens with Style Dictionary a little while ago and goes into a lot more depth on how to get started.

Your source of truth doesn’t even have to be a JSON file! In a post from earlier this year, Pavel Laptev shows us how to make these design tokens in Figma and, by using their API, abstract those values out of design mockups and use them in a codebase.

Pavel broke up his Figma doc into separate pages for his grid, spacers, palette and typography like this:

Right now, it seems like this requires a ton of effort to set up, but I reckon that tools like Sketch and Figma are only going to make stuff like this way easier for us in the near future – they probably want the source of truth to be in their specific design tool instead of some other tool.

The last thing I want to mention is this post by Brent Jackson where he wrote up some thoughts about interoperability when it comes to design systems. Specifically, he argues that there should be a specification for design tokens so that any CSS-in-JS library could consume that code in any format or style:

Design system tokens are meant to be flexible and work cross-platform, which means different teams, different implementations, and different libraries will name things differently. This is where this specification would fit in. A lot of interoperability could be realized, if we all, for example, named our color palette colors and named the font sizes we use fontSizes. What you do beyond that and what data format you use to store these values, is up to you. It's trivial to convert JSON to ES modules to YAML or even TOML, if that's your thing. It's also just a data structure, so transforming between other data structures (e.g. design tools or a GraphQL API) should also be possible. This standard also wouldn't try to solve the extremely complex problems of how to name the colors themselves.

Brent then went ahead and created a theme specification to solve this very problem. It looks like having a single standard for writing all our variables and settings would help us if we wanted to switch from one CSS-in-JS library to another, or if we wanted to switch to some other system that we haven’t imagined yet.

Anyway, I believe that design tokens are only starting to become mainstream and their popularity is about to increase as these tools, workflows, and standards become better with time — it’s all thoroughly exciting stuff!

The post What Are Design Tokens? appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.