Web Standards

Locate and identify website visitors by IP address

Css Tricks - Thu, 05/10/2018 - 3:45am

(This is a sponsored post.)

Big thanks to ipstack for sponsoring CSS-Tricks this week!

Have you ever had the need to know the general location of a visitor of your website? You can get that information, without having to explicitly ask for it, by the user’s IP address. You’re just going to need a API to give you that information, and that’s exactly what ipstack is.

Here’s me right now:

This works globally through an API that covers over 2 million unique locations in over 200,000 cities around the world, and it’s update dozens of times a day.

It’s a nice clean JSON API for all you front-end JavaScript folks! XML is there too, if you need it. You’re probably curious about all the data you can get, so let’s just take a look:

{ "ip": "", "hostname": "", "type": "ipv4", "continent_code": "NA", "continent_name": "North America", "country_code": "US", "country_name": "United States", "region_code": "CA", "region_name": "California", "city": "Los Angeles", "zip": "90013", "latitude": 34.0453, "longitude": -118.2413, "location": { "geoname_id": 5368361, "capital": "Washington D.C.", "languages": [ { "code": "en", "name": "English", "native": "English" } ], "country_flag": "https://assets.ipstack.com/images/assets/flags_svg/us.svg", "country_flag_emoji": "🇺🇸", "country_flag_emoji_unicode": "U+1F1FA U+1F1F8", "calling_code": "1", "is_eu": false }, "time_zone": { "id": "America/Los_Angeles", "current_time": "2018-03-29T07:35:08-07:00", "gmt_offset": -25200, "code": "PDT", "is_daylight_saving": true }, "currency": { "code": "USD", "name": "US Dollar", "plural": "US dollars", "symbol": "$", "symbol_native": "$" }, "connection": { "asn": 25876, "isp": "Los Angeles Department of Water & Power" } "security": { "is_proxy": false, "proxy_type": null, "is_crawler": false, "crawler_name": null, "crawler_type": null, "is_tor": false, "threat_level": "low", "threat_types": null } } What is this useful for?

All kinds of things! Whatever you want! But here’s some very practical ones:

  • Does your site display times? You can adjust those times to the user’s local time zone, so long as you know where they are.
  • Does your site display currency? You can adjust your prices to show local currencies, so long as you know where they are.
  • Does your site only work in certain countries due to laws, regulations, or other reasons? You might want to deliver different experiences to those different countries. ipstack is also often used for protection against potential security threats.

Lots of big companies like Microsoft, Airbnb, and Samsung use ipstack.


ipstack has a free tier covering up to 10,000 requests over a month, and plans start at a reasonable $9.99 a month covering 5 times that many requests and unlocking useful modules like the Time Zone and Currency modules. Plans scale up to any level, including millions of requests a day.

Direct Link to ArticlePermalink

The post Locate and identify website visitors by IP address appeared first on CSS-Tricks.

Where Lines Break is Complicated. Here’s all the Related CSS and HTML.

Css Tricks - Wed, 05/09/2018 - 11:43am

Say you have a really long word within some text inside an element that isn't wide enough to hold it. A common cause of that is a long URL finding it's way into copy. What happens? It depends on the CSS. How that CSS is controlling the layout and what the CSS is telling the text to do.

This is what a break-out text situation might be like:

The text hanging out of the box is a visual problem.

One possibility is overflow: hidden; which is a bit of a blunt force weapon that will stop the text (or anything else) from hanging out. Yet, it renders the text a bit inaccessible. In some desktop browsers with a mouse, you might be able to triple-click the line to select the URL and copy it, but you can't count on everyone knowing that or that it's possible in all scenarios.

Overflow is the right word here as well, as that's exactly what is happening. We have overflow: auto; at our disposal as well, which would trigger a horizontal scrollbar. Maybe suitable sometimes, but I imagine we'll all agree that's not generally an acceptable solution.

What we want is the dang long URL (or text of any kind) to break to the next line. There are options! Let's start with a place to attempt figure this stuff out.

Experimental Playground

My idea here is to have a resizeable panel of content combined with a variety of CSS property/values that you can toggle on and off to see the effects on the content.

This isn't comprehensive or perfectly executed, I'm sure. It's just some of the properties I'm aware of.

See the Pen Figuring Out Line Wrapping by Chris Coyier (@chriscoyier) on CodePen.

The Sledgehammer: `word-break: break-all;`

Allows words to be broken anywhere. The word-break property does "solve" the issue:

p { word-break: break-all; }

In an email exchange with fantasi, she explained that this works because the word-break property redefines what a word is. The break-all value essentially treats non-CJK as CJK, which can break just about anywhere (except stuff like periods and close parenthesis). The keep-all value does the reverse, treating CJK as non-CJK.

A Subtle Fix: `overflow-wrap: break-word;`

The overflow-wrap property seems to be the most effective solution for the problems we've laid out:

p { word-wrap: break-word; /* old name */ overflow-wrap: break-word; }

At first glance it might look very similar to the word-break: break-all; demo above, but notice how in the URL rather than breaking "pen" at "pe\n", it breaks at the end of that word where the slash is. Nicer.

fantasai explained:

"If a word can't break and would therefore overflow, then it can break anywhere to avoid overflow."

A Heavier Fix, Sometimes: `hyphens: auto;`

The hyphens property does what you might expect...allows for hyphenation in line breaks. Hyphens can sometimes do the trick in URLs and long words, but it's not guaranteed. A long number would trip it up, for example. Plus, hyphens affect all the text, breaking words more liberally to help text hug that right edge evenly.

p { hyphens: auto; }

fantasai told me:

"If a 'word' straddles the end of the line, we can hyphenate it."

I guess "word" helps put a finger on the issue there. Some problematically long strings aren't "words" so it can't be counted on to solve all overflow issues.

Future Sledgehammer: `line-break: anywhere;`

There is a property called line-break. It's mostly for punctuation, apparently, but I can't seem to see it working in any browser. fantasai tells me there will be a new value called anywhere which is:

"like word-break: break-all; except it actually breaks everything like a dumb terminal client"


Other HTML Stuff
  • The <br> element will break a line wherever it renders. Unless it's display: none;!
  • The <wbr> element is a "word break opportunity" meaning a long word that would normally cause an annoying overflow issue could be told that it's ok to break at a certain point. Useful! It behaves like a zero-width space.
Other CSS Stuff
  • The &shy; character is just like the <wbr> element.
  • You can inject a line break via pseudo element like ::before { content: "\A"; } as long as elment isn't inline (or if it is, it needs white-space: pre;)

The post Where Lines Break is Complicated. Here’s all the Related CSS and HTML. appeared first on CSS-Tricks.

Overriding Default Button Styles

Css Tricks - Wed, 05/09/2018 - 4:05am

There are a variety of "buttons" in HTML. You've got:

<button>Button</button> <input type="button" value="Button">

Plus, for better or worse, people like having links that are styled to match the look of other true buttons on the site

<a href="#0" class="button">Button</a>

One challenge is getting all those elements to look and layout exactly the same. We'll cover that a few ways.

Another challenge is getting people to use them correctly

This is a bit surprising to me — but I hear it often enough to worry about it — is that more and more developers are using <div>s for buttons. As in, they just reach for whatever generic, styling-free HTML is handy and build it up as needed. Andy Bell explains why a real button is better:

So, <button> elements are a pain in the butt to style right? That doesn’t mean you should attach your JavaScript events to a <div> or an <a href="#"> though. You see, when you use a <button>, you get keyboard events for free. You’re also helping screen reader users out because it’ll announce the element correctly.

And here's Andy again helping you out with a chunk of CSS that'll get you a cleanly styled button:

See the Pen Button Pal — some basic button styles by Andy Bell (@hankchizljaw) on CodePen.

It's that styling that just might be the mental roadblock

It's a bit understandable. Buttons are weird! They have a good amount of default styling (that come from the "User Agent Stylesheet") that varies from browser to browser and means you have work to do to get them exactly how you want.

See all the weirdness there?

  • Without any styling, the button is kinda little and has that native border/border-radius/box-shadow thing going on.
  • Just by setting the font-size, we lose all those defaults, but it's got a new default look, one with a border and square corners, a gradient background, and no box-shadow. This is essentially -webkit-appearance: button;.
  • Buttons have their own font-family, so don't inherit from the cascade unless you tell it to.

Here's Chrome's user agent stylesheet for buttons:

Firefox behaves a bit differently. See in the video above how setting border: 0; removed the border in Chrome, but also the background? Not the case in Firefox:

I only point this out to say, I get it, buttons are truly weird things in browsers. Factor in a dozen other browsers, mobile, and the idea that we want to style all those different elements to look exactly the same (see the opening of the article), and I have a modicum of empathy for people wanting to avoid this.

Never hurts to consult Normalize

Normalize does a good amount:

/** * 1. Change the font styles in all browsers. * 2. Remove the margin in Firefox and Safari. */ button, input, optgroup, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 1 */ line-height: 1.15; /* 1 */ margin: 0; /* 2 */ } /** * Show the overflow in IE. * 1. Show the overflow in Edge. */ button, input { /* 1 */ overflow: visible; } /** * Remove the inheritance of text transform in Edge, Firefox, and IE. * 1. Remove the inheritance of text transform in Firefox. */ button, select { /* 1 */ text-transform: none; } /** * Correct the inability to style clickable types in iOS and Safari. */ button, [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; }

I was a tiny bit surprised to see WTF, Forms? not cover buttons, only because of how much weirdness there is. But the form elements that project whips into shape are even more notoriously difficult!

A Style-Testing Kinda Thingy

I feel like the answer to this is basically a big ol' block of CSS. That's what Andy provided, and you could very likely come to one on your own by just being a little heavier handed than the usual of setting style rules with your buttons.

Still, I felt compelled to make a little tester machine thingy so you can toggle styles on and off and see how they all go together in whatever browser you happen to be in:

See the Pen Consistent button styles by Chris Coyier (@chriscoyier) on CodePen.


The biggest point here is to use the correct native elements, as you get a bunch of functionality and accessibility for free. But you might as well get the styling right, too!

While we're talking buttons, I'm gonna use the same quote I used in our When To Use The Button Element post from MDN:

Warning: Be careful when marking up links with the button role. Buttons are expected to be triggered using the Space key, while links are expected to be triggered through the Enter key. In other words, when links are used to behave like buttons, adding role="button" alone is not sufficient. It will also be necessary to add a key event handler that listens for the Space key in order to be consistent with native buttons.

You don't need role="button" on <button> because they are already buttons, but if you're going to make any other element button-like, you have more work to do to mimic the functionality.

Plus, don't forget about :hover and :focus styles! Once you've wrangled in the styles for the default state, this shouldn't be so hard, but you definitely need them!

button:hover, button:focus { background: #0053ba; } button:focus { outline: 1px solid #fff; outline-offset: -4px; } button:active { transform: scale(0.99); }

The post Overriding Default Button Styles appeared first on CSS-Tricks.

Grid Level 2 and Subgrid

Css Tricks - Tue, 05/08/2018 - 3:56am

I find the concept of subgrid a little hard to wrap my mind around.

I do understand the idea that we want to use nested semantic markup as we like and have elements participate in one grid so we don't have to flatten our markup just for layout reasons. But that is largely handled by display: contents;.

Rachel Andrew explains it in a way that finally clicked for me:

I have an item spanning three column tracks of the grid, it is also a Grid Container with three column tracks - however these do not line up with the tracks of the parent...

If the nested grid columns were to be defined as a subgrid, we would use the subgrid value of grid-template-columns on that child element. The child would then use the three column tracks that it spanned, and its children would lay out on those tracks.

It's not that the parent disappears, it's that it shares grid lines with the parent so that getting internal elements to line up with everything else happens naturally.

Direct Link to ArticlePermalink

The post Grid Level 2 and Subgrid appeared first on CSS-Tricks.

Decorating lines of text with box-decoration-break

Css Tricks - Tue, 05/08/2018 - 3:49am

An institution’s motto, an artist’s intro, a company’s tagline, a community’s principle, a service’s greeting… all of them have one thing in common: they’re one brief paragraph displayed on a website’s home page — or at least the about page!

It’s rare that just one word or one line of text welcomes you to a website. So, let’s look at some interesting ways we could style the lines of a paragraph.

To see how things currently are, let’s try giving borders to all the lines of some text in an inline span and see how it looks:

<p><span>Hummingbirds are birds from...</span></p> span { border: 2px solid; }

See the Pen Broken inline box. by Preethi (@rpsthecoder) on CodePen.

The edges appear broken, which they technically are, as the inline box has been fragmented into multiple lines. But we can fix those broken edges with box-decoration-break!

The box-decoration-break property in CSS can decorate the edges of fragments of a broken inline box (as well as of a page, column, and region boxes).

Its value, clone, does that with the same design that appears in the box’s unbroken edges, and its default value, slice, does not copy the decorations at the edges, keeping the break very visible like you saw in the demo above.

Let’s try it:

span { border: 2px solid; box-decoration-break: clone; }

See the Pen Broken inline box w/ box-decoration-break. by Preethi (@rpsthecoder) on CodePen.

The property affects not only the border but also the shadow, spacing, and background of the broken edges.

Let’s play with the background first. While writing the post on knockout text, I was working with the background-clip property and wanted to see if the design held up for multiple lines of text. It didn’t.

The background gradient I applied was not replicated in every line, and after clipping it, only the first one was left with a background. That is, unless box-decoration-break: clone is added:

<p><span>Singapore:<br>Lion City</span></p> span { background-image: linear-gradient(135deg, yellow, violet); background-clip: text; color: transparent; padding: .5em; box-decoration-break: clone; }

See the Pen Gradient multi-line text w/box-decoration-break. by Preethi (@rpsthecoder) on CodePen.

The background-clip property with the text value clips a background to the shape of its foreground text. Since we used box-decoration-break, the gradient background is shown and clipped uniformly across all the lines of the text.

Going back to the border, let’s see how its shape and shadow can be copied across the broken edges, along with padding:

<img src="tree.png"> <p><span>Supertrees are tree-like structures...</span></p> <img src="tree.png"> <p><span>Supertrees are tree-like structures...</span></p> span { background: rgb(230,157,231); border-radius: 50% 0%; box-shadow: 0 0 6px rgb(41,185,82), 0 0 3px beige inset; padding: .5em 1.3em; box-decoration-break: clone; } p:nth-of-type(2) span { background-clip: content-box; }

See the Pen Inline border shape & shadow w/box-decoration-break. by Preethi (@rpsthecoder) on CodePen.

In the second paragraph of the demo, the background is cropped until the content box (background-clip: content-box). As you can see, the crop happens in the broken edges as well, because of box-decoration-break: clone.

Another way we can style borders is with images. You might see a gradient border around the lines of text below, covering the broken edges, if the browser you’re now using supports border-image and the application of box-decoration-break over its result.

<p><span>The Malaysia–Singapore Second Link...</span></p> span { border: 2px solid; border-image: linear-gradient(45deg, #eeb075, #2d4944) 1; background: #eef6f3; padding: .5em 1.3em; box-decoration-break: clone; }

See the Pen Inline border image w/ box-decoration-break. by Preethi (@rpsthecoder) on CodePen.

An additional behavior we can tap into for decorating individual lines is of outline's. In supported browsers, box-decoration-break can add an outline to every line of the text, including the broken edges, which is useful for creating bicolored dashed borders.

<p><span>Cloud Forest replicates...</span></p> span { outline: 2px dashed rgb(216,255,248); box-shadow: 0 0 0 2px rgb(39,144,198); background: #fffede; padding: .5em 1.3em; animation: 1s animateBorder ease infinite; box-decoration-break: clone; } @keyframes animateBorder{ to{ outline-color: rgb(39,144,198); box-shadow: 0 0 0 2px rgb(216,255,248); } }

See the Pen Inline outline w/ box-decoration-break. by Preethi (@rpsthecoder) on CodePen.

As observed in the demo, box-decoration-break withstands animation.

Besides borders and backgrounds, box-decoration-break can also manage shapes applied over elements. There is not much use for it in inline boxes, and is maybe better used in a column or page box, although the application is not yet widely supported in browsers.

But to show an example of what that does, let’s try applying the clip-path property to the span.

The property clip-path itself is only fully supported by Firefox, so only in it you might see an expected outcome. But following are two images: the results of applying a circular clip path over the span, without and with box-decoration-break.

span { clip-path: circle(50% at 202.1165px 69.5px); ... } Circular clip-path on a span span { clip-path: circle(50% at 202.1165px 69.5px); box-decoration-break: clone; ... } Circular clip-path on a span with box-decoration-break: clone

You’ll notice in the first image that the 50% radius value is derived from the width of the inline box (the longest line) where box-decoration-break is not used.

The second image shows how box-decoration-break: clone redefines the computed value for 50% by basing them on the widths of the individual lines while keeping the center same as before.

And here’s how the inset function of clip-path (an inset rectangle) applied over the span clips it without and with box-decoration-break:

span { clip-path: inset(0); ... } Inset clip-path on a span span { clip-path: inset(0); box-decoration-break: clone; ... } Inset clip-path on a span with box-decoration-break: clone

Without box-decoration-break, only a portion of the first line that matches the length of the shortest is visible, and with box-decoration-break: clone, the first line is fully visible while the rest of the box is clipped.

So, maybe if you ever want to show only the first line and hide the rest, this can come in handy. But, as I mentioned before, this application is more suitable for other types of boxes than ones that are inline. Either way, I wanted to show you how it works.

Browser Support

As we've seen here, box-decoraton-break can be super useful and opens up a lot of possibilities, like creating neat text effects. The property enjoys a lot support with the -webkit prefix, but is still in Working Draft at the time of this writing and lacks any support in Internet Explorer and Edge. Here's where you can vote for Edge support.

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

DesktopChromeOperaFirefoxIEEdgeSafari69*1132NoNoTP*Mobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox11.3*11all62*66*57 Wrapping Up

The box-decoration-break: clone copies any border, spatial, and background designs applied on a fragmented inline box’s unbroken edges to its broken ones. This creates an even design across all the lines of the text, decorating them uniformly and can be super useful for all those blurbs of text that we commonly use on websites.

The post Decorating lines of text with box-decoration-break appeared first on CSS-Tricks.

New speakers, devrels, and videos

QuirksBlog - Tue, 05/08/2018 - 2:54am

When selecting speakers for our conferences we always hunt for a video of a prospective speaker, unless we’ve seen them for ourselves in the flesh. If we cannot find a video, we do not invite the speaker, since we cannot guarantee to our audience that they are excellent presenters. Not all conferences do so, but we do.

For some new speakers this is a bit of a hurdle. Not an insurmountable one — some local meet-ups and most conferences record their sessions — but it’s still an extra step. Local meet-up organisers take note: recording the sessions would be a huge service for your speakers — if you have the budget.

That was not what I wanted to talk about today, though. In the past months we conferred with quite a few developer relations departments about CSS Day and performance.now(), and they all proposed a speaker that they didn’t have a video of. So we said No.

For developer relations departments, whose job it is to get their people to speak at conferences, this is a far more serious oversight than for individuals.

So my advice to developer relations departments is to organise a local meet-up, get all their unknown speakers to speak, record all sessions, and put them online. I mean, they must have the budget to do that once, right? It would be a great gift to conference organisers around the world, even to those that do not require videos.

And while you’re at it, hey, also invite that one local speaker that you think should get more conference invitations.

VS Code Can Do That?

Css Tricks - Mon, 05/07/2018 - 10:30am

Clever microsite from Burke Holland and Sarah Drasner that highlights some of VS Code's coolest features. All fifteen of them are pretty darn cool. Here's a few other compelling features I've seen people use/love:

Personally, I'm still on Sublime. I gave VS Code the college try last year but failed. I can't even remember why now, which means it's probably about time to try again. If it was slowness, maybe it was because I was using too many add-ons.

Direct Link to ArticlePermalink

The post VS Code Can Do That? appeared first on CSS-Tricks.

Microsites for Case Studies

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

A lot of y'all have personal sites. Personal sites with portfolios. Or you work for or own an agency where showing off the work you do is arguably even more important. Often the portfolio area of a site is the most fretted and hard to pull off. Do you link to the live projects? Screenshots? How many? How much do you say? How much of the process do people care about?

I'm afraid I don't have all the answers for you. I don't really do much freelance, work for an agency, or have a need to present work I've done in this way.

But! I tweeted this the other day:


Build your case studies as microsites. Then they can just live alone and don't have to be a drag when redesigning your site.

If the microsite gets old and stogy, the project you're talking about probably has too.

— Chris Coyier (@chriscoyier) April 25, 2018

I was out to lunch with Rob from Sparkbox recently. A few years back, we worked together on a redesign of CodePen, and a byproduct of that was a microsite about that process.

I remember working on that microsite. It wasn't a burden, it was kinda fun. We built it as we went, when all that stuff was fresh in our minds. Now that site is kind of a monument to that project. Nobody needs to touch it. It doesn't load some global stylesheet from a main website. It's a sub-domained microsite. It'll be useful as long as it's useful. When it's not anymore, stop linking to it.

I've also watched loads of people struggle with what to put in that portfolio and how to deal with case studies. I've watched it be a burden to people redesigning their site or building one for the first time. I've also looked at a lot of personal sites lately, and the default is certainly to work the portfolio into the site itself.

Maybe for some of you, making your case studies into these microsites will be a useful way to go!

The post Microsites for Case Studies appeared first on CSS-Tricks.

CSS Environment Variables

Css Tricks - Fri, 05/04/2018 - 11:05am

We were all introduced to the env() function in CSS when all that drama about "The Notch" and the iPhone X was going down. The way that Apple landed on helping us move content away from those "unsafe" areas was to provide us essentially hard-coded variables to use:

padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);

Uh ok! Weird! Now, nine months later, an "Unofficial Proposal Draft" for env() has landed. This is how specs work, as I understand it. Sometimes browser vendors push forward with stuff they need, and then it's standardized. It's not always waiting around for standards bodies to invent things and then browser vendors implementing those things.

Are environment variables something to get excited about? Heck yeah! In a sense, they are like a more-limited version of CSS Custom Properties, but that means they can be potentially used for more things.

CSS environment variables are getting standardized:https://t.co/QKFBM3WFT2
Allow to get and use the browser- and author-defined variables: typography, colors, notch and other specific layout/device values.
They work in Media Queries, where CSS Custom Properties cannot be used. pic.twitter.com/FWrPiBiAqp

— Serg Hospodarets (@malyw) April 29, 2018

&#x1f440; Brand new spec for global env() variables in CSS: https://t.co/6YfXWFTyhN

Forget notches, the important thing here is the ability to separate CSS variables from the cascade. Cool ? for perf/code organization ? because you might be able to use them in media queries!

— Eric Portis (@etportis) April 30, 2018

Eric also points out some very awesome early thinking:

ISSUE 4 - Define the full set of places env() can be used.

  • Should be able to replace any subset of MQ syntax, for example.
  • Should be able to replace selectors, maybe?
  • Should it work on a rule level, so you can insert arbitrary stuff into a rule, like reusing a block of declarations?

Probably still changeable-with-JavaScript as well. I would think the main reason CSS Custom Properties don't work with media queries and selectors and such is because they do work with the cascade, which opens up some very strange infinite loop logic where it makes sense CSS doesn't want to tread.

If you're into the PostCSS thing, there is a plugin! But I'd warn... the same issues that befall preprocessing CSS Custom Properties applies here (except the first one in that article).

The post CSS Environment Variables appeared first on CSS-Tricks.

Inspecting Animations in DevTools

Css Tricks - Fri, 05/04/2018 - 3:57am

I stumbled upon the Animation panel in Chrome’s DevTools the other day and almost jumped out of my seat with pure joy. Not only was I completely unaware that such a thing exists, but it was better than what I could’ve hoped: it lets you control and manipulate CSS animations and visualize how everything works under the hood.

To access the panel, head to More Tools ? Animations in the top right-hand menu when DevTools is open:

Many of the tutorials I found about this were pretty complicated, so let’s take a step back and look at a smaller example to begin with: here’s a demo where the background-color of the html element will transition from black to orange on hover:

html { cursor: pointer; background-color: #333; transition: background-color 4s ease; } html:hover { background-color: #e38810; }

Let’s imagine that we want to nudge that transition time down from 4s. It can get pretty annoying just bumping that number up and down in the element inspector. I typically would’ve opened up DevTools, found the element in the DOM and then ever-so-slowly manipulate it by typing in a value or using the keyboard directional keys. Instead, we can fire up that demo, open DevTools, and switch to the Animation tab which ought to look something like this:

By default, Chrome will be "listening" for animations to take place. Once they do, they’ll be added to the list. See how those animation blocks are displayed sort of like an audio wave? That’s one frame, or act, of an animation and you can see on the timeline above it each frame that follows it. On an animation itself, the inspector will even show us which property is being changed, like background-color or transform. How neat is that?

We can then modify that animation by grabbing that bar and moving it about:

...and it updates the animation right away — no more clicking and editing an animation the old way! Also, you might’ve noticed that hovering over an animation frame will highlight the element that’s being animated in blue. This is handy if you’re editing a complex animation and forget what that crazy weird pseudo element does. If you have multiple animations on a page, then you can see them all listed in that section just like in this demo:

What we’re doing here is animating both the .square and the .circle when hovering on the html element, so there’s effectively two separate divs being animated in the same time frame — that’s why you can see them in the same section just like that.

I can see that inspecting animations in this way could be super useful for tiny icon design, too. Take this pen of Hamburger menu animations by Jesse Couch where you might want to slow everything down to get things just right. Well, with the animation inspector tool you can do exactly that:

Those buttons in the top left-hand corner will control the playback speed of the animation. So hitting 10% will slow things to a crawl — giving you enough time to really futz with things until they’re perfect.

I’ve focused on Chrome here but it’s not the only browser with an animation inspector — Firefox’s tool is in every way just as useful. The only immediate difference I found was that Chrome will listen for any animations on a page and will display them once their captured. But, with Firefox, you have to inspect the element and only then will it show you the animations attached to that element. So, if you’re doing super complex animations, then Chrome’s tool might be a smidge more helpful.

Animation Inspector Documentation

The post Inspecting Animations in DevTools appeared first on CSS-Tricks.

Responsive Knockout Text With Looping Video

Css Tricks - Thu, 05/03/2018 - 4:06am

Here’s an idea! Let’s make an an HTML <video> play inside the shape of some letters. Like "Knockout Text" except instead of an image behind, it’s video. A live demo will explain more clearly:

See the Pen basic pen by Giulio Mainardi (@mgiulio) on CodePen.

A key objective here is to develop this responsively. The idea is to not only scale the video in size to fit the parent container (as video generally does), but scale the text as well, maintaining the size relationship between the type and underlying video.

We’re going to get there by using the CSS clip-path property to clip the video against an SVG path defined within a <clipPath> element.

First we’ll cover the core concept. Then we’ll add some eye candy by adding a few more features and demonstrate them with a couple additional demos.

Setting Up the Video in HTML

Let’s start with the video markup. Inside the <video> tag we specify the URLs for the WebM and MP4 versions of the video, to support a broad range of browsers:

<video> <source src="/video/mt-baker.webm" type="video/webm"> <source src="/video/mt-baker.mp4" type="video/mp4"> </video>

Then we add some attributes to customize the video playing behavior:

<video loop autoplay muted playsinline> <source src="/video/mt-baker.webm" type="video/webm"> <source src="/video/mt-baker.mp4" type="video/mp4"> </video>
  • The loop attribute makes the video plays forever
  • The autoplay and muted attributes are used to allow the automatic video playback at page load on all devices and ensure it play without audio
  • The playsinline attribute tries to disable the full-screen expansion of the video when it is played on some mobile devices

Then a container is wrapped around the <video> element. This will come in handy when we'll spice up the basic demo with some visual effects.

Here’s the complete markup:

<div class="video-container"> <video loop autoplay muted playsinline> <source src="/video/mt-baker.webm" type="video/webm"> <source src="/video/mt-baker.mp4" type="video/mp4"> </video> </div> The Basic CSS to Position and Scale the Video

Here, the main task to fulfill is to make the video responsive. It must scale up and down, spanning the width of its parent container and keeping its intrinsic aspect ratio:

.video-container video { display: block; width: 100%; }

After formatting the video as a block-level element with display: block, assigning a 100% value to its width makes it as large as its container. And that's all we need, because the initial auto value of the height property and the video intrinsic aspect ratio make it uniformly scale, without distortion.

In the original demo, I repeated the video several times in the container to test this responsive behavior. Here’s the CSS I’m using to test the responsiveness of each video at different widths:

.video-container { margin: 40px auto; outline: 1px solid #dadada; &:nth-of-type(1) { width: 25%; } /* first video instance, and so on */ &:nth-of-type(2) { width: 50%; } &:nth-of-type(3) { width: 75%; } &:nth-of-type(4) { width: 100%; } }

The outline set on the containers will help us visualize the location and size of the videos when they are clipped. Speaking of which...

Clipping the Video in CSS

Thanks to the clip-path CSS property, we can define a region of an element to be displayed instead of the entire thing — and do it with a single line:

video { clip-path: url(#clip-00); }

With the url() function, we specify the id of the SVG clipPath element where the clipping text is defined.

Note that although the visible geometry of the video is altered by the clipping, the video element is still a rectangular box for the browser, so the page layout is the same as if the clipping was not used. This is part of the beauty of clipping and, if you’re new to the concept, then definitely check out Sarah’s explanation of it.

Now the trick is actually creating that clip path!

Creating the SVG `clipPath` element

I am going to create the text design, do the editing, then export the work in Inkscape. Similar steps could be put together with other vector editors. Feel free to report your experiences in the comments.

The first step is to keep note of the video aspect ratio, which is its width:height ratio.

Next, create a document with the same size as the video or just with the same aspect ratio. So, for example, if you’re video is 1000px wide and 500px tall, then you could use that as the document size or anything with a 2:1 ratio. This will act as a placeholder for the video, so make sure the document borders are visible. Also, remove the default layer created by the program, as this will simplify the code generated by SVG, avoiding the creation of unnecessary group elements.

Select the text tool, pick a nice bold and thick font, enter the text and stretch it to cover the document rectangle as you please.

Now, if we take a look at the code generated by Inkscape we see something like this:

<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:1147.68029785px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="23.404421" y="939.04187" id="text3336" sodipodi:linespacing="125%" transform="scale(0.8988993,1.1124717)" > <tspan sodipodi:role="line" id="tspan3338" x="23.404421" y="939.04187" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-family:Impact;-inkscape-font-specification:'Impact Condensed'" > TEXT </tspan> </text>

That's a bit unwieldy, so let's convert the SVG <text> element into a path:

<g transform="scale(0.8988993,1.1124717)" style="font-style:normal;font-weight:normal;font-size:1147.68029785px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="text3336" > <path d="m 545.68862,31.769213 0,181.566607 -140.09769,0 0,725.70605 -235.92452,0 0,-725.70605 -139.5373,0 0,-181.566607 515.55951,0 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-family:Impact;-inkscape-font-specification:'Impact Condensed'" id="path3348" /> <path d="m 599.48616,31.769213 393.39432,0 0,181.566607 -157.46981,0 0,172.03997 147.38277,0 0,172.60036 -147.38277,0 0,199.49911 173.16073,0 0,181.56661 -409.08524,0 0,-907.272657 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-family:Impact;-inkscape-font-specification:'Impact Condensed'" id="path3350" /> <path d="M 1554.9524,31.769213 1472.575,433.009 l 124.4067,506.03287 -218.5524,0 q -39.2273,-135.61457 -71.73,-330.07016 -8.9662,85.73978 -24.6572,182.127 l -22.4156,147.94316 -229.7602,0 85.1794,-506.03287 -85.1794,-401.239787 228.079,0 q 6.1643,37.546181 24.6572,124.967137 14.5702,66.68651 24.0968,122.16519 l 50.4352,-247.132327 197.8179,0 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-family:Impact;-inkscape-font-specification:'Impact Condensed'" id="path3352" /> <path d="m 2105.8165,31.769213 0,181.566607 -140.0976,0 0,725.70605 -235.9246,0 0,-725.70605 -139.5373,0 0,-181.566607 515.5595,0 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-family:Impact;-inkscape-font-specification:'Impact Condensed'" id="path3354" /> </g>

Now, we have a group containing a path element for each letter of the text. Un-grouping it leaves this set of paths at the root level. This step, besides removing the unneeded group, modifies the coordinates of the path elements to account for the transform that was applied to the removed parent group. So, after this step, there are no transform attributes in the SVG:

<path inkscape:connector-curvature="0" id="path3348" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:medium;line-height:125%;font-family:Impact;-inkscape-font-specification:'Impact Condensed';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 490.51912,35.34235 0,201.98771 -125.93372,0 0,807.32744 -212.07238,0 0,-807.32744 -125.429984,0 0,-201.98771 463.436084,0 z" /> <path inkscape:connector-curvature="0" id="path3350" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:medium;line-height:125%;font-family:Impact;-inkscape-font-specification:'Impact Condensed';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 538.87769,35.34235 353.62188,0 0,201.98771 -141.5495,0 0,191.3896 132.48227,0 0,192.01302 -132.48227,0 0,221.93711 155.65406,0 0,201.98771 -367.72644,0 0,-1009.31515 z" /> <path inkscape:connector-curvature="0" id="path3352" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:medium;line-height:125%;font-family:Impact;-inkscape-font-specification:'Impact Condensed';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 1397.7456,35.34235 -74.049,446.36791 111.8291,562.94724 -196.4566,0 q -35.2614,-150.86737 -64.478,-367.19371 -8.0597,95.38308 -22.1644,202.61114 l -20.1493,164.58257 -206.5313,0 76.5677,-562.94724 -76.5677,-446.36791 205.02,0 q 5.5411,41.769064 22.1644,139.0224 13.0971,74.18686 21.6606,135.90532 l 45.3362,-274.92772 177.8183,0 z" /> <path inkscape:connector-curvature="0" id="path3354" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:medium;line-height:125%;font-family:Impact;-inkscape-font-specification:'Impact Condensed';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 1892.917,35.34235 0,201.98771 -125.9337,0 0,807.32744 -212.0724,0 0,-807.32744 -125.43,0 0,-201.98771 463.4361,0 z" />

Those ugly style attributes are still there, but it doesn't matter because we are not going to use them.

We have finished with Inkscape, so we can save the SVG document and open it in our favorite code editor.

Saving SVG files from an illustration application is an art form in and of itself. Here are some common tips and common settings for Adobe Illustrator and a comparison of SVG exports from Illustrator, Sketch and Figma.

In the HTML page where the video is played, insert an inline SVG element. This will host the clip path:

<svg class="clipping-paths"> <defs> </defs> </svg>

We don't want this container element to affect the page layout, so:

.clipping-paths { width: 0; height: 0; position: absolute; }

Add a new clipPath element to the container SVG, with a proper id to identify it in the clip-path property, as seen before:

<svg class="clipping-paths"> <defs> <clipPath id="clip-00"></clipPath> <clipPath id="clip-01"></clipPath> ... </defs> </svg>

As showed in the above snippet, multiple clipping paths can be added, if needed.

Now, we must assign the objectBoundingBox value to the clipPath's attribute clipPathUnits:

<clipPath id="clip-00" clipPathUnits="objectBoundingBox"></clipPath>

This is one of the essential things to do to have a responsive cutout. We tell the browser which coordinate system to use for the numerical values listed in the d attributes of the paths that will be appended to the clipPath element.

The default value for the clipPathUnits attribute is userSpaceOnUse. According to the spec, this means that:

...the contents of the clipPath element represent values in the current user coordinate system in place at the time when the (clipPath)element is referenced (i.e., the user coordinate system for the element referencing the clipPath element via the clip-path property).

Instead, by using the other available value for clipPathUnits, objectBoundingBox, the coordinate values and the lengths specified in the clipPath content are considered as fractional values in the [0,1] range, relative to the bounding box of the clipped element. For instance, if a graphical primitive in the clipPath referred to the coordinates (0,0), (1,0), (1,1), (0,1) and (0.5,0.5), these points would represent respectively, the top left, top right, bottom right, bottom left corners, and the center of the video, no matter the actual size of the video on screen. It is this behavior that allows the text cutout to scale in the same way as the underlying video.

After having removed any transforms from the SVG file in Inkscape, all the numerical values of the path elements are now in the document range. To map them into the [0,1] interval required for objectBoundingBox, it is sufficient to divide such numerical values by the document size. The x coordinates are divided by the document width and the y coordinates by the document height.

To accomplish this division, a scaling with the SVG transform attribute can be employed:

<clipPath id="clip-00" clipPathUnits="objectBoundingBox" transform="scale(0.0005208333333333333, 0.000925925925925926)">

The horizontal scaling must be the reciprocal of the document width, while the vertical scaling must be the reciprocal of the document height. So, in our case, given that the document has the same exact size as the video, that is, 1920 X 1080, we get the two factors 1 / 1920 = 0.0005208333333333333 and 1 / 1080 = 0.000925925925925926.

The last step in this workflow is to copy the <path> elements from the file generated by Inkscape inside the clipPath element, getting something like this:

<clipPath id="clip-00" clipPathUnits="objectBoundingBox" transform="scale(0.0005208333333333333, 0.000925925925925926)"> <path d="m 341.4087,58.040727 0,951.927273 -112.60986,0 -66.8335,-432.74767 0,432.74767 -107.42188,0 0,-951.927273 107.42188,0 72.02149,428.631863 0,-428.631863 107.42187,0 z" /> ... <path d="m 1642.6782,58.040727 214.2334,0 0,190.503053 -85.7544,0 0,180.50751 80.2613,0 0,181.09549 -80.2613,0 0,209.31816 94.2994,0 0,190.50306 -222.7784,0 0,-951.927273 z" /> </clipPath>

To reiterate, we have copied just the d attribute of the paths, discarding all the other stuff generated by Inkscape.

Putting it All Together

And there we have it, gluing together the above snippets with some more code(see the pen source for details), we get the first basic demo:

Other Examples

We can reuse the above workflow to create some more cutouts, like in the second demo here:

The last example is worthy of attention because it is the negative of the text used in the first demo; that is, the internal and external regions delimited by the paths were swapped. So, the white text we see is a hole through which the background color of the page body is visible. This negative cutout was derived from the original with a difference path operation in Inkscape.

Adding Background Colors

Building on top of the basic demo, we can add a color to the text cutout by assigning a background-color to the video container, because this wrapper element is visible everywhere the video is clipped out:

.video-container { // ... &:nth-of-type(1) { background: #c6c7c5; } &:nth-of-type(2) { background: #dcf3ff; } &:nth-of-type(3) { background: #a2d2df; } &:nth-of-type(4) { background: #406e8d; } &:nth-of-type(5) { background: linear-gradient(180deg, #bdc3c2, #2d5d89); } }

The result can be seen in the third demo:

Adding Tint

How about tinting the video? We can do that with a pseudo element and CSS Blend Modes:

.video-container { /* ... */ position: relative; } .video-container::after { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; clip-path: url(#clip-00); } .video-container:nth-of-type(1) { background: #406e8d; } .video-container:nth-of-type(1)::after { background-color: #3f51b5; mix-blend-mode: screen; }

The ::after pseudo element of the video wrapper is absolutely positioned on top of the video, covering it entirely, and then it is clipped with the same path used for the video. In this way, it is possible to use different colors for the background and the tint.

Finally, after having assigned the desired tint color to the pseudo element, with the mix-blend-mode property we can pick one of the available blending modes to obtain the wanted effect.

Browser Support

At the time of writing, almost all the latest versions of desktop and mobile browsers support the CSS clip-path property. The prefixed version, -webkit-clip-path, has to be used on WebKit-based user agents such as Safari and Samsung Internet.

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

DesktopChromeOperaFirefoxIEEdgeSafari695254NoNoTP*Mobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox11.3*37*No626657

Unfortunately, an exception is given by the Microsoft browsers. There is definitely no support on Internet Explorer, and on Edge the feature is under development. Please vote it up on the Microsoft Developer Feedback page!

Of course, for the last demo, a browser supporting CSS Blend Modes is required. In this case, the support is wider, being this feature is even implemented by Edge.

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

DesktopChromeOperaFirefoxIEEdgeSafari301720No136.1Mobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox7.0-7.137No4.46657 References and Credits

Eric Meyer writes about the scaling of the SVG clipping path for an HTML element, using the objectBoundingBox value for the clipPathUnits attribute, and the scaling transform. That was a huge inspiration for this post.

Thanks to Coverr for the video that was used in these demos.

The post Responsive Knockout Text With Looping Video appeared first on CSS-Tricks.

?Incapsula DDoS Resiliency Score

Css Tricks - Thu, 05/03/2018 - 4:05am

(This is a sponsored post.)

These free training courses from Incapsula give you the technical knowledge and skills to accelerate your website and optimize content delivery. Website Performance Mastery Starts here in a fun, quiz-based online format, these free training courses give you the technical knowledge and skills to accelerate your website and optimize content delivery.

Is your website ready for a DDoS attack? Find out here.

Direct Link to ArticlePermalink

The post ?Incapsula DDoS Resiliency Score appeared first on CSS-Tricks.

Managing Heading Levels In Design Systems

Css Tricks - Thu, 05/03/2018 - 4:00am

Heydon Pickering looks into how to give a React component a certain heading (like <h1>, <h2>, etc.) depending on its context and thereby ensure that the DOM is still perfectly accessible for screen readers. Why is using the right heading important though? Heydon writes in the intro:

One thing that keeps coming back to me, in research, testing, and everyday conversation with colleagues and friends, is just how important headings are. For screen reader users, headings describe the relationships between sections and subsections and?—?where used correctly?—?provide both an outline and a means of navigation. Headings are infrastructure.

This reminds me of an excellent post by Amelia Bellamy-Royds where she explored all the problems caused by this “Document Outline Dilemma” or, say, a <h1> following a <h3>:

As it currently stands, the document outline is only of daily importance to screen-reader users, and those users are currently used to dealing with the mess of erratic heading levels in web pages. I'm sure many screen-reader users would appreciate heading levels being fixed. But fixing headings for screen-reader users doesn't just mean creating a tree of neatly nested headings with no skipped level numbers. It means creating a heading structure that accurately reflects the meaning intended by the creators of the web page, the meaning that visual users infer from style and layout. And in order to do that, we need to consider how meaning is communicated to all the users of web pages who aren't hearing each heading announced with a numerical level.

It’s remarkable to me that simple ol’ headings require so much attention, both in dealing with the usability concerns and the potential development workarounds.

Direct Link to ArticlePermalink

The post Managing Heading Levels In Design Systems appeared first on CSS-Tricks.

Getting The Most Out Of On-Site UX Research

Usability Geek - Wed, 05/02/2018 - 12:38pm
When you search for an image of a ‘UX designer’, you will likely get results depicting the same handful of scenes. You will probably get a bespectacled man hunched at a desk, sketching...
Categories: Web Standards

Container-Adapting Tabs With “More” Button

Css Tricks - Wed, 05/02/2018 - 3:51am

Or the priority navigation pattern, or progressively collapsing navigation menu. We can name it in at least three ways.

There are multiple UX solutions for tabs and menus and each of them have their own advantages over another, you just need to pick the best for the case you are trying to solve. At design and development agency Kollegorna we were debating on the most appropriate UX technique for tabs for our client’s website…

We agreed it should be a one-liner because the amount of tab items is unknown and narrowed our options down to two: horizontal scroll and adaptive with “more” button. Firstly, the problem with the former one is that horizontal scroll as a feature is not always visually obvious for users (especially for narrow elements like tabs) whereas what else can be more obvious than a button (“more”), right? Secondly, scrolling horizontally using a mouse-controlled device isn’t a very comfortable thing to do, so we might need to make our UI more complex with additional arrow buttons. All considered, we ended up choosing the later option:


The main intrigue here is if it’s possible to achieve that without JavaScript? Partly yes, however the limitations that it comes with probably make it only good for a concept museum rather than real life scenarios (anyway, Kenan did a really nice job). Still, the dependency on JS doesn’t mean we can’t make it usable if for some reason the technology is not available. Progressive enhancement and graceful degradation for the win!

Since the amount of tab items is uncertain or volatile, we will make use of Flexbox which ensures the items are nicely spread in the container element without setting the widths.

Initial Prototype

There are two lists both visually and technically: one is for items that fit in the container, and one for items that don’t. Since we’ll depend on JavaScript, it’s totally fine to have our initial markup with a single list only (we will duplicate it with JS):

<nav class="tabs"> <ul class="-primary"> <li><a href="...">Falkenberg</a></li> <li><a href="...">Braga</a></li> <!-- ... --> </ul> </nav>

With a tiny touch of flex-based CSS things are starting to get serious here. I’ll skip the decorative CSS properties in my examples here and place here what really matters:

.tabs .-primary { display: flex; } .tabs .-primary > li { flex-grow: 1; }

Here’s what we already have:

Graceful Degradation

Now before enhancing it progressively with JavaScript, let’s make sure it degrades gracefully if there is no JS available. There multiple of reasons for JS absence: it’s still loading, it has fatal errors, it failed to be transferred over the network.

.tabs:not(.--jsfied) { overflow-x: auto; -webkit-overflow-scrolling: touch; }

And once JavaScript is here, the --jsfied class name is added to the container element which neutralizes the CSS above:


Turns out the horizontal scroll strategy that I mentioned before might make a fine use here! When there’s not enough room for menu items the overflowing content gets clipped inside the container and scrollbars are displayed. That’s way better than empty space or something that’s broken, isn’t it?

Missing Parts

First off, let’s insert the missing DOM parts:

  • Secondary (dropdown) list which is a copy of the main list;
  • “More” button.
const container = document.querySelector('.tabs') const primary = container.querySelector('.-primary') const primaryItems = container.querySelectorAll('.-primary > li:not(.-more)') container.classList.add('--jsfied') // insert "more" button and duplicate the list primary.insertAdjacentHTML('beforeend', ` <li class="-more"> <button type="button" aria-haspopup="true" aria-expanded="false"> More &darr; </button> <ul class="-secondary"> ${primary.innerHTML} </ul> </li> `) const secondary = container.querySelector('.-secondary') const secondaryItems = secondary.querySelectorAll('li') const allItems = container.querySelectorAll('li') const moreLi = primary.querySelector('.-more') const moreBtn = moreLi.querySelector('button') moreBtn.addEventListener('click', (e) => { e.preventDefault() container.classList.toggle('--show-secondary') moreBtn.setAttribute('aria-expanded', container.classList.contains('--show-secondary')) })

Here we are nesting secondary list into primary and using some aria-* properties. We want our navigation menu to be accessible, right?

There’s also an event handler attached to the "more" button that toggles the --show-secondary class name on the container element. We’ll use it to show and hide the secondary list. Now let’s style the new parts. You may want to visually accent "more" button.

.tabs { position: relative; } .tabs .-secondary { display: none; position: absolute; top: 100%; right: 0; } .tabs.--show-secondary .-secondary { display: block; }

Here’s where that brought us to:

Obviously, we need some code that hides and shows the tabs…

Hiding and Showing Tabs in the Lists

Because of Flexbox, the tab items will never break into multiple lines and will shrink to their minimum possible widths. This means we can walk through the each item one by one, add up their widths, compare it to the width of .tabs element and toggle the visibility of particular tabs accordingly. For that we will create a function called doAdapt and wrap in the code below in this section.

To begin width, we should visually reveal all the items:

allItems.forEach((item) => { item.classList.remove('--hidden') })

On a side note, .--hidden works the way you’ve probably expected:

.tabs .--hidden { display: none; }

Math time! I’ll have to disappoint you if you expected some advanced mathematics. So, as described previously, we walk through the each primary tab by adding up their widths under stopWidth variable. We also perform a check if the item fits in the container, hide the item if not and save its index for later use.

let stopWidth = moreBtn.offsetWidth let hiddenItems = [] const primaryWidth = primary.offsetWidth primaryItems.forEach((item, i) => { if(primaryWidth >= stopWidth + item.offsetWidth) { stopWidth += item.offsetWidth } else { item.classList.add('--hidden') hiddenItems.push(i) } })

Hereafter, we need to hide the equivalent items from the secondary list that remained visible in the primary one. As well as hide “more” button if no tabs were hidden.

if(!hiddenItems.length) { moreLi.classList.add('--hidden') container.classList.remove('--show-secondary') moreBtn.setAttribute('aria-expanded', false) } else { secondaryItems.forEach((item, i) => { if(!hiddenItems.includes(i)) { item.classList.add('--hidden') } }) }

Finally, ensure doAdapt function is executed at the right moments:

doAdapt() // adapt immediately on load window.addEventListener('resize', doAdapt) // adapt on window resize

Ideally the resize event handler should be debounced to prevent unnecessary calculations.

Ladies and gentlemen, this is the result (play with resizing the demo window):

See the Pen Container-Adapting Tabs With "More" Button by Osvaldas (@osvaldas) on CodePen.

I could probably end my article here, but there is an extra mile we can walk to make it better and some things to note…


It has been implemented in the demo above, but we haven’t overviewed a small detail that improves the UX of our tabs widget. It’s hiding the dropdown list automatically if user clicks anywhere outside the list. For that we can bind a global click listener and check if the clicked element or any of its parents is the secondarylist or "more" button. If not, the dropdown list gets dismissed.

document.addEventListener('click', (e) => { let el = e.target while(el) { if(el === secondary || el === moreBtn) { return; } el = el.parentNode } container.classList.remove('--show-secondary') moreBtn.setAttribute('aria-expanded', false) }) Edge Cases Long Tab Titles

You might have been wondering how the widget behaves with long tab titles. Well, you have at least two options here...

  1. Let titles wrap to the next line which is how they behave by default (you can also enable word wrapping with word-wrap: break-word):
  1. Or you can disable all kinds of wrapping in the primary list with white-space: nowrap. The script is flexible enough to put the too-long items to the dropdown (where the titles are free to wrap) by stepping aside the shorter siblings:
Many Tabs

Even though the secondary list is position: absolute it doesn’t matter how long your document’s height is. As long as the container element or its parents are not position: fixed, the document will adapt and the bottom items will be reachable by scrolling down the page.

A Thing to be Aware Of

Things may become tricky if the tabs are buttons rather than anchors semantically, which means their response to clicks are decided by JavaScript, e.g.: dynamic tabs. The problem here is that tab button event handlers aren’t duplicated along with the markup. I see at least two approaches to solve that:

  • Place dynamic event handler attachments right after the adaptive tab code;
  • Use an event delegation method instead (think of jQuery’s live()).

Unfortunately, events occur in quantity: most likely your tabs will have a selected state that visually indicates the current tab so it’s also important to manage the states simultaneously. Otherwise, flip the tablet and you’re lost.

Browser Compatibility

Even though I used ES6 syntax in the examples and demo, it should be converted to ES5 by a compiler such as Babel to significantly widen the browser support (down to IE9 including).

You can also expand the Flexbox implementation with an older version and syntax (all the way down to IE10). If you need to also support non-Flexbox browsers you can always do feature detection with CSS @supports, apply the technique progressively, and rely on horizontal scroll for older browsers.

Happy tabbing!

The post Container-Adapting Tabs With “More” Button appeared first on CSS-Tricks.

Wakamai Fondue

Css Tricks - Tue, 05/01/2018 - 6:36am

Roel Nieskens released a tool that lets you upload a font file and see what’s inside, from how many characters it contains to the number of languages it supports. Here’s what you see once you upload a font, in this case Covik Sans Mono Black:

Why is this data useful? Well, I used this tool just the other day when I found a font file in a random Dropbox folder. What OpenType features does this font have? Are there any extra glyphs besides the Roman alphabet inside? Wakamai Fondue answered those questions for me in a jiffy.

Direct Link to ArticlePermalink

The post Wakamai Fondue appeared first on CSS-Tricks.

Wakamai Fondue

Css Tricks - Tue, 05/01/2018 - 6:36am

Roel Nieskens released a tool that lets you upload a font file and see what’s inside, from how many characters it contains to the number of languages it supports. Here’s what you see once you upload a font, in this case Covik Sans Mono Black:

Why is this data useful? Well, I used this tool just the other day when I found a font file in a random Dropbox folder. What OpenType features does this font have? Are there any extra glyphs besides the Roman alphabet inside? Wakamai Fondue answered those questions for me in a jiffy.

Direct Link to ArticlePermalink

The post Wakamai Fondue appeared first on CSS-Tricks.

Solved With CSS! Dropdown Menus

Css Tricks - Tue, 05/01/2018 - 3:59am

This post is the second in a series about the power of CSS.

Article Series:
  1. Colorizing SVG Backgrounds
  2. Dropdown Menus (this post)

CSS is getting increasingly powerful, and with features like CSS grid and custom properties (also known as CSS variables), we’re seeing some really creative solutions emerging. Some of those solutions focus around not only making the web prettier, but making it more accessible, and making styling accessible experiences better. I’m definitely here for it!

A common UI pattern that we see on the web are dropdown menus. They’re used to display related information in pieces, without overwhelming the user with buttons, text, and options. Somewhere that we see these a lot is inside of headers or navigation areas on websites.

A Google search for "dropdown menu" yields many examples

Let’s see if we can make one of these menus with CSS alone. We’ll create a list of links within a nav component like so:

<nav role="navigation"> <ul> <li><a href="#">One</a></li> <li><a href="#">Two</a></li> <li><a href="#">Three</a></li> </ul> </nav>

Now, say we want a sub-menu dropdown on the second navigation item. We can do the same thing there and include a list of links within that list item:

<nav role="navigation"> <ul> <li><a href="#">One</a></li> <li><a href="#">Two</a> <ul class="dropdown"> <li><a href="#">Sub-1</a></li> <li><a href="#">Sub-2</a></li> <li><a href="#">Sub-3</a></li> </ul> </li> <li><a href="#">Three</a></li> </ul> </nav>

We now have our two-tiered navigation system. In order to have the content hidden and displayed when we want it to be visible, we’ll need to apply some CSS. All style properties have been removed from the following example for clarity on interaction:

li { display: block; transition-duration: 0.5s; } li:hover { cursor: pointer; } ul li ul { visibility: hidden; opacity: 0; position: absolute; transition: all 0.5s ease; margin-top: 1rem; left: 0; display: none; } ul li:hover > ul, ul li ul:hover { visibility: visible; opacity: 1; display: block; } ul li ul li { clear: both; width: 100%; }

See the Pen Simple CSS Dropdown Menu with Hover by Una Kravets (@una) on CodePen.

Now, the submenu dropdown is hidden, but will be exposed and become visible when we hover over its correlating parent in the navigation bar. By styling ul li ul, we have access to that submenu, and by styling ul li ul li, we have access to the individual list items within it.

The Problem

This is starting to look like what we want, but we’re still far from finished at this point. Web accessibility is a core part of your product's development, and right now would be the perfect opportunity to bring this up. Adding role="navigation" is a good start, but in order for a navigation bar to be accessible, one should be able to tab through it (and focus on the proper item in a sensible order), and also have a screen reader accurately read out loud what is being focused on.

You can hover over any of the list items and clearly see what is being hovered over, but this isn’t true for tab navigation. Go ahead and try to tab through the example above. You lose track of where the focus is visually As you tab to Two in the main menu, you’ll see a focus indicator ring, but when you tab to the next item (one of its submenu items), that focus disappears.

Now, it’s important to note that theoretically you are focused on this other item, and that a screen reader would be able to parse that, reading Sub-One, but keyboard users will not be able to see what’s going on and will lose track.

The reason this happens is because, while we’re styling the hover of the parent element, as soon as we transition focus from the parent to one of the list items within that parent, we lose that styling. This makes sense from a CSS standpoint, but it’s not what we want.

Luckily, there is a new CSS pseudo class that will give us exactly what we want in this case, and it’s called :focus-within.

The Solution: `:focus-within`

The :focus-within pseudo selector is a part of the CSS Selectors Level 4 Spec and tells the browser to apply a style to a parent when any of its children are in focus. So in our case, this means that we can tab to Sub-One and apply a :focus-within style along with the :hover style of the parent and see exactly where we are in the navigation dropdown. In our case it would be ul li:focus-within > ul:

ul li:hover > ul, ul li:focus-within > ul, ul li ul:hover { visibility: visible; opacity: 1; display: block; }

See the Pen Simple CSS Dropdown Menu with Hover and :focus-within by Una Kravets (@una) on CodePen.

Sweet! It works!

Now, when we tab to the second item, our submenu pops up, and as we tab through the submenu, the visibility remains! Now, we can append our code to include :focus states alongside :hover to give keyboard users the same experience as our mouse users.

In most cases, such as on direct links, we usually can just write something like:

a:hover, a:focus { ... }

But in this case, since we’re applying hover styles based on the parent li, we can again utilize :focus-within to get the same look at feel when tabbing through. This is because we can’t actually focus on the li (unless we add a tabindex="0"). We’re actually focusing on the link (a) within it. :focus-within allows us to still apply styles to the parent li when focusing on the link (pretty darn cool!):

li:hover, li:focus-within { ... }

At this point, since we are applying a focus style, we can do something that’s typically not recommended (remove the styling of that blue outline focus ring). We can do this by:

li:focus-within a { outline: none; }

The above code specifies that when we focus within list items via the link (a), do not apply an outline to the link item (a). It’s pretty safe to write it this way, because we’re exclusively styling the hover state, and with browsers that do not support :focus-within, the link will still get a focus ring. Now our menu looks like this:

Final menu using :focus-within, :hover states, and customizing the focus ring to disappear

See the Pen Simple CSS Dropdown Menu with Hover and :focus-within and Focus states by Una Kravets (@una) on CodePen.

What About ARIA?

If you’re familiar with accessibility, you may have heard of ARIA labels and states. You can use these to your advantage to also create these types of dropdowns with built-in accessibility at the same time! You can find an excellent example here by Heydon Pickering. When including ARIA markup, your code would look a little more like this:

<nav role="navigation"> <ul> <li><a href="#">One</a></li> <li><a href="#" aria-haspopup="true">Two</a> <ul class="dropdown" aria-label="submenu"> <li><a href="#">Sub-1</a></li> <li><a href="#">Sub-2</a></li> <li><a href="#">Sub-3</a></li> </ul> </li> <li><a href="#">Three</a></li> </ul> </nav>

You’re adding aria-haspopup="true" to the parent of the dropdown menu to indicate an alternative state, and including aria-label="submenu" on the actual dropdown menu itself (in this case our list with class="dropdown".

These properties themselves will give you the functionality you need to show the dropdown menu, but the downside is that they only work with JavaScript enabled.

Browser Support Caveat

Speaking of caveats, let’s talk about browser support. While :focus-within does have pretty good browser support, it’s important to note that Internet Explorer and Edge are not supported, so your users on those platforms will not be able to see the navigation.

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

DesktopChromeOperaFirefoxIEEdgeSafari604752NoNo10.1Mobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox10.3NoNoNo6657

The ultimate solution here would be to use both ARIA markup and CSS :focus-within to ensure a solid dropdown experience for your users.

See the Pen Simple CSS Dropdown Menu with Hover and :focus-within and Focus states and ARIA by Una Kravets (@una) on CodePen.

If you want to be able to use this feature in the future, please upvote it on Edge User Voice! And upvote :focus-ring while you’re at it, so that we’ll be able to style that focus ring and create a beautiful interactive web experience for all &#x1f600;

More on `:focus-within` and A11Y

The post Solved With CSS! Dropdown Menus appeared first on CSS-Tricks.

In Defence Of ‘Poor’ SaaS Sign-Up Processes

Usability Geek - Mon, 04/30/2018 - 11:46am
Everybody knows that free trials are better than forcing users to book a demo. It is also widely accepted that you should be transparent about cost, and display pricing publicly on your website....
Categories: Web Standards

Animating Progress

Css Tricks - Mon, 04/30/2018 - 10:34am

Jonathan Snook on the complexity of animating the <progress> element. If you’re unfamiliar, that’s the element that spits out a bar chart-like visual that indicates a position between two values:

This example has custom styles, but you get the point.

Jonathan's post shows off a method for animating a change in progress value using CSS and a touch of JavaScript while making sure that it animates properly in every modern browser. The demo he made looks pretty neat. I’m sure this is going to be one of those posts I come back to again and again.

We recently shared a post by Dave Rupert that takes an SVG approach. Jeremias Menichelli also has an alternative approach, creating a ring shape and converting it into a React component.

Direct Link to ArticlePermalink

The post Animating Progress appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.