Developer News

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.

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:

Planning

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:

container.classList.add('--jsfied')

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…

Enhancements

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.

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.

Finger-friendly numerical inputs with `inputmode`

Css Tricks - Mon, 04/30/2018 - 3:49am

Forms are often a nightmare on mobile. We can make the process as pain-free as possible by reacting to context. Input fields that expect numerical values should have a numerical UI. Bringing up a number keyboard on small screens is easy on most platforms — just use a <input type="number">.

This big button numeric keyboard is finger-friendly and will help prevent users bouncing from your form in frustration. However, type="number" isn’t appropriate for all numbers.

On (most) larger screens, number inputs come with an incrementer/decrementer button. It’s a useful piece of UI we get for free by default. It does, however, make this kind of input totally inappropriate for a credit card number, for example.

The default UI for number inputs looks something like this in all desktop browsers

The spec itself makes this clear.

The type=number state is not appropriate for input that happens to only consist of numbers but isn’t strictly speaking a number. For example, it would be inappropriate for credit card numbers or US postal codes. A simple way of determining whether to use type=number is to consider whether it would make sense for the input control to have a spinbox interface (e.g., with "up" and "down" arrows). Getting a credit card number wrong by 1 in the last digit isn’t a minor mistake, it’s as wrong as getting every digit incorrect. So it would not make sense for the user to select a credit card number using "up" and "down" buttons. When a spinbox interface is not appropriate, type=text is probably the right choice (possibly with a pattern attribute).

It’s easy to hide the up and down buttons with CSS:

input[type="number"] { -moz-appearance: textfield; } input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }

It’s important to note that this isn’t the only difference between a number and text input. You should definitely follow the spec on this point! Some older browsers will strip out leading zeros for number inputs which would be a big problem for US ZIP codes. The often-useful maxlength attribute is ignored on number inputs.

yes yes yes! <input type=number> can finally die the fiery death it deserves!

— Monica Dinculescu (@notwaldorf) March 13, 2018

Why would anybody dislike such a useful input?

The answer comes down to validation and using the input for the wrong thing. The number input performs input sanitization by default. If a user enters anything that isn’t a valid number, the value will be equal to an empty string — regardless of what the user can see on the screen.

This input sanitization can trip developers up, and there’s no way to turn it off. If you want to allow input that isn’t a valid number, don’t use type="number".

Number input in Chrome. This might be valid input for your use case, but it’s illegitimate in the eyes of the number input. var numberinput = document.querySelector('input[type="number"]') numberinput.value // will be ""

This might not be what you would intuitively expect. However, if you follow the spec and only use the number input for what its designed for — actual numbers — this behavior is unproblematic.

Number Input Alternatives iOS Solution: Use the `pattern` Attribute on a Text Input

On iOS devices, using the pattern attribute with a value of [0-9]* will bring up the numeric keypad. This only works with this exact pattern — you can’t allow any extra characters.

<label for="creditcard">credit card number:</label> <input pattern="[0-9]*" type="text" name="creditcard"> iOS with pattern attribute

Bear in mind that an iPhone won’t let the user switch keyboard type when this keyboard is displayed. Make sure these are the only keys they need to fill in the input correctly.

If you want to bring up a keypad of large numeric keys on iOS, you need to use the pattern attribute even on number inputs. Otherwise, you’ll get small and finger-friendly buttons:

iOS keypad for <input type="number"> A Better Solution: `inputmode`

inputmode has been a WHATWG spec for a couple of years, and has finally been implemented by Chrome as of version 66:

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

DesktopChromeOperaFirefoxIEEdgeSafari66No20NoNoNoMobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid FirefoxNoNoNoNoNoNo

For the widest support possible, it can be combined with the pattern attribute for iOS:

<label for="creditcard">credit card number:</label> <input inputmode="numeric" pattern="[0-9]*" type="text" name="creditcard">

This gives developers full control of the mobile UI without any extra baggage. It makes the UI finger-friendly while being more versatile than the pattern attribute as we can allow any characters we like. It controls one thing — and one thing only. inputmode is a great solution for those cases when it's inappropriate to use type="number".

Some people would go further and ditch type="number" altogether once inputmode has better support. I’m not convinced that’s wise, but type="number" can be problematic.

if (numberInput.validity.valueMissing) { errorMessage.textContent = "field must not be empty" } Contrary to the human eye, the field is empty...

If you want to explicitly warn of empty number inputs, you’ll need to use:

if (numberInput.validity.valueMissing && !numberInput.validity.badInput) { errorMessage.textContent = "field must not be empty" }

According to Google, users abandon purchases twice as often on mobile as compared to desktop. Sales on phones account for only one third of all completed online purchases. Clearly people don’t tolerate fumbling through badly designed forms and jabbing at tiny inputs. Data entry needs to be effortless. While browser support is currently low, we're only really waiting on mobile browsers. Desktop support is largely irrelevant. The input elements introduced by HTML5 are great, but they miss some edge cases. This can fill in some gaps.

The post Finger-friendly numerical inputs with `inputmode` appeared first on CSS-Tricks.

Practical Jokes in the Browser

Css Tricks - Sat, 04/28/2018 - 3:03am

I know April Fool’s Day is at the beginning of this month, but hey, now you’ve got a year to prepare. Not to mention a gool ol’ practical joke can be done anytime.

Fair warning on this stuff… you gotta be tasteful. Putting someone’s stapler in the jello is pretty hilarious unless it’s somehow a family heirloom, or it’s someone who’s been the target of a little too much office prankery to the point it isn’t funny anymore. Do good. Have fun.

setTimeout(function() { var text = new SpeechSynthesisUtterance("LOLOLOLOLOLOLOLOL"); speechSynthesis.speak(text); }, 600000);

Direct Link to ArticlePermalink

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

CSS Blocks

Css Tricks - Fri, 04/27/2018 - 5:10am

A new entry into the CSS-in-JS landscape! Looks like the idea is that you write an individual CSS file for every component. You have to work in components, that's how the whole thing works. In the same isle as styled-components, css-modules, and glamorous.

Then you write :scope { } which is the base style for that component. Which I guess means you get out of having to pick a name! But also means you're pretty locked in (true with just about any style processing setup).

Then both the CSS and component are compiled, and probably optimized with its partner tool OptiCSS. The end result is super optimized styles. Since it's "template aware", the styles can be far more optimized than they could be by any system trying to optimize CSS in isolation.

Chris Eppstein:

With CSS Blocks, and OptiCSS running at its core, you get to write ergonomic CSS and let the build take care of making your stylesheets properly scoped, screaming fast, and fantastically small.

Speed, style scoping, and never/rarely having unsued CSS definitely seem like the big benefits to me. A non-trivial thing to move to, but sounds like it could be worth it for plenty of big sites and new sites.

A couple of setup repos to explore to see how it could work: css-blocks-webpack-3 and css-blocks-hello-world.

Direct Link to ArticlePermalink

The post CSS Blocks appeared first on CSS-Tricks.

Radial Gradient Recipes

Css Tricks - Thu, 04/26/2018 - 4:01am

Radial gradients are pretty dang cool. It's amazing we can paint the background of an element with them so easily. Easily is a relative term though. It's certainly easier than needing to create a graphic in third-party software to use as the background, and the syntax is highly learnable. But it's also not that easy to remember if you don't use it often, and it's more complicated than linear-gradient().

I figured I'd put together a page of reference examples, so if you know what you need but forget the syntax, it's easy to find that starter code example here.

Centered Bursts

The simplest possible syntax places the first color in the center of the element and the second color on the outside and that's that:

See the Pen Radial Gradient - Centered by Chris Coyier (@chriscoyier) on CodePen.

That will stretch the gradient into an ellipse on a non-square element though. If you don't like that, you can force the shape into a circle, like the second example here demonstrates:

See the Pen Radial Gradient - Circle vs. Ellipse by Chris Coyier (@chriscoyier) on CodePen.

You can also control the size by literally saying how large the circle/ellipse should be (the final color will still stretch to cover the element) by:

  • Using a keyword closest-side, farthest-side, closest-corner, farthest-corner
  • Explicitly saying like radial-gradient(circle 100px, ...)
  • Using color stops like radial-gradient(#56ab2f, #a8e063 150px)

See the Pen Radial Gradient - Sizing by Chris Coyier (@chriscoyier) on CodePen.

Here's some of that stuff in use:

See the Pen Usage of Radial Gradients by Chris Coyier (@chriscoyier) on CodePen.

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

Positioned

Besides controlling the size and shape of the gradient, the other big trick to know with radial gradients is that you can position the center of them.

This is one of the shortcomings, I find, with gradient generators. They help you pick colors and color stops and stuff, but they usually punt on the positioning stuff.

This is a beautiful gradient tool, but doesn't help with positioning or sizing. Some of them do help a little with positioning (see "Expert" settings), but don't expose all the possibilities.

The center of a radial gradient doesn't have to be in the center! For example, you can position the center in the top left like this:

.element { background: radial-gradient( at top left, var(--light), var(--dark) /* using variables just for fun! */ ) }

Here's all the four corners:

See the Pen Positioned Radial Gradients by Chris Coyier (@chriscoyier) on CodePen.

You can also be very specifically positioned. Here's an example of a gradient positioned exactly 195px from the left along the bottom of the element. It also has a specific size, but otherwise does the default ellipse shape:

.element { background: radial-gradient( 150px 40px at 195px bottom, #666, #222 ); }

See the Pen Specifically positioned gradient by Chris Coyier (@chriscoyier) on CodePen.

Another little thing to know is that you can use transparent in the gradients to expose the color behind if that's needed, or partially transparent colors like rgba(255, 255, 255, 0.5) to do the same at a colorized color stop.

Also, radial gradients can be used with multiple backgrounds, applying multiple of them to a single element, even overlapping!

.element { background: radial-gradient( circle at top left, rgba(255, 255, 255, 0.5), transparent 100px ), radial-gradient( circle at top right, rgba(255, 255, 255, 0.5), transparent 100px ), radial-gradient( at bottom left, rgba(255, 0, 255, 0.5), transparent 400px ), radial-gradient( at bottom right, rgba(255, 100, 100, 0.5), transparent 400px ); }

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

To highlight the idea that the center of the gradient can be anywhere, here's a gradient that follows the mouse:

See the Pen Radial Gradient Move With Mouse by Leo Sammarco (@lsammarco) on CodePen.

Resources

People tend to think about browser support, and rightfully so, but don't think too hard about it in this case. We're at pretty much across the board support even without any prefixes.

OK bye!

See the Pen CSS Sunset Sunrise by Marty Saetre (@msaetre) on CodePen.

The post Radial Gradient Recipes appeared first on CSS-Tricks.

?Level Up Your JavaScript Error Monitoring

Css Tricks - Thu, 04/26/2018 - 4:00am

(This is a sponsored post.)

Automatically detect and diagnose JavaScript errors impacting your users with Bugsnag without changing your code or adding try/catch blocks. Get comprehensive diagnostic reports, know immediately which errors are worth fixing, and debug in a fraction of the time compared to traditional tools.

Bugsnag detects every single error and prioritizes errors with the greatest impact on your users. Get support for 50+ platforms and integrate with the development and productivity tools your team already uses.

Bugsnag is used by the world's top engineering teams including Airbnb, Lyft, Square, Yelp, Eventbrite, Shopify, MailChimp, and Docker. Start your free trial today.

Direct Link to ArticlePermalink

The post ?Level Up Your JavaScript Error Monitoring appeared first on CSS-Tricks.

Understanding React `setState`

Css Tricks - Wed, 04/25/2018 - 3:36am

React components can, and often do, have state. State can be anything, but think of things like whether a user is logged in or not and displaying the correct username based on which account is active. Or an array of blog posts. Or if a modal is open or not and which tab within it is active.

React components with state render UI based on that state. When the state of components changes, so does the component UI.

That makes understanding when and how to change the state of your component important. At the end of this tutorial, you should know how setState works, and be able to avoid common pitfalls that many of us hit when when learning React.

Workings of `setState()`

setState() is the only legitimate way to update state after the initial state setup. Let’s say we have a search component and want to display the search term a user submits.

Here’s the setup:

import React, { Component } from 'react' class Search extends Component { constructor(props) { super(props) state = { searchTerm: '' } } }

We’re passing an empty string as a value and, to update the state of searchTerm, we have to call setState().

setState({ searchTerm: event.target.value })

Here, we’re passing an object to setState(). The object contains the part of the state we want to update which, in this case, is the value of searchTerm. React takes this value and merges it into the object that needs it. It’s sort of like the Search component asks what it should use for the value of searchTerm and setState() responds with an answer.

This is basically kicking off a process that React calls reconciliation. The reconciliation process is the way React updates the DOM, by making changes to the component based on the change in state. When the request to setState() is triggered, React creates a new tree containing the reactive elements in the component (along with the updated state). This tree is used to figure out how the Search component’s UI should change in response to the state change by comparing it with the elements of the previous tree. React knows which changes to implement and will only update the parts of the DOM where necessary. This is why React is fast.

That sounds like a lot, but to sum up the flow:

  • We have a search component that displays a search term
  • That search term is currently empty
  • The user submits a search term
  • That term is captured and stored by setState as a value
  • Reconciliation takes place and React notices the change in value
  • React instructs the search component to update the value and the search term is merged in

The reconciliation process does not necessarily change the entire tree, except in a situation where the root of the tree is changed like this:

// old <div> <Search /> </div> // new <span> <Search /> </span>

All <div> tags become <span> tags and the whole component tree will be updated as a result.

The rule of thumb is to never mutate state directly. Always use setState() to change state. Modifying state directly, like the snippet below will not cause the component to re-render.

// do not do this this.state = { searchTerm: event.target.value } Passing a Function to `setState()`

To demonstrate this idea further, let's create a simple counter that increments and decrements on click.

See the Pen setState Pen by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Let’s register the component and define the markup for the UI:

class App extends React.Component { state = { count: 0 } handleIncrement = () => { this.setState({ count: this.state.count + 1 }) } handleDecrement = () => { this.setState({ count: this.state.count - 1 }) } render() { return ( <div> <div> {this.state.count} </div> <button onClick={this.handleIncrement}>Increment by 1</button> <button onClick={this.handleDecrement}>Decrement by 1</button> </div> ) } }

At this point, the counter simply increments or decrements the count by 1 on each click.

But what if we wanted to increment or decrement by 3 instead? We could try to call setState() three times in the handleDecrement and handleIncrement functions like this:

handleIncrement = () => { this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 }) } handleDecrement = () => { this.setState({ count: this.state.count - 1 }) this.setState({ count: this.state.count - 1 }) this.setState({ count: this.state.count - 1 }) }

If you are coding along at home, you might be surprised to find that doesn’t work.

The above code snippet is equivalent to:

Object.assign( {}, { count: this.state.count + 1 }, { count: this.state.count + 1 }, { count: this.state.count + 1 }, )

Object.assign() is used to copy data from a source object to a target object. If the data being copied from the source to the target all have same keys, like in our example, the last object wins. Here's a simpler version of how Object.assign() works;

let count = 3 const object = Object.assign({}, {count: count + 1}, {count: count + 2}, {count: count + 3} ); console.log(object); // output: Object { count: 6 }

So instead of the call happening three times, it happens just once. This can be fixed by passing a function to setState(). Just as you pass objects to setState(), you can also pass functions, and that is the way out of the situation above.

If we edit the handleIncrement function to look like this:

handleIncrement = () => { this.setState((prevState) => ({ count: prevState.count + 1 })) this.setState((prevState) => ({ count: prevState.count + 1 })) this.setState((prevState) => ({ count: prevState.count + 1 })) }

...we can now increment count three times with one click.

In this case, instead of merging, React queues the function calls in the order they are made and updates the entire state ones it is done. This updates the state of count to 3 instead of 1.

Access Previous State Using Updater

When building React applications, there are times when you'll want to calculate state based the component’s previous state. You cannot always trust this.state to hold the correct state immediately after calling setState(), as it is always equal to the state rendered on the screen.

Let's go back to our counter example to see how this works. Let's say we have a function that decrements our count by 1. This function looks like this:

changeCount = () => { this.setState({ count: this.state.count - 1}) }

What we want is the ability to decrement by 3. The changeCount() function is called three times in a function that handles the click event, like this.

handleDecrement = () => { this.changeCount() this.changeCount() this.changeCount() }

Each time the button to decrement is clicked, the count will decrement by 1 instead of 3. This is because the this.state.count does not get updated until the component has been re-rendered. The solution is to use an updater. An updater allows you access the current state and put it to use immediately to update other items. So the changeCount() function will look like this.

changeCount = () => { this.setState((prevState) => { return { count: prevState.count - 1} }) }

Now we are not depending on the result of this.state. The states of count are built on each other so we are able to access the correct state which changes with each call to changeCount().

setState() should be treated asynchronously — in other words, do not always expect that the state has changed after calling setState().

Wrapping Up

When working with setState(), these are the major things you should know:

  • Update to a component state should be done using setState()
  • You can pass an object or a function to setState()
  • Pass a function when you can to update state multiple times
  • Do not depend on this.state immediately after calling setState() and make use of the updater function instead.

The post Understanding React `setState` appeared first on CSS-Tricks.

Grid to Flex

Css Tricks - Tue, 04/24/2018 - 11:04am

Una Kravets shows how to make layouts in CSS Grid with flexbox fallbacks for browsers that don’t support those grid properties just yet. Una writes:

CSS grid is AMAZING! However, if you need to support users of IE11 and below, or Edge 15 and below, grid won't really work as you expect...This site is a solution for you so you can start to progressively enhance without fear!

The site is a provides examples using common layouts and component patterns, including code snippets. For example:

See the Pen Grid To Flex -- Example 1 by Una Kravets (@una) on CodePen.

Direct Link to ArticlePermalink

The post Grid to Flex appeared first on CSS-Tricks.

JAMstack Comments

Css Tricks - Tue, 04/24/2018 - 7:30am

JAMstack sites are often seen as being static. A more accurate mental model for them would be that they are sites which have the ability to be hosted statically. The difference might seem semantic, but thanks to the rise of many tools and services which simplify running a build and deploying to static hosting infrastructure, such sites can feel much fresher and dynamic than you might imagine, while still capable of being served from static hosting infrastructure, with all the benefits that brings.

A feature often used as an example of why a site cannot be hosted statically is comments. A comments engine needs to handle submissions, allow for moderation, and is by its very nature, "dynamic".

Comment systems are generally thought of as quite dynamic content

Thanks to the growing ecosystem of tools available for JAMstack sites, there are solutions to this. Let's look at an example which you could use on your own site, which:

  • Does not depend on client-side JavaScript
  • Could work with any static site generator
  • Includes moderation
  • Sends notifications when new comments need moderating
  • Bakes the comments into your site, so that they load quickly and appear in searches

This example makes use of some of the features of Netlify, a platform for automating, deploying and hosting web projects, but many of the principles could be used with other platforms.

You can see the example site here.

Stashing our content

We'll create 2 forms to receive all of our comments at the different stages of their journey from commenter to content. When Netlify sees a <form>, it creates a unique data store for the data the form collects. We'll make great use of that.

  • Form 1) A queue to hold all of the new comment submissions. In other words, a store to hold all comments awaiting moderation.
  • Form 2) Contains all approved comments.

The act of moderation will be somebody looking at each new submission and deciding, "yep!" or "nope!". Those that get nope-d will be deleted from the queue. Those that are approved will be posted over to the approved comments form.

All of the comments in the approved comments form are used by our static site generator in subsequent site builds thanks to the API access Netlify gives to the submissions in our forms.

The comment form

Each page includes an HTML <form>. By adding the boolean attribute of netlify to any HTML form element in your site, Netlify will automatically generate an API for your form, and gathers all of the submissions to it for you. You'll also be able to access the submissions via that API later. Handy!

The comments <form> on each page will look a lot like this (some classes and extra copy omitted for clarity):

<form netlify name="comments-queue" action="/thanks"> <input name="path" type="hidden" value="{{ page.url }}"> <p> <label for="name">Your name</label> <input type="text" name="name" id="name"> </p> <p> <label for="email">Your email</label> <input type="email" name="email" id="email"> </p> <p> <label for="comment">Your comment</label> <textarea name="comment" id="comment"></textarea> </p> <p> <button type="submit">Post your comment</button> </p> </form>

You'll may notice that the form also includes a type="hidden" field to let us know which page on the site this comment is for. Our static site generator populates that for us when the site is generated, and well use it later when deciding which comments should be shown on which page.

Submissions and notifications

When a new comment is posted via the comment form, Netlify not only stashes that for us, but can also send a notification. That could be:

  • an email
  • a Slack notification
  • a webhook of our choosing.

These give us the chance to automate things a little.

New submissions result in a notification being posted to Slack. We'll get to see what was submitted and to which page right there in our Slack client.

To make things extra slick, we can massage that notification a little to include some action buttons. One button to delete the comment, one to approve it. Approving a new comment from a Slack notification on your phone while riding the bus feels good.

We can't make those buttons work without running a little bit of logic which, we can do in a Lambda function. Netlify recently added support for Lambda functions too, making the process of writing and deploying Lambdas part of the same deployment process. You'll not need to go rummaging around in Amazon's AWS configuration settings.

We'll use one Lambda function to add some buttons to our Slack notification, and another Lambda function to handle the actions of clicking either of those buttons.

Bring the comments into the site

With a freshly approved comment being posted to our approved comments form, we are back to using the submission event triggers that Netlify provides. Every time something is posted to the approved comments form, we'll want to include it in the site, so we have Netlify automatically rebuild and deploy our site.

Most static site generators have some notion of data files. Jekyll uses files in a [_data] directory, Hugo has a similar data directory. This example is using Eleventy as its static site generator which has a similar concept. We'll make use of this.

Each time we run our site build, whether in our local development environment or within Netlify through their automated builds, the first step is to pull all of our external data into local data files which our SSG can then use. We do that with a Gulp task.

Armed with a `comments.json` file which we have populated from a call to Netlify's form submission API which grabbed all of our approved comments, our SSG can now build the site as normal and bake the correct comments right into the HTML of our pages.

Some benefits

Well that was fun, but why bother?

Yes, you could use something like Disqus to add comments to a statically hosted site via a few lines of JavaScript. But that adds an external JavaScript dependency and results in the comments about your content living far away from the content itself. And it's only available once the JavaScript has loaded, pulled in the data and then injected it into your site.

Whereas this method results in comments that are baked right into the content of your site. They'll show up in searches on Google and they will load as part of your site without the need for any client-side JavaScript.

Even better, they'll be available for you to commit right into your code repository with the rest of your content, giving you more peace of mind and portability in the future.

The example site and all of its code are available to explore. You can try submitting comments if you like (although poor old Phil will need to moderate any comments on this example site before they appear, but that will just make him feel loved).

Better still, you can clone this example and deploy your own version to Netlify with just a few clicks. The example site explains how.

Just show me behind the scenes right now!

If you'd want to take a look at how things behave for the moderator of a site using this system without grabbing a copy of your own, this short video will walk through a comment being made, moderated and incorporated into the site.

The post JAMstack Comments appeared first on CSS-Tricks.

Server-Side Visualization With Nightmare

Css Tricks - Tue, 04/24/2018 - 3:36am

This is an extract from chapter 11 of Ashley Davis’s book Data Wrangling with JavaScript now available on the Manning Early Access Program. I absolutely love this idea as there is so much data visualization stuff on the web that relies on fully functioning client side JavaScript and potentially more API calls. It’s not nearly as robust, accessible, or syndicatable as it could be. If you bring that data visualization back to the server, you can bring progressive enhancement to the party. All example code and data can be found on GitHub.

When doing exploratory coding or data analysis in Node.js it is very useful to be able to render a visualization from our data. If we were working in browser-based JavaScript we could choose any one of the many charting, graphics, and visualization libraries. Unfortunately, under Node.js, we don’t have any viable options, so how otherwise can we achieve this?

We could try something like faking the DOM under Node.js, but I found a better way. We can make our browser-based visualization libraries work for us under Node.js using a headless browser. This is a browser that has no user interface. You can think of it as a browser that is invisible.

I use Nightmare under Node.js to capture visualizations to PNG and PDF files and it works really well!

The headless browser

When we think of a web-browser we usually think of the graphical software that we interact with on a day to day basis when browsing the web. Normally we interact with such a browser directly, viewing it with our eyes and controlling it with our mouse and keyboard as shown in Figure 1.

Figure 1: The normal state of affairs: our visualization renders in a browser and the user interacts directly with the browser

A headless browser on the other hand is a web-browser that has no graphical user interface and no direct means for us to control it. You might ask what is the use of a browser that we can’t directly see or interact with.

Well, as developers we would typically use a headless browser for automating and testing web sites. Let’s say that you have created a web page and you want to run a suite of automated tests against it to prove that it works as expected. The test suite is automated, which means it is controlled from code and this means that we need to drive the browser from code.

We use a headless browser for automated testing because we don’t need to directly see or interact with the web page that is being tested. Viewing such an automated test in progress is unnecessary, all we need to know is if the test passed or failed — and if it failed we would like to know why. Indeed, having a GUI for the browser under test would actually be a hindrance for a continuous-integration or continuous-deployment server, where many such tests can run in parallel.

So headless browsers are often used for automated testing of our web pages, but they are also incredibly useful for capturing browser-based visualizations and outputting them to PNG images or PDF files. To make this work we need a web server and a visualization, we must then write code to instance a headless browser and point it at our web server. Our code then instructs the headless browser to take a screenshot of the web page and save it to our file system as a PNG or PDF file.

Figure 2: We can use a headless browser under Node.js to capture our visualization to a static image file

Nightmare is my headless browser of choice. It is a Node.js library (installed via npm) that is built on Electron. Electron is a framework normally used for building cross-platform desktop apps that are based on web-technologies.

Why Nightmare?

It’s called Nightmare, but it’s definitely not a Nightmare to use. In fact, it’s the simplest and most convenient headless browser that I’ve used. It automatically includes Electron, so to get started we simply install Nightmare into our Node.js project as follows:

npm install --save nightmare

That’s all we need to install Nightmare and we can start using it immediately from JavaScript!

Nightmare comes with almost everything we need: A scripting library with an embedded headless browser. It also includes the communication mechanism to control the headless browser from Node.js. For the most part it’s seamless and well-integrated to Node.js.

Electron is built on Node.js and Chromium and maintained by GitHub and is the basis for a number of popular desktop applications.

Here are the reasons that I choose to use Nightmare over any other headless browser:

  • Electron is very stable.
  • Electron has good performance.
  • The API is simple and easy to learn.
  • There is no complicated configuration (just start using it).
  • It is very well integrated with Node.js.
Nightmare and Electron

When you install Nightmare via npm it automatically comes with an embedded version of Electron. So, we can say that Nightmare is not just a library for controlling a headless browser, it effectively is the headless browser. This is another reason I like Nightmare. With some of the other headless browsers, the control library is separate, or it’s worse than that and they don’t have a Node.js control library at all. In the worst case, you have to roll your own communication mechanism to control the headless browser.

Nightmare creates an instance of the Electron process using the Node.js child_process module. It then uses inter-process communication and a custom protocol to control the Electron instance. The relationship is shown in Figure 3.

Figure 3: Nightmare allows us to control Electron running as a headless browser Our process: Capturing visualizations with Nightmare

So what is the process of capturing a visualization to an image file? This is what we are aiming at:

  1. Acquire data.
  2. Start a local web server to host our visualization
  3. Inject our data into the web server
  4. Instance a headless browser and point it at our local web server
  5. Wait for the visualization to be displayed
  6. Capture a screenshot of the visualization to an image file
  7. Shutdown the headless browser
  8. Shutdown the local web server
Prepare a visualization to render

The first thing we need is to have a visualization. Figure 4 shows the chart we’ll work with. This a chart of New York City yearly average temperature for the past 200 years.

Figure 4: Average yearly temperature in New York City for the past 200 years

To run this code you need Node.js installed. For this first example we’ll also use live-server (any web server will do) to test the visualization (because we haven’t created our Node.js web server yet), install live server as follows:

npm install -g live-server

Then you can clone the example code repo for this blog post:

git clone https://github.com/Data-Wrangling-with-JavaScript/nodejs-visualization-example

Now go into the repo, install dependencies and run the example using live-server

cd nodejs-visualization-example/basic-visualization bower install live-server

When you run live-server your browser should automatically open and you should see the chart from Figure 4.

It’s a good idea to check that your visualization works directly in a browser before you try and capture it in a headless browser; there could easily be something wrong with it and problems are much easier to troubleshoot in a real browser than in the headless browser. live-server has live reload built-in, so now you have a nice little setup here when you can edit and improve the chart interactively before you try to capture it under Node.js.

This simple line chart was constructed with C3. Please take a look over the example code and maybe look at some of the examples in the C3 gallery to learn more about C3.

Starting the web server

To host our visualization, we need a web server. It’s not quite enough that we have a web server, we also need to be able to dynamically start and stop it. Listing 1 shows the code for our web server.

Listing 1 – Code for a simple web server that can be started and stopped const express = require('express'); const path = require('path'); module.exports = { start: () => { // Export a start function so we can start the web server on demand. return new Promise((resolve, reject) => { const app = express(); const staticFilesPath = path.join(__dirname, "public"); // Make our 'public' sub-directory accessible via HTTP. const staticFilesMiddleWare = express.static(staticFilesPath); app.use('/', staticFilesMiddleWare); const server = app.listen(3000, err => { // Start the web server! if (err) { reject(err); // Error occurred while starting web server. } else { resolve(server); // Web server started ok. } }); }); } }

The code module in listing 1 exports a start function that we can call to kickstart our web server. This technique, being able to start and stop our web server, is also very useful for doing automated integration testing on a web site. Imagine that you want to start your web server, run some tests against it and then stop it at the end.

So now we have our browser-based visualization and we have a web server that can be started and stopped on demand. These are the raw ingredients we need for capturing server-side visualizations. Let’s mix it up with Nightmare!

Rendering the web page to an image

Now let’s flesh out the code to capture a screenshot of the visualization with Nightmare. Listing 2 shows the code that instances Nightmare, points it at our web server and then takes the screenshot.

Listing 2 – Capturing our chart to an image file using Nightmare const webServer = require('./web-server.js'); const Nightmare = require('nightmare'); webServer.start() // Start the web server. .then(server => { const outputImagePath = "./output/nyc-temperatures.png"; const nightmare = new Nightmare(); // Create the Nightmare instance. return nightmare.goto("http://localhost:3000") // Point the browser at the web server we just started. .wait("svg") // Wait until the chart appears on screen. .screenshot(outputImagePath) // Capture a screenshot to an image file. .end() // End the Nightmare session. Any queued operations are completed and the headless browser is terminated. .then(() => server.close()); // Stop the web server when we are done. }) .then(() => { console.log("All done :)"); }) .catch(err => { console.error("Something went wrong :("); console.error(err); });

Note the use of the goto function, this is what actually directs the browser to load our visualization.

Web pages usually take some time to load. That’s probably not going to be very long, especially as we are running a local web server, but still we face the danger of taking a screenshot of the headless browser before or during its initial paint. That’s why we must call the wait function to wait until the chart’s <svg> element appears in the browser’s DOM before we call the screenshot function.

Eventually, the end function is called. Up until now we have effectively built a list of commands to send to the headless browser. The end function actually sends the commands to the browser, which takes the screenshot and outputs the file nyc-temperatures.png. After the image file has been captured we finish up by shutting down the web server.

You can find the completed code under the capture-visualization sub-directory in the repo. Go into the sub-directory and install dependencies:

cd nodejs-visualization-example/capture-visualization cd public bower install cd .. npm install live-server

Now you can try the code for yourself:

node index.js

This has been an extract from chapter 11 of Data Wrangling with JavaScript now available on the Manning Early Access Program. Please use this discount code fccdavis3 for a 37% discount. Please check The Data Wrangler for new updates on the book.

The post Server-Side Visualization With Nightmare appeared first on CSS-Tricks.

Native-Like Animations for Page Transitions on the Web

Css Tricks - Mon, 04/23/2018 - 3:35am

Some of the most inspiring examples I’ve seen of front-end development have involved some sort of page transitions that look slick like they do in mobile apps. However, even though the imagination for these types of interactions seem to abound, their presence on actual sites that I visit do not. There are a number of ways to accomplish these types of movement!

Here’s what we’ll be building:

Demo Site

GitHub Repo

We’ll build out the simplest possible distillation of these concepts so that you can apply them to any application, and then I’ll also provide the code for this more complex app if you’d like to dive in.

Today we’ll be discussing how to create them with Vue and Nuxt. There are a lot of moving parts in page transitions and animations (lol I kill me), but don’t worry! Anything we don’t have time to cover in the article, we’ll link off to with other resources.

Why?

The web has come under critique in recent years for appearing "dated" in comparison to native iOS and Android app experiences. Transitioning between two states can reduce cognitive load for your user, as when someone is scanning a page, they have to create a mental map of everything that's contained on it. When we move from page to page, the user has to remap that entire space. If an element is repeated on several pages but altered slightly, it mimics the experience we've been biologically trained to expect — no one just pops into a room or changes suddenly; they transition from another room into this one. Your eyes see someone that's smaller relative to you. As they get closer in proximity to you, they get bigger. Without these transitions, changes can be startling. They force the user to remap placement and even their understanding of the same element. It is for this reason that these effects become critical in an experience that helps the user feel at home and gather information quickly on the web.

The good news is, implementing these kind of transitions is completely doable. Let's dig in!

Prerequisite Knowledge

If you’re unfamiliar with Nuxt and how to work with it to create Vue.js applications, there’s another article I wrote on the subject here. If you’re familiar with React and Next.js, Nuxt.js is the Vue equivalent. It offers server-side rendering, code splitting, and most importantly, hooks for page transitions. Even though the page transition hooks it offers are excellent, that’s not how we’re going to accomplish the bulk of our animations in this tutorial.

In order to understand how the transitions we’re working with today do work, you’ll also need to have basic knowledge around the <transition /> component and the difference between CSS animations and transitions. I’ve covered both in more detail here. You’ll also need basic knowledge of the <transition-group /> component and this Snipcart post is a great resource to learn more about it.

Even though you’ll understand everything in more detail if you read these articles, I’ll give you the basic gist of what’s going on as we encounter things throughout the post.

Getting Started

First, we want to kick off our project by using the Vue CLI to create a new Nuxt project:

# if you haven’t installed vue cli before, do this first, globally: npm install -g @vue/cli # or yarn global add @vue/cli # then vue init nuxt/starter my-transitions-project npm i # or yarn # and npm i vuex node-sass sass-loader # or yarn add vuex node-sass sass-loader

Great! Now the first thing you’ll notice is that we have a pages directory. Nuxt will take any .vue files in that directory and automatically set up routing for us. Pretty awesome. We can make some pages to work with here, in our case: about.vue, and users.vue.

Setting Up Our Hooks

As mentioned earlier, Nuxt offers some page hooks which are really nice for page to page transitions. In other words, we have hooks for a page entering and leaving. So if we wanted to create an animation that would allow us to have a nice fade from page to page, we could do it because the class hooks are already available to us. We can even name new transitions per page and use JavaScript hooks for more advanced effects.

But what if we have some elements that we don’t want to leave and re-enter, but rather transition positions? In mobile applications, things don’t always leave when they move from state to state. Sometimes they transition seamlessly from one point to another and it makes the whole application feel very fluid.

Step One: Vuex Store

The first thing we’ll have to do is set up a centralized state management store with Vuex because we’re going to need to hold what page we’re currrently on.

Nuxt will assume this file will be in the store directory and called index.js:

import Vuex from 'vuex' const createStore = () => { return new Vuex.Store({ state: { page: 'index' }, mutations: { updatePage(state, pageName) { state.page = pageName } } }) } export default createStore

We’re storing both the page and we create a mutation that allows us to update the page.

Step Two: Middleware

Then, in our middleware, we’ll need a script that I’ve called pages.js. This will give us access to the route that’s changing and being updated before any of the other components, so it will be very efficient.

export default function(context) { // go tell the store to update the page context.store.commit('updatePage', context.route.name) }

We’ll also need to register the middleware in our nuxt.config.js file:

module.exports = { ... router: { middleware: 'pages' }, ... } Step Three: Register Our Navigation

Now, we’ll go into our layouts/default.vue file. This directory allows you to set different layouts for different page structures. In our case, we’re not going to make a new layout, but alter the one that we’re reusing for every page. Our template will look like this at first:

<template> <div> <nuxt/> </div> </template>

And that nuxt/ tag will insert anything that’s in the templates in our different pages. But rather than reusing a nav component on every page, we can add it in here and it will be presented consistently on every page:

<template> <div> <app-navigation /> <nuxt/> </div> </template> <script> import AppNavigation from '~/components/AppNavigation.vue' export default { components: { AppNavigation } } </script>

This is also great for us because it won’t rerender every time the page is re-routed. It will be consistent on every page and, because of this, we cannot plug into our page transition hooks but instead we can build our own with what we built between Vuex and the Middleware.

Step Four: Create our Transitions in the Navigation Component

Now we can build out the navigation, but I’m also going to use this SVG here to do a small demo of basic functionality we’re going to implement for a larger application

<template> <nav> <h2>Simple Transition Group For Layout: {{ page }}</h2> <!--simple navigation, we use nuxt-link for routing links--> <ul> <nuxt-link exact to="/"><li>index</li></nuxt-link> <nuxt-link to="/about"><li>about</li></nuxt-link> <nuxt-link to="/users"><li>users</li></nuxt-link> </ul> <br> <!--we use the page to update the class with a conditional--> <svg :class="{ 'active' : (page === 'about') }" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 447 442"> <!-- we use the transition group component, we need a g tag because it’s SVG--> <transition-group name="list" tag="g"> <rect class="items rect" ref="rect" key="rect" width="171" height="171"/> <circle class="items circ" key="circ" id="profile" cx="382" cy="203" r="65"/> <g class="items text" id="text" key="text"> <rect x="56" y="225" width="226" height="16"/> <rect x="56" y="252" width="226" height="16"/> <rect x="56" y="280" width="226" height="16"/> </g> <rect class="items footer" key="footer" id="footer" y="423" width="155" height="19" rx="9.5" ry="9.5"/> </transition-group> </svg> </nav> </template> <script> import { mapState } from 'vuex' export default { computed: mapState(['page']) } </script>

We’re doing a few things here. In the script, we bring in the page name from the store as a computed value. mapState will let us bring in anything else from the store, which will handy later when we deal with a lot of user information.

In the template, we have a regular nav with nuxt-links, which is what we use for routing links in Nuxt. We also have class that will be updated on a conditional based on the page (it will change to .active when it’s the about page.

We’re also using the <transition-group> component around a number of elements that will change positions. The <transition-group> component is a bit magical because it applies the concepts of FLIP under the hood. If you’ve heard of FLIP before, you’re going to be super excited to hear this because it’s a really performant way of animating on the web but usually takes a lot of calculations to implement. If you haven’t heard of FLIP before, it’s definitely good to read up to understand how it works, and maybe more importantly, all of the stuff you no longer have to do to make this kind of effect work! Can I get a "Hell yeah!"

Here is the CSS that makes this work. We basically state how we’d like all of the elements to be positioned on that “active” hook that we made. Then we tell the elements to have a transition applied if something changes. You'll notice I'm using 3D transforms even if I'm just moving something along one X or Y axis because transforms are better for performance than top/left/margin for reducing paint and I want to enable hardware acceleration.

.items, .list-move { transition: all 0.4s ease; } .active { fill: #e63946; .rect { transform: translate3d(0, 30px, 0); } .circ { transform: translate3d(30px, 0, 0) scale(0.5); } .text { transform: rotate(90deg) scaleX(0.08) translate3d(-300px, -35px, 0); } .footer { transform: translateX(100px, 0, 0); } }

Here is a reduced codepen without the page transitions, but just to show the movement:

See the Pen layout transition-group by Sarah Drasner (@sdras) on CodePen.

I want to point out that any implementations I use here are choices that I've made for placement and movement- you can really create any effect you like! I am choosing SVG here because it communicates the concept of layout in a small amount of code, but you don't need to use SVG. I'm also using transitions instead of animation because of how declarative they are by nature- you are in essence stating: "I want this to be repositioned here when this class is toggled in Vue", and then the transition's only job is to describe the movement as anything changes. This is great for this use-case because it's very flexible. I can then decide to change it to any other conditional placement and it will still work.

Great! This will now give us the effect, smooth as butter between pages, and we can still give the content of the page a nice little transition as well:

.page-enter-active { transition: opacity 0.25s ease-out; } .page-leave-active { transition: opacity 0.25s ease-in; } .page-enter, .page-leave-active { opacity: 0; }

I've also added in one of the examples from the Nuxt site to show that you can still do internal animations within the page as well:

View GitHub Repo

Ok, that works for a small demo, but now let’s apply it to something more real-world, like our example from before. Again, the demo site is here and the repo with all of the code is here.

It’s the same concept:

  • We store the name of the page in the Vuex store.
  • Middleware commits a mutation to let the store know the page has changed.
  • We apply a special class per page, and nest transitions for each page.
  • The navigation stays consistent on each page but we have different positions and apply some transitions.
  • The content of the page has a subtle transition and we build in some interactions based on user events

The only difference is that this is a slightly more involved implementation. The CSS that's applied to the elements will stay the same in the navigation component. We can tell the browser what position we want all the elements to be in, and since there's a transition applied to the element itself, that transition will be applied and it will move to the new position every time the page has changed.

// animations .place { .follow { transform: translate3d(-215px, -80px, 0); } .profile-photo { transform: translate3d(-20px, -100px, 0) scale(0.75); } .profile-name { transform: translate3d(140px, -125px, 0) scale(0.75); color: white; } .side-icon { transform: translate3d(0, -40px, 0); background: rgba(255, 255, 255, 0.9); } .calendar { opacity: 1; } }

That’s it! We keep it nice and simple and use flexbox, grid and absolute positioning in a relative container to make sure everything translates easily across all devices and we have very few media queries through this project. I’m mainly using CSS for the nav changes because I can declaratively state the placement of the elements and their transitions. For the micro-interactions of any user-driven event, I’m using JavaScript and GreenSock, because it allows me to coordinate a lot of movement very seamlessly and stabilizes transform-origin across browsers, but there are so many ways you could implement this. There are a million ways I could improve this demo application, or build on these animations, it's a quick project to show some possibilities in a real-life context.

Remember to hardware accelerate and use transforms, and you can achieve some beautiful, native-like effects. I’m excited to see what you make! The web has so much potential for beautiful movement, placement, and interaction that reduces cognitive load for the user.

The post Native-Like Animations for Page Transitions on the Web appeared first on CSS-Tricks.

Choosing a Responsive Email Framework: MJML vs. Foundation for Emails

Css Tricks - Fri, 04/20/2018 - 3:58am

Implementing responsive email design can be a bit of a drag. Building responsive emails isn’t simple at all, it is like taking a time machine back to 2001 when we were all coding website layouts in tables using Dreamweaver and Fireworks.

But there's hope! We have tools available that can make building email much easier and more like coding a modern site. Let’s take a look at a couple of different frameworks that set out to simplify things for us.

First, the Situation

You have to be compatible with lots of old email clients, many of which don’t even support the most basic web standards (floats, anyone?). You also have to deal with all sorts of webmail clients which, for security or technical reasons, have made their own opinionated choices about how to display your precious email.

Furthermore, now emails are read from different devices, with very different viewports and requirements.

The best solution, as is often the case, would be to keep things simple and stick to basic one-column designs, using multiple columns only for menus or simple interface elements of known width. You can produce great, effective designs using only one column, after all.

However end-users and clients, who are used to the “normal” browser-based web, may hold their email-viewing experience to the same high standards they do for viewing web pages in terms of graphics and responsiveness. Therefore, complex designs are expected: multiple columns, different behaviors on mobile devices as opposed to desktops, lots of images, etc., all of which have to be implemented consistently and pixel-perfect across all email clients. What options are available to make all that happen?

Option 1: Build From Scratch

One option you could choose is coding each email by hand, keeping it simple, and testing it while you go. This is a viable option only if:

  1. You have a very simple design to implement.
  2. You have direct control of the design, so you can eventually simplify things if you can’t come out with a consistent solution for what you intended to do.
  3. You can accept some degree of degradation on some older clients: you don’t mind if your email won’t look exactly the same (or even plain bad) in old Outlook clients, for example.
  4. You have a lot of time on your hands.

Obviously, you need to test your design heavily. Campaign Monitor has a great CSS guide you can reference during the build process and is sort of like Can I Use, but for email. After that, I recommend using automated test suites like Litmus or Email on Acid. Both offer you a complete testing suite and previews of how your email will look like on a huge variety of email clients. Expect some surprises, though, because often the same design does not look correct even on the same email client, if viewed on different browsers, or different operating systems. Fonts will render differently, margins will change, and so on.

Screenshot of the same email design tested on different devices on Email on Acid. Option 2: Use a Boilerplate Template

Another option is to use one of the various boilerplates available, like Sean Powelll's, which you can find here. Boilerplates already address many of the quirks of different email clients and platforms. This is sensible if:

  1. You are working alone, or on a small team.
  2. You have lots of experience, so you already know most of the quirks of email formatting because you’ve met them before.
  3. You have set up your own tools for managing components (for different newsletters which share some pieces of design), inlining styles (and yes, you should keep inlining your styles if your emails target an international audience), and have some kind of development toolkit in place (be it Gulp, Grunt or something similar) which will automate all of that for you.
  4. You have the kind of approach where you’d like to control everything in the code you produce and don’t like to rely on external tools.
  5. You prefer to solve your own bugs instead of having to solve possible bugs caused by the tool you are using.
Option 3: Use a Framework

However, if any of the following points are valid for you:

  1. You have to produce a lot of email templates with shared components.
  2. The job has to be carried out by a team of developers, who might change and/or have a variable degree of proficiency and experience with email implementation.
  3. You have little or no control on the original design.

...then you will likely benefit a lot from using a framework.

Currently, two of the most interesting and popular frameworks available are MJML and Foundation for Emails. The biggest advantages in using either framework is that they have already solved for you most of the quirks of email clients. They also provide you with an established workflow you can follow, both alone and as a team. They also handle responsive design very well, albeit differently from one another.

Let’s look at an overview of both frameworks and compare the best use cases for each before drawing some conclusions.

MJML

MJML is a project that was created internally by Mailjet, a company specializing in email marketing tools. It was then open-sourced. It works with its own custom, HTML-like templating language, using its own tags. For example:

<mj-text>Your text here</mj-text>

When you compile the final code, MJML will convert their tags into HTML for everything from tables to custom components they have created for you, all using its internal engine. It takes out the heavy lifting for creating complex markup and it’s all been tested.

MJML has a set of standard components. They include sections, columns, groups, buttons, images, social links (which are very easy to create), tables, accordions, etc. They even include a pre-styled carousel, which should work in most clients. All of these components translate well into responsive emails, apart from the “invoice” component which I could not get to work in my tests. All of these components have parameters you can pass in your code to customize their appearance.

For example, the social links component allows you to stack icons vertically and horizontally, and to choose background colors for the related icons. There are actually a lot more parameters you can play with, all with the intent of allowing for greater flexibility. Even the logo image files are already included in the package, which is a great plus.

Here’s a preview of a simple configuration of the social links component:

Screenshot from the MJML website.

You can also create your own custom components, or use components created by the community. There is just one community component available at the moment, however.

MJML handles responsiveness automatically, meaning that components will switch from multi-column (more items in the same row) to single-column (items are put one under the other instead of side-by-side) without any active intervention from the developer. This is a very flexible solution, and works fine in most cases, but it gives the developer a little less control over what happens exactly in the template. As the docs mention, it's worth keeping mind that:

For aesthetics purposes, MJML currently supports a maximum of 4 columns per section.

This is most likely not only an aesthetic preference but also about limiting possible drawbacks of having too many columns. The more columns you have, the more unpredictable the output, I guess.

How to Work With MJML

MJML can work as a command line tool, which you can install with npm, and output your files locally, with commands like:

$ mjml -r index.mjml -o index.html

This can be integrated in your build procedure via Gulp or the like, and in your development work by using a watch command, which will update your preview every time you save:

$ mjml --watch index.mjml -o index.html

MJML has plugins for Atom and Sublime Text. In Atom, it even supplies a real-time preview of your layout, which can be regenerated on every save. I haven’t tried it personally, but it seems very interesting:

Image from Atom.io

MJML also has its own simple desktop app, and it’s free. You can set up your code and components, have it build your designs for you, and get a real-time preview of the results, both for mobile and for desktop. I find that it works pretty well on Ubuntu, but the only drawback I’ve found is that you should never, never, never open your files with another editor while they’re open on the app, because the app crashes and the content of the file gets lost.

Here are some screenshots of the previews at work:

Desktop preview of email Mobile preview of email

The app can also be integrated with a free Mailjet account, which allows you to send test emails immediately to yourself. This is very handy to quickly check problematic clients if you have them available directly. (I would suggest taking out that old Windows machine you have in the storage room to check things in Outlook, and to do it as often as possible.) However, I would still recommend using either Litmus or Email on Acid to test your emails cross-client before deploying them because you can never be too careful and email standards can change just like they do in browsers.

Overall, I have found MJML very easy to use. However, when I tried to make a pixel-perfect template which was identical to the design our client requested, I had some difficulties dealing with custom margins for some images. Not all of the component parameters available worked as expected from their description in the documentation. In particular, I had some problems customizing image margins and padding between desktop and mobile.

Advantages
  • Pre-built components
  • Integration with Mailjet
  • Easy to use, with instant preview of your work (on Atom and Desktop App)
Disadvantages
  • A bit less reliable than Foundation for Emails if you have to do pixel-perfect designs
  • Some components have parameters that don’t work as expected
  • Desktop App not perfectly stable
  • Does not come with a structured set of folders for your content (see Foundation below)
Foundation for Emails

Foundation for Emails (formerly known as Ink — insert obligatory Prince quote here) is a framework by Zurb, the same folks who brought us the responsive front-end framework, Foundation for Sites.

When you download the Starter Kit you get a full development environment, complete with Node.js commands to run your project. It will setup a Node routine and even open your browser to give you an immediate preview of your work.

The files you have to use are already organized in folders and subfolders, with a clear indication of where to put your stuff. For example, it has directories specifically for partials, templates and images. I find this feature very important, because it is very easy to end up using different folders when you work on a team, and this leads to a lot of lost time looking for stuff that isn’t where you expect it to be. Enforcing conventions is not a limitation; when you work in a team it is indispensable.

TFFKAI — The Framework Formerly Known As Ink

Foundation for Emails comes with a boilerplate template, which is the starting point for your code. It is fully annotated, so you know how to extend it with your code. It comes with SASS/SCSS support, which is very very handy for complex projects. It also comes with its own inliner, so you don’t have to worry about converting all your CSS (or SASS/SCSS) into inline styles.

There’s a template engine behind this framework called Inky. And, just like MJML, it has custom tags that will automatically convert to HTML when it’s compiled. There are tags like <container>, <row>, <column>, which will be used to build your grid. The grid is based on a 12-column system, which allows you to subdivide your layout very accurately. Why 12? Because it is divisible by 2, 3, 4 and 6, making it very easy to make a 2-column, 3-column, 4-column, or 6-column layout.

Foundation for Emails uses Panini to compile the code. Panini is a custom library which compiles HTML pages using layouts. It supports Handlebars syntax and there are several helpers you can use to customize the behavior of components depending on where they’re being used. You can also create your own helpers if you need to and set each template’s custom variables with custom data. This is very useful if you have several templates sharing the same components.

There are several pre-built email templates available you can download, which cover many of the standard use cases for email, like newsletters and announcements. There are also a few pre-built components (with their own custom tags), including buttons, menus and callouts (which, I have to admit, I don’t see a purpose for in emails, but never mind).

A code sample from a Foundation for Emails template.

The main difference between Foundation for Emails with MJML is that Foundation for Emails defaults to desktop view, then scales for smaller screens. According to the docs, this is because many desktop clients do not support media queries and defaulting to the large screen layout makes it more compliant across email clients. That said, it only manages one breakpoint. You create the desktop version and the mobile version, and the mobile version switches under a certain number of pixels, which can be configured.

You can decide whether some components will be visible only on large or small screens using handy pre-defined classes like .hide-for-large and .show-for-large (although .hide-for-large might not be supported by all clients). You can also decide how much space a column will take by using specific classes. For example, a class of .large-6 and .small-12 on a div will make a column that occupies half the screen on desktop and the whole screen width on mobile. This allows for very specific and predictable layout results.

A preview of the same e-mail template, developed with Foundation for Emails, on Outlook 2007 (left) and iPhoneX (right).

Foundation for Emails is a bit clunkier to use than MJML, in my opinion, but it does allow for much tighter control on the layout. That makes it ideal for projects where you need to reproduce pixel-perfect designs, with very specific differences between mobile and desktop layouts.

Advantages
  • A more precise control over end results
  • Pre-built templates
  • Sass support
  • Great documentation
Disadvantages
  • The project file size is heavy and takes a lot of disk space
  • A little less intuitive to use than MJML's pre-defined parameters on components
  • Fewer components available for custom layouts
Conclusions

Producing email templates, even less than front-end development, is not an exact science. It requires a lot of trial and error and a LOT of testing. Whatever tool you use, if you need to support old clients, then you need to test the hell out of your layouts — especially if they have even the smallest degree of complexity. For example, if you have text that needs to sit beside an image, I recommend testing with content at different lengths and see what happens in all clients. If you have text that needs to overlap an image, it can be a bit of a nightmare.

The more complex the layout and the less control you have over the layout, then the more useful it is to use a framework over hand-coding your own emails, especially if the design is handed to you by a third party and has to be implemented as-is.

I wouldn't say that one framework is better than the other and that's not the point of this post. Rather, I would recommend MJML and Foundation for Emails for different use cases:

  • MJML for projects that have a quick turnaround and there is flexibility in the design.
  • Foundation for Emails for projects that require tighter control over the layout and where design is super specific.
Resources and Links

The post Choosing a Responsive Email Framework: MJML vs. Foundation for Emails appeared first on CSS-Tricks.

What are Higher-Order Components in React?

Css Tricks - Thu, 04/19/2018 - 3:58am

If you have been in the React ecosystem for a while, there is a possibility that you have heard about Higher Order Components. Let’s look at a simple implementation while also trying to explain the core idea. From here you should get a good idea of how they work and even put them to use.

Why Higher-Order Components?

As you build React applications, you will run into situations where you want to share the same functionality across multiple components.

For example: you need to manage the state of currently logged in users in your application. Instead of managing that state across all of the components that need that state, you could create a higher-order component to separate the logged in user state into a container component, then pass that state to the components that will make use of it.

The components that receive state from the higher-order component will function as presentational components. State gets passed to them and they conditionally render UI based on it. They do not bother with the management of state.

Let's see another example. Say you have three JSON files in your application. These files contain different data that will be loaded in your application in three different components. You want to give your users the ability to search the data loaded from these files. You could implement a search feature in all three of the components. This duplication may not be an issue at first, but as your application grows and more components need this functionality, the constant duplication will be cumbersome and prone to problems.

A better way forward is to create a higher-order component to handle the search functionality. With it, you can wrap the other components individually in your higher-order component.

How do Higher-Order Components Work?

The React docs say that higher-order components take a component and return a component.

The use of higher-order components comes in handy when you are architecturally ready for separating container components from presentation components. The presentation component is often a stateless functional component that takes props and renders UI. A stateless functional components are plain JavaScript functions that do not have states. Here’s an example:

import React from 'react' const App = ({name}) => { return ( <div> <h2>This is a functional component. Your name is {name}.</h2> </div> ) } ReactDOM.render(<App name='Kingsley' />, document.getElementById("root"));

The container component does the job of managing of state. The container, in this case, is the higher-order component.

In the search example we talked about earlier, the search component would be the container component that manages the search state and wraps the presentation components that need the search functionality. The presentation components otherwise have no idea of state or how it is being managed.

A Higher-Order Component Example

Let's start with a basic example. Here’s a higher-order component that transforms and returns usernames in uppercase:

const hoc = (WrappedComponent) => (props) => { return ( <div> <WrappedComponent {...props}> {props.children.toUpperCase()} </WrappedComponent> </div> ) }

This higher-order component receives a WrappedComponent as an argument. Then it returns new component with props passed to it creating a React element. We call .toUpperCase() on the props.children, to transform the passed props.children to uppercase.

To make use of this higher-order component, we need to create a component that receives props and renders the children.

const Username = (props) => ( <div>{props.children}</div> )

Next, we wrap Username with the higher-order component. Let's store that in a variable:

const UpperCaseUsername = hoc(Username)

In our App component, we can now make use of it like this:

const App = () => ( <div> <UpperCaseUsername>Kingsley</UpperCaseUsername> </div> );

The UpperCaseUsername component is merely a rendering of the Username UI that, in turn, pulls in state from the WrappedComponent acting as the higher-order component.

A More Practical Higher-Order Component

Imagine we want to create a list of locations with a search form that filters them. The JSON will be in flat files and loaded as separate components. Let’s start by loading the data.

Our first component will load locations for our users. We will make use of .map() to loop through the data contained in that JSON file.

import React from 'react' // Where the data is located import preload from './locations.json' // Manages the data import LocationCard from './LocationCard' // Renders the presentation of the data const Location = (props) => { return ( <div> <div> <div> <h2>Preferred Locations</h2> </div> </div> <div> {preload.data .map(location => <LocationCard key={location.id} {...location} />)} </div> </div> ) } export default Location

This component will render the data in a LocationCard component. I moved that to a different component to keep things clear. This component is a functional component that handles the presentation of our data. The data (location) from the file is received via props, and each location will be passed down to the LocationCard component.

Now we need a second component that, eventually, also will need search functionality. It will be very similar to the first component we just built, but it will have a different name and load data from a different place.

We want our users to be able to search for items using an input field. The list of items displayed on the app should be determined by the state of the search. This functionality will be shared across the two components we are working on. Thanks to the idea of higher order components, we can create a search container component and wrap it around other components.

Let's call the component withSearch. This component will render the input field for our search and also manage our searchTerm state. The searchTerm will be passed as props to the wrapped component, which will be used to filter the pulled data:

import React, { Component } from 'react' const withSearch = (WrappedComponent) => { return class extends Component { state = { searchTerm: '' } handleSearch = event => { this.setState({ searchTerm: event.target.value }) } render() { return ( <div> <div> <input onChange={this.handleSearch} value={this.state.searchTerm} type="text" placeholder="Search" /> </div> <WrappedComponent searchTerm={this.state.searchTerm} /> </div> ) } } } export default withSearch

The searchTerm is given a state of an empty string. The value entered by the user in the search box is obtained and used to set the new state for searchTerm. Next, we pass searchTerm to the WrappedComponent. We will make use of this when filtering the data.

To make use of the higher-order component, we need to make some changes to our presentational component.

import React, { Component } from 'react' // Where the data is located import preload from './locations.json' // Searches the data import withSearch from './withSearch // Manages the data import LocationCard from './LocationCard' // Renders the presentation of the data const Location = (props) => { const { searchTerm } = props return ( <div> <div> <div> <h2>Preferred Locations</h2> </div> </div> <div> {preload.data // Filter locations by the inputted search term .filter(location => `${location.name} ${location.zone} ${location.region}`.toUpperCase().indexOf(searchTerm.toUpperCase()) >= 0) // Loop through the locations .map(location => <LocationCard key={location.id} {...location} />)} </div> </div> ) } export default withSearch(Location)

The first thing we did above is to import the higher-order component. Then we add a filter method to filter the data based on what the user enters in the search input. Last, we need to wrap it with the withSearch component.

See the Pen hoc Pen by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Conclusion

Higher-Order Components do not have to be scary. After understanding the basics, you can put the concept to use by abstracting away functionalities that can be shared among different components.

More Resources

The post What are Higher-Order Components in React? appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.