emGee Software Solutions Custom Database Applications

Share this

CSS-Tricks

Tips, Tricks, and Techniques on using Cascading Style Sheets.
Updated: 1 week 18 hours ago

HTML for Zip Codes

Mon, 10/15/2018 - 16:56

I just overheard this discussion on Twitter, kicked off by Dave.

Me (coding a form): <input id="zip" type="number">
Tiny Devil (appears on shoulder): Yaaas! I love the optimism, ship it!
Me: Wait, why are you here? Is this going to blow up on me? What do you know that I don't?

— Dave SPOOPert (@davatron5000) October 9, 2018

It seems like zip codes are just numbers, right? So...

<input id="zip" name="zip" type="number">

The advantage there being able to take advantage of free validation from the browser, and triggering a more helpful number-based keyboard on mobile devices.

But Zach pointed out that type="number" is problematic for zip codes because zip codes can have leading zeros (e.g. a Boston zip code might be 02119). Filament group also has a little lib for fixing this.

This is the perfect job for inputmode, as Jeremy suggests<input id="zip" name="zip" type="text" inputmode="numeric" pattern="^(?(^00000(|-0000))|(\d{5}(|-\d{4})))$">

But the support is pretty bad at the time of this writing.

A couple of people mentioned trying to hijack type="tel" for it, but that has its own downsides, like rejecting properly formatted 9-digit zip codes.

So, zip codes, while they look like numbers, are probably best treated as strings. Another option here is to leave it as a text input, but force numbers with pattern, as Pamela Fox documents:

<input id="zip" name="zip" type="text" pattern="[0-9]*">

The post HTML for Zip Codes appeared first on CSS-Tricks.

Categories: Web Technologies

Sass Selector Combining

Mon, 10/15/2018 - 16:56

Brad Frost was asking about this the other day...

Sass people, which way do you do it and why? pic.twitter.com/dIBA9BIuCO

— Brad Frost (@brad_frost) October 1, 2018

.c-btn { &__icon { ... } }

I guess that's technically "nesting" but the selectors come out flat:

.c-button__icon { }

The question was whether you do that or just write out the whole selector instead, as you would with vanilla CSS. Brad's post gets into all the pro's and con's of both ways.

To me, I'm firmly in the camp of not "nesting" because it makes searching for selectors so much harder. I absolutely live by being able to search my project for fully expanded class names and, ironically, just as Brad was posting that poll, I was stumped by a combined class like this and changed it in one of my own code bases.

Robin Rendle also notes the difficulty in searching as an issue with an example that has clearly gone too far!

Direct Link to ArticlePermalink

The post Sass Selector Combining appeared first on CSS-Tricks.

Categories: Web Technologies

Lazy Loading Images with Vue.js Directives and Intersection Observer

Mon, 10/15/2018 - 07:00

When I think about web performance, the first thing that comes to my mind is how images are generally the last elements that appear on a page. Today, images can be a major issue when it comes to performance, which is unfortunate since the speed a website loads has a direct impact on users successfully doing what they came to the page to do (think conversation rates).

Very recently, Rahul Nanwani wrote up an extensive guide on lazy loading images. I’d like to cover the same topic, but from a different approach: using data attributes, Intersection Observer and custom directives in Vue.js.

What this’ll basically do is allow us to solve two things:

  1. Store the src of the image we want to load without loading it in the first place.
  2. Detect when the image becomes visible to the user and trigger the request to load the image.

Same basic lazy loading concept, but another way to go about it.

I created an example, based on an example described by Benjamin Taylor in his blog post. It contains a list of random articles each one containing a short description, image, and a link to the source of the article. We will go through the process of creating a component that is in charge of displaying that list, rendering an article, and lazy loading the image for a specific article.

Let’s get lazy! Or at least break this component down piece-by-piece.

Step 1: Create the ImageItem component in Vue

Let’s start by creating a component that will show an image (but with no lazy loading involved just yet). We’ll call this file ImageItem.vue. In the component template, we’ll use a figure tag that contains our image — the image tag itself will receive the src attribute that points to the source URL for the image file.

<template> <figure class="image__wrapper"> <img class="image__item" :src="source" alt="random image" > </figure> </template>

In the script section of the component, we receive the prop source that we’ll use for the src url of the image we are displaying.

export default { name: "ImageItem", props: { source: { type: String, required: true } } };

All this is perfectly fine and will render the image normally as is. But, if we leave it here, the image will load straight away without waiting for the entire component to be render. That’s not what we want, so let’s go to the next step.

Step 2: Prevent the image from being loaded when the component is created

It might sound a little funny that we want to prevent something from loading when we want to show it, but this is about loading it at the right time rather than blocking it indefinitely. To prevent the image from being loaded, we need to get rid of the src attribute from the img tag. But, we still need to store it somewhere so we can make use of it when we want it. A good place to keep that information is in a data- attribute. These allow us to store information on standard, semantic HTML elements. In fact, you may already be accustomed to using them as JavaScript selectors.

In this case, they’re a perfect fit for our needs!

<!--ImageItem.vue--> <template> <figure class="image__wrapper"> <img class="image__item" :data-url="source" // yay for data attributes! alt="random image" > </figure> </template>

With that, our image will not load because there is no source URL to pull from.

That’s a good start, but still not quite what we want. We want to load our image under specific conditions. We can request the image to load by replacing the src attribute with the image source URL kept in our data-url attribute. That’s the easy part. The real challenge is figuring out when to replace it with the actual source.

Our goal is to pin the load to the user’s screen location. So, when the user scrolls to a point where the image comes into view, that’s where it loads.

How can we detect if the image is in view or not? That’s our next step.

Step 3: Detect when the image is visible to the user

You may have experience using JavaScript to determine when an element is in view. You may also have experience winding up with some gnarly script.

For example, we could use events and event handlers to detect the scroll position, offset value, element height, and viewport height, then calculate whether an image is in the viewport or not. But that already sounds gnarly, doesn’t it?

But it could get worse. This has direct implications on performance. Those calculations would be fired on every scroll event. Even worse, imagine a few dozen images, each having to recalculate whether it is visible or not on each scroll event. Madness!

Intersection Observer to the rescue! This provides a very efficient way of detecting if an element is visible in the viewport. Specifically, it allows you to configure a callback that is triggered when one element — called the target — intersects with either the device viewport or a specified element.

So, what we need to do to use it? A few things:

  • create a new intersection observer
  • watch the element we wish to lazy load for visibility changes
  • load the element when the element is in viewport (by replacing src with our data-url)
  • stop watching for visibility changes (unobserve) after the load completes

Vue.js has custom directives to wrap all this functionality together and use it when we need it, as many times as we need it. Putting that to use is our next step.

Step 4: Create a Vue custom directive

What is a custom directive? Vue’s documentation describes it as a way to get low-level DOM access on elements. For example, changing an attribute of a specific DOM element which, in our case, could be changing the src attribute of an img element. Perfect!

We’ll break this down in a moment, but here’s what we’re looking at as far as the code:

export default { inserted: el => { function loadImage() { const imageElement = Array.from(el.children).find( el => el.nodeName === "IMG" ); if (imageElement) { imageElement.addEventListener("load", () => { setTimeout(() => el.classList.add("loaded"), 100); }); imageElement.addEventListener("error", () => console.log("error")); imageElement.src = imageElement.dataset.url; } } function handleIntersect(entries, observer) { entries.forEach(entry => { if (entry.isIntersecting) { loadImage(); observer.unobserve(el); } }); } function createObserver() { const options = { root: null, threshold: "0" }; const observer = new IntersectionObserver(handleIntersect, options); observer.observe(el); } if (window["IntersectionObserver"]) { createObserver(); } else { loadImage(); } } };

OK, let’s tackle this step-by-step.

The hook function allows us to fire a custom logic at a specific moment of a bound element lifecycle. We use the inserted hook because it is called when the bound element has been inserted into its parent node (this guarantees the parent node is present). Since we want to observe visibility of an element in relation to its parent (or any ancestor), we need to use that hook.

export default { inserted: el => { ... } }

The loadImage function is the one responsible for replacing the src value with data-url. In it, we have access to our element (el) which is where we apply the directive. We can extract the img from that element.

Next, we check if the image exists and, if it does, we add a listener that will fire a callback function when the loading is finished. That callback will be responsible for hiding the spinner and adding the animation (fade-in effect) to the image using a CSS class. We also add a second listener that will be called in the event that the URL fails to load.

Finally, we replace the src of our img element with the source URL of the image and show it!

function loadImage() { const imageElement = Array.from(el.children).find( el => el.nodeName === "IMG" ); if (imageElement) { imageElement.addEventListener("load", () => { setTimeout(() => el.classList.add("loaded"), 100); }); imageElement.addEventListener("error", () => console.log("error")); imageElement.src = imageElement.dataset.url; } }

We use Intersection Observer’s handleIntersect function, which is responsible for firing loadImage when certain conditions are met. Specifically, it is fired when Intersection Observer detects that the element enters the viewport or a parent component element.

The function has access to entries, which is an array of all elements that are watched by the observer and observer itself. We iterate through entries and check if a single entry becomes visible to our user with isIntersecting — and fire the loadImage function if it is. Once the image is requested, we unobserve the element (remove it from the observer’s watch list), which prevents the image from being loaded again. And again. And again. And…

function handleIntersect(entries, observer) { entries.forEach(entry => { if (entry.isIntersecting) { loadImage(); observer.unobserve(el); } }); }

The last piece is the createObserver function. This guy is responsible for creating our Intersection Observer and attaching it to our element. The IntersectionObserver constructor accepts a callback (our handleIntersect function) that is fired when the observed element passes the specified threshold and the options object that carries our observer options.

Speaking of the options object, it uses root as our reference object, which we use to base the visibility of our watched element. It might be any ancestor of the object or our browser viewport if we pass null. The object also specifies a threshold value that can vary from 0 to 1 and tells us at what percent of the target’s visibility the observer callback should be executed, with 0 meaning as soon as even one pixel is visible and 1 meaning the whole element must be visible.

And then, after creating the Intersection Observer, we attach it to our element using the observe method.

function createObserver() { const options = { root: null, threshold: "0" }; const observer = new IntersectionObserver(handleIntersect, options); observer.observe(el); } Step 5: Registering directive

To use our newly created directive, we first need to register it. There are two ways to do it: globally (available everywhere in the app) or locally (on a specified component level).

Global registration

For global registration, we import our directive and use the Vue.directive method to pass the name we want to call our directive and directive itself. That allows us to add a v-lazyload attribute to any element in our code.

// main.js import Vue from "vue"; import App from "./App"; import LazyLoadDirective from "./directives/LazyLoadDirective"; Vue.config.productionTip = false; Vue.directive("lazyload", LazyLoadDirective); new Vue({ el: "#app", components: { App }, template: "<App/>" }); Local registration

If we want to use our directive only in a specific component and restrict the access to it, we can register the directive locally. To do that, we need to import the directive inside the component that will use it and register it in the directives object. That will give us the ability to add a v-lazyload attribute to any element in that component.

import LazyLoadDirective from "./directives/LazyLoadDirective"; export default { directives: { lazyload: LazyLoadDirective } } Step 6: Use a directive on the ImageItem component

Now that our directive has been registered, we can use it by adding v-lazyload on the parent element that carries our image (the figure tag in our case).

<template> <figure v-lazyload class="image__wrapper"> <ImageSpinner class="image__spinner" /> <img class="image__item" :data-url="source" alt="random image" > </figure> </template> Browser Support

We’d be remiss if we didn’t make a note about browser support. Even though the Intersection Observe API it is not supported by all browsers, it does cover 73% of users (as of this writing).

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

DesktopChromeOperaFirefoxIEEdgeSafari584555No16NoMobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid FirefoxNo46No676962

Not bad. Not bad at all.

But! Having in mind that we want to show images to all users (remember that using data-url prevents the image from being loaded at all), we need to add one more piece to our directive. Specifically, we need to check if the browser supports Intersection Observer, and it it doesn’t, fire loadImage instead. This will be our fallback.

if (window["IntersectionObserver"]) { createObserver(); } else { loadImage(); } Summary

Lazy loading images can significantly improve page performance because it takes the page weight hogged by images and loads them in only when the user actually needs them.

For those still not convinced if it is worth playing with lazy loading, here’s some raw numbers from the simple example we’ve been using. The list contains 11 articles with one image per article. That’s a total of 11 images (math!). It’s not like that’s a ton of images but we can still work with it.

Here’s what we get rending all 11 images without lazy loading on a 3G connection:

The 11 image requests contribute to an overall page size of 3.2 MB. Oomph.

Here’s the same page putting lazy loading to task:

Say what? Only one request for one image. Our page is now 1.4 MB. We saved 10 requests and reduced the page size by 56%.

Is it a simple and isolated example? Yes, but the numbers still speak for themselves. Hopefully you find lazy loading an effective way to fight the battle against page bloat and that this specific approach using Vue with Intersection Observer comes in handy.

The post Lazy Loading Images with Vue.js Directives and Intersection Observer appeared first on CSS-Tricks.

Categories: Web Technologies

POSTing an Indeterminate Checkbox Value

Fri, 10/12/2018 - 12:02

There is a such thing as an indeterminate checkbox value. It's a checkbox (<input type="checkbox">) that isn't checked. Nor is it not checked. It's indeterminate.

We can even select a checkbox in that state and style it with CSS!

Some curious points though:

  1. It's only possible to set via JavaScript. There is no HTML attribute or value for it.
  2. It doesn't POST (or GET or whatever else) or have a value. It's like being unchecked.

So, say you had a form like this:

<form action="" method="POST" id="form"> <input name="name" type="text" value="Chris" /> <input name="vegetarian" type="checkbox" class="veg"> <input type="submit" value="Submit"> </form>

And, for whatever reason, you make that checkbox indeterminate:

let veg = document.querySelector(".veg"); veg.indeterminate = true;

If you serialize that form and take a look at what will POST, you'll get "name=Chris". No value for the checkbox. Conversely, had you checked the checkbox in the HTML and didn't touch it in JavaScript, you'd get "name=Chris&vegetarian=on".

Apparently, this is by design. Checkboxes are meant to be boolean, and the indeterminate value is just an aesthetic thing meant to indicate that visual "child" checkboxes are in a mixed state (some checked, some not). That's fine. Can't change it now without serious breakage of websites.

But say you really need to know on the server if a checkbox is in that indeterminate state. The only way I can think of is to have a buddy hidden input that you keep in sync.

<input name="vegetarian" type="checkbox" class="veg"> <input name="vegetarian-value" type="hidden" class="veg-value"> let veg = document.querySelector(".veg"); let veg_value = document.querySelector(".veg-value"); veg.indeterminate = true; veg_value.value = "indeterminate";

I've set the indeterminate value of one input and I've set another hidden input value to "indeterminate", which I can POST. Serialized means it looks like "name=Chris&vegetarian-value=indeterminate". Good enough.

See the Pen Can you POST an intermediate value? by Chris Coyier (@chriscoyier) on CodePen.

The post POSTing an Indeterminate Checkbox Value appeared first on CSS-Tricks.

Categories: Web Technologies

The Way We Talk About CSS

Fri, 10/12/2018 - 12:01

There’s a ton of very quotable stuff from Rachel Andrew’s latest post all about CSS and how we talk about it in the community:

CSS has been seen as this fragile language that we stumble around, trying things out and seeing what works. In particular for layout, rather than using the system as specified, we have so often exploited things about the language in order to achieve far more complex layouts than it was ever designed for. We had to, or resign ourselves to very simple looking web pages.

Rachel goes on to argue that we probably shouldn’t disparage CSS for being so weird when there are very good reasons for why and how it works — not to mention that it’s getting exponentially more predictable and powerful as time goes by:

There is frequently talk about how developers whose main area of expertise is CSS feel that their skills are underrated. I do not think we help our cause by talking about CSS as this whacky, quirky language. CSS is unlike anything else, because it exists to serve an environment that is unlike anything else. However we can start to understand it as a designed language, with much consistency. It has codified rules and we can develop ways to explain and teach it, just as we can teach our teams to use Bootstrap, or the latest JavaScript framework.

I tend to feel the same way and I’ve been spending a lot of time thinking about how best to reply to folks that argue that “CSS is dumb and weird.” It can sometimes be a demoralizing challenge, attempting to explain why your career and area of expertise is a useful one.

I guess the best way to start doing that is to stand up and say, “No, CSS is not dumb and weird. CSS is awesome!”

Direct Link to ArticlePermalink

The post The Way We Talk About CSS appeared first on CSS-Tricks.

Categories: Web Technologies

Styling the Gutenberg Columns Block

Fri, 10/12/2018 - 07:25

WordPress 5.0 is quickly approaching, and the new Gutenberg editor is coming with it. There’s been a lot of discussion in the WordPress community over what exactly that means for users, designers, and developers. And while Gutenberg is sure to improve the writing experience, it can cause a bit of a headache for developers who now need to ensure their plugins and themes are updated and compatible.

One of the clearest ways you can make sure your theme is compatible with WordPress 5.0 and Gutenberg is to add some basic styles for the new blocks Gutenberg introduces. Aside from the basic HTML blocks (like paragraphs, headings, lists, and images) that likely already have styles, you’ll now have some complex blocks that you probably haven’t accounted for, like pull quotes, cover images, buttons, and columns. In this article, we’re going to take a look at some styling conventions for Gutenberg blocks, and then add our own styles for Gutenberg’s Columns block.

Block naming conventions

First things first: how are Gutenberg blocks named? If you’re familiar with the code inspector, you can open that up on a page using the block you want to style, and check it for yourself:

The Gutenberg Pull Quote block has a class of wp-block-pullquote.

Now, it could get cumbersome to do that for each and every block you want to style, and luckily, there is a method to the madness. Gutenberg blocks use a form of the Block, Element, Modifier (BEM) naming convention. The main difference is that the top level for each of the blocks is wp . So, for our pull quote, the name is wp-block-pullquote. Columns would be wp-block-columns, and so on. You can read more about it in the WordPress Development Handbook.

Class name caveat

There is a small caveat here in that the block name may not be the only class name you’re dealing with. In the example above, we see that the class alignright is also applied. And Gutenberg comes with two new classes: alignfull and alignwide. You’ll see in our columns that there’s also a class to tell us how many there are. But we’ll get to that soon.

Applying your own class names

Gutenberg blocks also give us a way to apply our own classes:

The class added to the options panel in the Gutenberg editor (left). It gets applied to the element, as seen in DevTools (right).

This is great if you want to have a common set of classes for blocks across different themes, want to apply previously existing classes to blocks where it makes sense, or want to have variations on blocks.

Much like the current (or “Classic") WordPress post editor, Gutenberg makes as few choices as possible for the front end, leaving most of the heavy lifting to us. This includes the columns, which basically only include enough styles to make them form columns. So we need to add the padding, margins, and responsive styles.

Styling columns

Time to get to the crux of the matter: let’s style some columns! The first thing we’ll need to do is find a theme that we can use. There aren’t too many that have extensive Gutenberg support yet, but that’s actually good in our case. Instead, we’re going to use a theme that’s flexible enough to give us a good starting point: Astra.

Astra is available for free in the WordPress Theme Directory. (Source)

Astra is a free, fast, and flexible theme that has been designed to work with page builders. That means that it can give us a really good starting template for our columns. Speaking of which, we need some content. Here’s what we’ll be working with:

Our columns inside the Gutenberg editor.

We have a three-column layout with images, headings, and text. The image above is what the columns look like inside the Gutenberg editor. Here’s what they look like on the front end:

Our columns on the front end.

You can see there are a few differences between what we see in the editor and what we see on the front end. Most notably, there is no spacing in between the columns on the front end. The left end of the heading on the front end is also lined up with the left edge of the first column. In the editor, it is not because we’re using the alignfull class.

Note: For the sake of this tutorial, we're going to treat .alignfull, .alignwide, and no alignment the same, since the Astra theme does not support the new classes yet.

How Gutenberg columns work

Now that we have a theme, we to answer the question: “how do columns in Gutenberg work?"

Until recently, they were actually using CSS grid, but then switched to flexbox. (The reasoning was that flexbox offers wider browser support.) That said, the styles are super light:

.wp-block-columns { display: flex; } .wp-block-column { flex: 1; }

We’ve got a pen with the final styles if you want to see the result we are aiming for. You can see in it that Gutenberg is only defining the flexbox and then stating each column should be the same length. But you’ll also notice a couple of other things:

  • The parent container is wp-block-columns.
  • There’s also the class has-3-columns, noting the number of columns for us. Gutenberg supports anywhere from two to six columns.
  • The individual columns have the class wp-block-column.

This information is enough for us to get started.

Styling the parents

Since we have flexbox applied by default, the best action to take is to make sure these columns look good on the front end in a larger screen context like we saw earlier.

First and foremost, let’s add some margins to these so they aren’t running into each other, or other elements:

/* Add vertical breathing room to the full row of columns. */ .wp-block-columns { margin: 20px 0; } /* Add horiztonal breathing room between individual columns. */ .wp-block-column { margin: 0 20px; }

Since it’s reasonable to assume the columns won’t be the only blocks on the page, we added top and bottom margins to the whole parent container so there’s some separation between the columns and other blocks on the page. Then, so the columns don’t run up against each other, we apply left and right margins to each individual column.

Columns with some margins added.

These are starting to look better already! If you want them to look more uniform, you can always throw text-align: justify; on the columns, too.

Making the columns responsive

The layout starts to fall apart when we move to smaller screen widths. Astra does a nice job with reducing font sizes as we shrink down, but when we start to get around 764px, things start to get a little cramped:

Our columns at 764px wide.

At this point, since we have three columns, we can explicitly style the columns using the .has-3-columns class. The simplest solution would be to remove flexbox altogether:

@media (max-width: 764px) { .wp-block-columns.has-3-columns { display: block; } }

This would automatically convert our columns into blocks. All we’d need to do now is adjust the padding and we’re good to go — it’s not the prettiest solution, but it’s readable. I’d like to get a little more creative, though. Instead, we’ll make the first column the widest, and then the other two will remain columns under the first one.

This will only work depending on the content. I think here it’s forgivable to give Yoda priority as the most notable Jedi Master.

Let’s see what that looks like:

@media screen and (max-width: 764px) { .wp-block-columns.has-3-columns { flex-flow: row wrap; } .has-3-columns .wp-block-column:first-child { flex-basis: 100%; } }

In the first few lines after the media query, we’re targeting .has-3-columns to change the flex-flow to row wrap. This will tell the browser to allow the columns to fill the container but wrap when needed.

Then, we target the first column with .wp-block-column:first-child and we tell the browser to make the flex-basis 100%. This says, “make the first column fill all available space." And since we’re wrapping columns, the other two will automatically move to the next line. Our result is this:

Our newly responsive columns.

The nice part about this layout is that with row wrap, the columns all become full-width on the smallest screens. Still, as they start to get hard to read before that, we should find a good breakpoint and set the styles ourselves. Around 478px should do nicely:

@media (max-width: 478px) { .wp-block-columns.has-3-columns { display: block; } .wp-block-column { margin: 20px 0; } }

This removes the flex layout, and reverses the margins on the individual columns, maintaining the spacing between them as they move to a stacked layout.

Our small screen layout.

Again, you can see all these concepts come together in the following demo:

See the Pen Gutenberg Columns by Joe Casabona (@jcasabona) on CodePen.

If you want to see a different live example, you can find one here.

Wrapping up

So, there you have it! In this tutorial, we examined how Gutenberg’s Columns block works, it’s class naming conventions, and then applied basic styles to make the columns look good at every screen size on the front end. From here, you can take this code and run with it — we’ve barely scratched the surface and you can do tons more with the CSS alone. For example, I recently made this pricing table using only Gutenberg Columns:

(Live Demo)

And, of course, there are the other blocks. Gutenberg puts a lot of power into the hands of content editors, but even more into the hands of theme developers. We no longer need to build the infrastructure for doing more complex layouts in the WordPress editor, and we no longer need to instruct users to insert shortcodes or HTML to get what need on a page. We can add a little CSS to our themes and let content creators do the rest.

If you want to get more in-depth into preparing your theme for Gutenberg, you can check out my course, Theming with Gutenberg. We go over how to style lots of different blocks, set custom color palettes, block templates, and more.

The post Styling the Gutenberg Columns Block appeared first on CSS-Tricks.

Categories: Web Technologies

Valid CSS Content

Thu, 10/11/2018 - 07:03

There is a content property in CSS that's made to use in tandem with the ::before and ::after pseudo elements. It injects content into the element.

Here's an example:

<div data-done="&#x2705;" class="email"> chriscoyier@gmail.com </div> .email::before { content: attr(data-done) " Email: "; /* This gets inserted before the email address */ }

The property generally takes anything you drop in there. However, there are some invalid values it won't accept. I heard from someone recently who was confused by this, so I had a little play with it myself and learned a few things.

This works fine:

/* Valid */ ::after { content: "1"; }

...but this does not:

/* Invalid, not a string */ ::after { content: 1; }

I'm not entirely sure why, but I imagine it's because 1 is a unit-less number (i.e. 1 vs. 1px) and not a string. You can't trick it either! I tried to be clever like this:

/* Invalid, no tricks */ ::after { content: "" 1; }

You can output numbers from attributes though, as you might suspect:

<div data-price="4">Coffee</div> /* This "works" */ div::after { content: " $" attr(data-price); }

But of course, you'd never use generated content for important information like a price, right?! (Please don't. It's not very accessible, nor is the text selectable.)

Even though you can get and display that number, it's just a string. You can't really do anything with it.

<div data-price="4" data-sale-modifier="0.9">Coffee</div> /* Not gonna happen */ div::after { content: " $" calc(attr(data-price) * attr(data-sale-modifier)); }

You can't use numbers, period:

/* Nope */ ::after { content: calc(2 + 2); }

Heads up! Don't try concatenating strings like you might in PHP or JavaScript:

/* These will break */ ::after { content: "1" . "2" . "3"; content: "1" + "2" + "3"; /* Use spaces */ content: "1" "2" "3"; /* Or nothing */ content: "1 2 3"; /* The type of quote (single or double) doesn't matter, but content not coming back from attr() does need to be quoted. */ }

There is a thing in the spec for converting attributes into the actual type rather than treating them all like strings...

<wood length="12" /> wood { width: attr(length em); /* or other values like "number", "px", or "url" */ }

...but I'm fairly sure that isn't working anywhere yet. Plus, it doesn't help us with pseudo elements anyway, since strings already work and numbers don't.

The person who reached out to me over email was specifically confused why they were unable to use calc() on content. I'm not sure I can help you do math in this situation, but it's worth knowing that pseudo elements can be counters, and those counters can do their own limited form of math. For example, here's a counter that starts at 12 and increments by -2 for each element at that level in the DOM.

See the Pen Backwards Double Countdown by Chris Coyier (@chriscoyier) on CodePen.

The only other thing we haven't mentioned here is that a pseudo element can be an image. For example:

p:before { content: url(image.jpg); }

...but it's weirdly limited. You can't even resize the image. ¯\_(ツ)_/¯

Much more common is using an empty string for the value (content: "";) which can do things like clear floats but also be positioned, sized and have a background of its own.

The post Valid CSS Content appeared first on CSS-Tricks.

Categories: Web Technologies

Quick Tip: Debug iOS Safari on a true local emulator (or your actual iPhone/iPad)

Thu, 10/11/2018 - 07:02

We've been able to do this for years, largely for free (ignoring the costs of the computer and devices), but I'm not sure as many people know about it as they should.

TL;DR: XCode comes with a "Simulator" program you can pop open to test in virtual iOS devices. If you then open Safari's Develop/Debug menu, you can use its DevTools to inspect right there — also true if you plug in your real iOS device.

Direct Link to ArticlePermalink

The post Quick Tip: Debug iOS Safari on a true local emulator (or your actual iPhone/iPad) appeared first on CSS-Tricks.

Categories: Web Technologies

Deliver exceptional customer experiences in your product

Thu, 10/11/2018 - 06:58

(This is a sponsored post.)

​Pendo is a product cloud that helps create lovable products that customers can’t live without. Pendo enables product teams to understand product usage, collect user feedback, measure NPS, assist users in their apps and promote new features in product — all without requiring any engineering resources. This unique combination of capabilities is all built on a common infrastructure of product data and results in better onboarding, increased user engagement, improved customer satisfaction, reduced churn, and increased revenue.

Pendo is the proven choice of innovative product leaders at Salesforce, Marketo, Zendesk, Citrix, BMC and many more leading companies.

Request a demo of Pendo today.​

Direct Link to ArticlePermalink

The post Deliver exceptional customer experiences in your product appeared first on CSS-Tricks.

Categories: Web Technologies

The dialog element

Wed, 10/10/2018 - 13:28

Chris Manning digs into <dialog>:

A dialog element provides:

  • An element that is easy to show and hide, including an open boolean attribute on the element itself.
  • Two versions: a standard popover or modal version.
  • A ::backdrop pseudo-element for modal types.
  • Built-in focus: see dialog focusing steps.
  • ARIA role support (dialog is the implied default). Also accepts the alertdialog role.
  • A pending stack for multiple dialogs.
  • A DOM interface with the open boolean and methods show, showModal, and close.

And those are just some highlights! Showing content on top of other content has never been easier.

This is the evolution of the web at it's best. Identifying a major developer struggle and helping solve it.

Direct Link to ArticlePermalink

The post The dialog element appeared first on CSS-Tricks.

Categories: Web Technologies

What are Durable Functions?

Tue, 10/09/2018 - 06:55

Oh no! Not more jargon! What exactly does the term Durable Functions mean? Durable functions have to do with Serverless architectures. It’s an extension of Azure Functions that allow you to write stateful executions in a serverless environment.

Think of it this way. There are a few big benefits that people tend to focus on when they talk about Serverless Functions:

  • They’re cheap
  • They scale with your needs (not necessarily, but that’s the default for many services)
  • They allow you to write event-driven code

Let’s talk about that last one for a minute. When you can write event-driven code, you can break your operational needs down into smaller functions that essentially say: when this request comes in, run this code. You don’t mess around with infrastructure, that’s taken care of for you. It’s a pretty compelling concept.

In this paradigm, you can break your workflow down into smaller, reusable pieces which, in turn, can make them easier to maintain. This also allows you to focus on your business logic because you’re boiling things down to the simplest code you need run on your server.

So, here’s where Durable Functions come in. You can probably guess that you’re going to need more than one function to run as your application grows in size and has to maintain more states. And, in many cases, you’ll need to coordinate them and specify the order in which they should be run for them to be effective. It's worth mentioning at this point that Durable Functions are a pattern available only in Azure. Other services have variations on this theme. For example, the AWS version is called Step Functions. So, while we're talking about something specific to Azure, it applies more broadly as well.

Durable in action, some examples

Let’s say you’re selling airline tickets. You can imagine that as a person buys a ticket, we need to:

  1. check for the availability of the ticket
  2. make a request to get the seat map
  3. get their mileage points if they’re a loyalty member
  4. give them a mobile notification if the payment comes through and they have an app installed/have requested notifications

(There’s typically more, but we’re using this as a base example)

Sometimes these will all run be run concurrently, sometimes not. For instance, let’s say they want to purchase the ticket with their mileage rewards. Then you’d have to first check the awards, and then the availability of the ticket. And then do some dark magic to make sure no customers, even data scientists, can actually understand the algorithm behind your rewards program.

Orchestrator functions

Whether you’re running these functions at the same moment, running them in order, or running them according to whether or not a condition is met, you probably want to use what’s called an orchestrator function. This is a special type of function that defines your workflows, doing, as you might expect, orchestrating the other functions. They automatically checkpoint their progress whenever a function awaits, which is extremely helpful for managing complex asynchronous code.

Without Durable Functions, you run into a problem of disorganization. Let’s say one function relies on another to fire. You could call the other function directly from the first, but whoever is maintaining the code would have to step into each individual function and keep in their mind how it’s being called while maintaining them separately if they need changes. It's pretty easy to get into something that resembles callback hell, and debugging can get really tricky.

Orchestrator functions, on the other hand, manage the state and timing of all the other functions. The orchestrator function will be kicked off by an orchestration trigger and supports both inputs and outputs. You can see how this would be quite handy! You’re managing the state in a comprehensive way all in one place. Plus, the serverless functions themselves can keep their jobs limited to what they need to execute, allowing them to be more reusable and less brittle.

Let’s go over some possible patterns. We’ll move beyond just chaining and talk about some other possibilities.

Pattern 1: Function chaining

This is the most straightforward implementation of all the patterns. It's literally one orchestrator controlling a few different steps. The orchestrator triggers a function, the function finishes, the orchestrator registers it, and then then next one fires, and so on. Here's a visualization of that in action:

See the Pen Durable Functions: Pattern #1- Chaining by Sarah Drasner (@sdras) on CodePen.

Here's a simple example of that pattern with a generator.

const df = require("durable-functions") module.exports = df(function*(ctx) { const x = yield ctx.df.callActivityAsync('fn1') const y = yield ctx.df.callActivityAsync('fn2', x) const z = yield ctx.df.callActivityAsync('fn3', y) return yield ctx.df.callActivityAsync('fn3', z) })

I love generators! If you're not familiar with them, check out this great talk by Bodil on the subject).

Pattern 2: Fan-out/fan-in

If you have to execute multiple functions in parallel and need to fire one more function based on the results, a fan-out/fan-in pattern might be your jam. We'll accumulate results returned from the functions from the first group of functions to be used in the last function.

See the Pen Durable Functions: Pattern #2, Fan Out, Fan In by Sarah Drasner (@sdras) on CodePen.

const df = require('durable-functions') module.exports = df(function*(ctx) { const tasks = [] // items to process concurrently, added to an array const taskItems = yield ctx.df.callActivityAsync('fn1') taskItems.forEach(item => tasks.push(ctx.df.callActivityAsync('fn2', item)) yield ctx.df.task.all(tasks) // send results to last function for processing yield ctx.df.callActivityAsync('fn3', tasks) }) Pattern 3: Async HTTP APIs

It's also pretty common that you'll need to make a request to an API for an unknown amount of time. Many things like the distance and amount of requests processed can make the amount of time unknowable. There are situations that require some of this work to be done first, asynchronously, but in tandem, and then another function to be fired when the first few API calls are completed. Async/await is perfect for this task.

See the Pen Durable Functions: Pattern #3, Async HTTP APIs by Sarah Drasner (@sdras) on CodePen.

const df = require('durable-functions') module.exports = df(async ctx => { const fn1 = ctx.df.callActivityAsync('fn1') const fn2 = ctx.df.callActivityAsync('fn2') // the responses come in and wait for both to be resolved await fn1 await fn2 // then this one this one is called await ctx.df.callActivityAsync('fn3') })

You can check out more patterns here! (Minus animations. &#x1f609;)

Getting started

If you'd like to play around with Durable Functions and learn more, there's a great tutorial here, with corresponding repos to fork and work with. I'm also working with a coworker on another post that will dive into one of these patterns that will be out soon!

Alternative patterns

Azure offers a pretty unique thing in Logic Apps, which allows you the ability to design workflows visually. I'm usually a code-only-no-WYSIWYG lady myself, but one of the compelling things about Logic Apps is that they have readymade connectors with services like Twilio and SendGrid, so that you don't have to write that slightly annoying, mostly boilerplate code. It can also integrate with your existing functions so you can abstract away just the parts connect to middle-tier systems and write the rest by hand, which can really help with productivity.

The post What are Durable Functions? appeared first on CSS-Tricks.

Categories: Web Technologies

Unbuttoning Buttons

Mon, 10/08/2018 - 13:21

We dug into overriding default buttons styles not long ago here on CSS-Tricks. With garden-variety fully cross-browser-supported styles, you're looking at 6-10 CSS rules to tear down anything you need to off a button and then put in place your own styles. Hardly a big deal if you ask me, especially since it's extremely likely you'll be styling buttons anyway.

Scott O'Hara has taken a look as well. I think the solution offered to use a <span role="button" tabindex="0" onClick="..."> is a little bizarre since you need bring your own keyboard handling with is non-trivial and requires JavaScript. But there are a couple of interesting other CSS explorations, neither of which stacked up for different reasons:

  • display: contents; - some semantics-based accessibility problems.
  • all: unset; - doesn't reset display value, not good enough browser support.

Direct Link to ArticlePermalink

The post Unbuttoning Buttons appeared first on CSS-Tricks.

Categories: Web Technologies

Using Recompose to Share Functionality Between React Components

Mon, 10/08/2018 - 06:46

Sharing functionality between React components is a pretty common need. The concept is that we can establish the behavior in one place and then extend it across different components. Higher-Order Components are one way to do this. Yet, there is another way using a library called Recompose.

GitHub Repo

What is Recompose?

The documentation helps us answer that:

Recompose is a React utility belt for function components and higher-order components. Think of it like lodash for React.

Basically, it’s a library for React that contains a bunch of helpers that return different higher-order components — which is nice because it takes some of the grunt work out of defining common React patterns and making them immediately available to extend to other components.

What exactly can it do? Well, let’s walk through a few examples together.

Add state to functional stateless components

If you couldn’t guess it by the name, a functional stateless component does not have any states. It merely accepts props and returns UI to the front end.

const Greeting = props => <p> Hello, {props.name}! </p>

In scenarios where you want to make use of state in your functional stateless component, you have to convert it to a class component. This is where Recompose comes in handy.

Recompose provides you with the withState() helper to add state to your functional stateless components. It manages a single state value. You cannot manage more than one state value in withState() like you will do in your class component. You pass in a function to update the state value and an optional default stated value.

Here’s how withState() is structured:

withState( stateName: string, // the name we call our state stateUpdaterName: string, // the name of the function to call initialState: any | (props: Object) => any // optional default state to pass ): HigherOrderComponent

A counter is a common example that’s used to demonstrate a concept. Here’s how we can create a super simple counter using Recompose’s withState() helper:

const App = withState("count", "handleCounter", 0)(({ count, handleCounter }) => { return ( <div> <p>{count}</p> <button onClick={() => handleCounter(n => n + 1)}>Increment</button> <button onClick={() => handleCounter(n => n - 1)}>Decrement</button> </div> ); });

Since the withState() helper is already available to us, we can call it right away and provide it with the parameters it needs. Again, those are:

  • stateName: The name we call our state
  • stateUpdaterName: The name of the function to call
  • initialState: Optional default state to pass

Those parameters are then integrated into the UI markup we want to render on the front end.

There’s another way we could have made our counter component and it’s worth looking at to get more practice putting a Recompose helper to use.

First, we create a higher-order component using withState() and the required parameters.

const enhanced = withState("counter", "handleCounter", 0);

Next, we make the Counter component, working in the withState() parameters:

const Counter = ({ counter, handleCounter }) => ( <div> <h1>{counter}</h1> <button onClick={() => handleCounter(n => n + 1)}>Increment</button> <button onClick={() => handleCounter(n => n - 1)}>Decrement</button> </div> );

Note that the name of the state and updater function is passed as props to the Counter component.

Finally, we create our App component by wrapping the Counter component in the higher-order enhanced component.

const App = enhanced(Counter);

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

Here is another popular approach:

const enhanced = withState("count", "handleCounter", 0); const App = enhanced(({ count, handleCounter }) => { return ( <div> <p>{count}</p> <button onClick={() => handleCounter(n => n + 1)}>Increment</button> <button onClick={() => handleCounter(n => n - 1)}>Decrement</button> </div> ); });

See the Pen Recompose withState v2 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Handle state using withHandlers()

Recompose also has a withHandlers() helper that allows you handle state by defining functions that will be used to update a component’s state. And, you can use it right alongside withState()!

These are basically higher-order functions that take in props and return a function handler. Let’s break down the structure like we did in the previous example.

withHandlers({ incrementCounter: props => event => { event.preventDefault(); props.handleCounter(props.count + 1); } })

First off, we’ve identified incrementCounter, which will be available to our Counter component to update the count value on click.

Next, we construct the counter like we did before — as a higher-order component using withState():

const enhancedState = withState("count", "handleCounter", 0);

Now, we define our functions putting withHandlers() to use:

const enhancedHandler = withHandlers({ incrementCounter: props => event => { event.preventDefault(); props.handleCounter(props.count + 1); }, decrementCounter: props => event => { event.preventDefault(); props.handleCounter(props.count - 1); } });

We’ve constructed a higher-order component we’re calling enhancedHandler and used withState() to define two function handlers in it: incrementCounter and decrementCounter. These handlers contain parameters that will be received as props by the components that call them. They will be needed if we want to update the state of the component defined using withState().

Alright, on to creating our counter component:

const Counter = ({ count, incrementCounter, decrementCounter }) => ( <div> <h1>{count}</h1> <button onClick={incrementCounter}>Increment</button> <button onClick={decrementCounter}>Decrement</button> </div> );

See that? The state and handlers are expected to be passed as props to the counter component.

To make use of the higher-order components we defined, we have to pass the Counter component to enhancedHandler and wrap that as a parameter to enhancedState.

In other words:

const App = enhancedState(enhancedHandler(Counter));

See the Pen Recompose withState & withHandlers by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Composing multiple higher-order components

In that last example, we made use of two higher-order components. Is there a better of chaining them together? Most definitely! Recompose provides us with a compose() helper to do exactly that. We can use compose() to create a component that composes both higher-order components in one fell swoop.

const enhanced = compose( withState("count", "handleCounter", 0), withHandlers({ incrementCounter: props => event => { event.preventDefault(); props.handleCounter(props.count + 1); }, decrementCounter: props => event => { event.preventDefault(); props.handleCounter(props.count - 1); } }) );

Now, we can use the enhanced component in our App component:

const App = enhanced(({ count, incrementCounter, decrementCounter }) => { return ( <div> <p>{count}</p> <button onClick={incrementCounter}>Increment</button> <button onClick={decrementCounter}>Decrement</button> </div> ); });

See the Pen Recompose - compose withState & withHandlers by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Manage state using Redux like reducer

Another nice thing Recompose does is allow you to manage state using a reducer function (withReducer). A reducer updates the state of a component in response to a particular action.

The structure of the withReducer() looks like this:

withReducer<S, A>( stateName: string, dispatchName: string, reducer: (state: S, action: A) => S, initialState: S | (ownerProps: Object) => S ): HigherOrderComponent</S>

The first parameter is the name of the state. The second is the dispatch method. dispatch will be used in dispatching actions like we have in Redux. Next, we have the reducer and the initial state.

In the context of our counter component, withReducer() will update the state of the count: the count will go up with an action we’ll call increment and, conversely, the count will go down with an action we’ll call decrement.

First, we create an enhanced component by composing withReducer and withHandlers.

const enhanced = compose( withReducer( "count", "dispatch", (state, action) => { switch (action.type) { case "INCREMENT": return state + 1; case "DECREMENT": return state - 1; default: return state; } }, 0 ), withHandlers({ incrementCounter: ({ dispatch }) => e => dispatch({ type: "INCREMENT" }), decrementCounter: ({ dispatch }) => e => dispatch({ type: "DECREMENT" }) }) );

incrementCounter and decrementCounter will respond to DOM events and dispatch an action type. The state will be updated depending on the action type. Next, we need to make use of this in our component.

const App = enhanced(({ count, incrementCounter, decrementCounter }) => { return ( <div> <p>{count}</p> <button onClick={incrementCounter}>Increment</button> <button onClick={decrementCounter}>Decrement</button> </div> ); });

See the Pen Recompose - reducer by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Pretty neat, right?

Hopefully this gives you a good idea of what Recompose is and how the library’s wealth of helpers can streamline React development, particularly when it comes to managing and calling states.

Naturally, there’s a lot more to Recompose than what we’ve covered here. A quick scan of the API documentation will show that there are many higher-order components that you can put to use, depending on your application’s requirements. Go forth, build, and please feel free to drop a comment in if you have any questions!

The post Using Recompose to Share Functionality Between React Components appeared first on CSS-Tricks.

Categories: Web Technologies

Material Design Animation Guides

Fri, 10/05/2018 - 15:53

I've seen two guides posted to Medium about animation in the last month that have seriously blown up!

There is a lot to learn in each one! The demonstration animations they use are wonderfully well done and each guide demonstrates an interesting and effective animation technique, often paired next to a less successful technique to drive the point home. They are both heavily focused on Material Design though, which is fine, but I think Val Head said it best:

Google wrote material design for branding Google things. When you use material design on things that aren’t Google, you’re kind of using Google’s branding on a thing that is not Google, and that’s weird. Material design is Google’s opinion on motion. It’s Google’s branding opinion on motion. It’s not a de facto standard of how motion should happen.

The post Material Design Animation Guides appeared first on CSS-Tricks.

Categories: Web Technologies

One Invalid Pseudo Selector Equals an Entire Ignored Selector

Fri, 10/05/2018 - 06:45

Perhaps you know this one: if any part of a selector is invalid, it invalidates the whole selector. For example:

div, span::butt { background: red; }

Even though div is a perfectly valid selector, span:butt is not, thus the entire selector is invalidated — neither divs nor span::butt elements on the page will have a red background.

Normally that's not a terribly huge problem. It may even be even useful, depending on the situation. But there are plenty of situations where it has kind of been a pain in the, uh, <code>:butt.

Here's a classic:

::selection { background: lightblue; }

For a long time, Firefox didn't understand that selector, and required a vendor prefix (::-moz-selection) to get the same effect. (This is no longer the case in Firefox 62+, but you take the point.)

In other words, this wasn't possible:

/* would break for everyone */ ::selection, ::-moz-selection { background: lightblue; }

That would break for browsers that understood ::selection and break for Firefox that only understood ::-moz-selection. It made it ripe territory for a preprocessor @mixin, that's for sure.

That was annoying enough that browsers have apparently fixed it. In a conversation with Estelle Weyl, I learned that this is being changed. She wrote in the MDN docs:

Generally, if there is an invalid pseudo-element or pseudo-class within in a chain or group of selectors, the whole selector list is invalid. If a pseudo-element (but not pseudo-class) has a -webkit- prefix, As of Firefox 63, Blink, Webkit and Gecko browsers assume it is valid, not invalidating the selector list.

This isn't for any selector; it's specifically for pseudo-elements. That is, double colons (::).

Here's a test:

See the Pen Ignored Invalid Selecotrs??? by Chris Coyier (@chriscoyier) on CodePen.

I'd call that a positive change.

The post One Invalid Pseudo Selector Equals an Entire Ignored Selector appeared first on CSS-Tricks.

Categories: Web Technologies

CSS Only Floated Labels with :placeholder-shown pseudo class

Thu, 10/04/2018 - 11:08

The floated label technique has been around for a good long while and the general idea is this: we have an text input with the placeholder attribute acting as a label. When a user types into that input, the label moves from inside the input to outside of it.

Like so:

Although I don’t see this pattern used on the web all that much, I do think it’s an interesting one! There are different approaches to it, but Nick Salloum describes a new one using a combination of :not and :placeholder-shown:

This UI technique does indeed slightly bend the definitions of label and placeholder listed above, in the sense that we’re giving the placeholder more initial importance in having to explain the input to the user, but it’s a tradeoff for a neat UI component, and one that I’m personally comfortable making.

I wonder if there are other peculiar ways :not and :placeholder-shown could be put to use.

Direct Link to ArticlePermalink

The post CSS Only Floated Labels with :placeholder-shown pseudo class appeared first on CSS-Tricks.

Categories: Web Technologies

Moving Backgrounds With Mouse Position

Thu, 10/04/2018 - 07:04

Let's say you wanted to move the background-position on an element as you mouse over it to give the design a little pizzazz. You have an element like this:

<div class="module" id="module"></div>

And you toss a background on it:

.module { background-image: url(big-image.jpg); }

You can adjust the background-position in JavaScript like this:

const el = document.querySelector("#module"); el.addEventListener("mousemove", (e) => { el.style.backgroundPositionX = -e.offsetX + "px"; el.style.backgroundPositionY = -e.offsetY + "px"; });

See the Pen Move a background with mouse by Chris Coyier (@chriscoyier) on CodePen.

Or, you could update CSS custom properties in the JavaScript instead:

const el = document.querySelector("#module"); el.addEventListener("mousemove", (e) => { el.style.setProperty('--x', -e.offsetX + "px"); el.style.setProperty('--y', -e.offsetY + "px"); }); .module { --x: 0px; --y: 0px; background-image: url(large-image.jpg); background-position: var(--x) var(--y); }

See the Pen Move a background with mouse by Chris Coyier (@chriscoyier) on CodePen.

Here's an example that moves the background directly in JavaScript, but with a transition applied so it slides to the new position rather than jerking around the first time you enter:

See the Pen Movable Background Ad by Chris Coyier (@chriscoyier) on CodePen.

Or, you could move an actual element instead (rather than the background-position). You'd do this if there is some kind of content or interactivity on the sliding element. Here's an example of that, which sets CSS custom properties again, but then actually moves the element via a CSS translate() and a calc() to temper the speed.

See the Pen Hotjar Moving Heatmap Ad by Chris Coyier (@chriscoyier) on CodePen.

I'm sure there are loads of other ways to do this — a moving SVG viewBox, scripts controlling a canvas, webGL... who knows! If you have some fancier ways to handle this, link 'em up in the comments.

The post Moving Backgrounds With Mouse Position appeared first on CSS-Tricks.

Categories: Web Technologies

The industry’s best open API

Thu, 10/04/2018 - 07:02

(This is a sponsored post.)

With our robust SDK, super clean dashboard, detailed documentation, and world-class support, HelloSign API is one of the most flexible and powerful APIs on the market. Start building for free today.

Direct Link to ArticlePermalink

The post The industry’s best open API appeared first on CSS-Tricks.

Categories: Web Technologies

The Codification of Design

Wed, 10/03/2018 - 15:20

Jonathan Snook on managing the complexity between what designers make and what developers end up building:

Everything that a designer draws in a Sketch or Photoshop file needs to be turned into code. Code needs to be developed, delivered to the user, and maintained by the team.

That means that complexity in design can lead to complexity in code.

That’s not to say that complexity isn’t allowed. However, it is important to consider what the impact of that complexity is—especially as it relates to your codebase.

Jonathan continues in that post to argue that designers and developers need to be in a constant feedback loop in order to properly assess whether the complexity of the design is worth the complexity of the engineering solution.

I’ve been thinking about this sort of thing for a really long time as it applies to my work in design systems — I have a feeling this issue stems from the fact that designers and developers are trading with different currencies. Designers generally care about the user experience above anything else while developers may prioritize the code under the hood, willing to over-engineer something for this one tiny detail.

As Snook mentions later in his post, pattern libraries won’t solve this problem entirely:

This is why it’s important to have these conversations during the design process. It’s important to understand what the priorities are within your team. It’s important to understand what tradeoffs you’re willing to make. Without consensus within your team, you’ll continue to butt heads as the requirements of the front-end development team conflict with the requirements of the design team.

So, the best way to get those two groups to exchange the same currency is with talking, instead of tools. Or, perhaps by designing with code.

Direct Link to ArticlePermalink

The post The Codification of Design appeared first on CSS-Tricks.

Categories: Web Technologies

How Do You Put a Border on Three Sides of an Element?

Wed, 10/03/2018 - 09:12

I saw a little conversation about this the other day and figured it would be fun to look at all the different ways to do it. None of them are particularly tricky, but perhaps you'll favor one over another for clarity of syntax, efficiency, or otherwise.

Let's assume we want a border on the bottom, left, and right (but not top) of an element.

Explicitly declare each side .three-sides { border-bottom: 2px solid black; border-right: 2px solid black; border-left: 2px solid black; }

While that's pretty clear, it's still making use of shorthand. Completely expanded it would be like this:

.three-sides { border-bottom-color: black; border-bottom-style: solid; border-bottom-width: 2px; border-left-color: black; border-left-style: solid; border-left-width: 2px; border-right-color: black; border-right-style: solid; border-right-width: 2px; } Knock off one of the sides

You can save a little code by declaring the border on all four sides with shorthand and then removing the one you don't want:

.three-sides { border: 2px solid black; border-top: 0; } Shorthand just the width .three-sides { border-color: black; border-style: solid; /* top, right, bottom, left - just like margin and padding */ border-width: 0 2px 2px 2px; }

As a fun little aside here, you don't need to declare the border color to get a border to show up, because the color will inherit the currentColor! So this would work fine:

.three-sides { /* no color declared */ border-style: solid; border-width: 0 2px 2px 2px; }

And you'd have red borders if you did:

.three-sides { color: red; border-style: solid; border-width: 0 2px 2px 2px; }

Strange, but true.

If you want to add the color explicity, you can kinda mix-and-match shorthand, so this will work fine:

.three-sides { border: solid green; border-width: 2px 0 2px 2px; }

The post How Do You Put a Border on Three Sides of an Element? appeared first on CSS-Tricks.

Categories: Web Technologies

Pages